diff options
author | 2022-10-31 16:17:08 -0400 | |
---|---|---|
committer | 2022-10-31 16:17:08 -0400 | |
commit | c57282a8cb70113071a9c1d1f9e0868a533d9500 (patch) | |
tree | ee9fcd7f0078c2a4d08bc3c5174e700a0e98265c | |
parent | AntiSpoof: bump to master at 2022-10-31 (diff) | |
download | extensions-c57282a8cb70113071a9c1d1f9e0868a533d9500.tar.gz extensions-c57282a8cb70113071a9c1d1f9e0868a533d9500.tar.bz2 extensions-c57282a8cb70113071a9c1d1f9e0868a533d9500.zip |
Update CheckUser
Signed-off-by: Brian Evans <grknight@gentoo.org>
335 files changed, 27940 insertions, 9140 deletions
diff --git a/CheckUser/.eslintignore b/CheckUser/.eslintignore new file mode 100644 index 00000000..57872d0f --- /dev/null +++ b/CheckUser/.eslintignore @@ -0,0 +1 @@ +/vendor/ diff --git a/CheckUser/.eslintrc.json b/CheckUser/.eslintrc.json index d4172e97..04f9da7a 100644 --- a/CheckUser/.eslintrc.json +++ b/CheckUser/.eslintrc.json @@ -1,11 +1,6 @@ { "root": true, "extends": [ - "wikimedia/client", - "wikimedia/jquery", - "wikimedia/mediawiki" - ], - "rules": { - "no-jquery/no-global-selector": "off" - } + "wikimedia/server" + ] } diff --git a/CheckUser/.gitignore b/CheckUser/.gitignore index a9c17893..8cbb489c 100644 --- a/CheckUser/.gitignore +++ b/CheckUser/.gitignore @@ -1,6 +1,7 @@ /composer.lock /node_modules/ /vendor/ +tests/selenium/log # Editors *.kate-swp @@ -12,6 +13,7 @@ .buildpath .classpath .settings +.env cscope.files cscope.out *.orig @@ -22,3 +24,5 @@ project.index sublime-* sftp-config.json /.eslintcache +## vscode +.vscode/ diff --git a/CheckUser/.phan/config.php b/CheckUser/.phan/config.php index 837b5111..8701b942 100644 --- a/CheckUser/.phan/config.php +++ b/CheckUser/.phan/config.php @@ -9,6 +9,7 @@ $cfg['directory_list'] = array_merge( '../../extensions/CentralAuth', '../../extensions/EventLogging', '../../extensions/GuidedTour', + '../../extensions/GlobalBlocking' ] ); @@ -19,6 +20,7 @@ $cfg['exclude_analysis_directory_list'] = array_merge( '../../extensions/CentralAuth', '../../extensions/EventLogging', '../../extensions/GuidedTour', + '../../extensions/GlobalBlocking' ] ); diff --git a/CheckUser/.phpcs.xml b/CheckUser/.phpcs.xml index 1090030b..99b2cb57 100644 --- a/CheckUser/.phpcs.xml +++ b/CheckUser/.phpcs.xml @@ -1,16 +1,13 @@ <?xml version="1.0"?> <ruleset> - <rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki"> - <exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationProtected" /> - <exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic" /> - <exclude name="MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName" /> - <exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment" /> - <exclude name="MediaWiki.ControlStructures.AssignmentInControlStructures.AssignmentInControlStructures" /> - </rule> + <rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki" /> <rule ref="Generic.Files.LineLength"> <exclude-pattern>CheckUser\.alias\.php</exclude-pattern> </rule> + <rule ref="MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName"> + <exclude-pattern>src/Hooks\.php</exclude-pattern> + </rule> <file>.</file> - <arg name="extensions" value="php,inc" /> + <arg name="extensions" value="php" /> <arg name="encoding" value="UTF-8" /> </ruleset> diff --git a/CheckUser/CheckUser.alias.php b/CheckUser/CheckUser.alias.php index 05978cbf..7c907001 100644 --- a/CheckUser/CheckUser.alias.php +++ b/CheckUser/CheckUser.alias.php @@ -14,13 +14,14 @@ $specialPageAliases['en'] = [ 'CheckUserLog' => [ 'CheckUserLog' ], 'Investigate' => [ 'Investigate' ], 'InvestigateBlock' => [ 'InvestigateBlock' ], - 'InvestigateLog' => [ 'InvestigateLog' ], ]; /** Arabic (العربية) */ $specialPageAliases['ar'] = [ 'CheckUser' => [ 'تدقيق_مستخدم' ], 'CheckUserLog' => [ 'سجل_تدقيق_المستخدم' ], + 'Investigate' => [ 'تحقيق' ], + 'InvestigateBlock' => [ 'منع_التحقيق' ], ]; /** Egyptian Arabic (مصرى) */ @@ -100,6 +101,7 @@ $specialPageAliases['ce'] = [ $specialPageAliases['cs'] = [ 'CheckUser' => [ 'Zkontrolovat uživatele' ], 'CheckUserLog' => [ 'Protokolovací záznamy kontrol uživatele' ], + 'Investigate' => [ 'Prošetřit_uživatele' ], ]; /** German (Deutsch) */ @@ -135,7 +137,6 @@ $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) */ @@ -148,6 +149,8 @@ $specialPageAliases['eu'] = [ $specialPageAliases['fa'] = [ 'CheckUser' => [ 'بازرسی_کاربر' ], 'CheckUserLog' => [ 'سیاهه_بازرس_کاربر' ], + 'Investigate' => [ 'بررسی' ], + 'InvestigateBlock' => [ 'بررسی_بستن' ], ]; /** Finnish (suomi) */ @@ -187,7 +190,6 @@ $specialPageAliases['he'] = [ 'CheckUser' => [ 'בדיקת_משתמש' ], 'CheckUserLog' => [ 'יומן_בדיקת_משתמשים' ], 'Investigate' => [ 'חקירה' ], - 'InvestigateLog' => [ 'יומן_חקירות' ], ]; /** Hindi (हिन्दी) */ @@ -259,6 +261,8 @@ $specialPageAliases['km'] = [ $specialPageAliases['ko'] = [ 'CheckUser' => [ '사용자검사', '사용자확인' ], 'CheckUserLog' => [ '사용자검사기록', '사용자확인기록' ], + 'Investigate' => [ '조사' ], + 'InvestigateBlock' => [ '조사차단' ], ]; /** Colognian (Ripoarisch) */ diff --git a/CheckUser/Gruntfile.js b/CheckUser/Gruntfile.js index 75a9a1dc..f396b04f 100644 --- a/CheckUser/Gruntfile.js +++ b/CheckUser/Gruntfile.js @@ -1,12 +1,6 @@ -/*! - * Grunt file - * - * @package CheckUser - */ - -/* eslint-env node */ +'use strict'; module.exports = function ( grunt ) { - var conf = grunt.file.readJSON( 'extension.json' ); + const conf = grunt.file.readJSON( 'extension.json' ); grunt.loadNpmTasks( 'grunt-eslint' ); grunt.loadNpmTasks( 'grunt-banana-checker' ); grunt.loadNpmTasks( 'grunt-stylelint' ); @@ -16,19 +10,17 @@ module.exports = function ( grunt ) { options: { cache: true }, - all: [ - '*.{js,json}', - 'modules/**/*.{js,json}' - ] + all: '.' }, stylelint: { all: [ - 'modules/**/*.{css,less}' + '**/*.{css,less}', + '!vendor/**', + '!node_modules/**' ] }, banana: conf.MessagesDirs } ); grunt.registerTask( 'test', [ 'eslint', 'banana', 'stylelint' ] ); - grunt.registerTask( 'default', 'test' ); }; diff --git a/CheckUser/archives/patch-cu_changes_indexes.sql b/CheckUser/archives/patch-cu_changes_indexes.sql deleted file mode 100644 index 9c81058f..00000000 --- a/CheckUser/archives/patch-cu_changes_indexes.sql +++ /dev/null @@ -1,11 +0,0 @@ --- Improves indexes for better peformance with large result sets --- vim: autoindent syn=mysql sts=2 sw=2 --- Replace /*$wgDBprefix*/ with the proper prefix - -ALTER TABLE /*$wgDBprefix*/cu_changes - ADD INDEX cuc_ip_hex_time (cuc_ip_hex,cuc_timestamp), - ADD INDEX cuc_user_ip_time (cuc_user,cuc_ip,cuc_timestamp), - ADD INDEX cuc_xff_hex_time (cuc_xff_hex,cuc_timestamp), - DROP INDEX cuc_ip_hex, - DROP INDEX cuc_xff_hex, - DROP INDEX cuc_user; diff --git a/CheckUser/archives/patch-cu_changes_indexes2.sql b/CheckUser/archives/patch-cu_changes_indexes2.sql deleted file mode 100644 index 645962ba..00000000 --- a/CheckUser/archives/patch-cu_changes_indexes2.sql +++ /dev/null @@ -1,7 +0,0 @@ --- Improves indexes for better peformance with large result sets --- vim: autoindent syn=mysql sts=2 sw=2 --- Replace /*$wgDBprefix*/ with the proper prefix - -ALTER TABLE /*$wgDBprefix*/cu_changes - ADD INDEX cuc_user_ip_time (cuc_user,cuc_ip,cuc_timestamp), - DROP INDEX cuc_user_time; diff --git a/CheckUser/archives/patch-cu_changes_privatedata.sql b/CheckUser/archives/patch-cu_changes_privatedata.sql deleted file mode 100644 index 47dd8e5d..00000000 --- a/CheckUser/archives/patch-cu_changes_privatedata.sql +++ /dev/null @@ -1,6 +0,0 @@ --- Add column for storing encrypted private data --- vim: autoindent syn=mysql sts=2 sw=2 --- Replace /*$wgDBprefix*/ with the proper prefix - -ALTER TABLE /*$wgDBprefix*/cu_changes - ADD COLUMN (`cuc_private` MEDIUMBLOB default NULL); diff --git a/CheckUser/composer.json b/CheckUser/composer.json index 50a9b603..c0aaff44 100644 --- a/CheckUser/composer.json +++ b/CheckUser/composer.json @@ -1,23 +1,25 @@ { "require-dev": { - "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" + "mediawiki/mediawiki-codesniffer": "39.0.0", + "mediawiki/mediawiki-phan-config": "0.11.1", + "mediawiki/minus-x": "1.1.1", + "php-parallel-lint/php-console-highlighter": "1.0.0", + "php-parallel-lint/php-parallel-lint": "1.3.2" }, "scripts": { "test": [ "parallel-lint . --exclude vendor --exclude node_modules", - "phpcs -p -s", + "@phpcs", "minus-x check ." ], "fix": [ "minus-x fix .", "phpcbf" - ] + ], + "phan": "phan -d . --long-progress-bar", + "phpcs": "phpcs -sp --cache" }, "require": { - "firebase/php-jwt": "~5.2.0" + "firebase/php-jwt": "^5.2.0" } } diff --git a/CheckUser/cu_changes.pg.sql b/CheckUser/cu_changes.pg.sql deleted file mode 100644 index b7232d03..00000000 --- a/CheckUser/cu_changes.pg.sql +++ /dev/null @@ -1,35 +0,0 @@ --- Tables for the CheckUser extension --- vim: autoindent syn=pgsql sts=2 sw=2 --- This is the Postgres version --- See cu_changes.sql for details on each column - -BEGIN; - -CREATE SEQUENCE cu_changes_cu_id_seq; -CREATE TABLE cu_changes ( - cuc_id INTEGER NOT NULL DEFAULT nextval('cu_changes_cu_id_seq'), - cuc_namespace SMALLINT NOT NULL DEFAULT 0, - cuc_title TEXT NOT NULL DEFAULT '', - cuc_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, - cuc_user_text TEXT NOT NULL, - cuc_actiontext TEXT NOT NULL DEFAULT '', - cuc_comment TEXT NOT NULL DEFAULT '', - cuc_minor CHAR NOT NULL DEFAULT 0, - cuc_page_id INTEGER NULL REFERENCES page(page_id) ON DELETE SET NULL, - cuc_this_oldid INTEGER NOT NULL DEFAULT 0, - cuc_last_oldid INTEGER NOT NULL DEFAULT 0, - cuc_type SMALLINT NOT NULL DEFAULT 0, - cuc_timestamp TIMESTAMPTZ, - cuc_ip CIDR, - cuc_ip_hex TEXT, - cuc_xff TEXT, - cuc_xff_hex TEXT, - cuc_agent TEXT, - cuc_private BYTEA -); - -CREATE INDEX cuc_ip_hex_time ON cu_changes( cuc_ip_hex, cuc_timestamp ); -CREATE INDEX cuc_user_ip_time ON cu_changes( cuc_user, cuc_ip, cuc_timestamp ); -CREATE INDEX cuc_xff_hex_time ON cu_changes( cuc_xff_hex, cuc_timestamp ); - -COMMIT; diff --git a/CheckUser/cu_changes.sql b/CheckUser/cu_changes.sql deleted file mode 100644 index e88b52c8..00000000 --- a/CheckUser/cu_changes.sql +++ /dev/null @@ -1,60 +0,0 @@ --- Tables for the CheckUser extension --- vim: autoindent syn=mysql sts=2 sw=2 - -CREATE TABLE /*_*/cu_changes ( - -- Primary key - cuc_id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, - - -- When pages are renamed, their RC entries do _not_ change. - cuc_namespace int NOT NULL default '0', - cuc_title varchar(255) binary NOT NULL default '', - - -- user.user_id - cuc_user INTEGER NOT NULL DEFAULT 0, - cuc_user_text VARCHAR(255) NOT NULL DEFAULT '', - - -- Edit summary - cuc_actiontext varchar(255) binary NOT NULL default '', - cuc_comment varchar(255) binary NOT NULL default '', - cuc_minor bool NOT NULL default '0', - - -- Key to page_id (was cur_id prior to 1.5). - -- This will keep links working after moves while - -- retaining the at-the-time name in the changes list. - cuc_page_id int(10) unsigned NOT NULL default '0', - - -- rev_id of the given revision - cuc_this_oldid int(10) unsigned NOT NULL default '0', - - -- rev_id of the prior revision, for generating diff links. - cuc_last_oldid int(10) unsigned NOT NULL default '0', - - -- RecentChange type identifiers: RC_EDIT, RC_NEW or RC_LOG - cuc_type tinyint(3) unsigned NOT NULL default '0', - - -- Event timestamp - cuc_timestamp CHAR(14) NOT NULL default '', - - -- IP address, visible - cuc_ip VARCHAR(255) NULL default '', - - -- IP address as hexidecimal - cuc_ip_hex VARCHAR(255) default NULL, - - -- XFF header, visible, all data - cuc_xff VARCHAR(255) BINARY NULL default '', - - -- XFF header, last IP, as hexidecimal - cuc_xff_hex VARCHAR(255) default NULL, - - -- User agent - cuc_agent VARCHAR(255) BINARY default NULL, - - -- Private Data - cuc_private MEDIUMBLOB default NULL -) /*$wgDBTableOptions*/; - -CREATE INDEX /*i*/cuc_ip_hex_time ON /*_*/cu_changes (cuc_ip_hex,cuc_timestamp); -CREATE INDEX /*i*/cuc_user_ip_time ON /*_*/cu_changes (cuc_user,cuc_ip,cuc_timestamp); -CREATE INDEX /*i*/cuc_xff_hex_time ON /*_*/cu_changes (cuc_xff_hex,cuc_timestamp); -CREATE INDEX /*i*/cuc_timestamp ON /*_*/cu_changes (cuc_timestamp); diff --git a/CheckUser/cu_log.pg.sql b/CheckUser/cu_log.pg.sql deleted file mode 100644 index 8ccf17d0..00000000 --- a/CheckUser/cu_log.pg.sql +++ /dev/null @@ -1,25 +0,0 @@ - -BEGIN; - -CREATE SEQUENCE cu_log_cul_id_seq; -CREATE TABLE cu_log ( - cul_id INTEGER NOT NULL DEFAULT nextval('cu_log_cul_id_seq'), - cul_timestamp TIMESTAMPTZ, - cul_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, - cul_user_text TEXT NOT NULL, - cul_reason TEXT NOT NULL DEFAULT '', - cul_type TEXT NOT NULL DEFAULT '', - cul_target_id INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, - cul_target_text TEXT NOT NULL DEFAULT '', - cul_target_hex TEXT NOT NULL DEFAULT '', - cul_range_start TEXT NOT NULL DEFAULT '', - cul_range_end TEXT NOT NULL DEFAULT '' -); - -CREATE INDEX cul_timestamp ON cu_log (cul_timestamp); -CREATE INDEX cul_user ON cu_log (cul_user); -CREATE INDEX cul_type_target ON cu_log (cul_type,cul_target_id); -CREATE INDEX cul_target_hex ON cu_log (cul_target_hex); -CREATE INDEX cul_range_start ON cu_log (cul_range_start); - -COMMIT; diff --git a/CheckUser/cu_log.sql b/CheckUser/cu_log.sql deleted file mode 100644 index 91583be3..00000000 --- a/CheckUser/cu_log.sql +++ /dev/null @@ -1,41 +0,0 @@ --- CheckUser log table --- vim: autoindent syn=mysql sts=2 sw=2 - -CREATE TABLE /*_*/cu_log ( - -- Unique identifier - cul_id int unsigned not null primary key auto_increment, - - -- Timestamp of CheckUser action - cul_timestamp binary(14) not null, - - -- User who performed the action - cul_user int unsigned not null, - cul_user_text varchar(255) binary not null, - - -- Reason given - cul_reason varchar(255) binary not null, - - -- 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 - -- For username targets, this is the user_id - cul_target_id int unsigned not null default 0, - - -- Text target, interpretation depends on cul_type - cul_target_text blob not null, - - -- If the target was an IP address, this contains the hexadecimal form of the IP - cul_target_hex varbinary(255) not null default '', - -- If the target was an IP range, these fields contain the start and end, in hex form - cul_range_start varbinary(255) not null default '', - cul_range_end varbinary(255) not null default '' -) /*$wgDBTableOptions*/; - -CREATE INDEX /*i*/cul_user ON /*_*/cu_log (cul_user, cul_timestamp); -CREATE INDEX /*i*/cul_type_target ON /*_*/cu_log (cul_type,cul_target_id, cul_timestamp); -CREATE INDEX /*i*/cul_target_hex ON /*_*/cu_log (cul_target_hex, cul_timestamp); -CREATE INDEX /*i*/cul_range_start ON /*_*/cu_log (cul_range_start, cul_timestamp); -CREATE INDEX /*i*/cul_timestamp ON /*_*/cu_log (cul_timestamp); diff --git a/CheckUser/extension.json b/CheckUser/extension.json index 72336eb3..07630928 100644 --- a/CheckUser/extension.json +++ b/CheckUser/extension.json @@ -10,7 +10,7 @@ "license-name": "GPL-2.0-or-later", "type": "specialpage", "requires": { - "MediaWiki": ">= 1.35.0", + "MediaWiki": ">= 1.39.0", "platform": { "ext-openssl": "*" } @@ -73,33 +73,50 @@ "CheckUserMaximumRowCount": { "value": 5000, "description": "Maximum number of rows in cu_changes to be used in any query" + }, + "CheckUserInvestigateMaximumRowCount": { + "value": 25000, + "description": "Maximum number of rows in cu_changes to be grouped in the Compare table query" + }, + "CheckUserActorMigrationStage": { + "value": 259 + }, + "CheckUserLogActorMigrationStage": { + "value": 259 } }, "APIListModules": { - "checkuser": "ApiQueryCheckUser", - "checkuserlog": "ApiQueryCheckUserLog" + "checkuser": { + "class": "MediaWiki\\CheckUser\\Api\\ApiQueryCheckUser", + "services": [ + "UserIdentityLookup", + "RevisionLookup", + "CheckUserLogService" + ] + }, + "checkuserlog": "MediaWiki\\CheckUser\\Api\\ApiQueryCheckUserLog" }, "HookHandlers": { "preferences": { "class": "MediaWiki\\CheckUser\\HookHandler\\Preferences" + }, + "Hooks": { + "class": "MediaWiki\\CheckUser\\Hooks" } }, "Hooks": { - "RecentChange_save": [ - "CheckUserHooks::updateCheckUserData", - "CheckUserHooks::maybePruneIPData" - ], - "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", + "RecentChange_save": "Hooks", + "EmailUser": "Hooks", + "User::mailPasswordInternal": "Hooks", + "LocalUserCreated": "Hooks", + "UserMergeAccountFields": "MediaWiki\\CheckUser\\Hooks::onUserMergeAccountFields", + "RenameUserSQL": "MediaWiki\\CheckUser\\Hooks::onRenameUserSQL", + "LoadExtensionSchemaUpdates": "Hooks", + "ContributionsToolLinks": "Hooks", + "PerformRetroactiveAutoblock": "Hooks", + "AuthManagerLoginAuthenticateAudit": "Hooks", + "SpecialPage_initList": "Hooks", + "UserToolLinksEdit": "Hooks", "GetPreferences": "preferences" }, "MessagesDirs": { @@ -111,7 +128,7 @@ "attributes": { "EventLogging": { "Schemas": { - "SpecialInvestigate": 20261100 + "SpecialInvestigate": "/analytics/legacy/specialinvestigate/1.0.0" } } }, @@ -119,34 +136,19 @@ "ext.checkUser": { "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.investigate": { - "localBasePath": "modules/ext.checkUser.investigate", - "remoteExtPath": "CheckUser/modules/ext.checkUser.investigate", "packageFiles": [ - "init.js", - "tables.js", - "copy.js", - "blockform.js", + "dispatcher.js", + "checkuser/cidr.js", + "checkuser/caMultiLock.js", + "checkuserlog/highlightScroll.js", + "investigateblock/investigateblock.js", + "investigate/init.js", + "investigate/InvestigateMenuSelectWidget.js", + "investigate/tables.js", + "investigate/copy.js", + "investigate/blockform.js", { - "name": "message.json", + "name": "investigate/message.json", "callback": "MediaWiki\\CheckUser\\ToolLinksMessages::getParsedMessage", "callbackParam": "checkuser-investigate-compare-toollinks" } @@ -157,15 +159,24 @@ "oojs-ui.styles.icons-editing-core", "oojs-ui.styles.icons-editing-advanced", "oojs-ui.styles.icons-interactions", + "oojs-ui.styles.icons-location", "oojs-ui.styles.icons-moderation", "oojs-ui.styles.icons-user", + "mediawiki.pager.styles", "mediawiki.storage", "mediawiki.Title", "mediawiki.Uri", + "mediawiki.util", "mediawiki.widgets" ], "messages": [ + "checkuser-centralauth-multilock", + "checkuser-centralauth-multilock-list", + "checkuser-centralauth-multilock-list-item", + "checkuser-cidr-too-small", + "checkuser-cidr-affected-ips", "checkuser-investigate-compare-copy-button-label", + "checkuser-investigate-compare-copy-button-label-hide", "checkuser-investigate-compare-copy-message-label", "checkuser-investigate-compare-table-button-add-ip-targets-label", "checkuser-investigate-compare-table-button-add-user-targets-label", @@ -177,21 +188,19 @@ "checkuser-investigate-subtitle-continue-button-label" ] }, - "ext.checkUser.investigateblock.styles": { - "localBasePath": "modules/ext.checkUser.investigateblock.styles", - "remoteExtPath": "CheckUser/modules/ext.checkUser.investigateblock.styles", + "ext.checkUser.styles": { + "class": "ResourceLoaderLessVarFileModule", + "localBasePath": "modules/ext.checkUser.styles", + "remoteExtPath": "CheckUser/modules/ext.checkUser.styles", "styles": [ + "checkuser.less", + "investigate.less", "investigateblock.less" - ] - }, - "ext.checkUser.investigateblock": { - "localBasePath": "modules/ext.checkUser.investigateblock", - "remoteExtPath": "CheckUser/modules/ext.checkUser.investigateblock", - "packageFiles": [ - "investigateblock.js" ], - "dependencies": [ - "oojs-ui-widgets" + "lessMessages": [ + "brackets-start", + "brackets-end", + "pipe-separator" ] }, "ext.guidedTour.tour.checkuserinvestigateform": { @@ -214,7 +223,7 @@ ], "dependencies": [ "ext.guidedTour", - "ext.checkUser.investigate" + "ext.checkUser" ], "messages": [ "checkuser-investigate-tour-useragents-title", @@ -242,30 +251,44 @@ ], "SpecialPages": { "CheckUser": { - "class": "SpecialCheckUser", + "class": "MediaWiki\\CheckUser\\CheckUser\\SpecialCheckUser", "services": [ - "LinkBatchFactory" + "LinkBatchFactory", + "BlockPermissionCheckerFactory", + "BlockUserFactory", + "UserGroupManager", + "CentralIdLookupFactory", + "WikiPageFactory", + "PermissionManager", + "UserIdentityLookup", + "CheckUserTokenQueryManager", + "DBLoadBalancer", + "ActorMigration", + "UserFactory", + "RevisionStore", + "CheckUserLogService", + "CommentFormatter", + "UserEditTracker", + "UserNamePrefixSearch", + "UserNameUtils" ] }, "CheckUserLog": { - "class": "SpecialCheckUserLog", + "class": "MediaWiki\\CheckUser\\CheckUser\\SpecialCheckUserLog", "services": [ - "LinkBatchFactory" + "LinkBatchFactory", + "PermissionManager", + "CommentStore" ] } }, "AutoloadClasses": { - "CheckUserHooks": "includes/CheckUserHooks.php", - "CheckUserLogPager": "includes/CheckUserLogPager.php", - "SpecialCheckUser": "includes/specials/SpecialCheckUser.php", - "SpecialCheckUserLog": "includes/specials/SpecialCheckUserLog.php", - "CheckUserEncryptedData": "includes/CheckUserEncryptedData.php", - "ApiQueryCheckUser": "includes/api/ApiQueryCheckUser.php", - "ApiQueryCheckUserLog": "includes/api/ApiQueryCheckUserLog.php", - "PopulateCheckUserTable": "maintenance/populateCheckUserTable.php" + "PopulateCheckUserTable": "maintenance/populateCheckUserTable.php", + "MediaWiki\\CheckUser\\Maintenance\\PopulateCucActor": "maintenance/populateCucActor.php", + "MediaWiki\\CheckUser\\Maintenance\\PopulateCulActor": "maintenance/populateCulActor.php" }, "ServiceWiringFiles": [ - "includes/ServiceWiring.php" + "src/ServiceWiring.php" ], "AutoloadNamespaces": { "MediaWiki\\CheckUser\\": "src/" diff --git a/CheckUser/i18n/af.json b/CheckUser/i18n/af.json index 9a2f601b..cf93e7b9 100644 --- a/CheckUser/i18n/af.json +++ b/CheckUser/i18n/af.json @@ -9,7 +9,6 @@ ] }, "checkuser-desc": "Subsidies gebruikers met die toepaslike toestemming om die vermoë om gebruikers se IP-adresse om seker te maak en ander inligting", - "checkuser-logcase": "Die logboek soek-funksie is kassensitief.", "checkuser": "Kontroleer gebruiker", "checkuserlog": "Gaan gebruiker log", "checkuser-contribs": "kontroleer gebruiker se IP-adresse", @@ -40,7 +39,6 @@ "checkuser-nomatch-edits": "Niks gevind nie.\nDie Laaste wysig was op $1 op $2.", "checkuser-check": "Kontroleer", "checkuser-log-fail": "Kan nie logboek inskrywing byvoeg nie", - "checkuser-nolog": "Logboek lêer nie gevind.", "checkuser-blocked": "Versper", "checkuser-gblocked": "Globaal geblokkeer", "checkuser-locked": "Gesluit", diff --git a/CheckUser/i18n/an.json b/CheckUser/i18n/an.json index 8ae2ccf2..27def737 100644 --- a/CheckUser/i18n/an.json +++ b/CheckUser/i18n/an.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "Ista aina repasa os zaguers cambeos ta mirar as IPs usatas por un usuario u amostrar as edicions y datos d'usuario ta una adreza IP. Os usuarios y edicions feitos por un cliente IP pueden trobar-se por meyo de cabeceras XFF adhibindo a IP con \"/xff\". Se da soporte a IPv4 (CIDR $1-32) y IPv6 (CIDR $2-128).\nNo s'otendrán más de 5000 edicions por razons de prestacions. Faiga servir ista aina d'alcuerdo con as politicas d'o procheuto.", "checkuser-desc": "Concede a os usuarios con o premiso adecuau a capacidat ta comprebar as adrezas IP d'os usuarios y atras informacions", - "checkuser-logcase": "En mirar os rechistros se fa destinción entre mayusclas y minusclas.", "checkuser": "Comprebación d'usuarios", "checkuserlog": "Rechistro de CheckUser (comprebación d'usuarios)", "group-checkuser": "Comprebadors d'usuarios", @@ -26,7 +25,6 @@ "checkuser-nomatch": "No s'ha trobato garra concordancia", "checkuser-check": "Comprebar", "checkuser-log-fail": "No s'ha puesto adhibir ista dentrada ta o rechistro", - "checkuser-nolog": "No s'ha trobato garra fichero de rechistro.", "checkuser-blocked": "Bloqueyato", "checkuser-too-many": "Bi ha masiaus resultaus (seguntes a estimación d'a busca), cal que emplegue un CIDR más chicot. Aquí bi son as adrezas IP emplegatas (maximo 5000, ordenatas por adreza):", "checkuser-user-nonexistent": "O usuario especificato no existe.", diff --git a/CheckUser/i18n/api/cs.json b/CheckUser/i18n/api/cs.json new file mode 100644 index 00000000..0c8b7a80 --- /dev/null +++ b/CheckUser/i18n/api/cs.json @@ -0,0 +1,10 @@ +{ + "@metadata": { + "authors": [ + "Martin Urbanec" + ] + }, + "apihelp-query+checkuser-param-reason": "Důvod kontroly.", + "apihelp-query+checkuser-param-limit": "Omezení počtu výsledků.", + "apihelp-query+checkuserlog-param-limit": "Omezení počtu výsledků." +} diff --git a/CheckUser/i18n/api/de.json b/CheckUser/i18n/api/de.json index 8f509daf..b9f6fccd 100644 --- a/CheckUser/i18n/api/de.json +++ b/CheckUser/i18n/api/de.json @@ -1,6 +1,7 @@ { "@metadata": { "authors": [ + "FF-11", "FF11", "McDutchie", "Metalhead64", @@ -28,5 +29,6 @@ "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" + "apierror-checkuser-invalidmode": "Ungültiger Abfragemodus", + "checkuser-api-help-param-direction": "In welcher Richtung soll aufgezählt werden:\n;newer:Älteste zuerst auflisten. Hinweis: $1from muss vor $1to sein.\n;older:Neueste zuerst auflisten (Standard). Hinweis: $1from muss nach $1to sein." } diff --git a/CheckUser/i18n/api/en-gb.json b/CheckUser/i18n/api/en-gb.json index 84ddae6d..afd04578 100644 --- a/CheckUser/i18n/api/en-gb.json +++ b/CheckUser/i18n/api/en-gb.json @@ -5,21 +5,5 @@ "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" + "apihelp-query+checkuser-description": "Check which IP addresses are used by a given username, or which usernames are used by a given IP." } diff --git a/CheckUser/i18n/api/en.json b/CheckUser/i18n/api/en.json index ea701dcd..51423294 100644 --- a/CheckUser/i18n/api/en.json +++ b/CheckUser/i18n/api/en.json @@ -28,5 +28,6 @@ "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" + "apierror-checkuser-invalidmode": "Invalid request mode", + "checkuser-api-help-param-direction": "In which direction to enumerate:\n;newer:List oldest first. Note: $1from has to be before $1to.\n;older:List newest first (default). Note: $1from has to be later than $1to." } diff --git a/CheckUser/i18n/api/es.json b/CheckUser/i18n/api/es.json index a4f2f8c8..fb7b3913 100644 --- a/CheckUser/i18n/api/es.json +++ b/CheckUser/i18n/api/es.json @@ -1,7 +1,9 @@ { "@metadata": { "authors": [ + "Agent", "Fitoschido", + "Hasley", "JasterTDC", "Macofe", "MarcoAurelio", @@ -18,15 +20,15 @@ "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-description": "Obtener entradas del registro de comprobación de usuarios.", + "apihelp-query+checkuserlog-summary": "Obtener entradas del registro de comprobación de usuarios.", + "apihelp-query+checkuserlog-param-user": "Nombre del usuario con permiso de comprobador 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", + "apihelp-query+checkuserlog-example-1": "Mostrar comprobaciones de [[User:Example]]", + "apihelp-query+checkuserlog-example-2": "Mostrar comprobaciones 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/fr.json b/CheckUser/i18n/api/fr.json index cb17d1b4..1bd0b21a 100644 --- a/CheckUser/i18n/api/fr.json +++ b/CheckUser/i18n/api/fr.json @@ -4,22 +4,24 @@ "Element303", "Gomoko", "McDutchie", + "Thibaut120094", + "Verdy p", "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-request": "Type de demande CheckUser :\n; userips\n: Obtenir l’adresse IP de l’utilisateur cible.\n; edits\n: Obtenir les modifications de l’adresse IP ou de la plage cible.\n; ipusers\n: 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-param-timecond": "Limite de temps des données de l’utilisateur (comme « -2 weeks » ou « 2 weeks ago »).", + "apihelp-query+checkuser-param-xff": "Utiliser les données XFF au lieu de l’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-user": "Nom d’utilisateur du Vérificateur d’utilisateurs.", "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.", @@ -27,6 +29,7 @@ "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" + "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 non valide", + "checkuser-api-help-param-direction": "Dans quelle direction énumérer :\n; « newer »\n: lister les plus anciens en premier. Note : $1start doit antérieur à $1end.\n; « older »\n: lister les nouveaux en premier (par défaut). Note : $1start doit être postérieur à $1end." } diff --git a/CheckUser/i18n/api/he.json b/CheckUser/i18n/api/he.json index 3b81b8d7..41bc2b1d 100644 --- a/CheckUser/i18n/api/he.json +++ b/CheckUser/i18n/api/he.json @@ -26,5 +26,6 @@ "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": "מצב בקשה בלתי־תקין" + "apierror-checkuser-invalidmode": "מצב בקשה בלתי־תקין", + "checkuser-api-help-param-direction": "באיזה כיוון למנות:\n;newer:לרשום את הישנים ביותר בהתחלה. לתשומת לבך: $1from חייב להיות לפני $1to.\n;older:לרשום את החדשים ביותר בהתחלה (ברירת מחדל). לתשומת לבך: $1from חייב להיות אחרי $1to." } diff --git a/CheckUser/i18n/api/ia.json b/CheckUser/i18n/api/ia.json index f95f83d6..bb97c69f 100644 --- a/CheckUser/i18n/api/ia.json +++ b/CheckUser/i18n/api/ia.json @@ -25,5 +25,6 @@ "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" + "apierror-checkuser-invalidmode": "Modo de requesta invalide", + "checkuser-api-help-param-direction": "In qual direction enumerar:\n;newer:Listar le plus vetules primo. Nota: $1from debe esser ante $1to.\n;older:Listar le plus noves primo (option predefinite). Nota: $1from debe esser post $1to." } diff --git a/CheckUser/i18n/api/id.json b/CheckUser/i18n/api/id.json index 636f1545..4991c309 100644 --- a/CheckUser/i18n/api/id.json +++ b/CheckUser/i18n/api/id.json @@ -1,11 +1,13 @@ { "@metadata": { "authors": [ + "Daud I.F. Argana", "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-summary": "Memeriksa 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.", @@ -15,11 +17,15 @@ "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-summary": "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" + "apihelp-query+checkuserlog-example-2": "Tampilkan pemeriksaan dari 192.0.2.0/24 setelah 2011-10-15T23:00:00Z", + "apierror-checkuser-missingsummary": "Anda harus memberikan alasan pemeriksaan.", + "apierror-checkuser-timelimit": "Anda harus menggunakan batas waktu yang tepat (seperti \"-2 weeks\" atau \"2 weeks ago\").", + "apierror-checkuser-invalidmode": "Mode permintaan tidak sah" } diff --git a/CheckUser/i18n/api/ja.json b/CheckUser/i18n/api/ja.json index eba89e76..976db2cc 100644 --- a/CheckUser/i18n/api/ja.json +++ b/CheckUser/i18n/api/ja.json @@ -27,5 +27,6 @@ "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-missingsummary": "調査理由を明確にする必要があります。", + "apierror-checkuser-timelimit": "正しい期間を設定してください(例: \"-2 weeks\" または \"2 weeks ago\")" } diff --git a/CheckUser/i18n/api/mk.json b/CheckUser/i18n/api/mk.json index 890708dc..be9c3a0c 100644 --- a/CheckUser/i18n/api/mk.json +++ b/CheckUser/i18n/api/mk.json @@ -26,5 +26,6 @@ "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": "Неважечки режим на побарување" + "apierror-checkuser-invalidmode": "Неважечки режим на побарување", + "checkuser-api-help-param-direction": "Во која насока да се набројува:\n;newer:Прво најстарите. Напомена: $1from мора да биде пред $1to.\n;older:Прво најновите (по основно). Напомена: $1from мора да биде подоцна од $1to." } diff --git a/CheckUser/i18n/api/nb.json b/CheckUser/i18n/api/nb.json index 5d613225..a2ff0592 100644 --- a/CheckUser/i18n/api/nb.json +++ b/CheckUser/i18n/api/nb.json @@ -26,5 +26,6 @@ "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" + "apierror-checkuser-invalidmode": "Ugyldig forespørselsmodus", + "checkuser-api-help-param-direction": "Hvilken retning det skal listes opp:\n;never:List opp de eldste først. Merk: $1from må være før $1to.\n;older:List opp de nyeste først (standard). Merk: $1from må være senere enn $1to." } diff --git a/CheckUser/i18n/api/pl.json b/CheckUser/i18n/api/pl.json index c1b6f3db..e0f43914 100644 --- a/CheckUser/i18n/api/pl.json +++ b/CheckUser/i18n/api/pl.json @@ -29,5 +29,6 @@ "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" + "apierror-checkuser-invalidmode": "Nieprawidłowy tryb żądania", + "checkuser-api-help-param-direction": "Kolejność wyliczania:\n;newer:Wymieniaj najpierw starsze wpisy. Uwaga: $1from musi być przed $1to.\n;older:Wymieniaj najpierw nowsze wpisy (domyślnie). Uwaga: $1from musi być po $1to." } diff --git a/CheckUser/i18n/api/pt.json b/CheckUser/i18n/api/pt.json index b687a994..397d5d3c 100644 --- a/CheckUser/i18n/api/pt.json +++ b/CheckUser/i18n/api/pt.json @@ -25,5 +25,6 @@ "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" + "apierror-checkuser-invalidmode": "Modo de pedido inválido", + "checkuser-api-help-param-direction": "A direção da enumeração:\n;newer:Listar o mais antigo primeiro. Nota: $1from tem de estar antes de $1to.\n;older:Listar o mais recente primeiro (padrão). Nota: $1from tem de estar depois de $1to." } diff --git a/CheckUser/i18n/api/qqq.json b/CheckUser/i18n/api/qqq.json index e0f98b27..6ba1ff5d 100644 --- a/CheckUser/i18n/api/qqq.json +++ b/CheckUser/i18n/api/qqq.json @@ -28,5 +28,6 @@ "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}}" + "apierror-checkuser-invalidmode": "{{doc-apierror}}", + "checkuser-api-help-param-direction": "{{doc-apihelp-param|description=any standard \"dir\" parameter|noseealso=1}}\n\nSee also:\n* {{msg-mw|api-help-param-direction}}" } diff --git a/CheckUser/i18n/api/scn.json b/CheckUser/i18n/api/scn.json index 3b065279..b72b675c 100644 --- a/CheckUser/i18n/api/scn.json +++ b/CheckUser/i18n/api/scn.json @@ -1,11 +1,12 @@ { "@metadata": { "authors": [ + "Ajeje Brazorf", "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-description": "Cuntrolla quali nnirizzi IP sunnu adupirati dûn nomu utenti datu, o quali nomi utenti sunnu adupirati d'un 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.", diff --git a/CheckUser/i18n/api/sh.json b/CheckUser/i18n/api/sh.json index 6059c6f8..c8805934 100644 --- a/CheckUser/i18n/api/sh.json +++ b/CheckUser/i18n/api/sh.json @@ -25,5 +25,6 @@ "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" + "apierror-checkuser-invalidmode": "Nevažeći način upita", + "checkuser-api-help-param-direction": "U kojem smjeru nabrajati:\n;never:Prvo najstarije. Napomena: $1from mora biti prije $1to.\n;older:Prvo najnovije (zadano). Napomena: $1from mora biti kasnije od $1to." } diff --git a/CheckUser/i18n/api/tr.json b/CheckUser/i18n/api/tr.json index 72bd50d0..9a09e3a5 100644 --- a/CheckUser/i18n/api/tr.json +++ b/CheckUser/i18n/api/tr.json @@ -3,14 +3,16 @@ "authors": [ "BaRaN6161 TURK", "Hedda", + "Khalvar", "McDutchie", "Sadrettin", + "SaldırganSincap", "Ö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-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.\n;ipusers: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ı.", @@ -29,5 +31,6 @@ "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" + "apierror-checkuser-invalidmode": "Geçersiz istek modu", + "checkuser-api-help-param-direction": "Hangi yönde numaralandırılacağı:\n;newer:Önce en eskisini listeleyin. Not: $1start, $1end önce olmalıdır.\n;older:Önce en yenisini listeleyin (varsayılan). Not: $1start, $1end geç olmalıdır." } diff --git a/CheckUser/i18n/api/uk.json b/CheckUser/i18n/api/uk.json index 95270a8f..5a5d1cc4 100644 --- a/CheckUser/i18n/api/uk.json +++ b/CheckUser/i18n/api/uk.json @@ -27,5 +27,6 @@ "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": "Неправильний параметр запиту" + "apierror-checkuser-invalidmode": "Неправильний параметр запиту", + "checkuser-api-help-param-direction": "У якому напрямку перелічувати:\n;newer:Спочатку найстаріші. Примітка: значення $1from повинне бути до $1to.\n;older:Спочатку найновіші (за замовчуванням). Примітка: значення $1from повинно бути після $1to." } diff --git a/CheckUser/i18n/api/zh-hant.json b/CheckUser/i18n/api/zh-hant.json index bce3aac0..55bd8006 100644 --- a/CheckUser/i18n/api/zh-hant.json +++ b/CheckUser/i18n/api/zh-hant.json @@ -29,5 +29,6 @@ "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": "無效請求模式" + "apierror-checkuser-invalidmode": "無效請求模式", + "checkuser-api-help-param-direction": "列舉的方向:\n;newer:最早的優先。注意:$1from 應在 $1to 之前。\n;older:最新的優先(預設)。注意:$1from 應在 $1to 之後。" } diff --git a/CheckUser/i18n/ar.json b/CheckUser/i18n/ar.json index 004a7a78..ae6191d3 100644 --- a/CheckUser/i18n/ar.json +++ b/CheckUser/i18n/ar.json @@ -3,122 +3,152 @@ "authors": [ "AHmed Khaled", "Alnokta", + "Asma", "AwamerT", "Ciphers", "Meno25", "Mido", "NEHAOUA", "OsamaK", + "SaldırganSincap", "ديفيد", "علاء", "محمد أحمد عبد الفتاح" ] }, - "checkuser-summary": ";ملاحظات\n* تفحص هذه الأداة أحدث التغييرات بهدف استرجاع عنوان الآي بي المُستخدم بواسطة مستخدم ما أو بهدف إظهار تعديلات/بيانات عنوان الآي بي.\n* المستخدمون والتعديلات التي تتم بواسطة عنوان آي بي العميل من الممكن استرجاعها من خلال رؤوس XFF ويتم ذلك من خلال إلحاق \"/xff\" في نهاية عنوان الآي بي. عناوين آي بي في4 (CIDR $1-32) وَآي بي في6 (CIDR $2-128) مدعومة.\n* لن يتم عرض أكثر من 5000 تعديل لأسباب تتعلق بالأداء.\n* استخدام هذه الأداة يتم وفقاً للسياسات.", - "checkuser-desc": "يمنح المستخدمين بالسماح المطلوب القدرة على فحص عناوين الأيبي لمستخدم ما ومعلومات أخرى", - "checkuser-logcase": "بحث السجل حساس لحالة الحروف.", + "checkuser-summary": "* تفحص هذه الأداة أحدث التغييرات بهدف استرجاع عنوان البروتوكول المُستخدم بواسطة مستخدم ما أو بهدف إظهار تعديلات/بيانات عنوان البروتوكول.\n* المستخدمون والتعديلات التي تتم بواسطة عنوان بروتوكول العميل يمكن استرجاعها من خلال رؤوس XFF، وذلك عبر إلحاق \"/xff\" في نهاية عنوان البروتوكول. يدعم عناوين بروتوكولات الإصدار الرابع (CIDR $1-32) وبروتوكولات الإصدار السادس (CIDR $2-128).\n* لن تعرض الأداة أكثر من $3 تعديل لأسباب تتعلق بالأداء.\n* استخدم هذه الأداة وفقًا للسياسات.", + "checkuser-desc": "يمنح المستخدمين بالسماح المطلوب القدرة على فحص عناوين البروتوكول لمستخدمٍ ما ومعلومات أخرى", "checkuser": "تدقيق مستخدم", "checkuserlog": "سجل تدقيق المستخدم", - "checkuser-contribs": "افحص عناوين أيبي المستخدم", + "checkuser-contribs": "افحص عناوين البروتوكولات المستخدم", "checkuser-contribs-log": "تدقيقات المستخدم الأخيرة", + "checkuser-contribs-log-initiator": "تدقيقات المستخدم التي أجراها هذا المستخدم", "group-checkuser": "مدققو مستخدم", "group-checkuser-member": "{{GENDER:$1|مدقق مستخدم}}", - "right-checkuser": "افحص عناوين أيبي المستخدم والمعلومات الأخرى", + "right-checkuser": "افحص عناوين بروتوكول المستخدم والمعلومات الأخرى", "right-checkuser-log": "رؤية سجل تدقيق المستخدم", - "action-checkuser": "افحص عناوين أيبي المستخدم والمعلومات الأخرى", + "action-checkuser": "افحص عناوين بروتوكول المستخدم والمعلومات الأخرى", "action-checkuser-log": "عرض سجل تدقيق المستخدم", "grouppage-checkuser": "{{ns:project}}:تدقيق مستخدم", "checkuser-reason": "السبب:", "checkuser-reason-api": "واجهة برمجة التطبيقات", "checkuser-showlog": "التبديل إلى سجل تدقيق المستخدم", "checkuser-query": "فحص أحدث التغييرات", - "checkuser-target": "عنوان الأيبي أو اسم المستخدم:", + "checkuser-target": "عنوان البروتوكول أو اسم المستخدم:", "checkuser-users": "اعرض المستخدمين", "checkuser-edits": "الحصول على التعديلات", - "checkuser-ips": "اعرض الأيبيهات", + "checkuser-ips": "اعرض عناوين البروتوكولات", "checkuser-period": "المدة:", "checkuser-week-1": "آخر أسبوع", "checkuser-week-2": "آخر أسبوعين", - "checkuser-month": "آخر 30 يوم", + "checkuser-month": "آخر 30 يومًا", + "checkuser-month-2": "آخر 60 يومًا", "checkuser-all": "الكل", - "checkuser-cidr-label": "جد النطاق المشترك والعناوين المتأثرة لقائمة من الأيبيهات", + "checkuser-cidr-label": "جد النطاق المشترك والعناوين المتأثرة لقائمة من عناوين البروتوكولات", "checkuser-cidr-res": "CIDR مشترك:", + "checkuser-cidr-affected-ips": "عدد عناوين البروتوكولات المتأثرة:", + "checkuser-cidr-too-small": "النطاق واسع جدًا", "checkuser-empty": "لا توجد مدخلات في السجل.", "checkuser-nomatch": "لم يتم العثور على مدخلات مطابقة.", - "checkuser-nomatch-edits": "لا تطابق تم العثور عليه.\nآخر تعديل كان في $1 الساعة $2.", + "checkuser-nomatch-edits": "لم يعثر على أي تطابقٍ.\nآخر تعديل كان في $1 الساعة $2.", "checkuser-check": "فحص", "checkuser-check-this-user": "دقق هذا المستخدم", + "checkuser-investigate-this-user": "تحقق من هذا المستخدم", "checkuser-recent-checks": "تدقيقات المستخدم الأخيرة", "checkuser-log-fail": "غير قادر على إضافة مدخلة للسجل", - "checkuser-nolog": "لم يتم العثور على ملف سجل.", + "checkuser-log-checks-by": "تدقيقات بواسطة", + "checkuser-log-checks-on": "تدقيقات على", "checkuser-blocked": "ممنوع", - "checkuser-gblocked": "ممنوع منعا عاما", + "checkuser-gblocked": "ممنوع منعًا عالميًا", "checkuser-locked": "مغلق", - "checkuser-wasblocked": "تم منعه مسبقا", + "checkuser-wasblocked": "مُنع سابقًا", "checkuser-localonly": "غير موحد", "checkuser-massblock": "امنع المستخدمين المختارين", - "checkuser-massblock-text": "الحسابات المختارة سيتم منعها لا نهائيا، مع تفعيل المنع التلقائي وتعطيل إنشاء الحسابات.\nعناوين الأيبي سيتم منعها لمدة 1 أسبوع لمستخدمي الأيبي فقط ومع تعطيل إنشاء الحسابات.", + "checkuser-massblock-text": "ستمنع الحسابات المختارة بشكل دائم، مع تفعيل المنع التلقائي وتعطيل إنشاء الحسابات.\nستمنع عناوين البروتوكولات لمدة أسبوع واحد لمستخدمي عنوان البروتوكول فقط مع تعطيل إنشاء الحسابات.", "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": "'''لا مستخدمون تم منعهم.'''", - "checkuser-block-limit": "تم اختيار عدد كبير من المستخدمين.", - "checkuser-block-noreason": "يجب أن تعطي سببا لعمليات المنع.", - "checkuser-centralauth-multilock": "منع متعدد للحسابات المحددة", + "checkuser-block-failure": "'''لم يمنع أي مستخدم.'''", + "checkuser-block-limit": "اختير عددٌ كبيرٌ من المستخدمين.", + "checkuser-block-noreason": "يجب أن تحدد سببًا للمنع.", + "checkuser-centralauth-multilock": "إغلاق الحسابات المحددة", "checkuser-noreason": "يجب أن تقدم سببًا لهذا الاستعلام.", - "checkuser-too-many": "نتائج كثيرة جدا (بناء على استعلام تقريبي)، من فضلك قلل CIDR.\nهذه هي الأيبيهات المستخدمة (5000 كحد أقصى، مرتبة بالعنوان):", + "checkuser-too-many": "نتائج كثيرة جدًا (اعتمادً على استعلامٍ تقريبي)، من فضلك قلل CIDR.\nهذه هي عناوين البروتوكولات المستخدمة ($1 كحدٍ أقصى، مرتبة حسب العنوان):", "checkuser-user-nonexistent": "المستخدم المحدد غير موجود.", - "checkuser-search": "بحث في إدخالات سجل تدقيق المستخدم", + "checkuser-target-nonexistent": "الهدف المحدد غير موجود.", + "checkuser-initiator-nonexistent": "البادئ المحدد غير موجود.", + "checkuser-search": "بحث في مدخلات سجل تدقيق المستخدم", "checkuser-search-submit": "بحث", - "checkuser-search-initiator": "بادىء", - "checkuser-search-target": "هدف", + "checkuser-search-initiator": "البادىء", + "checkuser-search-target": "الهدف", "checkuser-log-search-target": "الهدف:", + "checkuser-log-search-initiator": "البادىء:", "checkuser-log-search-type": "البحث حسب:", "checkuser-ipeditcount": "~$1 من كل المستخدمين", "checkuser-showmain": "تغيير إلى استمارة تدقيق المستخدم الرئيسية", - "checkuser-limited": "'''هذه النتائج تم اختصارها لأسباب تتعلق بالأداء.'''", - "checkuser-log-entry-userips": "$3، $1 حصل على عناوين الأيبي ل$2", + "checkuser-show-investigate": "تغيير إلى استمارة التحقق الرئيسية", + "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-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": "أخفق تسجيل الدخول إلى {{SITENAME}} كـ$1", - "checkuser-login-success": "تم تسجيل الدخول بنجاح إلى {{SITENAME}} كـ$1", + "checkuser-log-entry-investigate": "$3، $1 حصل على معلوماتٍ عن $2", + "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", "group-checkuser.css": "/* الأنماط المتراصة CSS المعروضة هنا ستؤثر على مدققي المستخدم فقط */", - "group-checkuser.js": "/* الجافا سكريبت المعروضة هنا ستؤثر على مدققي المستخدم فقط */", + "group-checkuser.js": "/* جافا سكريبت المعروضة هنا ستؤثر على مدققي المستخدم فقط */", + "checkuser-link-investigate-label": "جرب أداة تدقيق المستخدم الجديدة", "checkuser-investigateblock": "منع المستخدمين", + "checkuser-investigateblock-target": "أسماء المستخدمين وعناوين البروتوكولات", + "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-investigate-log": "سجلات التحقيق", - "checkuser-investigate-log-entry": "$3, $1 بحث عن معلومات لـ<bdi>$2</bdi> $4", - "checkuser-investigate-log-empty": "لم يتم العثور على مدخلات سجل التحقيق.", - "checkuser-investigate-log-subtitle": "التحويل إلى استمارة التحقيق", + "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 تم منعهم.", + "checkuser-investigateblock-notices-failed": "لا يمكن إضافة بعض الإخطارات إلى صفحات المستخدمين أو صفحات نقاشهم.", "checkuser-investigate": "فحص", "checkuser-investigate-page-subtitle": "التحقيق الحالي حول $1", "checkuser-investigate-subtitle-block-button-label": "منع", - "checkuser-investigate-indicator-new-investigation": "تحقيق جديد", + "checkuser-investigate-subtitle-cancel-button-label": "إلغاء", + "checkuser-investigate-subtitle-continue-button-label": "استمرار", + "checkuser-investigate-subtitle-show-checkuser": "تبديل إلى تدقيق المستخدم", + "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-legend": "البحث عن أسماء المستخدمين أو عناوين ونطاقات البروتوكولات", + "checkuser-investigate-notice-no-results": "لا توجد أي نتائج.", + "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": "آخر 30 يومًا", "checkuser-investigate-reason-label": "السبب", + "checkuser-investigate-preliminary-notice-ip-targets": "لا تتضمن علامة تبويب معلومات الحساب أي معلومات عن البروتوكولات. للتفاصيل طالع <span class=\"plainlinks\">[$1 تبويب عناوين البروتوكولات ومعلومات جهاز المستخدم]</span>.", "checkuser-investigate-preliminary-table-cell-blocked": "ممنوع", "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|تعديل|تعديلات}}", "checkuser-investigate-preliminary-table-cell-unblocked": "غير ممنوع", @@ -130,9 +160,41 @@ "checkuser-investigate-preliminary-table-header-wiki": "الويكي", "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "لم يعثر على الويكي", "checkuser-investigate-filters-legend": "المرشحات", + "checkuser-investigate-filters-exclude-targets-label": "أخفِ المستخدمين أو عناوين البروتوكولات التالية", + "checkuser-investigate-timeline-notice-no-results": "لا توجد أي نتائج: لم يكن هناك أي نشاط مسجل لهؤلاء المستخدمين أو عناوين البروتوكولات في آخر 90 يومًا", + "checkuser-investigate-timeline-notice-no-results-filters": "لا توجد نتائج مطابقة لمعايير الترشيح هذه. حاول إزالة بعض المرشحات لتوسيع البحث.", "checkuser-investigate-compare-copy-button-label": "أظهر نص الويكي", + "checkuser-investigate-compare-copy-button-label-hide": "أخفٍ نص الويكي", + "checkuser-investigate-compare-toollinks-whois": "WHOIS", + "checkuser-investigate-compare-toollinks-ipcheck": "تحقق من البروكسي", + "checkuser-investigate-compare-copy-message-label": "هل ترغب في نسخ هذه المعلومات على شكل جدول ويكي؟", + "checkuser-investigate-compare-notice-exceeded-limit": "نظرًا لقيودٍ تقنية، فقد وصلنا إلى عدد المدخلات التي يمكن عرضها. البيانات التي تم إرجاعها للأهداف التالية غير كاملة: $1. يرجى محاولة استخدام أهداف أقل أو نافذة زمنية أصغر أو نطاقات بروتوكول أضيق.", + "checkuser-investigate-compare-notice-no-results": "لا توجد أي نتائج: لم يتم إجراء أي تعديلات من هؤلاء المستخدمين أو عناوين البروتوكولات في آخر 90 يومًا", + "checkuser-investigate-compare-notice-no-results-filters": "لا توجد نتائج مطابقة لمعايير الترشيح هذه. حاول إزالة بعض المرشحات لتوسيع البحث.", + "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-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-useragent": "وكيل المستخدم" + "checkuser-investigate-compare-table-header-ip": "عنوان البروتوكول", + "checkuser-investigate-compare-table-header-useragent": "جهاز المستخدم", + "checkuser-investigate-subtitle-link-restart-tour": "أعد تشغيل الجولة", + "checkuser-investigate-tour-targets-title": "تدقيق عدة مستخدمين وعناوين البروتوكولات؟", + "checkuser-investigate-tour-targets-desc": "أضف ما يصل إلى $1 {{PLURAL:$1|مستخدم أو آيبي|مستخدمين أو آيبيهات}} واحصل على جميع المعلومات في مكانٍ واحد. لا تقلق، سننشئ سجل تدقيق مستخدم منفصلًا لكلٍ منهم.", + "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": "انسخ جدول المقارنة بنقرة واحدة وخذه إلى ويكي المدققين. لاحظ أنك تنسخ فقط ما هو مرئي وليس كل صفحات التدقيق." } diff --git a/CheckUser/i18n/arz.json b/CheckUser/i18n/arz.json index 9fdd20ad..eb2783da 100644 --- a/CheckUser/i18n/arz.json +++ b/CheckUser/i18n/arz.json @@ -8,7 +8,6 @@ }, "checkuser-summary": "الوسيلة دى بتدور فى احدث التغييرات علشان ترجع الايبيهات اللى استعملها يوزر او علشان تعرض بيانات التعديل/اليوزر لعنوان الاى بى.\nاليوزرز و التعديلات اللى اتعملت من أى بى عميل ممكن تترجع عن طريق عناوين XFF لو زودت على الاى بى \"/xff\".\nIPv4 (CIDR $1-32) و IPv6 (CIDR $2-128) مدعومين.\nمش اكتر من 5000 تعديل ممكن تتعرض بسبب الاداء.\nاستخدم دا بطريقة موافقة للسياسة.", "checkuser-desc": "بيدى لليوزرز بعد الاذن المناسب القدرة على التشييك على عنوان الاى بى بتاع اى يوزر و معلومات تانية", - "checkuser-logcase": "التدوير فى السجل حساس لحالة الحروف", "checkuser": "التشييك على اليوزر", "checkuserlog": "سجل تشييك اليوزر", "group-checkuser": "التشييك على اليوزرز", @@ -35,7 +34,6 @@ "checkuser-nomatch-edits": "لا تطابق تم العثور عليه.\nآخر تعديل كان فى $1 الساعة $2.", "checkuser-check": "فحص", "checkuser-log-fail": "مش قادر يضيف مدخلة للسجل", - "checkuser-nolog": "سجل الملف ماتلقاش.", "checkuser-blocked": "ممنوع", "checkuser-gblocked": "ممنوع منعا عاما", "checkuser-locked": "مغلق", diff --git a/CheckUser/i18n/as.json b/CheckUser/i18n/as.json index 8e72e6dd..b25922d5 100644 --- a/CheckUser/i18n/as.json +++ b/CheckUser/i18n/as.json @@ -2,11 +2,26 @@ "@metadata": { "authors": [ "Bishnu Saikia", - "Chaipau" + "Chaipau", + "Simbu123" ] }, + "checkuser-desc": "উপযুক্ত অনুমতিৰ সৈতে সদস্যসকলক অন্য সদস্যৰ আইপি ঠিকনা আৰু অন্যান্য তথ্য পৰীক্ষা কৰাৰ ক্ষমতা প্ৰদান কৰে", + "checkuser": "সদস্য পৰীক্ষণ", + "checkuserlog": "সদস্য পৰীক্ষণ অভিলেখ", + "checkuser-contribs": "সদস্যৰ আইপি ঠিকনাসমূহ পৰীক্ষা কৰক", + "checkuser-contribs-log": "শেহতীয়া সদস্য পৰীক্ষণ", + "group-checkuser": "সদস্য পৰীক্ষক", + "group-checkuser-member": "{{GENDER:$1|সদস্য পৰীক্ষক}}", + "action-checkuser": "সদস্যৰ আইপি ঠিকনা আৰু অন্যান্য তথ্য পৰীক্ষা কৰক", + "grouppage-checkuser": "{{ns:project}}:সদস্য পৰীক্ষক", "checkuser-reason": "কাৰণ:", - "checkuser-search": "সন্ধান কৰক", + "checkuser-period": "সময়কাল:", + "checkuser-week-1": "যোৱা সপ্তাহ", + "checkuser-week-2": "যোৱা দুই সপ্তাহ", + "checkuser-month": "যোৱা ৩০ দিন", + "checkuser-all": "সকলো", + "checkuser-search": "সদস্য পৰীক্ষণৰ অভিলেখ সন্ধান কৰক", "checkuser-search-submit": "সন্ধান কৰক", "checkuser-search-target": "লক্ষ্য" } diff --git a/CheckUser/i18n/ast.json b/CheckUser/i18n/ast.json index 35f1e4c9..e7f11f18 100644 --- a/CheckUser/i18n/ast.json +++ b/CheckUser/i18n/ast.json @@ -7,12 +7,12 @@ "Macofe", "MarcoAurelio", "McDutchie", + "Tokvo", "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.", "checkuser-desc": "Permite a los usuarios colos permisos afechiscos la posibilidá de comprobar les direiciones IP d'usuarios y otres informaciones", - "checkuser-logcase": "La busca nel rexistru distingue ente mayúscules y minúscules.", "checkuser": "Comprobador d'usuariu", "checkuserlog": "Rexistru de comprobadores d'usuariu", "checkuser-contribs": "verificar IP del usuariu", @@ -46,7 +46,6 @@ "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 ficheru del rexistru.", "checkuser-blocked": "Bloquiáu", "checkuser-gblocked": "Bloquiáu globalmente", "checkuser-locked": "Candáu", @@ -85,7 +84,7 @@ "checkuser-autocreate-action": "creóse automáticamente", "checkuser-create-action": "creóse", "checkuser-email-action": "unvió un corréu electrónicu a \"$1\"", - "checkuser-reset-action": "reestableció la contraseña del usuariu «$1»", + "checkuser-reset-action": "reestableció la contraseña del usuariu $1", "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", diff --git a/CheckUser/i18n/av.json b/CheckUser/i18n/av.json index 3f048c67..a354a619 100644 --- a/CheckUser/i18n/av.json +++ b/CheckUser/i18n/av.json @@ -1,9 +1,10 @@ { "@metadata": { "authors": [ + "Omarov M.", "Аль-Гимравий" ] }, - "checkuser-reason": "ГІилла:", - "checkuser-target": "IP-адрес яги гІахьалчиясул цІар:" + "checkuser-reason": "ГӀилла:", + "checkuser-target": "IP-адрес яги хӀалтӀизабунцӀар:" } diff --git a/CheckUser/i18n/avk.json b/CheckUser/i18n/avk.json index 48bbf41e..d64eb9d3 100644 --- a/CheckUser/i18n/avk.json +++ b/CheckUser/i18n/avk.json @@ -14,7 +14,6 @@ "checkuser-empty": "\"Log\" iyeltak tir vlardaf.", "checkuser-nomatch": "Nedoy trasiks", "checkuser-check": "Stujera", - "checkuser-nolog": "Mek trasiyin \"log\" iyeltak.", "checkuser-blocked": "Elekan", "checkuser-search": "Aneyara", "checkuser-search-submit": "Aneyara", diff --git a/CheckUser/i18n/az.json b/CheckUser/i18n/az.json index 19ded4fe..2394896a 100644 --- a/CheckUser/i18n/az.json +++ b/CheckUser/i18n/az.json @@ -3,6 +3,7 @@ "authors": [ "Cekli829", "Emperyan", + "NMW03", "Neriman2003", "PPerviz", "Toghrul Rahimli", @@ -13,41 +14,40 @@ }, "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}}", + "group-checkuser-member": "{{GENDER:$1|təftişçi}}", "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", + "action-checkuser": "istifadəçilərin IP-ünvanını və daha çox məlumatı yoxlamaq", + "action-checkuser-log": "təftişçi jurnalına baxmaq", "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-query": "Son dəyişikliklər sorğusu", "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-users": "İstifadəçiləri tap", + "checkuser-edits": "Redaktələri tap", + "checkuser-ips": "IP ünvanlarını tap", + "checkuser-period": "Müddət:", + "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-all": "hamısı", + "checkuser-cidr-label": "IP ünvanlarının siyahısı üçün ümumi aralığı və təsirlənmiş IP ünvanlarını tap", "checkuser-cidr-res": "Common CIDR:", - "checkuser-empty": "Jurnalda heç nə yoxdur.", + "checkuser-empty": "Jurnal heç nə ehtiva etmir.", "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-nomatch-edits": "Heç bir nəticə tapılmadı.\nSon redaktə $2 $1 tarixində edilib.", "checkuser-check": "Yoxla", "checkuser-check-this-user": "Bu istifadəçini yoxla", + "checkuser-investigate-this-user": "Bu istifadəçini araşdır", "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", @@ -59,6 +59,7 @@ "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-reblock": "Mövcud blokları ləğv et", "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.'''", @@ -66,7 +67,7 @@ "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-too-many": "Çox nəticə var. (sorğunun qiymətləndirilməsinə görə), CIDR-ni daraltın. Burada istifadə olunan IP ünvanları ($1 maks., ü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", @@ -76,6 +77,7 @@ "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-show-investigate": "Araşdırma ə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", @@ -83,6 +85,7 @@ "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-log-entry-investigate": "$3, $1, $2 üçün məlumat axtardı", "checkuser-autocreate-action": "avtomatik yaradıldı", "checkuser-create-action": "yaradılıb", "checkuser-email-action": "\"$1\" istifadəçisinə e-poçt göndər", @@ -92,5 +95,79 @@ "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'''" + "checkuser-link-investigate-label": "Yeni Təftişçi alətini sınayın", + "checkuser-investigateblock": "İstifadəçiləri blokla", + "checkuser-investigateblock-target": "İstifadəçi adları və IP-ünvanları", + "checkuser-investigateblock-actions": "Bloklanacaq fəaliyyətlər", + "checkuser-investigateblock-reason": "Səbəb", + "checkuser-investigateblock-options": "Əlavə seçimlər", + "checkuser-investigateblock-email-label": "E-poçt göndərməyin qarşısını almaq", + "checkuser-investigateblock-usertalk-label": "Bloklandıqda öz müzakirə səhifəsini redaktə etməsinin qarşısını alın", + "checkuser-investigateblock-reblock-label": "Mövcud blokları ləğv et", + "checkuser-investigateblock-notice-user-page-label": "İstifadəçi səhifəsində xəbərdarlıq yerləşdir", + "checkuser-investigateblock-notice-talk-page-label": "İstifadəçi müzakirəsi səhifəsində xəbərdarlıq yerləşdir", + "checkuser-investigateblock-notice-position-label": "Mövqe", + "checkuser-investigateblock-notice-text-label": "Vikimətn", + "checkuser-investigateblock-notice-append": "Aşağıya əlavə et", + "checkuser-investigateblock-notice-prepend": "Yuxarıya əlavə et", + "checkuser-investigateblock-notice-replace": "Səhifədəki məzmunla dəyiş", + "checkuser-investigateblock-failure": "Heç bir istifadəçi bloklanmadı. Mövcud blokları ləğv etmək üçün: \"{{int:checkuser-investigateblock-reblock-label}}\". Yeni blok mövcud blokla eynidirsə, blok ləğv edilməyəcək.", + "checkuser-investigateblock-success": "'''{{PLURAL:$2|İstifadəçi|İstifadəçilər}} $1 bloklanıb'''", + "checkuser-investigateblock-notices-failed": "Bəzi bildirişlər istifadəçi səhifələrinə və ya istifadəçi müzakirə səhifələrinə əlavə edilə bilmədi.", + "checkuser-investigate": "Araşdır", + "checkuser-investigate-page-subtitle": "$1 üçün mövcud araşdırma", + "checkuser-investigate-subtitle-block-button-label": "Blokla", + "checkuser-investigate-subtitle-cancel-button-label": "İmtina", + "checkuser-investigate-subtitle-continue-button-label": "Davam et", + "checkuser-investigate-subtitle-show-checkuser": "Təftişə keç", + "checkuser-investigate-indicator-new-investigation": "Yeni araşdırma", + "checkuser-investigate-indicator-logs": "Qeydlər", + "checkuser-investigate-legend": "İstifadəçi adları, IP-ünvanları və IP aralıqlarını axtar", + "checkuser-investigate-notice-no-results": "Nəticə yoxdur.", + "checkuser-investigate-tab-preliminary-check": "Hesab məlumatı", + "checkuser-investigate-tab-compare": "IPlər & User agentlər", + "checkuser-investigate-tab-timeline": "Zaman qrafiki", + "checkuser-investigate-targets-label": "İstifadəçi adları və IP-ünvanları", + "checkuser-investigate-targets-placeholder": "İstifadəçi Adı və ya 1.1.1.1", + "checkuser-investigate-duration-label": "Müddət", + "checkuser-investigate-duration-option-all": "Hamısı", + "checkuser-investigate-duration-option-1w": "Son həftə", + "checkuser-investigate-duration-option-2w": "Son 2 həftə", + "checkuser-investigate-duration-option-30d": "Son 30 gün", + "checkuser-investigate-reason-label": "Səbəb", + "checkuser-investigate-preliminary-notice-ip-targets": "Hesab məlumat bölməsi IPlər haqqında məlumat ehtiva etmir. Həmin məlumatlar üçün <span class=\"plainlinks\">[$1 IPlər & User agentlər]</span> səhifəsinə nəzər yetirin.", + "checkuser-investigate-preliminary-table-cell-blocked": "Bloklandı", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|redaktə}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Bloklanmadı", + "checkuser-investigate-preliminary-table-header-blocked": "Status", + "checkuser-investigate-preliminary-table-header-editcount": "Redaktələr", + "checkuser-investigate-preliminary-table-header-groups": "Qruplar", + "checkuser-investigate-preliminary-table-header-name": "İstifadəçi adı", + "checkuser-investigate-preliminary-table-header-registration": "Əlavə edilmə tarixi", + "checkuser-investigate-preliminary-table-header-wiki": "Viki", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Viki tapılmadı", + "checkuser-investigate-filters-legend": "Filtrlər", + "checkuser-investigate-filters-exclude-targets-label": "Aşağıdakı istifadəçiləri və ya IPləri gizlət", + "checkuser-investigate-timeline-notice-no-results": "Heç bir nəticə yoxdur. bu istifadəçilərdən və ya IPlərdən son 90 gün ərzində heç bir fəaliyyət qeydə alınmayıb.", + "checkuser-investigate-timeline-notice-no-results-filters": "Bu filtr meyarlarına uyğun heç bir nəticə yoxdur. Axtarışı genişləndirmək üçün bəzi filtrləri silməyə çalışın.", + "checkuser-investigate-compare-copy-button-label": "Vikimətni göstər", + "checkuser-investigate-compare-toollinks-ipcheck": "Proksi yoxlanışı", + "checkuser-investigate-compare-copy-message-label": "Bu məlumatı Vikimətn cədvəli olaraq kopyalamaq istəyirsiniz?", + "checkuser-investigate-compare-notice-exceeded-limit": "Texniki məhdudiyyətlər səbəbindən təqdim edilə bilən qeydlərin sayına çatdıq. Aşağıdakı hədəflər üçün göstərilmiş məlumatlar yarımçıqdır: $1. Zəhmət olmasa daha az hədəf, daha kiçik vaxt və ya daha dar IP aralığından istifadə etməyə çalışın.", + "checkuser-investigate-compare-notice-no-results": "Heç bir nəticə yoxdur: son 90 gündə bu istifadəçilərdən və ya IP-lərdən heç bir redaktə edilməyib", + "checkuser-investigate-compare-notice-no-results-filters": "Bu filtr meyarlarına uyğun heç bir nəticə yoxdur. Axtarışı genişləndirmək üçün bəzi filtrləri silməyə çalışın.", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Bu istifadəçinin bütün IPlərini göstər", + "checkuser-investigate-compare-table-button-add-user-targets-label": "Bu IP-dəki bütün istifadəçiləri göstər", + "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Bu IP-ni araşdırmaya əlavə et", + "checkuser-investigate-compare-table-button-checks-label": "Yoxlanışlar", + "checkuser-investigate-compare-table-button-contribs-label": "Töhfələr", + "checkuser-investigate-compare-table-button-filter-label": "Nəticələrdən filtrlə", + "checkuser-investigate-compare-table-cell-unregistered": "Qeydiyyatsız", + "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|redaktə}}]</b>", + "checkuser-investigate-compare-table-cell-other-edits": "<i>(bütün istifadəçilərdən ~$1)</i>", + "checkuser-investigate-compare-table-header-username": "İstifadəçi adı", + "checkuser-investigate-compare-table-header-activity": "Tarix aralığı", + "checkuser-investigate-compare-table-header-ip": "IP", + "checkuser-investigate-compare-table-header-useragent": "İstifadəçi agenti", + "checkuser-investigate-subtitle-link-restart-tour": "Turu yenidən başlat" } diff --git a/CheckUser/i18n/ba.json b/CheckUser/i18n/ba.json index 2a240764..9cda41e0 100644 --- a/CheckUser/i18n/ba.json +++ b/CheckUser/i18n/ba.json @@ -12,7 +12,6 @@ }, "checkuser-summary": "Был ҡорал ҡатнашыусы тарафынан ҡулланылған IP адрестарҙы алыр өсөн йәки IP адрестан эшләнгән үҙгәртеүҙәрҙе/ҡатнашыусыларҙы ҡарар өсөн ҡулланыла ала.\nIP адрестан эшләнгән үҙгәртеүҙәр һәм ҡатнашыусылар күрһәтелгән XFF-башлыҡтар аша, IP адрестан һуң \"/xff\" өҫтәп, алына ала. IPv4 (CIDR $1-32) һәм IPv6 (CIDR $2-128) ҡулланыла ала.\nЕтештереүсәнлек маҡсаттарында тәүге 5000 үҙгәртеү генә күрһәтеләсәк.\nБыл ҡоралды ҡағиҙәләргә ярашлы ҡулланығыҙ.", "checkuser-desc": "Ҡатнашыусыларҙың IP адрестарын һәм башҡа мәғлүмәтте тикшереү хоҡуғын ҡатнашыусыларға бирә", - "checkuser-logcase": "Журнал яҙмаларында эҙләү ҙур/бәләкәй хәрефкә һиҙгер.", "checkuser": "Ҡулланыусыны тикшер", "checkuserlog": "Ҡулланыусыларҙы тикшереү журналы", "checkuser-contribs": "Ҡулланыусынын IP адресын тикшерергә", @@ -46,7 +45,6 @@ "checkuser-check-this-user": "Был ҡулланыусыны тикшерергә", "checkuser-recent-checks": "Был ҡулланыусының яңыраҡ булған тикшереүҙәре", "checkuser-log-fail": "Журналға яҙыу өҫтәп булмай", - "checkuser-nolog": "Журнал файлы табылманы", "checkuser-blocked": "Бикле", "checkuser-gblocked": "Глобаль кимәлдә бикле", "checkuser-locked": "Бикле", diff --git a/CheckUser/i18n/ban.json b/CheckUser/i18n/ban.json new file mode 100644 index 00000000..1c9cec11 --- /dev/null +++ b/CheckUser/i18n/ban.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Chinamoonroll" + ] + }, + "checkuser-create-action": "sampun kakardi", + "checkuser-reset-action": "jumu kruna sandi sang anganggé $1" +} diff --git a/CheckUser/i18n/bcc.json b/CheckUser/i18n/bcc.json index 563b6ab2..4ab8e765 100644 --- a/CheckUser/i18n/bcc.json +++ b/CheckUser/i18n/bcc.json @@ -6,7 +6,6 @@ ] }, "checkuser-desc": "کاربرانء اجازت دن گون مناسبین اجازت آدرسان آی پی یک کاربری و دگه اطلاعاتء کنترل بکنت", - "checkuser-logcase": "گردگ ته آمار به الفبای هورد و مزنین حساسنت.", "checkuser": "کنترل کاربر", "checkuserlog": "آمار کنترل کاربر", "group-checkuser": "کنترل کابران", @@ -24,7 +23,6 @@ "checkuser-nomatch": "هچ همدابی در نکپت", "checkuser-check": "کنترل", "checkuser-log-fail": "نه تونی ورودی آمار اضافه کنت", - "checkuser-nolog": "فایل آماری در نه کپت", "checkuser-blocked": "محدود", "checkuser-too-many": "بازگین نتیجه, لطفا CIDR هورد تر کن.\nادان آی پی آنی هستند که استفاده کننت(5000 ماکسیمم، گون آدرس ردیف بوتگن):", "checkuser-user-nonexistent": "مشخص بوتگین کاربر موجود نهنت", diff --git a/CheckUser/i18n/bcl.json b/CheckUser/i18n/bcl.json index d2a2a641..1a11caba 100644 --- a/CheckUser/i18n/bcl.json +++ b/CheckUser/i18n/bcl.json @@ -8,7 +8,6 @@ }, "checkuser-summary": "Ining kasangkapan minahingopya kan dae pa sana nahahaloy na mga kaliwatan tanganing huguton an mga estada kan IP na pinaggamit nin sarong paragamit o ipahiling an niliwat/paragamit na datos para sa sarong estada kan IP.\nAn mga paragamit asin mga niliwat nin sarong estada kan IP nin kliyente mapupuwedeng mahuhugot sa paagi kan XFF na mga kapamayuhanan sa pagdudugang kan estada kan IP nin \"/xff\". An IPv4(CIDR $1-32) asin IPv6(CIDR $2-128) an suportado.\nDae masobra sa 5,000 na mga pagliwat an ipagbabalik nin huli sa mga rason nin paggigibo.\nGamita ini na uyon sa palisiya.", "checkuser-desc": "Minagawad sa mga paragamit nin magkakanigong permiso sa abilidad na magrikisa kan mga estada nin mga IP kan paragamit asin iba pang impormasyon", - "checkuser-logcase": "An talaan nin paghahanap sarong sensitibo sa pindutan.", "checkuser": "Rikisahon an paragamit", "checkuserlog": "Rikisahon an talaan nin paragamit", "checkuser-contribs": "rikisahon an mga estada kan IP nin paragamit", @@ -40,7 +39,6 @@ "checkuser-nomatch-edits": "Mayong mga katugma an nanagboan.\nAn huring pagliwat kaidtong $1 mga $2.", "checkuser-check": "Rikisaron", "checkuser-log-fail": "Dae naggibo na magdugang nin entrada sa talaan", - "checkuser-nolog": "Dae nanagboan an sagunson nin talaan", "checkuser-blocked": "Pigbágat", "checkuser-gblocked": "Pankinabanon na pinagkubkob", "checkuser-locked": "Pinagkandado", diff --git a/CheckUser/i18n/be-tarask.json b/CheckUser/i18n/be-tarask.json index bf9e0f12..6b7ae341 100644 --- a/CheckUser/i18n/be-tarask.json +++ b/CheckUser/i18n/be-tarask.json @@ -5,12 +5,13 @@ "EugeneZelenko", "Jim-by", "Red Winged Duck", + "Renessaince", + "Vlad5250", "Wizardist" ] }, - "checkuser-summary": "Гэты інструмэнт праглядае апошнія зьмены для атрыманьня ІР-адрасоў удзельніка альбо паказвае рэдагаваньні/зьвесткі ўдзельніка па ІР-адрасе.\nУдзельнікі і рэдагаваньні, якія рабіліся з ІР-адрасу, пазначаным ў загалоўках XFF, можна атрымаць, дадаўшы да ІР-адрасу «/xff». Падтрымліваюцца IPv4 (CIDR $1-32) і IPv6 (CIDR $2-128).\nЗ прычыны прадукцыйнасьці будуць паказаны ня больш за 5000 рэдагаваньняў.\nКарыстайцеся гэтым інструмэнтам толькі згодна з правіламі.", + "checkuser-summary": "Гэты інструмэнт праглядае апошнія зьмены для атрыманьня ІР-адрасоў удзельніка альбо паказвае рэдагаваньні/зьвесткі ўдзельніка па ІР-адрасе.\nУдзельнікі і рэдагаваньні, якія рабіліся з ІР-адрасу, пазначаным ў загалоўках XFF, можна атрымаць, дадаўшы да ІР-адрасу «/xff». Падтрымліваюцца IPv4 (CIDR $1-32) і IPv6 (CIDR $2-128).\nЗ прычыны прадукцыйнасьці будуць паказаны ня больш за $3 рэдагаваньняў.\nКарыстайцеся гэтым інструмэнтам толькі згодна з правіламі.", "checkuser-desc": "Дае магчымасьць удзельнікам з адпаведнымі правамі правяраць ІР-адрасы і іншую інфармацыю ўдзельнікаў", - "checkuser-logcase": "Пошук па журнале адчувальны да рэгістру літараў.", "checkuser": "Праверыць удзельніка", "checkuserlog": "Журнал праверак удзельнікаў", "checkuser-contribs": "праверыць IP-адрасы ўдзельніка", @@ -34,6 +35,7 @@ "checkuser-week-1": "апошні тыдзень", "checkuser-week-2": "апошнія два тыдні", "checkuser-month": "апошнія 30 дзён", + "checkuser-month-2": "апошнія 60 дзён", "checkuser-all": "усе", "checkuser-cidr-label": "Знайсьці агульны дыяпазон і зьвязаныя адрасы па сьпісе ІР-адрасоў", "checkuser-cidr-res": "Агульны CIDR:", @@ -41,8 +43,10 @@ "checkuser-nomatch": "Супадзеньні ня знойдзеныя.", "checkuser-nomatch-edits": "Супадзеньняў ня знойдзена.\nАпошняе рэдагаваньне зроблена $1 у $2.", "checkuser-check": "Праверыць", + "checkuser-check-this-user": "Праверыць гэтага ўдзельніка", + "checkuser-investigate-this-user": "Даследаваць гэтага ўдзельніка", + "checkuser-recent-checks": "Апошнія праверкі гэтага ўдзельніка", "checkuser-log-fail": "Немагчыма дадаць запіс у журнал", - "checkuser-nolog": "Ня знойдзены файл журнала.", "checkuser-blocked": "Заблякаваны", "checkuser-gblocked": "Заблякаваны глябальна", "checkuser-locked": "Заблякаваны", @@ -50,25 +54,71 @@ "checkuser-localonly": "Не аб’яднаны", "checkuser-massblock": "Заблякаваць выбраныя рахункі ўдзельнікаў", "checkuser-massblock-text": "Выбраныя рахункі будуць заблякаваны назаўсёды з аўтаматычным блякаваньнем і забаронай стварэньня новых рахункаў.\nІР-адрасы будуць заблякаваныя на 1 тыдзень для незарэгістраваных удзельнікаў з забаронай стварэньня новых рахункаў.", + "checkuser-blockemail": "Забараніць адсылку э-пошты", + "checkuser-blocktalk": "Забараніць рэдагаваць іхнія старонкі ўдзельнікаў падчас блякаваньня", "checkuser-blocktag": "Замяніць старонкі ўдзельнікаў на:", "checkuser-blocktag-talk": "Замяніць старонкі гутарак удзельнікаў на:", + "checkuser-reblock": "Перазапісаць існыя блякаваньні", "checkuser-massblock-commit": "Заблякаваць выбраныя рахункі ўдзельнікаў", "checkuser-block-success": "'''Цяпер $2 {{PLURAL:$2|рахунак удзельніка|рахункі удзельнікаў|рахункаў удзельнікаў}} $1 {{PLURAL:$2|заблякаваны|заблякаваныя|заблякаваныя}}.'''", "checkuser-block-failure": "'''Няма заблякаваных рахункаў удзельнікаў.'''", "checkuser-block-limit": "Выбрана зашмат рахункаў удзельнікаў.", "checkuser-block-noreason": "Вам неабходна пазначыць прычыну блякаваньня.", "checkuser-noreason": "Вам неабходна падаць прычыну гэтага запыту.", - "checkuser-too-many": "Зашмат вынікаў (згодна з ацэнкай запыту), калі ласка, абмяжуйце CIDR.\nТут пададзеныя ўжытыя ІР-адрасы (максымум 5000, адсартаваныя паводле адрасу):", + "checkuser-too-many": "Зашмат вынікаў (згодна з ацэнкай запыту), калі ласка, абмяжуйце CIDR.\nТут пададзеныя ўжытыя ІР-адрасы (максымум $1, адсартаваныя паводле адрасу):", "checkuser-user-nonexistent": "Пазначанага рахунку ўдзельніка не існуе.", "checkuser-search": "Пошук у запісах журналу праверкі ўдзельнікаў", "checkuser-search-submit": "Шукаць", "checkuser-search-initiator": "ініцыятар", "checkuser-search-target": "мэта", + "checkuser-log-search-target": "Мэта:", + "checkuser-log-search-initiator": "Ініцыятар:", + "checkuser-log-search-type": "Пошук па:", "checkuser-ipeditcount": "~$1 ад усіх удзельнікаў", "checkuser-showmain": "Вярнуцца да галоўнай формы праверкі ўдзельнікаў", "checkuser-limited": "'''Гэты вынік быў скарочаны, з прычыны прадукцыйнасьці сыстэмы.'''", "checkuser-autocreate-action": "быў створаны аўтаматычна", "checkuser-create-action": "створаны", "checkuser-email-action": "даслаць ліст удзельніку «$1»", - "checkuser-reset-action": "скасаваў пароль для ўдзельніка «$1»" + "checkuser-reset-action": "скасаваў пароль для ўдзельніка $1", + "checkuser-investigateblock": "Заблякаваць удзельнікаў", + "checkuser-investigateblock-reason": "Прычына", + "checkuser-investigateblock-options": "Дадатковыя опцыі", + "checkuser-investigateblock-email-label": "Забараніць адсылку э-пошты", + "checkuser-investigateblock-usertalk-label": "Забараніць рэдагаваць іхнія старонкі ўдзельнікаў падчас блякаваньня", + "checkuser-investigateblock-reblock-label": "Перазапісаць існыя блякаваньні", + "checkuser-investigateblock-notice-position-label": "Пазыцыя", + "checkuser-investigateblock-notice-text-label": "Вікітэкст", + "checkuser-investigate": "Даследаваць", + "checkuser-investigate-subtitle-block-button-label": "Заблякаваць", + "checkuser-investigate-subtitle-cancel-button-label": "Скасаваць", + "checkuser-investigate-subtitle-continue-button-label": "Працягнуць", + "checkuser-investigate-subtitle-show-checkuser": "Перайсьці на Праверку ўдзельнікаў", + "checkuser-investigate-indicator-logs": "Журналы", + "checkuser-investigate-notice-no-results": "Няма вынікаў.", + "checkuser-investigate-tab-preliminary-check": "Зьвесткі пра рахунак", + "checkuser-investigate-tab-timeline": "Храналёгія", + "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-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-toollinks-ipcheck": "Праверка проксі", + "checkuser-investigate-compare-table-button-checks-label": "Праверкі", + "checkuser-investigate-compare-table-button-contribs-label": "Унёсак", + "checkuser-investigate-compare-table-cell-unregistered": "Незарэгістраваны", + "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": "Агент удзельніка" } diff --git a/CheckUser/i18n/be.json b/CheckUser/i18n/be.json index 58d5005e..076336ce 100644 --- a/CheckUser/i18n/be.json +++ b/CheckUser/i18n/be.json @@ -2,9 +2,88 @@ "@metadata": { "authors": [ "Artsiom91", + "No Sleep till Krupki", + "Tomato Cream", + "Vlad5250", "Тест" ] }, + "checkuser-desc": "Дае магчымасць удзельнікам з адпаведнымі правамі правяраць ІР-адрасы і іншую інфармацыю ўдзельнікаў", + "checkuser": "Праверыць удзельніка", + "checkuserlog": "Журнал праверак удзельнікаў", + "checkuser-contribs": "праверыць IP-адрасы ўдзельніка", + "checkuser-contribs-log": "апошнія праверкі ўдзельніка", + "right-checkuser": "Праверка ІР-адрасоў і іншай інфармацыі ўдзельнікаў", + "right-checkuser-log": "Прагляд журнала праверкі ўдзельнікаў", + "action-checkuser": "правяраць ІР-адрасы і іншую інфармацыю ўдзельнікаў", + "action-checkuser-log": "праглядаць журнал праверкі ўдзельнікаў", "checkuser-reason": "Прычына:", - "checkuser-localonly": "Не аб’яднаны" + "checkuser-reason-api": "API: $1", + "checkuser-showlog": "Перайсці на журнал праверкі ўдзельнікаў", + "checkuser-target": "Адрас IP або імя ўдзельніка:", + "checkuser-check": "Праверыць", + "checkuser-check-this-user": "Праверыць гэтага ўдзельніка", + "checkuser-investigate-this-user": "Даследаваць гэтага ўдзельніка", + "checkuser-recent-checks": "Нядаўнія праверкі гэтага ўдзельніка", + "checkuser-log-fail": "Немагчыма дадаць запіс у журнал", + "checkuser-blocked": "Заблакаваны", + "checkuser-gblocked": "Глабальна заблакаваны", + "checkuser-locked": "Замкнуты", + "checkuser-wasblocked": "Заблакаваны раней", + "checkuser-localonly": "Не аб’яднаны", + "checkuser-massblock": "Заблакаваць выбраных удзельнікаў", + "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|заблакіраваны|заблакіраваныя}}.", + "checkuser-block-failure": "'''Ніводны ўдзельнік не быў заблакаваны.'''", + "checkuser-block-limit": "Выбрана зашмат удзельнікаў.", + "checkuser-block-noreason": "Вы павінны ўказаць прычыну блакаванняў.", + "checkuser-centralauth-multilock": "Замкнуць некалькі глабальных рахункаў", + "checkuser-noreason": "Вы павінны ўказаць прычыну для гэтага запыту.", + "checkuser-too-many": "Зашмат вынікаў (у адпаведнасці з ацэнкай запыту), калі ласка, звузіце CIDR.\nВось якія IP-адрасы выкарыстоўваюцца (макс. $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-showmain": "Вярнуцца да галоўнай формы праверкі ўдзельнікаў", + "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": "Даследаваць", + "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-subtitle-show-checkuser": "Перайсці на Праверку ўдзельнікаў", + "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": "Заблакаваны" } diff --git a/CheckUser/i18n/bg.json b/CheckUser/i18n/bg.json index 17384eef..e0d2de9d 100644 --- a/CheckUser/i18n/bg.json +++ b/CheckUser/i18n/bg.json @@ -12,9 +12,8 @@ "Vodnokon4e" ] }, - "checkuser-summary": "Този инструмент сканира последните промени, за да извлече IP адресите, използвани от потребител, или за да покаже информация за редакциите и потребителите от даден IP адрес.\nИнформация за потребители и редакции от даден IP адрес може да се извлече и от XFF headers, като в края на IP адреса се добави „/xff“. Поддържат се IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128).\nОт съображения, свързани с производителността на уикито, ще бъдат показани не повече от 5000 редакции.\nИзползвайте инструмента съобразно установената политика.", + "checkuser-summary": "Този инструмент сканира последните промени, за да извлече IP адресите, използвани от потребител, или за да покаже информация за редакциите и потребителите от даден IP адрес.\nИнформация за потребители и редакции от даден IP адрес може да се извлече и от XFF заглавки, като в края на IP адреса се добави „/xff“. Поддържат се IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128).\nОт съображения за ефективност ще бъдат върнати не повече от $3 редакции.\nИзползвайте инструмента съобразно установената политика.", "checkuser-desc": "Предоставя на потребители с подходящите права възможност за проверка на потребителски IP адреси и друга информация", - "checkuser-logcase": "Търсенето в дневника е чувствително към регистъра на буквите.", "checkuser": "Проверяване на потребител", "checkuserlog": "Дневник на проверките на потребители", "checkuser-contribs": "проверка на IP-адресите на потребителя", @@ -47,7 +46,6 @@ "checkuser-check-this-user": "Проверка на потребителя", "checkuser-recent-checks": "Последни проверки на потребителя", "checkuser-log-fail": "Беше невъзможно да се добави запис в дневника", - "checkuser-nolog": "Не беше открит дневник.", "checkuser-blocked": "Блокиран", "checkuser-gblocked": "Глобално блокиран", "checkuser-locked": "Заключено", @@ -66,7 +64,7 @@ "checkuser-block-noreason": "Трябва да се посочи причина за блокиранията.", "checkuser-centralauth-multilock": "Заключване на избраните сметки", "checkuser-noreason": "Необходимо е да се посочи основание за тази заявка.", - "checkuser-too-many": "Твърде много резултати (според оценката на заявката), моля уточнете CIDR.\nПоказани са използваните IP адреси (най-много 5 000, сортирани по адрес):", + "checkuser-too-many": "Твърде много резултати (според оценката на заявката), моля уточнете CIDR.\nПоказани са използваните IP адреси (най-много $1, сортирани по адрес):", "checkuser-user-nonexistent": "Посоченият потребител не съществува.", "checkuser-search": "Търсене в дневника на проверките", "checkuser-search-submit": "Търсене", @@ -80,6 +78,6 @@ "checkuser-autocreate-action": "беше автоматично създадена", "checkuser-create-action": "е създаден", "checkuser-email-action": "изпрати е-писмо на потребител „$1“", - "checkuser-reset-action": "промяна на парола за потребител „$1“", + "checkuser-reset-action": "нулиране парола на потребител $1", "checkuser-token-fail": "Сесията не е успешна. Опитайте отново." } diff --git a/CheckUser/i18n/bjn.json b/CheckUser/i18n/bjn.json new file mode 100644 index 00000000..b833b789 --- /dev/null +++ b/CheckUser/i18n/bjn.json @@ -0,0 +1,10 @@ +{ + "@metadata": { + "authors": [ + "Ezagren" + ] + }, + "checkuser-investigate-legend": "Gagai ngaran pamakai, alamat IP, atawa rantang IP", + "checkuser-investigate-notice-no-results": "Kadada hasil.", + "checkuser-investigate-compare-table-cell-unregistered": "Kada tadaptar" +} diff --git a/CheckUser/i18n/blk.json b/CheckUser/i18n/blk.json new file mode 100644 index 00000000..93fd715b --- /dev/null +++ b/CheckUser/i18n/blk.json @@ -0,0 +1,11 @@ +{ + "@metadata": { + "authors": [ + "Khun Kt", + "咽頭べさ" + ] + }, + "group-checkuser": "စောႏတနာႏစဲစ်ထွားသားဖိုင်ႏ", + "checkuser-target": "အုဲင်ပီလိပ်စာ တဝ်းလဲ့ ကေားသုင်ꩻသားမိဥ်ꩻ:", + "checkuser-month-2": "အဆုဲင်ꩻသွတ်ꩻ လꩻလဲဉ်း မွူးနီꩻ ၆၀" +} diff --git a/CheckUser/i18n/bn.json b/CheckUser/i18n/bn.json index b9e52dcc..22abc09c 100644 --- a/CheckUser/i18n/bn.json +++ b/CheckUser/i18n/bn.json @@ -9,12 +9,12 @@ "Sourav Halder", "Wikitanvir", "Zaheen", + "আজিজ", "আফতাবুজ্জামান" ] }, "checkuser-summary": "এই সরঞ্জামটি সাম্প্রতিক পরিবর্তনসমূহ বিশ্লেষণ করে একজন ব্যবহারকারীর ব্যবহৃত আইপিগুলি নিয়ে আসে কিংবা কোন একটি আইপির জন্য সম্পাদনা/ব্যবহারকারী উপাত্ত প্রদর্শন করে।\nকোন ক্লায়েন্ট আইপি-র জন্য ব্যবহারকারী ও সম্পাদনা XFF হেডারসমূহের সাহায্যে নিয়ে আসা যায়; এজন্য আইপির সাথে \"/xff\" যোগ করতে হয়। IPv4 (CIDR $1-32) এবং IPv6 (CIDR $2-128) এই সরঞ্জামে সমর্থিত।\nদক্ষতাজনিত কারণে ৫০০০-এর বেশি সম্পাদনা নিয়ে আসা হবে না।\nনীতিমালা মেনে এটি ব্যবহার করুন।", "checkuser-desc": "যথাযথ অনুমোদনপ্রাপ্ত ব্যবহারকারীদেরকে অন্য ব্যবহারকারীদের আইপি ঠিকানা এবং অন্যান্য তথ্য পরীক্ষা করার ক্ষমতা দেয়", - "checkuser-logcase": "লগ অনুসন্ধান বড়/ছোট হাতের অক্ষরের উপর নির্ভরশীল", "checkuser": "ব্যবহারকারী পরীক্ষণ", "checkuserlog": "ব্যবহারকারী পরীক্ষণ লগ", "checkuser-contribs": "ব্যবহারকারীর আইপি ঠিকানা পরীক্ষা করুন", @@ -42,13 +42,13 @@ "checkuser-cidr-label": "আইপি ঠিকানার একটি তালিকার জন্য সাধারণ পরিসীমা এবং প্রভাবিত আইপি ঠিকানাগুলি খুঁজুন", "checkuser-cidr-res": "সাধারণ সিআইডিআর:", "checkuser-empty": "এই লগে কিছুই নেই।", - "checkuser-nomatch": "মিলে যায় এমন কিছু পাওয়া যায়নি।", + "checkuser-nomatch": "কোন মিল খুঁজে পাওয়া যায়নি।", "checkuser-nomatch-edits": "কোন মিল খুঁজে পাওয়া যায়নি।\nশেষ সম্পাদনাটি ছিল $1 তারিখে $2 টায়।", "checkuser-check": "পরীক্ষা করুন", "checkuser-check-this-user": "এই ব্যবহারাকারীকে পরীক্ষণ করুন", + "checkuser-investigate-this-user": "এই ব্যবহারাকারীকে তদন্ত করুন", "checkuser-recent-checks": "এই ব্যবহারকারীর জন্য সাম্প্রতিক পরীক্ষাগুলি", "checkuser-log-fail": "লগ ভুক্তিতে যোগ করা সম্ভব হচ্ছে না", - "checkuser-nolog": "কোন লগ ফাইল পাওয়া যায়নি।", "checkuser-blocked": "বাধাপ্রাপ্ত", "checkuser-gblocked": "বৈশ্বিকভাবে বাধাপ্রাপ্ত", "checkuser-locked": "অবরুদ্ধ", @@ -58,11 +58,12 @@ "checkuser-massblock-text": "আইপি ঠিকানাগুলির স্বয়ংক্রিয় অবরুদ্ধ সক্রিয়করণ এবং অ্যাকাউন্ট সৃষ্টি নিষ্ক্রিয়করণ সহ, নির্বাচিত অ্যাকাউন্টগুলি অনির্দিষ্টকালের জন্য অবরুদ্ধ করা হবে।\nআইপি ঠিকানাগুলি বেনামী ব্যবহারকারীদের জন্য শুধুমাত্র এক সপ্তাহের জন্য অবরুদ্ধ হবে এবং অ্যাকাউন্ট সৃষ্টি নিষ্ক্রিয় করা হবে।", "checkuser-blockemail": "ইমেইল পাঠানো থেকে বিরত রাখো", "checkuser-blocktalk": "বাধা থাকা অবস্থায় তাদের নিজস্ব আলাপ পাতা সম্পাদনা করা থেকে বিরত রাখো", - "checkuser-blocktag": "যেটির মাধ্যমে ব্যবহারকারী পাতা প্রতিস্থাপন করবেন:", - "checkuser-blocktag-talk": "যেটির মাধ্যমে আলাপ পাতা প্রতিস্থাপন করবেন:", + "checkuser-blocktag": "এটি দিয়ে ব্যবহারকারীর পাতা প্রতিস্থাপন করুন:", + "checkuser-blocktag-talk": "এটি দিয়ে আলাপ পাতা প্রতিস্থাপন করুন:", + "checkuser-reblock": "বিদ্যমান বাধা পরিবর্তন করো", "checkuser-massblock-commit": "নির্বাচিত ব্যবহারকারীদের বাধা দিন", - "checkuser-block-success": "'''$1 {{PLURAL:$2|ব্যবহারকারী|ব্যবহারকারীগণ}} এখন অবরুদ্ধ আছে।'''", - "checkuser-block-failure": "'''বাধাদানকৃত কোনো ব্যবহারকারী নেই।'''", + "checkuser-block-success": "'''$1 {{PLURAL:$2|ব্যবহারকারী|ব্যবহারকারীগণ}} এখন অবরুদ্ধ।'''", + "checkuser-block-failure": "'''বাধাপ্রাপ্ত কোনো ব্যবহারকারী নেই।'''", "checkuser-block-limit": "অনেক বেশি ব্যবহারকারী নির্বাচিত করা হয়েছে।", "checkuser-block-noreason": "আপনাকে অবশ্যই এই বাধাদানের জন্য একটি কারণ উল্লেখ করতে হবে।", "checkuser-centralauth-multilock": "নির্বাচিত অ্যাকাউন্টগুলি বহু তালাবদ্ধ করুন", @@ -76,7 +77,8 @@ "checkuser-log-search-target": "লক্ষ্য:", "checkuser-log-search-type": "অনুসন্ধান করুন এই অনুসারে:", "checkuser-ipeditcount": "সকল ব্যবহারকারী মিলিয়ে ~$1টি", - "checkuser-showmain": "CheckUser মূল ফর্মে ফেরত যান", + "checkuser-showmain": "ব্যবহারকারী পরীক্ষকের মূল ফর্মে ফেরত যান", + "checkuser-show-investigate": "তদন্তের মূল ফরমে ফেরত যান", "checkuser-limited": "'''এসব ফলাফল কর্মক্ষমতার কারণে ছেঁটে ফেলা হয়েছে।'''", "checkuser-log-entry-userips": "$3, $1 $2-এর জন্য আইপি ঠিকানাগুলি পেয়েছেন", "checkuser-log-entry-ipedits": "$3, $1 <bdi>$2</bdi>-এর জন্য সম্পাদনাগুলি পেয়েছেন", @@ -84,16 +86,24 @@ "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-log-entry-investigate": "$3, $1, $2-এর জন্য তথ্য সন্ধান করেছেন", "checkuser-autocreate-action": "স্বয়ংক্রিয়ভাবে তৈরি হয়েছিলো", "checkuser-create-action": "তৈরি করা হয়েছে", "checkuser-email-action": "ব্যবহারকারী \"$1\" কে একটি ইমেইল পাঠিয়েছে", - "checkuser-reset-action": "ব্যবহারকারী \"$1\"-এর জন্য পাসওয়ার্ড পুনঃস্থাপন করো", + "checkuser-reset-action": "ব্যবহারকারী \"$1\"-এর পাসওয়ার্ড পুনঃস্থাপন হয়েছে", "checkuser-token-fail": "সেশন ব্যর্থতা। অনুগ্রহপূর্বক আবার চেষ্টা করুন।", "checkuser-login-failure": "$1 হিসেবে {{SITENAME}}-এ প্রবেশ করতে ব্যর্থ", - "checkuser-login-success": "$1 হিসেবে {{SITENAME}}-এ প্রবেশ সফল হয়েছে", + "checkuser-login-success": "$1 হিসেবে {{SITENAME}}-এ সফলভাবে প্রবেশ করেছেন", + "checkuser-link-investigate-label": "নতুন ব্যবহারকারী পরীক্ষণ সরঞ্জাম ব্যবহার করে দেখুন", + "checkuser-investigateblock": "ব্যবহারকারীদের বাধা দিন", "checkuser-investigateblock-target": "ব্যবহারকারী নাম বা আইপি ঠিকানা", "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": "উইকিপাঠ্য", @@ -103,11 +113,14 @@ "checkuser-investigateblock-success": "{{PLURAL:$2|ব্যবহারকারী}} $1 এখন বাধাপ্রাপ্ত।", "checkuser-investigateblock-notices-failed": "কিছু বিজ্ঞপ্তি ব্যবহারকারীর পাতাগুলি বা আলাপ পাতাগুলিতে যোগ করা যায়নি।", "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": "ব্যবহারকারীর নামগুলি, আইপি ঠিকানাগুলি বা আইপি পরিসীমাগুলির জন্য অনুসন্ধান করুন", + "checkuser-investigate-notice-no-results": "কোনও ফলাফল পাওয়া যায়নি।", "checkuser-investigate-tab-preliminary-check": "অ্যাকাউন্টের তথ্য", "checkuser-investigate-tab-compare": "আইপি ও ব্যবহারকারী এজেন্ট", "checkuser-investigate-tab-timeline": "সময়ক্রম", @@ -126,17 +139,28 @@ "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-copy-button-label-hide": "উইকিপাঠ্য আড়াল করুন", + "checkuser-investigate-compare-toollinks-whois": "হুইজ", + "checkuser-investigate-compare-toollinks-ipcheck": "প্রক্সি পরীক্ষা", + "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-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-compare-table-cell-unregistered": "অনিবন্ধিত", - "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|সম্পাদনা|সম্পাদনাগুলি}}]</b>", + "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": "ব্যবহারকারী এজেন্ট" + "checkuser-investigate-compare-table-header-useragent": "ব্যবহারকারী এজেন্ট", + "checkuser-investigate-subtitle-link-restart-tour": "ট্যুর পুনরাম্ভ করুন", + "checkuser-investigate-tour-targets-title": "একাধিক ব্যবহারকারী ও আইপি পরীক্ষা করছেন?" } diff --git a/CheckUser/i18n/bnn.json b/CheckUser/i18n/bnn.json new file mode 100644 index 00000000..78389876 --- /dev/null +++ b/CheckUser/i18n/bnn.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Akamycoco" + ] + }, + "checkuser-investigate-preliminary-table-header-editcount": "Kapha mapatas" +} diff --git a/CheckUser/i18n/br.json b/CheckUser/i18n/br.json index fc2cbee3..20e407dd 100644 --- a/CheckUser/i18n/br.json +++ b/CheckUser/i18n/br.json @@ -7,9 +7,8 @@ "Y-M D" ] }, - "checkuser-summary": "Furchal a ra an ostilh-mañ ar c'hemmoù diwezhañ a-benn klask ar chomlec'h IP implijet gant un implijer bennak, diskouez a ra holl degasadennoù ur chomlec'h IP (ha pa vefe bet enrollet), pe roll ar c'hontoù implijet gant ur chomlec'h IP. Gallout a ra ar c'hontoù hag ar c'hemmoù bezañ kavet gant un IP XFF mard echu gant \"/xff\". Posupl eo implijout ar protokoloù IPv4 (CIDR $1-32) hag IPv6 (CIDR $2-128). Bevennet eo an niver a gemmoù a c'haller lakaat war wel da {{formatnum:5000}} evit abegoù nerzh ar servijer. Grit gant an ostilh-mañ en ur zoujañ d'ar garta implijout.", + "checkuser-summary": "Furchal a ra an ostilh-mañ ar c'hemmoù diwezhañ a-benn klask ar chomlec'h IP implijet gant un implijer bennak, diskouez a ra holl degasadennoù ur chomlec'h IP (ha pa vefe bet enrollet), pe roll ar c'hontoù implijet gant ur chomlec'h IP. Gallout a ra ar c'hontoù hag ar c'hemmoù bezañ kavet gant un IP XFF mard echu gant \"/xff\". Posupl eo implijout ar protokoloù IPv4 (CIDR $1-32) hag IPv6 (CIDR $2-128).\nNe vo kaset en-dro nemet $3 kemm da vuiañ evit abegoù nerzh ar servijer.\nGrit gant an ostilh-mañ en ur zoujañ d'ar garta implijout.", "checkuser-desc": "Reiñ a ra an tu d'an dud aotreet evit se da wiriañ chomlec'hioù IP an implijerien ha da gaout titouroù all", - "checkuser-logcase": "Kizidik eo ar c'hlask er marilh ouzh an direnneg (pennlizherennoù/lizherennoù munud)", "checkuser": "Gwiriañ an implijer", "checkuserlog": "Marilh kontrolliñ an implijerien", "checkuser-contribs": "gwiriañ chomlec'hioù IP an implijer", @@ -41,7 +40,6 @@ "checkuser-nomatch-edits": "Kenglot ebet kavet.\nD'an $1 da $2 eo bet graet ar c'hemm diwezhañ.", "checkuser-check": "Gwiriañ", "checkuser-log-fail": "Dibosupl ouzhpennañ ar moned d'ar marilh", - "checkuser-nolog": "Restr ebet er marilh", "checkuser-blocked": "Stanket", "checkuser-gblocked": "Stankañ dre-vras", "checkuser-locked": "Prennet", @@ -57,7 +55,7 @@ "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-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-too-many": "Re a zisoc'hoù (hervez istimadur ar reked), strishait ar CIDR mar plij.\nSetu an IPoù implijet ($1 d'ar muiañ, urzhiet dre ar chomlec'h) :", "checkuser-user-nonexistent": "N'eus ket eus an implijer merket", "checkuser-search": "Klask", "checkuser-search-submit": "Klask", @@ -69,10 +67,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": "adderaouekaet eo bet 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ñ" + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Diskouez holl IPoù an implijer-mañ" } diff --git a/CheckUser/i18n/bs.json b/CheckUser/i18n/bs.json index 8b7c5e45..dec0c3d7 100644 --- a/CheckUser/i18n/bs.json +++ b/CheckUser/i18n/bs.json @@ -10,7 +10,6 @@ }, "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.", "checkuser-desc": "Daje korisnicima s odgovarajućim pravima mogućnost provjere korisničkih IP adresa i drugih informacija", - "checkuser-logcase": "Pretraga zapisnika razlikuje velika i mala slova.", "checkuser": "Provjera korisnika", "checkuserlog": "Zapisnik CheckUsera", "checkuser-contribs": "provjeri korisničke IPe", @@ -40,7 +39,6 @@ "checkuser-nomatch-edits": "Nije pronađen traženi upit.\nPosljednja izmjena bila je $1 u $2.", "checkuser-check": "Provjera", "checkuser-log-fail": "Ne mogu dodati stavku u zapisnik", - "checkuser-nolog": "Zapisnik nije pronađen.", "checkuser-blocked": "Blokiran", "checkuser-gblocked": "Blokiran globalno", "checkuser-locked": "Zaključano", diff --git a/CheckUser/i18n/ca.json b/CheckUser/i18n/ca.json index eea3ca9a..8d91fa0a 100644 --- a/CheckUser/i18n/ca.json +++ b/CheckUser/i18n/ca.json @@ -23,7 +23,6 @@ }, "checkuser-summary": "Aquest instrument efectua una cerca als canvis recents per a comprovar les adreces IP fetes servir per un usuari o per a mostrar les edicions d'una certa adreça IP.\nLes edicions i usuaris d'un client IP es poden obtenir via capçaleres XFF afegint /xff al final de la IP. Tant les adreces IPv4 (CIDR $1-32) com les IPv6 (CIDR $2-128) són admeses.\nPer raons d'efectivitat i de memòria no es retornen més de 5000 edicions. Recordeu que aquesta eina només es pot usar d'acord amb les polítiques corresponents i amb respecte a la legislació sobre privadesa.", "checkuser-desc": "Permet als usuaris amb els permisos adients l'habilitat de comprovar les adreces IP que fan servir els usuaris enregistrats.", - "checkuser-logcase": "Les majúscules es tracten de manera diferenciada en la cerca dins el registre.", "checkuser": "Comprova l'usuari", "checkuserlog": "Registre del verificador de comptes d'usuari", "checkuser-contribs": "comprova les IP de l'usuari", @@ -52,7 +51,6 @@ "checkuser-nomatch-edits": "No s'ha trobat.\nL'última modificació va ser el $1 a $2.", "checkuser-check": "Comprova", "checkuser-log-fail": "No s'ha pogut afegir al registre", - "checkuser-nolog": "No s'ha trobat el fitxer del registre.", "checkuser-blocked": "Blocat", "checkuser-gblocked": "Blocat globalment", "checkuser-locked": "Blocat", @@ -82,7 +80,5 @@ "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-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 b4cce00b..e47d38fc 100644 --- a/CheckUser/i18n/ce.json +++ b/CheckUser/i18n/ce.json @@ -18,7 +18,7 @@ "checkuser-reason-api": "API: $1", "checkuser-showlog": "Гайта тептар", "checkuser-query": "Деха керла нисдарш", - "checkuser-target": "IP-адрес я декъашхочун цӀе:", + "checkuser-target": "IP-адрес йа декъашхочун цӀе:", "checkuser-users": "Керла декъашхой", "checkuser-edits": "Нисдарш хьажа", "checkuser-ips": "Деха IP-адрес", @@ -30,7 +30,7 @@ "checkuser-nomatch": "ХӀума цакарина", "checkuser-nomatch-edits": "Цакарий.\nТӀеххьара нисдар дина $1 $2.", "checkuser-check": "Хьажа", - "checkuser-log-fail": "Цатарло тептар тӀе дӀаяздар тӀоха", + "checkuser-log-fail": "Цатарло тептар чу тӀетоха дӀайаздар", "checkuser-blocked": "Блоктоьхна", "checkuser-gblocked": "Глобалан блоктоьхна", "checkuser-locked": "Блоктоьхна", @@ -40,7 +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 3151bb3d..4138b513 100644 --- a/CheckUser/i18n/ckb.json +++ b/CheckUser/i18n/ckb.json @@ -1,9 +1,11 @@ { "@metadata": { "authors": [ + "Aram", "Asoxor", "Calak", "Cwtiyar", + "Halbast", "ئارام بکر" ] }, @@ -19,8 +21,8 @@ "checkuser-showlog": "لۆگ نیشان بدە", "checkuser-query": "دوایین گۆڕانکارییەکان بگەڕێ", "checkuser-target": "ناونیشانی ئایپی یان ناوی بەکارھێنەر:", - "checkuser-users": "بەکارھێنەرەکان پێرست بکە", - "checkuser-edits": "دەستکارییەکان پێرست بکە", + "checkuser-users": "بەکارھێنەرەکان پێڕست بکە", + "checkuser-edits": "دەستکارییەکان پێڕست بکە", "checkuser-ips": "ناونیشانەکان ئایپی پێرست بکە", "checkuser-period": "ماوە:", "checkuser-week-1": "حەوتەیەک لەمە پێش", @@ -30,7 +32,6 @@ "checkuser-cidr-res": "CIDR ھاوبەش:", "checkuser-empty": "لۆگ ھیچی تێدا نییە.", "checkuser-check": "بپشکنە", - "checkuser-nolog": "پەڕگەی لۆگ نەدۆزرایەوە.", "checkuser-blocked": "بەربەست کراو", "checkuser-gblocked": "بەربەست کراوی جیھانی", "checkuser-wasblocked": "پێشتر بەربەست کراوە", diff --git a/CheckUser/i18n/cs.json b/CheckUser/i18n/cs.json index fbe3ace8..952306bb 100644 --- a/CheckUser/i18n/cs.json +++ b/CheckUser/i18n/cs.json @@ -5,17 +5,18 @@ "Danny B.", "Dvorapa", "Li-sung", + "Martin Urbanec", "Matěj Suchánek", "Mormegil" ] }, - "checkuser-summary": "Tento nástroj zkoumá poslední změny a umožňuje získat IP adresy uživatelů nebo zobrazit editace a uživatele z dané IP adresy.\nUživatele a editace z klientské IP adresy lze získat z hlaviček XFF přidáním „/xff“ k IP. Je podporováno IPv4 (CIDR $1–32) a IPv6 (CIDR $2-128).\nZ výkonnostních důvodů lze zobrazit maximálně 5000 editací. Používejte tento nástroj v souladu s pravidly.", + "checkuser-summary": "Tento nástroj zkoumá poslední změny a umožňuje získat IP adresy uživatelů nebo zobrazit editace a uživatele z dané IP adresy.\nUživatele a editace z klientské IP adresy lze získat z hlaviček XFF přidáním „/xff“ k IP. Je podporováno IPv4 (CIDR $1–32) a IPv6 (CIDR $2-128).\nZ výkonnostních důvodů lze zobrazit maximálně $3 editací. Používejte tento nástroj v souladu s pravidly.", "checkuser-desc": "Poskytuje uživatelům s příslušným oprávněním možnost zjišťovat IP adresy uživatelů a další související informace", - "checkuser-logcase": "Hledání v záznamech rozlišuje velikosti písmen.", "checkuser": "Kontrola uživatele", "checkuserlog": "Kniha kontroly uživatelů", "checkuser-contribs": "kontrola uživatelových IP", "checkuser-contribs-log": "nedávné kontroly uživatele", + "checkuser-contribs-log-initiator": "kontroly uživatelů provedené tímto uživatelem", "group-checkuser": "Revizoři", "group-checkuser-member": "{{GENDER:$1|revizor|revizorka|revizor}}", "right-checkuser": "Kontrolování uživatelské IP adresy a dalších informací", @@ -35,6 +36,7 @@ "checkuser-week-1": "poslední týden", "checkuser-week-2": "poslední dva týdny", "checkuser-month": "posledních 30 dní", + "checkuser-month-2": "posledních 60 dní", "checkuser-all": "všechno", "checkuser-cidr-label": "Zjištění společného rozsahu ze seznamu IP adres", "checkuser-cidr-res": "Společný CIDR:", @@ -43,9 +45,9 @@ "checkuser-nomatch-edits": "Nic odpovídajícího nebylo nalezeno. Poslední editace proběhla $2, $1.", "checkuser-check": "Zkontrolovat", "checkuser-check-this-user": "Zkontrolovat tohoto uživatele", + "checkuser-investigate-this-user": "Prověřit tohoto uživatele", "checkuser-recent-checks": "Nedávné kontroly tohoto uživatele", "checkuser-log-fail": "Nepodařilo se zapsat do záznamů", - "checkuser-nolog": "Soubor záznamů nebyl nalezen.", "checkuser-blocked": "zablokováno", "checkuser-gblocked": "globálně zablokováno", "checkuser-locked": "zamčeno", @@ -57,6 +59,7 @@ "checkuser-blocktalk": "Zabránit editovat vlastní uživatelskou diskusi po dobu zablokování", "checkuser-blocktag": "Nahradit obsah uživatelských stránek textem:", "checkuser-blocktag-talk": "Nahradit obsah uživatelských diskusí textem:", + "checkuser-reblock": "Přepsat existující zablokování", "checkuser-massblock-commit": "Zablokovat vybrané uživatele", "checkuser-block-success": "'''{{PLURAL:$2|Uživatel|Uživatelé}} $1 {{PLURAL:$2|je zablokován|jsou zablokováni}}.'''", "checkuser-block-failure": "'''Žádný uživatel nebyl zablokován.'''", @@ -66,11 +69,14 @@ "checkuser-noreason": "K tomuto dotazu musíte uvést důvod.", "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-target-nonexistent": "Zadaný cíl neexistuje.", + "checkuser-initiator-nonexistent": "Zadaný kontrolující neexistuje.", "checkuser-search": "Hledání v záznamech kontroly uživatelů", "checkuser-search-submit": "Hledat", "checkuser-search-initiator": "kontrolující", "checkuser-search-target": "kontrolováno", "checkuser-log-search-target": "Cíl:", + "checkuser-log-search-initiator": "Kontrolující:", "checkuser-log-search-type": "Hledat podle:", "checkuser-ipeditcount": "asi $1 od všech uživatelů", "checkuser-showmain": "Přepnout na hlavní formulář Kontroly uživatele", @@ -81,6 +87,7 @@ "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-log-entry-investigate": "$3, $1 zjišťuje informace o $2", "checkuser-autocreate-action": "byl automaticky vytvořen", "checkuser-create-action": "byl vytvořen", "checkuser-email-action": "odeslal e-mail uživateli „$1“", @@ -89,5 +96,65 @@ "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", "group-checkuser.css": "/* Zde uvedené CSS bude ovlivňovat pouze revizory */", - "group-checkuser.js": "/* Zde uvedený JavaScript bude použit pouze pro revizory */" + "group-checkuser.js": "/* Zde uvedený JavaScript bude použit pouze pro revizory */", + "checkuser-link-investigate-label": "Vyzkoušet nový nástroj CheckUser", + "checkuser-investigateblock": "Zablokovat uživatele", + "checkuser-investigateblock-target": "Uživatelská jména a IP adresy", + "checkuser-investigateblock-actions": "Zablokovat činnosti", + "checkuser-investigateblock-reason": "Důvod", + "checkuser-investigateblock-options": "Další nastavení", + "checkuser-investigateblock-email-label": "Zablokovat posílání e-mailů", + "checkuser-investigateblock-usertalk-label": "Zabránit editovat vlastní uživatelskou diskusi po dobu zablokování", + "checkuser-investigateblock-reblock-label": "Přepsat existující zablokování", + "checkuser-investigateblock-notice-user-page-label": "Zanechat upozornění na uživatelské stránce", + "checkuser-investigateblock-notice-talk-page-label": "Zanechat upozornění na diskusní stránce", + "checkuser-investigateblock-notice-position-label": "Pozice", + "checkuser-investigateblock-notice-text-label": "Wikitext", + "checkuser-investigateblock-notice-append": "Na konec stránky", + "checkuser-investigateblock-notice-prepend": "Na začátek stránky", + "checkuser-investigateblock-notice-replace": "Nahradit stránku", + "checkuser-investigateblock-failure": "Žádní uživatelé nebyli zablokováni. Abyste přepsali existující zablokování, zaškrtněte „{{int:checkuser-investigateblock-reblock-label}}“. Zablokování nebude přepsáno, pokud je nový blok stejný jako ten existující.", + "checkuser-investigateblock-success": "{{PLURAL:$2|Uživatel|Uživatelé}} $1 {{PLURAL:$2|je nyní zablokován|jsou nyní zablokováni}}.", + "checkuser-investigate-subtitle-block-button-label": "Zablokovat", + "checkuser-investigate-subtitle-cancel-button-label": "Storno", + "checkuser-investigate-subtitle-continue-button-label": "Pokračovat", + "checkuser-investigate-subtitle-show-checkuser": "Přepnout na klasické rozhraní CheckUser", + "checkuser-investigate-indicator-logs": "Protokolovací záznamy", + "checkuser-investigate-legend": "Hledat uživatelská jména, IP adresy nebo rozsahy IP adres", + "checkuser-investigate-notice-no-results": "Nebyly nalezeny žádné výsledky.", + "checkuser-investigate-tab-preliminary-check": "Informace o účtu", + "checkuser-investigate-tab-timeline": "Časová osa", + "checkuser-investigate-targets-label": "Uživatelská jména a IP adresy:", + "checkuser-investigate-targets-placeholder": "Uživatelské jméno nebo 1.1.1.1", + "checkuser-investigate-duration-label": "Délka", + "checkuser-investigate-duration-option-all": "Vše", + "checkuser-investigate-duration-option-1w": "Poslední týden", + "checkuser-investigate-duration-option-2w": "Poslední dva týdny", + "checkuser-investigate-duration-option-30d": "Posledních 30 dní", + "checkuser-investigate-reason-label": "Důvod", + "checkuser-investigate-preliminary-table-cell-blocked": "Zablokován", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|editace|editace|editací}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Není zablokován", + "checkuser-investigate-preliminary-table-header-blocked": "Stav", + "checkuser-investigate-preliminary-table-header-editcount": "Editací", + "checkuser-investigate-preliminary-table-header-groups": "Skupiny", + "checkuser-investigate-preliminary-table-header-name": "Uživatelské jméno", + "checkuser-investigate-preliminary-table-header-registration": "Datum připojení účtu", + "checkuser-investigate-preliminary-table-header-wiki": "Projekt", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Projekt nenalezen", + "checkuser-investigate-filters-legend": "Filtry", + "checkuser-investigate-filters-exclude-targets-label": "Skrýt následující uživatele nebo IP adresy", + "checkuser-investigate-compare-toollinks-ipcheck": "Kontrola proxy", + "checkuser-investigate-compare-copy-message-label": "Chcete zkopírovat výsledky jako wikitext tabulku?", + "checkuser-investigate-compare-table-button-checks-label": "Kontroly", + "checkuser-investigate-compare-table-button-contribs-label": "Příspěvky", + "checkuser-investigate-compare-table-cell-unregistered": "Neregistrovaný", + "checkuser-investigate-compare-table-header-username": "Uživatelské jméno", + "checkuser-investigate-compare-table-header-activity": "Časové období", + "checkuser-investigate-compare-table-header-ip": "IP adresa", + "checkuser-investigate-compare-table-header-useragent": "User-Agent", + "checkuser-investigate-subtitle-link-restart-tour": "Restartovat průvodce", + "checkuser-investigate-tour-targets-title": "Zkontrolovat více uživatelů/IP adres?", + "checkuser-investigate-tour-block-title": "Chcete je zablokovat?", + "checkuser-investigate-tour-copywikitext-title": "Chcete si data zkopírovat?" } diff --git a/CheckUser/i18n/cy.json b/CheckUser/i18n/cy.json index 6fef7aa5..9b45bb3e 100644 --- a/CheckUser/i18n/cy.json +++ b/CheckUser/i18n/cy.json @@ -7,7 +7,6 @@ }, "checkuser-summary": "Mae'r teclyn hwn yn sganio newidiadau diweddar i gael hyd i'r cyfeiriadau IP a ddefnyddir gan ddefnyddiwr, neu i ddangos data golygu neu ddata defnyddiwr ar gyfer rhyw gyfeiriad IP. \nGall y teclyn gael hyd i ddefnyddwyr rhyw gyfeiriad IP cleient, neu'r golygiadau a ddaw ohono, drwy atodi \"/xff\" i'r cyfeiriad IP. Mae IPv4 (CIDR $1-32) a IPv6 (CIDR $2-128) yn cael eu cynnal. \nNi chaiff mwy na 5,000 o olygiadau eu dychwelyd er mwyn peidio amharu ar berfformiad y wefan. \nDefnyddiwch hwn yn unol â'n polisi.", "checkuser-desc": "Yn rhoi'r gallu i ddefnyddwyr awdurdodedig archwilio cyfeiriadau IP defnyddwyr a gwybodaeth arall amdanynt.", - "checkuser-logcase": "Yn gwahaniaethu rhwng llythrennau mawr a bach wrth chwilio.", "checkuser": "Archwilio defnyddwyr", "checkuserlog": "Lòg archwilio defnyddwyr", "checkuser-contribs": "archwilio IP y defnyddiwr", @@ -39,7 +38,6 @@ "checkuser-nomatch-edits": "Dim yn cyfateb i'r chwiliad.\nGolygwyd ddiwethaf ar $1 am $2.", "checkuser-check": "Archwilier", "checkuser-log-fail": "Yn methu ychwanegu cofnod lòg", - "checkuser-nolog": "Dim ffeil lòg i'w gael.", "checkuser-blocked": "Wedi ei flocio", "checkuser-gblocked": "Wedi ei flocio'n gydwici", "checkuser-locked": "Ar glo", diff --git a/CheckUser/i18n/da.json b/CheckUser/i18n/da.json index 304ddfff..929db0aa 100644 --- a/CheckUser/i18n/da.json +++ b/CheckUser/i18n/da.json @@ -17,7 +17,6 @@ }, "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}}.", "checkuser-desc": "Giver brugere med den rette godkendelse muligheden for at tjekke brugeres IP-adresser og anden information", - "checkuser-logcase": "Logsøgning er case sensitiv (der gøres forskel på store og små bogstaver)", "checkuser": "Tjekbruger", "checkuserlog": "Tjekbrugerlog", "checkuser-contribs": "Tjek brugerens ip-adresser", @@ -41,6 +40,7 @@ "checkuser-week-1": "forrige uge", "checkuser-week-2": "sidste to uger", "checkuser-month": "sidste 30 dage", + "checkuser-month-2": "sidste 60 dage", "checkuser-all": "alle", "checkuser-cidr-label": "Find fælles interval og påvirkede IP-adresser for en liste af IP-adresser", "checkuser-cidr-res": "Fælles CIDR:", @@ -49,9 +49,9 @@ "checkuser-nomatch-edits": "Ingen matchende resultater blev fundet.\nSeneste redigering var $1 $2.", "checkuser-check": "Tjek", "checkuser-check-this-user": "Tjek denne bruger", + "checkuser-investigate-this-user": "Undersøg denne bruger", "checkuser-recent-checks": "Nylige tjek af denne bruger", "checkuser-log-fail": "Kunne ikke tilføje log-post", - "checkuser-nolog": "Logfilen blev ikke fundet.", "checkuser-blocked": "Blokeret", "checkuser-gblocked": "Blokeret globalt", "checkuser-locked": "Låst", @@ -113,6 +113,7 @@ "checkuser-investigate-preliminary-table-header-editcount": "Redigeringer", "checkuser-investigate-preliminary-table-header-groups": "Grupper", "checkuser-investigate-preliminary-table-header-name": "Brugernavn", + "checkuser-investigate-preliminary-table-header-wiki": "Wiki", "checkuser-investigate-filters-legend": "Filtre", "checkuser-investigate-compare-copy-button-label": "Vis wikitekst", "checkuser-investigate-compare-table-button-contribs-label": "Bidrag", diff --git a/CheckUser/i18n/de.json b/CheckUser/i18n/de.json index b51f3dde..4e5e49a3 100644 --- a/CheckUser/i18n/de.json +++ b/CheckUser/i18n/de.json @@ -1,6 +1,9 @@ { "@metadata": { "authors": [ + "Ameisenigel", + "Brettchenweber", + "FF-11", "FF11", "Geitost", "J. 'mach' wust", @@ -17,13 +20,13 @@ "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.", + "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 $3 Bearbeitungen ausgegeben. Benutze CheckUser ausschließlich in Übereinstimmung mit den Datenschutzrichtlinien.", "checkuser-desc": "Ermöglicht die Überprüfung von IP-Adressen sowie weiterer Informationen von Benutzern", - "checkuser-logcase": "Die Suche im Logbuch unterscheidet zwischen Groß- und Kleinschreibung.", "checkuser": "Checkuser", "checkuserlog": "Checkuser-Logbuch", "checkuser-contribs": "IP-Adressen des Benutzers prüfen", "checkuser-contribs-log": "letzte Benutzerprüfungen", + "checkuser-contribs-log-initiator": "von diesem Benutzer durchgeführte Abfragen", "group-checkuser": "Checkuser-Berechtigte", "group-checkuser-member": "{{GENDER:$1|Checkuser-Berechtigter|Checkuser-Berechtigte}}", "right-checkuser": "IP-Adressen sowie Zusammenhänge zwischen IP-Adressen und angemeldeten Benutzern prüfen", @@ -43,17 +46,23 @@ "checkuser-week-1": "letzte 7 Tage", "checkuser-week-2": "letzte 14 Tage", "checkuser-month": "letzte 30 Tage", + "checkuser-month-2": "letzte 60 Tage", "checkuser-all": "alle", "checkuser-cidr-label": "Gemeinsamen Adressbereich und betroffene Adressen für eine Liste von IP-Adressen ermitteln", "checkuser-cidr-res": "Gemeinschaftlicher IP-Adressbereich:", + "checkuser-cidr-affected-ips": "Betroffene IP-Adressen:", + "checkuser-cidr-too-small": "Die Range ist zu groß", + "checkuser-range-outside-limit": "Der Bereich $1 liegt außerhalb der zulässigen Grenzen.", "checkuser-empty": "Das Logbuch enthält keine Einträge.", "checkuser-nomatch": "Es wurden keine Übereinstimmungen gefunden.", "checkuser-nomatch-edits": "Es wurde keine Übereinstimmungen gefunden.\nDie letzte Bearbeitung hat am $1 um $2 Uhr stattgefunden.", "checkuser-check": "Abfragen", "checkuser-check-this-user": "Diesen Benutzer überprüfen", + "checkuser-investigate-this-user": "Diesen Benutzer untersuchen", "checkuser-recent-checks": "Letzte Überprüfungen für diesen Benutzer", "checkuser-log-fail": "Der Logbuch-Eintrag kann nicht hinzugefügt werden.", - "checkuser-nolog": "Es ist keine Logbuchdatei vorhanden.", + "checkuser-log-checks-by": "Prüfungen durch", + "checkuser-log-checks-on": "Prüfungen von", "checkuser-blocked": "gesperrt", "checkuser-gblocked": "global gesperrt", "checkuser-locked": "global gesperrt", @@ -72,17 +81,22 @@ "checkuser-block-limit": "Es wurden zu viele Benutzer ausgewählt.", "checkuser-block-noreason": "Du musst einen Grund für die Sperre angeben.", "checkuser-centralauth-multilock": "Ausgewählte Benutzerkonten sperren", + "checkuser-centralauth-multilock-list-item": "Link $1", "checkuser-noreason": "Für diese Abfrage muss eine Begründung angegeben werden.", "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-target-nonexistent": "Die angegebene Ziel existiert nicht.", + "checkuser-initiator-nonexistent": "Der angegebene CheckUser-Berechtigte existiert nicht.", "checkuser-search": "Einträge im Checkuser-Logbuch durchsuchen", "checkuser-search-submit": "Suche", "checkuser-search-initiator": "CheckUser-Berechtigter", "checkuser-search-target": "Abfrageziel (Benutzerkonto/IP-Adresse)", "checkuser-log-search-target": "Ziel:", + "checkuser-log-search-initiator": "CheckUser-Berechtigter:", "checkuser-log-search-type": "Suchen nach:", "checkuser-ipeditcount": "~ $1 von allen Benutzern", "checkuser-showmain": "Zum CheckUser-Hauptformular wechseln", + "checkuser-show-investigate": "Zum Hauptformular Untersuchung 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 <bdi>$2</bdi> ab", @@ -90,12 +104,14 @@ "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-log-entry-investigate": "$3, $1 hat Informationen nachgeschlagen für $2", "checkuser-autocreate-action": "wurde automatisch erstellt", "checkuser-create-action": "wurde erstellt", "checkuser-email-action": "sendete E-Mail an „$1“", - "checkuser-reset-action": "forderte ein Passwort für {{GENDER:$1|Benutzer|Benutzerin}} „$1“ an", + "checkuser-reset-action": "forderte ein Passwort für {{GENDER:$1|Benutzer|Benutzerin}} $1 an", "checkuser-token-fail": "Sitzungsfehler. Bitte erneut versuchen.", "checkuser-login-failure": "Anmeldung bei {{SITENAME}} als $1 fehlgeschlagen", + "checkuser-login-failure-with-good-password": "Anmeldung bei {{SITENAME}} als $1 fehlgeschlagen, es wurde aber das richtige Passwort verwendet", "checkuser-login-success": "Erfolgreich bei {{SITENAME}} angemeldet als $1", "checkuser-link-investigate-label": "Das neue CheckUser-Tool testen", "checkuser-investigateblock": "Benutzer sperren", @@ -116,15 +132,12 @@ "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-subtitle-show-checkuser": "Zu Checkuser wechseln", "checkuser-investigate-indicator-new-investigation": "Neue Untersuchung", "checkuser-investigate-indicator-logs": "Logbücher", "checkuser-investigate-legend": "Suche nach Benutzernamen, IP-Adressen oder IP-Bereiche", @@ -132,7 +145,7 @@ "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-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", @@ -153,9 +166,10 @@ "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": "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-copy-button-label-hide": "Wikitext ausblenden", "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.", @@ -168,7 +182,7 @@ "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-edits": "<b>[$1 {{PLURAL:$1|Bearbeitung/Aktion|Bearbeitungen/Aktionen}}]</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", diff --git a/CheckUser/i18n/diq.json b/CheckUser/i18n/diq.json index 63cfb45e..3560cb53 100644 --- a/CheckUser/i18n/diq.json +++ b/CheckUser/i18n/diq.json @@ -13,29 +13,28 @@ }, "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.", "checkuser-desc": "Karberan rê destur bide ke adresanê IPyan u enformasyonê bînan kontrol bike", - "checkuser-logcase": "Ena bigêrayîşê logî case sensitive o.", - "checkuser": "Teftişwan", + "checkuser": "Teftişkar", "checkuserlog": "Cıkewtışê karberi qontrol ke", "checkuser-contribs": "adresanê IPyê karberi kontrol ke", "checkuser-contribs-log": "weynayışê peyênê karberi", - "group-checkuser": "Weynayoği", - "group-checkuser-member": "{{GENDER:$1|Kontrolkar}}", + "group-checkuser": "Teftişkari", + "group-checkuser-member": "{{GENDER:$1|teftişkar}}", "right-checkuser": "Adresanê IPyê karberi û melumatê bini kontrol ke", "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", + "grouppage-checkuser": "{{ns:project}}:Teftişkar", "checkuser-reason": "Sebeb:", "checkuser-reason-api": "API: $1", "checkuser-showlog": "Qeydê asayışi weçinê", - "checkuser-query": "Bigêrayîşî de vurnayîşanê penîyan", + "checkuser-query": "Vurnayışanê peyênan pers kerê", "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": "Dom:", - "checkuser-week-1": "hefteyê verînî", - "checkuser-week-2": "di hefteyê verînî", + "checkuser-week-1": "hefteyo verên", + "checkuser-week-2": "dı hefteyê verêni", "checkuser-month": "30 rocê verînî", "checkuser-all": "pêro", "checkuser-cidr-label": "Qe yew listeyê IPyanî, yew menzilê ortakî u adresanê IPyanî bivîne", @@ -45,7 +44,6 @@ "checkuser-nomatch-edits": "Çik çin o.\nVurnayîşê tewr penî seet $1 u rocê $2 de biyo.", "checkuser-check": "Kontrol bike", "checkuser-log-fail": "Nieşkeno log debiker", - "checkuser-nolog": "Qeydê dosya nêvineya.", "checkuser-blocked": "Kılit biyo", "checkuser-gblocked": "Global de blok biya", "checkuser-locked": "Kilit biya", @@ -65,7 +63,7 @@ "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-initiator": "Serniyayoğ", "checkuser-search-target": "hedef", "checkuser-log-search-target": "Etiket:", "checkuser-ipeditcount": "~$1 karberan pêrıne ra", diff --git a/CheckUser/i18n/dsb.json b/CheckUser/i18n/dsb.json index 5af493b0..2c14fd61 100644 --- a/CheckUser/i18n/dsb.json +++ b/CheckUser/i18n/dsb.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "Toś ten rěd skanujo aktualne změny, aby wótwołał IP-adresy wužywarja abo pokazał změny/wužywarske daty za IP-adresu.\nWužywarje a změny IP-adresy daju se pśez głowowe smužki XFF wótwołaś, z tym až \"/xff\" pśidawa se IP-adresy. IPv4 (CIDR $1-32) a IPv6 (CIDR $2-128) se pódpěratej.\nZ pśicynow wugbałosći wróśijo se nic wěcej ako 5000 změnow. Wužyj CheckUser pó zasadach priwatnosći.", "checkuser-desc": "Dajo wužywarjam z wótpowědnym pšawom móžnosć IP-adrese a druge informacije wužywarja kontrolowaś", - "checkuser-logcase": "Pytanje w protokolu rozeznawaju mjazy wjeliko- a małopisanjom.", "checkuser": "Kontrola wužywarjow", "checkuserlog": "Protokol kontrole wužywarjow", "checkuser-contribs": "Wužywarske IP pśeglědaś", @@ -38,7 +37,6 @@ "checkuser-nomatch-edits": "Žedne wótpowědniki namakane.\nSlědna změna jo $1 $2 była.", "checkuser-check": "Kontrolěrowaś", "checkuser-log-fail": "Protokolowy zapisk njedajo se pśidaś", - "checkuser-nolog": "Žedna protokolowa dataja namakana.", "checkuser-blocked": "Blokěrowany", "checkuser-gblocked": "Globalnje blokěrowany", "checkuser-locked": "Zastajony", diff --git a/CheckUser/i18n/el.json b/CheckUser/i18n/el.json index 4d4e711b..d7208f68 100644 --- a/CheckUser/i18n/el.json +++ b/CheckUser/i18n/el.json @@ -5,6 +5,7 @@ "Assassingr", "Consta", "Crazymadlover", + "Giorgos456", "Glavkos", "K sal 15", "Konsnos", @@ -17,7 +18,6 @@ }, "checkuser-summary": "Αυτό το εργαλείο σαρώνει τις πρόσφατες αλλαγές για να ανακτήσει τις IP διευθύνσεις που χρησιμοποιούνται από ένα χρήστη ή για να δείξει τα δεδομένα επεξεργασιών/χρηστών για μία IP.\nΧρήστες και επεξεργασίες από μία σταθερή IP μπορούν να ανακτηθούν μέσω XFF επικεφαλίδων προσαρτώντας \"/xff\" στην IP. Το IPv4 (CIDR $1-32) και το IPv6 (CIDR $2-128) υποστηρίζονται.\nΌχι περισσότερες από 5000 επεξεργασίες θα επιστραφούν για λόγους απόδοσης.\nΧρησιμοποιήστε αυτό σύμφωνα με την πολιτική.", "checkuser-desc": "Παρέχει στους χρήστες με την κατάλληλη άδεια την ικανότητα να ελέγχουν τη διεύθυνση IP ενός χρήστη καθώς και άλλες πληροφορίες", - "checkuser-logcase": "Η αναζήτηση στο αρχείο καταγραφής διακρίνει πεζά από κεφαλαία.", "checkuser": "Ελεγκτής", "checkuserlog": "Αρχείο καταγραφής ελεγχών", "checkuser-contribs": "έλεγχος των IP χρηστών", @@ -31,7 +31,7 @@ "grouppage-checkuser": "{{ns:project}}:Ελεγκτής", "checkuser-reason": "Λόγος:", "checkuser-reason-api": "API: $1", - "checkuser-showlog": "Εμφάνιση αρχείου καταγραφής", + "checkuser-showlog": "Εναλλαγή στο αρχείο καταγραφής CheckUser", "checkuser-query": "Αναζήτηση στις πρόσφατες αλλαγές", "checkuser-target": "Διεύθυνση IP ή όνομα χρήστη:", "checkuser-users": "Λήψη χρηστών", @@ -49,7 +49,6 @@ "checkuser-nomatch-edits": "Δεν βρέθηκαν αποτελέσματα που να ταιριάζουν.\nΗ τελευταία επεξεργασία ήταν στις $1 στις $2.", "checkuser-check": "Έλεγχος", "checkuser-log-fail": "Δεν είναι δυνατή η προσθήκη εγγραφής στο αρχείο καταγραφών", - "checkuser-nolog": "Δεν βρέθηκε κανένα αρχείο καταγραφής.", "checkuser-blocked": "Φραγμένος", "checkuser-gblocked": "Καθολικά φραγμένος", "checkuser-locked": "Κλειδωμένο", @@ -65,9 +64,9 @@ "checkuser-block-limit": "Έχουν επιλεχθεί πάρα πολλοί χρήστες.", "checkuser-block-noreason": "Πρέπει να αιτιολογήσετε τις φραγές.", "checkuser-noreason": "Πρέπει να δώσετε μια αιτία για αυτή την ερώτηση.", - "checkuser-too-many": "Πάρα πολλά αποτελέσματα (σύμφωνα με την εκτίμηση σειράς), παρακαλούμε στενέψτε το CIDR.\nΠαρακάτω είναι οι διευθύνσεις IP που χρησιμοποιούνται (με ανώτατο όριο τις 5000, ταξινομημένες κατά διεύθυνση):", + "checkuser-too-many": "Πάρα πολλά αποτελέσματα (σύμφωνα με την εκτίμηση σειράς), παρακαλούμε στενέψτε το CIDR.\nΠαρακάτω είναι οι διευθύνσεις IP που χρησιμοποιούνται (με ανώτατο όριο τις $1, ταξινομημένες κατά διεύθυνση):", "checkuser-user-nonexistent": "Ο συγκεκριμένος χρήστης δεν υπάρχει.", - "checkuser-search": "Αναζήτηση", + "checkuser-search": "Αναζήτηση καταχωρήσεων καταγραφών ελέγχου χρήστη", "checkuser-search-submit": "Αναζήτηση", "checkuser-search-initiator": "ελεγκτής", "checkuser-search-target": "στόχος", diff --git a/CheckUser/i18n/en-ca.json b/CheckUser/i18n/en-ca.json deleted file mode 100644 index 60822a8c..00000000 --- a/CheckUser/i18n/en-ca.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "@metadata": { - "authors": [ - "Guycn2" - ] - }, - "checkuser-showlog": "Switch to CheckUser log" -} diff --git a/CheckUser/i18n/en-gb.json b/CheckUser/i18n/en-gb.json deleted file mode 100644 index 9790a7eb..00000000 --- a/CheckUser/i18n/en-gb.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "@metadata": { - "authors": [ - "Andibing", - "Bjh21", - "Chase me ladies, I'm the Cavalry", - "Guycn2", - "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 users' IP addresses and other information", - "checkuser-logcase": "The log search is case sensitive.", - "checkuser": "Check user", - "checkuserlog": "Check user log", - "checkuser-contribs": "check user IP addresses", - "checkuser-contribs-log": "recent user checks", - "group-checkuser": "Check users", - "group-checkuser-member": "{{GENDER:$1|check user}}", - "right-checkuser": "Check users' IP addresses and other information", - "right-checkuser-log": "View the checkuser log", - "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:", - "checkuser-reason-api": "API: $1", - "checkuser-showlog": "Switch to CheckUser log", - "checkuser-query": "Query recent changes", - "checkuser-target": "IP address or username:", - "checkuser-users": "Get users", - "checkuser-edits": "Get edits", - "checkuser-ips": "Get IP addresses", - "checkuser-period": "Duration:", - "checkuser-week-1": "last week", - "checkuser-week-2": "last two weeks", - "checkuser-month": "last 30 days", - "checkuser-all": "all", - "checkuser-cidr-label": "Find common range and affected IP addresses for a list of IP addresses", - "checkuser-cidr-res": "Common CIDR:", - "checkuser-empty": "The log contains no items.", - "checkuser-nomatch": "No matches found.", - "checkuser-nomatch-edits": "No matches found.\nLast edit was on $1 at $2.", - "checkuser-check": "Check", - "checkuser-log-fail": "Unable to add log entry", - "checkuser-nolog": "No log file found.", - "checkuser-blocked": "Blocked", - "checkuser-gblocked": "Blocked globally", - "checkuser-locked": "Locked", - "checkuser-wasblocked": "Previously blocked", - "checkuser-localonly": "Not unified", - "checkuser-massblock": "Block selected users", - "checkuser-massblock-text": "Selected accounts will be blocked indefinitely, with autoblocking of IP addresses enabled and account creation disabled.\nIP addresses will be blocked for one week for anonymous users only and account creation will be disabled.", - "checkuser-blockemail": "Prevent from sending email", - "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-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.'''", - "checkuser-block-limit": "Too many users selected.", - "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-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", - "checkuser-search-initiator": "initiator", - "checkuser-search-target": "target", - "checkuser-log-search-target": "Target:", - "checkuser-log-search-type": "Search by:", - "checkuser-ipeditcount": "~$1 from all users", - "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 <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." -} diff --git a/CheckUser/i18n/en.json b/CheckUser/i18n/en.json index e2fb8ada..bb1bea1c 100644 --- a/CheckUser/i18n/en.json +++ b/CheckUser/i18n/en.json @@ -3,16 +3,17 @@ "authors": [ "Tim Starling", "Aaron Schulz", - "John Du Hart" + "John Du Hart", + "Dreamy Jazz" ] }, - "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-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 $3 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 users' IP addresses and other information", - "checkuser-logcase": "The log search is case sensitive.", "checkuser": "Check user", "checkuserlog": "Check user log", "checkuser-contribs": "check user IP addresses", "checkuser-contribs-log": "recent user checks", + "checkuser-contribs-log-initiator": "user checks done by this user", "group-checkuser": "Check users", "group-checkuser-member": "{{GENDER:$1|check user}}", "right-checkuser": "Check users' IP addresses and other information", @@ -32,17 +33,23 @@ "checkuser-week-1": "last week", "checkuser-week-2": "last two weeks", "checkuser-month": "last 30 days", + "checkuser-month-2": "last 60 days", "checkuser-all": "all", "checkuser-cidr-label": "Find common range and affected IP addresses for a list of IP addresses", "checkuser-cidr-res": "Common CIDR:", + "checkuser-cidr-affected-ips": "Affected IP addresses:", + "checkuser-cidr-too-small": "Range is too large", + "checkuser-range-outside-limit": "The range $1 is outside the allowed limits.", "checkuser-empty": "The log contains no items.", "checkuser-nomatch": "No matches found.", "checkuser-nomatch-edits": "No matches found.\nLast edit was on $1 at $2.", "checkuser-check": "Check", "checkuser-check-this-user": "Check this user", + "checkuser-investigate-this-user": "Investigate this user", "checkuser-recent-checks": "Recent checks for this user", "checkuser-log-fail": "Unable to add log entry", - "checkuser-nolog": "No log file found.", + "checkuser-log-checks-by": "checks by", + "checkuser-log-checks-on": "checks on", "checkuser-blocked": "Blocked", "checkuser-gblocked": "Blocked globally", "checkuser-locked": "Locked", @@ -61,17 +68,23 @@ "checkuser-block-limit": "Too many users selected.", "checkuser-block-noreason": "You must give a reason for the blocks.", "checkuser-centralauth-multilock": "Multi lock selected accounts", + "checkuser-centralauth-multilock-list": "Multi lock the selected accounts using the links:", + "checkuser-centralauth-multilock-list-item": "Link $1", "checkuser-noreason": "You must give a reason for this query.", "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-target-nonexistent": "The specified target does not exist.", + "checkuser-initiator-nonexistent": "The specified initiator does not exist.", "checkuser-search": "Search check user log entries", "checkuser-search-submit": "Search", "checkuser-search-initiator": "initiator", "checkuser-search-target": "target", "checkuser-log-search-target": "Target:", + "checkuser-log-search-initiator": "Initiator:", "checkuser-log-search-type": "Search by:", "checkuser-ipeditcount": "~$1 from all users", "checkuser-showmain": "Switch to CheckUser main form", + "checkuser-show-investigate": "Switch to Investigate 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 <bdi>$2</bdi>", @@ -79,14 +92,16 @@ "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-log-entry-investigate": "$3, $1 looked up information 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-userlinks-ip": "(<span class=\"plainlinks\">[https://www.robtex.com/whois/$1.html WHOIS/RDNS]</span>)", - "checkuser-toollinks": "<span class=\"plainlinks\">[[https://www.robtex.com/whois/$1.html WHOIS/RDNS] ·\n[https://www.robtex.com/rbls/$1.html RBLs] ·\n[http://www.dnsstuff.com/tools/tracert.ch?ip=$1 Traceroute] ·\n[https://www.ip2location.com/$1 Geolocate] ·\n[https://www.dan.me.uk/torcheck?ip=$1 Tor check]]</span>", + "checkuser-reset-action": "reset password for user $1", + "checkuser-userlinks-ip": "(<span class=\"plainlinks\">[https://www.robtex.com/ip-lookup/$1 WHOIS/RDNS]</span>)", + "checkuser-toollinks": "<span class=\"plainlinks\">[[https://www.robtex.com/ip-lookup/$1 WHOIS/RDNS] ·\n[https://www.ip2location.com/$1 Geolocate]]</span>", "checkuser-token-fail": "Session failure. Please try again.", "checkuser-login-failure": "Failed to log in to {{SITENAME}} as $1", + "checkuser-login-failure-with-good-password": "Failed to log in to {{SITENAME}} as $1 but had the correct password", "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 */", @@ -109,15 +124,12 @@ "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-subtitle-show-checkuser": "Switch to CheckUser", "checkuser-investigate-indicator-new-investigation": "New investigation", "checkuser-investigate-indicator-logs": "Logs", "checkuser-investigate-legend": "Search for usernames, IP addresses or IP ranges", @@ -125,7 +137,7 @@ "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-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", @@ -149,7 +161,8 @@ "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-copy-button-label-hide": "Hide 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?", @@ -163,7 +176,7 @@ "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-edits": "<b>[$1 {{PLURAL:$1|edit/action|edits/actions}}]</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", @@ -177,7 +190,7 @@ "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-filterip-desc": "Remove the clutter by filtering out usernames, 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?", diff --git a/CheckUser/i18n/eo.json b/CheckUser/i18n/eo.json index 17f961d0..6e7c9402 100644 --- a/CheckUser/i18n/eo.json +++ b/CheckUser/i18n/eo.json @@ -9,7 +9,6 @@ }, "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.", "checkuser-desc": "Rajtigas al uzantoj kun la taŭga permeso la kapableco kontroli la IP-adreson de uzanto kaj alia informo", - "checkuser-logcase": "La protokola serĉo estas usklecodistinga.", "checkuser": "Kontrolanto de IP-adresoj", "checkuserlog": "Protokolo pri kontrolado de uzantoj", "checkuser-contribs": "kontroli IP-adresojn de uzantoj", @@ -41,7 +40,6 @@ "checkuser-nomatch-edits": "Neniuj trafoj troviĝis. Lasta redakto estis je $1, $2.", "checkuser-check": "Kontroli", "checkuser-log-fail": "Ne eblis aldoni protokoleron.", - "checkuser-nolog": "Neniu protokolo estas trovita.", "checkuser-blocked": "Forbarita", "checkuser-gblocked": "Forbarita ĝenerale", "checkuser-locked": "Ŝlosita", diff --git a/CheckUser/i18n/es.json b/CheckUser/i18n/es.json index ac737b54..b65e9ef6 100644 --- a/CheckUser/i18n/es.json +++ b/CheckUser/i18n/es.json @@ -1,14 +1,17 @@ { "@metadata": { "authors": [ + "Agent", "Aleator", "AlimanRuna", "Armando-Martin", "Canaan9801", "Crazymadlover", + "DannyS712", "Dferg", "Dmcdevit", "Fitoschido", + "Francodiaz7", "Geryescalier", "Gustronico", "Hasley", @@ -38,23 +41,23 @@ "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 $3 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": "Verificación de usuarios", - "checkuserlog": "Registro de verificación de usuarios", - "checkuser-contribs": "verificar las direcciones IP del usuario", + "checkuser": "Comprobar usuarios", + "checkuserlog": "Registro de comprobación de usuarios", + "checkuser-contribs": "comprobar las direcciones IP del usuario", "checkuser-contribs-log": "comprobaciones efectuadas sobre este usuario recientemente", - "group-checkuser": "Verificadores de usuarios", - "group-checkuser-member": "{{GENDER:$1|verificador de usuarios|verificadora de usuarios}}", + "checkuser-contribs-log-initiator": "comprobaciones hechas por este usuario", + "group-checkuser": "Comprobadores de usuarios", + "group-checkuser-member": "{{GENDER:$1|comprobador de usuarios|comprobadora de usuarios}}", "right-checkuser": "Comprobar las direcciones IP y otra información de los usuarios", - "right-checkuser-log": "Ver el registro de verificación de usuarios", + "right-checkuser-log": "Ver el registro de comprobaciones de usuarios", "action-checkuser": "comprobar las direcciones IP y otra información de los usuarios", - "action-checkuser-log": "ver el registro de checkuser", + "action-checkuser-log": "ver el registro de comprobarusuario", "grouppage-checkuser": "{{ns:project}}:Verificador de usuarios", "checkuser-reason": "Motivo:", "checkuser-reason-api": "API: $1", - "checkuser-showlog": "Cambiar al registro de CheckUser", + "checkuser-showlog": "Cambiar al registro de ComprobarUsuario", "checkuser-query": "Buscar en cambios recientes", "checkuser-target": "Usuario o dirección IP:", "checkuser-users": "Obtener usuarios", @@ -64,20 +67,25 @@ "checkuser-week-1": "última semana", "checkuser-week-2": "últimas dos semanas", "checkuser-month": "últimos 30 días", + "checkuser-month-2": "últimos 60 días", "checkuser-all": "todos", "checkuser-cidr-label": "Encontrar rango común y afectados de una lista de direcciones de IP", "checkuser-cidr-res": "CIDR común:", + "checkuser-cidr-affected-ips": "Direcciones IP afectadas:", + "checkuser-cidr-too-small": "El intervalo es demasiado grande", "checkuser-empty": "No hay elementos en el registro.", "checkuser-nomatch": "No se encontraron coincidencias.", "checkuser-nomatch-edits": "No se encontraron coincidencias.\nLa última edición fue el $1 a las $2.", - "checkuser-check": "Verificar", - "checkuser-check-this-user": "Verificar a este usuario", + "checkuser-check": "Comprobar", + "checkuser-check-this-user": "Comprobar a este usuario", + "checkuser-investigate-this-user": "Investigar a este usuario", "checkuser-recent-checks": "Verificaciones recientes efectuadas sobre este usuario", "checkuser-log-fail": "No se puede añadir este elemento al registro.", - "checkuser-nolog": "No se encuentra ningún archivo de registro.", + "checkuser-log-checks-by": "comprobaciones por", + "checkuser-log-checks-on": "comprobaciones sobre", "checkuser-blocked": "Bloqueado", "checkuser-gblocked": "Bloqueado globalmente", - "checkuser-locked": "Cuenta bloqueada globalmente", + "checkuser-locked": "Cuenta globalmente inhabilitada", "checkuser-wasblocked": "Bloqueado anteriormente", "checkuser-localonly": "No unificada", "checkuser-massblock": "Bloquear usuarios seleccionados", @@ -96,14 +104,18 @@ "checkuser-noreason": "Debes dar una razón para esta consulta.", "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-target-nonexistent": "El objetivo especificado no existe.", + "checkuser-initiator-nonexistent": "El comprobador especificado no existe.", + "checkuser-search": "Buscar entradas del registro de ComprobarUsuario", "checkuser-search-submit": "Buscar", - "checkuser-search-initiator": "verificador", + "checkuser-search-initiator": "comprobador", "checkuser-search-target": "usuario verificado", - "checkuser-log-search-target": "Destino:", + "checkuser-log-search-target": "Usuario comprobado:", + "checkuser-log-search-initiator": "Comprobador:", "checkuser-log-search-type": "Buscar por:", "checkuser-ipeditcount": "~$1 de todos los usuarios", - "checkuser-showmain": "Cambiar al formulario principal de verificador de usuarios (CheckUser)", + "checkuser-showmain": "Cambiar al formulario principal del comprobador de usuarios (ComprobarUsuario)", + "checkuser-show-investigate": "Cambiar al formulario principal de investigación", "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 <bdi>$2</bdi>", @@ -111,6 +123,7 @@ "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-log-entry-investigate": "$3, $1 obtuvo información de $2", "checkuser-autocreate-action": "fue creada automáticamente", "checkuser-create-action": "se creó", "checkuser-email-action": "envió un correo electrónico {{GENDER:$1|al usuario|a la usuaria}} «$1»", @@ -118,9 +131,9 @@ "checkuser-token-fail": "Fallo en la sesión. Intenta de nuevo.", "checkuser-login-failure": "Error al tratar de iniciar sesión como \"$1\" en {{SITENAME}}", "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 */", - "checkuser-link-investigate-label": "Prueba la nueva herramienta CheckUser", + "group-checkuser.css": "/* El código CSS colocado aquí sólo afectará a los usuarios con permisos de checkuser (ComprobarUsuario) */", + "group-checkuser.js": "/* El código JavaScript colocado en esta página sólo afectará a los usuarios con permisos de checkuser (ComprobarUsuario) */", + "checkuser-link-investigate-label": "Prueba la nueva herramienta ComprobarUsuario", "checkuser-investigateblock": "Bloquear usuarios", "checkuser-investigateblock-target": "Nombres de usuario y direcciones IP", "checkuser-investigateblock-actions": "Acciones que bloquear", @@ -139,15 +152,12 @@ "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-subtitle-show-checkuser": "Cambio a ComprobarUsuario", "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", @@ -155,7 +165,7 @@ "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-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", @@ -179,6 +189,7 @@ "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-copy-button-label-hide": "Ocultar 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.", @@ -191,7 +202,7 @@ "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-edits": "<b>[$1 {{PLURAL:$1|edición/acción|ediciones/acciones}}]</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", diff --git a/CheckUser/i18n/et.json b/CheckUser/i18n/et.json index 2896ed20..516cd5c2 100644 --- a/CheckUser/i18n/et.json +++ b/CheckUser/i18n/et.json @@ -7,7 +7,6 @@ ] }, "checkuser-desc": "Võimaldab vajalike õigustega kasutajal teise kasutaja IP-aadresse ja muud teavet kontrollida.", - "checkuser-logcase": "Logi otsing on tõusutundlik.", "checkuser": "Kasutajakontroll", "checkuserlog": "Kasutajakontrolli logi", "checkuser-contribs": "kasutaja IP-aadresside kontroll", @@ -36,7 +35,6 @@ "checkuser-nomatch-edits": "Vasteid ei leitud.\nViimane redigeerimisaeg: $1, $2.", "checkuser-check": "Kontrolli", "checkuser-log-fail": "Logisissekande lisamine ei õnnestu.", - "checkuser-nolog": "Logifaili ei leitud.", "checkuser-blocked": "Blokeeritud", "checkuser-gblocked": "Globaalselt blokeeritud", "checkuser-locked": "Lukustatud", diff --git a/CheckUser/i18n/eu.json b/CheckUser/i18n/eu.json index 6c59ea6f..f0c5e537 100644 --- a/CheckUser/i18n/eu.json +++ b/CheckUser/i18n/eu.json @@ -44,5 +44,5 @@ "checkuser-email-action": "\"$1\" lankideari posta elektroniko bat bidali", "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" + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Erabiltzaile honen IPak erakutsi" } diff --git a/CheckUser/i18n/fa.json b/CheckUser/i18n/fa.json index be9256c4..0a7f1489 100644 --- a/CheckUser/i18n/fa.json +++ b/CheckUser/i18n/fa.json @@ -1,13 +1,16 @@ { "@metadata": { "authors": [ + "Ajam", "Alirezaaa", + "Beginneruser", "Danialbehzadi", "E THP", "Ebraminio", "FarsiNevis", "GMozafarian", "Huji", + "Jeeputer", "Mehran", "MehranVB", "Mjbmr", @@ -16,12 +19,12 @@ ] }, "checkuser-summary": "این ابزار تغییرات اخیر را برای به دست آوردن نشانیهای آیپی استفاده شده توسط یک کاربر و یا تعیین ویرایشها و اطلاعات کاربری مرتبط با یک نشانی آیپی جستجو میکند.\nکاربرها و ویرایشهای مرتبط با یک نشانی آیپی را میتوان با توجه به اطلاعات سرآیند اکسافاف (با افزودن «/xff» به انتهای نشانی آیپی) پیدا کرد.\nهر دو پروتکل IPv4 (معادل CIDR $1-32) و IPv6 (معادل CIDR $2-128) توسط این ابزار پشتیبانی میشوند.\nبنا به دلایل عملکردی، بیش از ۵۰۰۰ ویرایش بازگردانده نمیشود.\nاز این ابزار طبق سیاستها استفاده کنید.", - "checkuser-desc": "به کاربران اختیارات لازم را برای بررسی نشانیهای آیپی و دیگر اطلاعات دیگر یک کاربر میدهد", - "checkuser-logcase": "جستجوی سیاهه به کوچک یا بزرگ بودن حروف حساس است.", + "checkuser-desc": "به کاربران امتیازات لازم را برای بررسی نشانیهای آیپی و دیگر اطلاعات دیگر یک کاربر میدهد", "checkuser": "بازرسی کاربر", "checkuserlog": "سیاهه بازرسی کاربر", "checkuser-contribs": "بازرسی نشانیهای آیپی کاربر", "checkuser-contribs-log": "بازرسیهای کاربر اخیر", + "checkuser-contribs-log-initiator": "بازرسیهای انجام شده توسط این کاربر", "group-checkuser": "بازرسان کاربر", "group-checkuser-member": "{{GENDER:$1|بازرس کاربر}}", "right-checkuser": "بازرسی نشانیهای آیپی و دیگر اطلاعات کاربر", @@ -41,36 +44,41 @@ "checkuser-week-1": "هفتهٔ گذشته", "checkuser-week-2": "دو هفتهٔ گذشته", "checkuser-month": "۳۰ روز گذشته", + "checkuser-month-2": "۶۰ روز گذشته", "checkuser-all": "همه", "checkuser-cidr-label": "پیدا کردن بازههای مشترک آیپی و آیپیهای تاثیرپذیرفته برای یک فهرست از نشانیهای آیپی", "checkuser-cidr-res": "سیآیدیآر مشترک:", + "checkuser-cidr-affected-ips": "نشانیهای آیپی تحت تأثیر:", + "checkuser-cidr-too-small": "بازه بسیار بزرگ است", "checkuser-empty": "سیاهه حاوی هیچ موردی نیست.", "checkuser-nomatch": "موردی که مطابقت داشته باشد پیدا نشد.", "checkuser-nomatch-edits": "مورد مطابق پیدا نشد.\nآخرین ویرایش در $1 ساعت $2 بود.", "checkuser-check": "بازرسی", "checkuser-check-this-user": "بازرسی این کاربر", + "checkuser-investigate-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": "حسابهای انتخاب شده برای همیشه بسته خواهند شد، قطع دسترسی خودکار هم فعال خواهد بود و از ایجاد حساب کاربری هم جلوگیری خواهد شد. نشانیهای آیپی برای یک هفته فقط برای کاربران ناشناس بسته خواهند شد و از ایجاد حساب کاربری توسط آنان جلوگیری خواهد شد.", + "checkuser-massblock": "بستن کاربران انتخاب شده", + "checkuser-massblock-text": "حسابهای انتخاب شده برای همیشه بسته خواهند شد، قطع دسترسی خودکار هم فعال خواهد بود و از ایجاد حساب هم جلوگیری خواهد شد. نشانیهای آیپی برای یک هفته فقط برای کاربران ناشناس بسته خواهند شد و از ایجاد حساب توسط آنان جلوگیری خواهد شد.", "checkuser-blockemail": "ممانعت از ارسال ایمیل", "checkuser-blocktalk": "ممانعت از ویرایش صفحه بحث در زمانی که بسته است", "checkuser-blocktag": "جایگزین کردن صفحهٔ کاربرها با:", "checkuser-blocktag-talk": "جایگزین کردن صفحههای بحث با:", - "checkuser-massblock-commit": "بستن کاربرهای انتخاب شده", + "checkuser-reblock": "رونویسی کردن قطع دسترسیهای موجود", + "checkuser-massblock-commit": "بستن کاربران انتخاب شده", "checkuser-block-success": "'''دسترسی {{PLURAL:$2|حساب|حسابهای}} $1 اینک {{PLURAL:$2|بستهاست|بستهاست}}.'''", "checkuser-block-failure": "'''هیچ کاربری بسته نشد.'''", "checkuser-block-limit": "تعداد بیش از اندازهای از کاربران انتخاب شدهاند.", "checkuser-block-noreason": "شما باید دلیلی برای قطع دسترسیها ارائه کنید.", "checkuser-centralauth-multilock": "بستنهای چندگانه حسابهای کاربری انتخابشده", + "checkuser-centralauth-multilock-list-item": "پیوند $1", "checkuser-noreason": "شما باید دلیلی برای این درخواست وارد کنید.", - "checkuser-too-many": "تعداد نتایج بسیار زیاد است (طبق تخمینهای پرسمان)، لطفاً سیآیدیآر را محدودتر کنید.\nدر زیر نشانیهای آیپی استفاده شده را میبینید (حداکثر ۵۰۰۰ مورد، به ترتیب نشانی):", + "checkuser-too-many": "تعداد نتایج بسیار زیاد است (طبق تخمینهای پرسمان)، لطفاً سیآیدیآر را محدودتر کنید.\nدر زیر نشانیهای آیپی استفاده شده را میبینید (حداکثر $1 مورد، به ترتیب نشانی):", "checkuser-user-nonexistent": "کاربر مورد نظر وجود ندارد.", "checkuser-search": "جستجوی موارد سیاههٔ بازرسی کاربر", "checkuser-search-submit": "جستجو", @@ -80,6 +88,7 @@ "checkuser-log-search-type": "جستجو با:", "checkuser-ipeditcount": "~$1 از همهٔ کاربران", "checkuser-showmain": "رفتن به فرم اصلی بازرسی کاربر", + "checkuser-show-investigate": "رفتن به فرم بررسی اصلی", "checkuser-limited": "'''این نتایج برای کارآیی سامانه کوتاه شدهاند.'''", "checkuser-log-entry-userips": "$3، $1 نشانیهای آیپی $2 را گرفت", "checkuser-log-entry-ipedits": "$3، $1 ویرایشهای <bdi>$2</bdi> را گرفت", @@ -87,13 +96,88 @@ "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-log-entry-investigate": "$3، $1 اطلاعات $2 را گرفت", "checkuser-autocreate-action": "به طور خودکار ساخته شد", "checkuser-create-action": "ایجاد شد", "checkuser-email-action": "به کاربر «$1» ایمیل ارسال شد", - "checkuser-reset-action": "گذرواژه کاربر «$1» را از نو تنظیم کرد", + "checkuser-reset-action": "بازنشانی گذرواژه برای کاربر $1", "checkuser-token-fail": "نشست با شکست مواجه شد. لطفاً دوباره سعی کنید.", "checkuser-login-failure": "در ورود به {{SITENAME}} با حساب $1 ناموفق بود", "checkuser-login-success": "در ورود به {{SITENAME}} با حساب $1 موفق بود", + "checkuser-link-investigate-label": "ابزار جدید بازرسی کاربر را بیازمایید", + "checkuser-investigateblock": "بستن کاربران", + "checkuser-investigateblock-target": "نامهای کاربری و نشانیهای آیپی", + "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": "وارسی", + "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-subtitle-show-checkuser": "تغییر وضعیت به بازرسی کاربر", + "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-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-registration": "تاریخ ضمیمهشدن", + "checkuser-investigate-preliminary-table-header-wiki": "ویکی", "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "ویکی یافته نشد", - "checkuser-investigate-compare-table-button-filter-label": "پالایش نتایج" + "checkuser-investigate-filters-legend": "پالایهها", + "checkuser-investigate-filters-exclude-targets-label": "پنهان کردن این حسابها یا نشانیهای آیپی", + "checkuser-investigate-compare-copy-button-label": "نمایش ویکیمتن", + "checkuser-investigate-compare-copy-button-label-hide": "نهفتن ویکیمتن", + "checkuser-investigate-compare-toollinks-ipcheck": "بررسی پروکسی", + "checkuser-investigate-compare-copy-message-label": "میخواهید این اطلاعات را به صورت یک جعبهٔ ویکیمتن کپی کنید؟", + "checkuser-investigate-compare-notice-exceeded-limit": "به دلیل محدودیتهای فنی، به حدنصاب شمار مواردی که میتوان نشان داد رسیدیم. دادههایی که برای این اهداف نمایش داده شدهاند ناقص هستند: $1. لطفاً از اهداف کمتری استفاده کنید، بازهٔ زمانی را کوچکتر کنید، یا بازهٔ آیپی کوچکتری استفاده کنید.", + "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-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": "عامل کاربر", + "checkuser-investigate-tour-targets-title": "بازرسی چندین حساب یا آیپی؟", + "checkuser-investigate-tour-useragents-title": "مطابقت عامل کاربر", + "checkuser-investigate-tour-addusertargets-title": "نیاز به زمینهٔ بیشتر؟", + "checkuser-investigate-tour-filterip-title": "محدود کردن وارسی؟", + "checkuser-investigate-tour-block-title": "میخواهید بسته شود؟", + "checkuser-investigate-tour-copywikitext-title": "کپی کردن دادهها؟" } diff --git a/CheckUser/i18n/fi.json b/CheckUser/i18n/fi.json index 8188324a..9046365d 100644 --- a/CheckUser/i18n/fi.json +++ b/CheckUser/i18n/fi.json @@ -8,8 +8,10 @@ "Crt", "Jaakonam", "Jack Phoenix", + "MITO", "McSalama", "Nike", + "Nwme", "Olli", "Pxos", "Pyscowicz", @@ -22,11 +24,11 @@ }, "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.", "checkuser-desc": "Antaa oikeutetuille käyttäjille mahdollisuuden tarkastaa käyttäjän IP-osoitteita ja muita tietoja.", - "checkuser-logcase": "Haku lokista on kirjainkokoriippuvainen.", "checkuser": "Osoitepaljastin", "checkuserlog": "Osoitepaljastinloki", "checkuser-contribs": "tarkasta käyttäjän IP-osoitteet", "checkuser-contribs-log": "viimeisimmät käyttäjätarkastukset", + "checkuser-contribs-log-initiator": "käyttäjän suorittamat käyttäjätarkastukset", "group-checkuser": "osoitepaljastimen käyttäjät", "group-checkuser-member": "{{GENDER:$1|osoitepaljastimen käyttäjä}}", "right-checkuser": "Tarkastaa käyttäjän IP-osoitteita ja muita tietoja", @@ -46,6 +48,7 @@ "checkuser-week-1": "viimeisin viikko", "checkuser-week-2": "viimeiset kaksi viikkoa", "checkuser-month": "viimeiset 30 päivää", + "checkuser-month-2": "viimeiset 60 päivää", "checkuser-all": "kaikki", "checkuser-cidr-label": "Etsi yleinen osoiteavaruus annetulle IP-luettelolle", "checkuser-cidr-res": "Yleinen CIDR", @@ -54,9 +57,9 @@ "checkuser-nomatch-edits": "Osumia ei löytynyt.\nViimeinen muokkaus on tehty $1 kello $2.", "checkuser-check": "Tarkasta", "checkuser-check-this-user": "Tarkasta tämä käyttäjä", + "checkuser-investigate-this-user": "Tutki tätä käyttäjää", "checkuser-recent-checks": "Viimeisimmät tarkastukset tälle käyttäjälle", "checkuser-log-fail": "Lokitapahtuman lisäys epäonnistui", - "checkuser-nolog": "Lokitiedostoa ei löytynyt.", "checkuser-blocked": "Estetty", "checkuser-gblocked": "Estetty järjestelmänlaajuisesti", "checkuser-locked": "Lukittu", @@ -68,6 +71,7 @@ "checkuser-blocktalk": "Estä käyttäjää muokkaamasta omaa keskustelusivuaan eston aikana", "checkuser-blocktag": "Korvaa käyttäjäsivut sisällöllä:", "checkuser-blocktag-talk": "Korvaa keskustelusivut sisällöllä:", + "checkuser-reblock": "Ohita olemassaolevat estot", "checkuser-massblock-commit": "Estä valitut käyttäjät", "checkuser-block-success": "'''{{PLURAL:$2|Käyttäjä|Käyttäjät}} $1 on nyt estetty.'''", "checkuser-block-failure": "'''Yhtään käyttäjää ei estetty.'''", @@ -75,26 +79,37 @@ "checkuser-block-noreason": "Estoille on annettava syy.", "checkuser-centralauth-multilock": "Lukitse valitut tunnukset", "checkuser-noreason": "Sinun tulee antaa syy tälle kyselylle.", - "checkuser-too-many": "Liian monta tulosta (kyselyarvion mukaan), pienennä CIDR-aluetta.\nKäytetyt IP-osoitteet (enintään 5000, järjestetty osoitteen mukaan):", + "checkuser-too-many": "Liian monta tulosta (kyselyarvion mukaan), pienennä CIDR-aluetta.\nKäytetyt IP-osoitteet (enintään $1, järjestetty osoitteen mukaan):", "checkuser-user-nonexistent": "Määritettyä käyttäjää ei ole olemassa.", "checkuser-search": "Etsi osoitinpaljastinlokin merkinnöistä", "checkuser-search-submit": "Hae", "checkuser-search-initiator": "alullepanija", "checkuser-search-target": "kohde", "checkuser-log-search-target": "Kohde:", + "checkuser-log-search-initiator": "Alullepanija:", "checkuser-log-search-type": "Etsi:", "checkuser-ipeditcount": "noin $1 muokkausta kaikilta käyttäjiltä", "checkuser-showmain": "Siirry osoitepaljastimen päälomakkeeseen", + "checkuser-show-investigate": "Siirry käyttäjän tutkimisen 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 <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-log-entry-investigate": "$3, $1 haki tietoa käyttäjästä $2", "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-link-investigate-label": "Kokeile uutta osoitepaljastin-työkalua", + "checkuser-investigateblock": "Estä käyttäjät", + "checkuser-investigateblock-target": "Käyttäjätunnukset ja IP-osoitteet", + "checkuser-investigateblock-reason": "Syy", + "checkuser-investigateblock-options": "Lisävalinnat", + "checkuser-investigateblock-email-label": "Estä sähköpostin lähettäminen", + "checkuser-investigateblock-usertalk-label": "Estä käyttäjää muokkaamasta omaa keskustelusivuaan eston aikana", + "checkuser-investigateblock-reblock-label": "Ohita olemassaolevat estot", "checkuser-investigate-subtitle-block-button-label": "Estä", "checkuser-investigate-subtitle-cancel-button-label": "Peruuta", "checkuser-investigate-subtitle-continue-button-label": "Jatka", diff --git a/CheckUser/i18n/fr.json b/CheckUser/i18n/fr.json index 599e238c..6c58d096 100644 --- a/CheckUser/i18n/fr.json +++ b/CheckUser/i18n/fr.json @@ -3,8 +3,10 @@ "authors": [ "Actualisateur", "ChrisPtDe", + "Cigaryno", "DavidL", "Derugon", + "DreZhsh", "Eihel", "Element303", "Eneelk", @@ -28,43 +30,49 @@ "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-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.\nAu plus $3 modifications 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", - "checkuser-logcase": "La recherche dans le journal est sensible à la casse.", "checkuser": "Vérificateur d’utilisateur", "checkuserlog": "Journal des vérifications d’utilisateurs", - "checkuser-contribs": "vérifier les adresses IP", - "checkuser-contribs-log": "Vérifications récentes d’utilisateurs", + "checkuser-contribs": "vérifier des adresses IP", + "checkuser-contribs-log": "vérifications récentes d’utilisateurs", + "checkuser-contribs-log-initiator": "vérifications d’utilisateurs effectuées par cet utilisateur", "group-checkuser": "Vérificateurs d’utilisateurs", - "group-checkuser-member": "{{GENDER:$1|vérificateur d’utilisateur|vérificatrice d’utilisateur}}", + "group-checkuser-member": "vérificat{{GENDER:$1|eur|rice}} 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 des utilisateurs et d’autres informations", - "action-checkuser-log": "Visualiser le journal des vérifications des utilisateurs", + "action-checkuser-log": "visualiser le journal des vérifications d’utilisateurs", "grouppage-checkuser": "{{ns:project}}:Vérificateurs d’utilisateurs", - "checkuser-reason": "Motif :", - "checkuser-reason-api": "API: $1", + "checkuser-reason": "Motif :", + "checkuser-reason-api": "API : $1", "checkuser-showlog": "Basculer sur le journal CheckUser", "checkuser-query": "Recherche des modifications récentes", - "checkuser-target": "Nom d’utilisateur ou adresse IP :", + "checkuser-target": "Nom d’utilisateur ou adresse IP :", "checkuser-users": "Obtenir les utilisateurs", "checkuser-edits": "Obtenir les modifications", "checkuser-ips": "Obtenir les adresses IP", - "checkuser-period": "Durée :", + "checkuser-period": "Durée :", "checkuser-week-1": "la semaine dernière", "checkuser-week-2": "les deux dernières semaines", "checkuser-month": "les trente derniers jours", + "checkuser-month-2": "les 60 derniers jours", "checkuser-all": "tout", "checkuser-cidr-label": "Chercher une plage commune et les adresses affectées pour une liste d’adresses IP", - "checkuser-cidr-res": "Plage CIDR commune :", + "checkuser-cidr-res": "Plage CIDR commune :", + "checkuser-cidr-affected-ips": "Adresses IP concernées :", + "checkuser-cidr-too-small": "La plage est trop grande", + "checkuser-range-outside-limit": "La plage $1 est en dehors des limites autorisées.", "checkuser-empty": "Le journal ne contient aucun élément.", "checkuser-nomatch": "Recherches infructueuses.", - "checkuser-nomatch-edits": "Aucune occurrence trouvée. La dernière modification a eu lieu le $1 à $2.", + "checkuser-nomatch-edits": "Aucune occurrence trouvée.\nLa dernière modification a eu lieu le $1 à $2.", "checkuser-check": "Vérifier", "checkuser-check-this-user": "Vérifier cet utilisateur", + "checkuser-investigate-this-user": "Investiguer sur cet utilisateur", "checkuser-recent-checks": "Dernières vérifications concernant cet utilisateur", "checkuser-log-fail": "Impossible d’ajouter l’entrée du journal.", - "checkuser-nolog": "Aucun fichier journal trouvé.", + "checkuser-log-checks-by": "vérifications par", + "checkuser-log-checks-on": "vérifications du", "checkuser-blocked": "Bloqué", "checkuser-gblocked": "Bloqué globalement", "checkuser-locked": "Verrouillé", @@ -74,39 +82,47 @@ "checkuser-massblock-text": "Les comptes sélectionnés seront bloqués indéfiniment, avec le blocage automatique activé et la création de compte désactivée.\nLes adresses IP seront bloquées pendant une semaine uniquement pour les utilisateurs sous IP et avec la création de compte désactivée.", "checkuser-blockemail": "Empêcher l’utilisateur d’envoyer des courriels", "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-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é.'''", "checkuser-block-limit": "Trop d’utilisateurs sélectionnés.", "checkuser-block-noreason": "Vous devez donner un motif justifiant les blocages.", - "checkuser-centralauth-multilock": "Verrouiller les comptes sélectionnés", + "checkuser-centralauth-multilock": "Verrouiller de multiples comptes sélectionnés", + "checkuser-centralauth-multilock-list": "Verrouillez plusieurs comptes sélectionnés à l’aide des liens :", + "checkuser-centralauth-multilock-list-item": "Lien $1", "checkuser-noreason": "Vous devez donner une raison pour cette requête.", - "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-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 ou l’utilisatrice indiqué(e) n’existe pas.", + "checkuser-target-nonexistent": "La cible spécifiée n’existe pas.", + "checkuser-initiator-nonexistent": "L’initiateur spécifié n’existe pas.", "checkuser-search": "Rechercher les entrées du journal de vérification d’utilisateur", "checkuser-search-submit": "Rechercher", - "checkuser-search-initiator": "l’initiateur", + "checkuser-search-initiator": "initiateur", "checkuser-search-target": "la cible", - "checkuser-log-search-target": "Cible :", - "checkuser-log-search-type": "Rechercher par :", + "checkuser-log-search-target": "Cible :", + "checkuser-log-search-initiator": "Initiateur :", + "checkuser-log-search-type": "Rechercher par :", "checkuser-ipeditcount": "~$1 par tous les utilisateurs", "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-show-investigate": "Basculer vers le formulaire principal d’investigation", + "checkuser-limited": "'''Ces résultats ont été tronqués pour des raisons liées aux performances.'''", "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 <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-log-entry-investigate": "$3, $1 a consulté les informations pour $2", "checkuser-autocreate-action": "a été créé automatiquement", "checkuser-create-action": "a été créé", "checkuser-email-action": "a envoyé un courriel à l’utilisateur « $1 »", - "checkuser-reset-action": "réinitialise le mot de passe de l’utilisateur « $1 »", + "checkuser-reset-action": "réinitialisation du mot de passe de l’utilisateur $1", "checkuser-token-fail": "Échec de session. Veuillez réessayer.", "checkuser-login-failure": "Échec de connexion à {{SITENAME}} en tant que $1", + "checkuser-login-failure-with-good-password": "Échec de la connexion à {{SITENAME}} en tant que $1, mais le mot de passe était correct.", "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 » */", @@ -117,88 +133,86 @@ "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-usertalk-label": "Empêcher l’utilisateur de modifier sa propre page de discussion lorsqu’il 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-user-page-label": "Laisser une alerte sur une page utilisateur", + "checkuser-investigateblock-notice-talk-page-label": "Laisser une alerte 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-text-label": "Wikicode", + "checkuser-investigateblock-notice-append": "Ajouter à la fin de la page", + "checkuser-investigateblock-notice-prepend": "Ajouter 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-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|Les utilisateurs}} $1 {{PLURAL:$2|es|son}}t désormais bloqué{{PLURAL:$2||s}}.", + "checkuser-investigateblock-notices-failed": "Certains avis n’ont pas pu être ajoutés aux pages utilisateur ou aux pages de discussion utilisateur.", "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-subtitle-show-checkuser": "Basculer vers CheckUser", "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-preliminary-check": "Informations du 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-tab-timeline": "Chronologie", + "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-duration-option-1w": "La semaine dernière", + "checkuser-investigate-duration-option-2w": "Les 2 dernières semaines", + "checkuser-investigate-duration-option-30d": "Les 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-edits": "$1 modification{{PLURAL:$1||s}}", "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-registration": "Rattaché le", "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-timeline-notice-no-results": "Il n’y a aucun résultat : aucune activité enregistrée n’a eu lieu pour ces utilisateurs ou ces adresses IP dans les 90 derniers jours.", + "checkuser-investigate-timeline-notice-no-results-filters": "Il n’y a aucun 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 wikicode", + "checkuser-investigate-compare-copy-button-label-hide": "Masquer le wikicode", + "checkuser-investigate-compare-toollinks-whois": "WHOIS", + "checkuser-investigate-compare-toollinks-ipcheck": "Vérification de mandataire (proxy)", + "checkuser-investigate-compare-copy-message-label": "Souhaitez-vous copier ces informations sous forme de tableau en wikicode ?", + "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 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 aucun résultat : aucune modification n’a été effectuée par ces utilisateurs ou adresses IP au cours des 90 derniers jours.", + "checkuser-investigate-compare-notice-no-results-filters": "Il n’y a aucun 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-checks-label": "Vérifications", "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-edits": "<b>[$1 modification{{PLURAL:$1||s}} ou action{{PLURAL:$1||s}}]</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-targets-title": "Vérification de plusieurs utilisateurs et adresses IP ?", + "checkuser-investigate-tour-targets-desc": "Ajoutez jusqu’à $1 nom{{PLURAL:$1||s}} d’utilisateur ou adresse{{PLURAL:$1||s}} IP et obtenez toutes les informations en un seul endroit. Ne vous inquiétez pas, nous allons créer pour chacun d’eux un journal distinct du Vérificateur d’adresses IP.", + "checkuser-investigate-tour-useragents-title": "Agents utilisateur correspondants ?", "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-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-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-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/frc.json b/CheckUser/i18n/frc.json index 651f34cc..365f8539 100644 --- a/CheckUser/i18n/frc.json +++ b/CheckUser/i18n/frc.json @@ -6,7 +6,6 @@ ] }, "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-logcase": "La charche des notes est sensible aux lettres basses ou hautes.", "checkuser": "'Gardez-voir à l'useur encore", "checkuserlog": "Notes de la Garde d'useur", "group-checkuser": "'Gardez-voir aux useurs encore", @@ -23,6 +22,5 @@ "checkuser-nomatch": "Rien pareil trouvé.", "checkuser-check": "Charche", "checkuser-log-fail": "Pas capable d'additionner la note", - "checkuser-nolog": "Rien trouvé dans les notes.", "checkuser-search": "Charche" } diff --git a/CheckUser/i18n/frp.json b/CheckUser/i18n/frp.json index 8aa1999c..865bbc85 100644 --- a/CheckUser/i18n/frp.json +++ b/CheckUser/i18n/frp.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "Ceti outil parcôrt los dèrriérs changements a la rechèrche de les adrèces IP empleyês per un usanciér, montre tôs los changements d’una adrèce IP (méma encartâ), ou ben liste los comptos utilisâs per una adrèce IP.\nLos comptos et los changements fêts per una adrèce IP clianta d’un sèrvor mandatèro (''proxy'') aprovâ pôvont étre rècupèrâs avouéc les en-tétes XFF en apondent l’adrèce IP avouéc « /xff ». Les adrèces IPv4 (CIDR /$1 a /32) et IPv6 (CIDR /§2 a /128) sont recognues.\nLo nombro de changements montrâblos est limitâ a {{formatnum:5000}} por des quèstions de pèrformence.\nLo volyéd utilisar dedens les limites de la chârta d’usâjo.", "checkuser-desc": "Balye la possibilitât a les gens qu’ont la pèrmission que vat avouéc de controlar les adrèces IP des usanciérs et pués d’ôtres enformacions los regardent.", - "checkuser-logcase": "La rechèrche dens lo jornal est sensibla a la câssa.", "checkuser": "Controlor d’usanciér", "checkuserlog": "Jornal des contrôlos d’usanciérs", "checkuser-contribs": "controlar les adrèces IP ux usanciérs", @@ -37,7 +36,6 @@ "checkuser-nomatch-edits": "Gins de corrèspondance trovâ.\nLo dèrriér changement est arrevâ lo $1 a $2.", "checkuser-check": "Rechèrche", "checkuser-log-fail": "Empossiblo d’apondre l’entrâ du jornal.", - "checkuser-nolog": "Gins de fichiér jornal trovâ.", "checkuser-blocked": "Blocâ", "checkuser-gblocked": "Blocâ dens l’ensemblo", "checkuser-locked": "Vèrrolyê", diff --git a/CheckUser/i18n/fy.json b/CheckUser/i18n/fy.json index 0fb0bad6..4e3f7514 100644 --- a/CheckUser/i18n/fy.json +++ b/CheckUser/i18n/fy.json @@ -9,7 +9,7 @@ }, "group-checkuser": "Meidoggerneisjoggers", "group-checkuser-member": "meidogger{{GENDER:$1|neisjogger|neisjochster}}", - "right-checkuser": "IP-adressen en oare ynformaasje fan meidoggers kontrolearje", + "right-checkuser": "YP-adressen en oare ynformaasje fan meidoggers kontrolearje", "grouppage-checkuser": "{{ns:project}}:Meidoggerneisjoggers", "checkuser-reason": "Reden:", "checkuser-search": "Sykje", diff --git a/CheckUser/i18n/ga.json b/CheckUser/i18n/ga.json index bfa7650c..2cc06f16 100644 --- a/CheckUser/i18n/ga.json +++ b/CheckUser/i18n/ga.json @@ -8,7 +8,6 @@ ] }, "checkuser-summary": "Scanann an uirlis seo na athruithe is déanaí chun na seolaidh IP úsáideoira a fháil ná taispeáin na sonraí eagarthóireachta/úsáideoira don seoladh IP.\nIs féidir úsáideoirí agus eagarthóireachta mar IP cliant a fháil le ceanntáisc XFF mar an IP a iarcheangail le \"/xff\". IPv4 (CIDR $1-32) agus IPv6 (CIDR $2-128) atá tacaíocht.\nLe fáth feidhmiúcháin, ní féidir níos mó ná 5000 eagarthóireachta a thabhairt ar ais ar an am cheana. Déan úsáid de réir polsaí.", - "checkuser-logcase": "Tá na logaí seo cásíogair.", "checkuser": "Seic úsáideoir", "checkuserlog": "Logaí checkuser", "group-checkuser": "Seiceanna úsáideoir", @@ -29,7 +28,6 @@ "checkuser-nomatch": "Ní faigheann aon comhoiriúnaigh.", "checkuser-check": "Iarratais", "checkuser-log-fail": "Ní féidir iontráil a cur sa log", - "checkuser-nolog": "Ní bhfaigheann comhad loga.", "checkuser-blocked": "Cosanta", "checkuser-gblocked": "Cosanta domhandach", "checkuser-locked": "Glasáilte", diff --git a/CheckUser/i18n/gl.json b/CheckUser/i18n/gl.json index e38517c5..d2de87ec 100644 --- a/CheckUser/i18n/gl.json +++ b/CheckUser/i18n/gl.json @@ -13,7 +13,6 @@ }, "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.", "checkuser-desc": "Garante que usuarios cos permisos apropiados poidan comprobar os enderezos IP dos usuarios e acceder a outra información", - "checkuser-logcase": "A procura no rexistro distingue entre maiúsculas e minúsculas.", "checkuser": "Verificador de usuarios", "checkuserlog": "Rexistro de comprobacións de usuarios", "checkuser-contribs": "comprobar os enderezos IP do usuario", @@ -47,7 +46,6 @@ "checkuser-check-this-user": "Verificar este usuario", "checkuser-recent-checks": "Verificacións recentes para este usuario", "checkuser-log-fail": "Non é posible engadir unha entrada no rexistro", - "checkuser-nolog": "Non se atopou ningún ficheiro de rexistro.", "checkuser-blocked": "Bloqueado", "checkuser-gblocked": "Bloqueado globalmente", "checkuser-locked": "Bloqueado", diff --git a/CheckUser/i18n/gsw.json b/CheckUser/i18n/gsw.json index e0881695..d8cce742 100644 --- a/CheckUser/i18n/gsw.json +++ b/CheckUser/i18n/gsw.json @@ -9,7 +9,6 @@ }, "checkuser-summary": "Des Wärchzyyg dursuecht di letschten Änderige go d IP-Adrässe vun eme Benutzers bzw. d Bearbeitige/Benutzernäme fir e IP-Adräss usefinde. Benutzer un Bearbeitige vun ere IP-Adräss chenne au noch Informatione us dr XFF-Header abgfrogt wäre. Doderzue muess dr IP-Adräss e „/xff“ aaghänkt wäre. IPv4 (CIDR $1-32) un IPv6 (CIDR $2-128) wäre unterstitzt.\nUs Performance-Grind wäre hegschtens 5000 Bearbeitige usgee. Nimm CheckUser usschließli in Ibereinstimmig mit dr Dateschutzrichtlinie.", "checkuser-desc": "Erlaubt Benutzer mit dr jewyylige Rächt d IP-Adrässe un wyteri Informatione vu Benutzer z priefe", - "checkuser-logcase": "D Suech im Logbuech unterscheidet zwische Groß- un Chleischreibig.", "checkuser": "Checkuser", "checkuserlog": "Checkuser-Logbuech", "checkuser-contribs": "IP-Adrässe vu Benutzer priefe", @@ -40,7 +39,6 @@ "checkuser-nomatch-edits": "Kei Ibereinstimmige gfunde. Letschti Bearbeitig isch am $1 am $2 gsi.", "checkuser-check": "Usfiere", "checkuser-log-fail": "Logbuech-Yytrag cha nit zuegfiegt wäre.", - "checkuser-nolog": "Kei Logbuechdatei vorhande.", "checkuser-blocked": "Gsperrt", "checkuser-gblocked": "Wältwyt gsperrt", "checkuser-locked": "Zue", diff --git a/CheckUser/i18n/gu.json b/CheckUser/i18n/gu.json index f1b6bd38..f853887d 100644 --- a/CheckUser/i18n/gu.json +++ b/CheckUser/i18n/gu.json @@ -6,9 +6,9 @@ "KartikMistry" ] }, + "group-checkuser": "સભ્ય તપાસકો", "checkuser-reason": "કારણ:", "checkuser-all": "બધા", - "checkuser-nolog": "કોઇ લૉગ ફાઇલ મળી નહી.", "checkuser-locked": "તાળું મારેલ", "checkuser-search": "શોધો", "checkuser-search-submit": "શોધો", diff --git a/CheckUser/i18n/ha.json b/CheckUser/i18n/ha.json index d1f7c91a..1fb61a48 100644 --- a/CheckUser/i18n/ha.json +++ b/CheckUser/i18n/ha.json @@ -1,7 +1,11 @@ { "@metadata": { - "authors": [] + "authors": [ + "Amire80" + ] }, + "action-checkuser": "duba adireshin IP na edita da wasu sauran bayanan na'ura", + "action-checkuser-log": "duba rajistan check user", "checkuser-reason": "Dalili:", "checkuser-all": "duka", "checkuser-search": "Nema", diff --git a/CheckUser/i18n/he.json b/CheckUser/i18n/he.json index 9eac0140..07a3eda1 100644 --- a/CheckUser/i18n/he.json +++ b/CheckUser/i18n/he.json @@ -7,16 +7,19 @@ "Rotemliss", "Steeve815", "YaronSh", - "דגש חזק" + "Yona b", + "דגש", + "דגש חזק", + "לואיקה" ] }, - "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יש להשתמש בכלי זה בהתאם למדיניות.", + "checkuser-summary": "הכלי הזה סורק את השינויים האחרונים במטרה למצוא את כתובות ה־IP שמשתמש מסוים עשה בהן שימוש או כדי להציג את כל המידע על המשתמשים שהשתמשו בכתובת IP מסוימת ועל העריכות שבוצעו ממנה.\nניתן לקבל עריכות ומשתמשים מכתובות IP של הכותרת X-Forwarded-For באמצעות הוספת הטקסט \"<span dir=\"ltr\">/xff</span>\" לסוף הכתובת. הן כתובות IPv4 (כלומר, CIDR $1-32) והן כתובות IPv6 (כלומר, CIDR $2-128) נתמכות.\nלא יוחזרו יותר מ־$3 עריכות מסיבות של עומס על השרתים.\nיש להשתמש בכלי הזה בהתאם למדיניות.", "checkuser-desc": "מתן אפשרות למשתמשים עם ההרשאות המתאימות לבדוק כתובות IP ומידע נוסף של משתמשים", - "checkuser-logcase": "החיפוש ביומנים הוא תלוי־רישיות.", "checkuser": "בדיקת משתמש", "checkuserlog": "יומן בדיקות", "checkuser-contribs": "בדיקת כתובות ה־IP", "checkuser-contribs-log": "בדיקות אחרונות של המשתמש", + "checkuser-contribs-log-initiator": "בדיקות משתמשים שנעשו על־ידי המשתמש הזה", "group-checkuser": "בודקים", "group-checkuser-member": "{{GENDER:$1|בודק|בודקת}}", "right-checkuser": "מציאת כתובות IP ומידע נוסף של משתמשים", @@ -36,17 +39,23 @@ "checkuser-week-1": "השבוע האחרון", "checkuser-week-2": "השבועיים האחרונים", "checkuser-month": "30 הימים האחרונים", + "checkuser-month-2": "60 הימים האחרונים", "checkuser-all": "הכול", "checkuser-cidr-label": "מציאת טווח משותף וכתובות מושפעות עבור רשימה של כתובות IP", "checkuser-cidr-res": "CIDR משותף:", + "checkuser-cidr-affected-ips": "כתובות IP מושפעות:", + "checkuser-cidr-too-small": "הטווח גדול מדי", + "checkuser-range-outside-limit": "הטווח $1 מחוץ למגבלות המותרות.", "checkuser-empty": "אין פריטים ביומן.", "checkuser-nomatch": "לא נמצאו התאמות.", "checkuser-nomatch-edits": "לא נמצאו התאמות.\nהעריכה האחרונה בוצעה ב־$1 ב־$2.", "checkuser-check": "בדיקה", "checkuser-check-this-user": "בדיקת המשתמש הזה", + "checkuser-investigate-this-user": "לחקור את המשתמש הזה", "checkuser-recent-checks": "בדיקות אחרונות עבור המשתמש הזה", "checkuser-log-fail": "לא היה ניתן להוסיף פריט ליומן", - "checkuser-nolog": "לא נמצא קובץ יומן.", + "checkuser-log-checks-by": "בדיקות על־ידי", + "checkuser-log-checks-on": "בדיקות על", "checkuser-blocked": "חסום", "checkuser-gblocked": "חסום באופן גלובלי", "checkuser-locked": "נעול", @@ -65,17 +74,23 @@ "checkuser-block-limit": "נבחרו יותר מדי משתמשים.", "checkuser-block-noreason": "יש לתת סיבה לחסימות.", "checkuser-centralauth-multilock": "נעילה מרובה של חשבונות שנבחרו", + "checkuser-centralauth-multilock-list": "נעילה מרובה של חשבונות שנבחרו באמצעות הקישורים:", + "checkuser-centralauth-multilock-list-item": "קישור $1", "checkuser-noreason": "יש לכתוב סיבה לשאילתה הזאת.", "checkuser-too-many": "יותר מדי תוצאות (לפי ההערכה של השאילתה), נא לצמצם את ה־CIDR.\nהנה כתובת ה־IP שהיו בשימוש ($1 לכל היות, ממוינות לפי הכתובת):", "checkuser-user-nonexistent": "המשתמש שצוין לא נמצא.", + "checkuser-target-nonexistent": "היעד שצוין אינו קיים.", + "checkuser-initiator-nonexistent": "יוזם הבדיקה שצוין אינו קיים.", "checkuser-search": "חיפוש רשומות ביומן בדיקת משתמשים", "checkuser-search-submit": "חיפוש", - "checkuser-search-initiator": "בודק", + "checkuser-search-initiator": "יוזם הבדיקה", "checkuser-search-target": "נבדק", "checkuser-log-search-target": "יעד:", + "checkuser-log-search-initiator": "יוזם הבדיקה:", "checkuser-log-search-type": "חיפוש לפי:", "checkuser-ipeditcount": "בערך $1 מכל המשתמשים", "checkuser-showmain": "מעבר לטופס הבדיקה הראשי", + "checkuser-show-investigate": "מעבר לטופס חקירה הראשי", "checkuser-limited": "'''הדף נקטע כדי לחסוך במשאבים.'''", "checkuser-log-entry-userips": "$3, משתמש $1 קיבל כתובות IP עבור $2", "checkuser-log-entry-ipedits": "$3, משתמש $1 קיבל עריכות עבור <bdi>$2</bdi>", @@ -83,12 +98,14 @@ "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-log-entry-investigate": "$3, $1 {{GENDER:$1|חיפש|חיפשה}} מידע על $2", "checkuser-autocreate-action": "נוצר אוטומטית", "checkuser-create-action": "נוצר", "checkuser-email-action": "נשלח דואר אלקטרוני למשתמש \"$1\"", - "checkuser-reset-action": "איפס את הסיסמה של המשתמש \"$1\"", - "checkuser-token-fail": "כשל שיחה. נא לנסות שוב.", + "checkuser-reset-action": "איפס את הסיסמה של המשתמש $1", + "checkuser-token-fail": "כשל התחברות. נא לנסות שוב.", "checkuser-login-failure": "לא הצליח להיכנס לאתר {{SITENAME}} בתור $1", + "checkuser-login-failure-with-good-password": "הכניסה לאתר {{SITENAME}} בתור $1 נכשלה, אבל הסיסמה הייתה נכונה", "checkuser-login-success": "נכנס בהצלחה לאתר {{SITENAME}} בתור $1", "group-checkuser.css": "/* הסגנונות הנכתבים כאן ישפיעו על בודקים בלבד */", "group-checkuser.js": "/* כל הסקריפטים הנכתבים כאן ייטענו עבור בודקים בלבד */", @@ -111,15 +128,12 @@ "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-subtitle-continue-button-label": "להמשיך", + "checkuser-investigate-subtitle-show-checkuser": "מעבר לבדיקת משתמש", "checkuser-investigate-indicator-new-investigation": "חקירה חדשה", "checkuser-investigate-indicator-logs": "יומנים", "checkuser-investigate-legend": "חיפוש שמות משתמש, כתובות IP או טווחי IP", @@ -127,7 +141,7 @@ "checkuser-investigate-tab-preliminary-check": "מידע על החשבון", "checkuser-investigate-tab-compare": "כתובות IP וסוכני לקוח", "checkuser-investigate-tab-timeline": "ציר זמן", - "checkuser-investigate-targets-label": "שמות משתמש וכתובות IP", + "checkuser-investigate-targets-label": "שמות משתמש וכתובות IP:", "checkuser-investigate-targets-placeholder": "שם־משתמש או 1.1.1.1", "checkuser-investigate-duration-label": "משך זמן", "checkuser-investigate-duration-option-all": "הכול", @@ -151,9 +165,10 @@ "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-button-label-hide": "הסתרת קוד ויקי", + "checkuser-investigate-compare-toollinks-ipcheck": "בדיקת שרת מתווך (פרוקסי)", "checkuser-investigate-compare-copy-message-label": "האם {{GENDER:|תרצה|תרצי}} להעתיק את המידע הזה בתור טבלה בקוד ויקי?", - "checkuser-investigate-compare-notice-exceeded-limit": "בשל מגבלות טכניות, הגענו למספר המרבי של רשומות שאפשר להציג. הנתונים שהוחזרו ליעדים הבעים אינם מלאים $1. נא לנסות להשתמש בפחות יעדים, חלון זמן קטן יותר, או טווחי IP צרים יותר.", + "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 של המשתמש הזה", @@ -163,7 +178,7 @@ "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-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": "טווח תאריכים", @@ -173,13 +188,13 @@ "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-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-block-desc": "זה מאפשר לך לבחור את המשתמשים {{GENDER:|שאתה רוצה|שאת רוצה|שברצונך}} לחסום, ואז מעביר אותך לטופס החסימה כדי לבחור את החסימה המתאימה.", "checkuser-investigate-tour-copywikitext-title": "רוצה להעתיק את הנתונים?", - "checkuser-investigate-tour-copywikitext-desc": "{{GENDER:|העתק|העתיקי}} את טבלת ההשוואה בלחיצה אחת {{GENDER:|וקח|וקחי}} אותה ל־CUWiki. {{GENDER:|שים|שימי}} לב לכך {{GENDER:|שאתה מעתיק|שאת מעתיקה}} רק את מה שמוצג ולא את כל הדפים של החקירה." + "checkuser-investigate-tour-copywikitext-desc": "{{GENDER:|העתק|העתיקי|נא להעתיק}} את טבלת ההשוואה בלחיצה אחת {{GENDER:|וקח|וקחי|ולקחת}} אותה ל־CUWiki. {{GENDER:|שים לב שאתה מעתיק|שימי לב שאת מעתיקה|נא לשים לב לכך שהעתקת}} רק את מה שמוצג ולא את כל דפי החקירה." } diff --git a/CheckUser/i18n/hi.json b/CheckUser/i18n/hi.json index 6978b7cd..132ccc6d 100644 --- a/CheckUser/i18n/hi.json +++ b/CheckUser/i18n/hi.json @@ -5,80 +5,192 @@ "Ansumang", "Archana mathur", "Kaustubh", + "Saurmandal", "Sfic", "Shyam", "Siddhartha Ghai", "जनक राज भट्ट" ] }, - "checkuser-summary": "यह उपकरण हाल में किये गये बदलावों की जाँच किसी सदस्य द्वारा प्रयुक्त सारे आई॰पी पते खोजने के लिए, अथवा किसी आई॰पी का उपयोग करने वाले सभी सदस्यों का सम्पादन एवं सदस्य डाटा खोजने के लिए करता है।\nXFF headers का प्रयोग कर के किसी आई॰पी से सम्बद्ध सदस्य एवं सम्पादन जानकारी आई॰पी पते के आगे \"/xff\" लगाकर खोजी जा सकती है। IPv4 (CIDR $1-32) और IPv6 (CIDR $2-128) समर्थित हैं।\nप्रदर्शन कारणों की वजह से पाँच हज़ार से अधिक सम्पादन नहीं दिखाए जाएँगे।\nइसे नीति के अनुसार प्रयोग करें।", - "checkuser-desc": "उपयुक्त अधिकार रखने वाले सदस्यों को अन्य सदस्यों के आई॰पी पते एवं अन्य जानकारी देखने की अनुमति देता है।", - "checkuser-logcase": "लॉग में खोज लिपि पर आधारित (case sensitive) है।", + "checkuser-summary": "यह उपकरण हाल में हुए बदलावों को जाँचकर किसी सदस्य द्वारा उपयुक्त IP पते प्राप्त करता है या फिर किसी IP पते द्वारा सारे संपादन दिखाता है।\nसदस्य, और किसी क्लाइंट IP द्वारा संपादन IP पते के आखिर में \"/xff\" जोड़कर XFF हैडर्स के ज़रिए प्राप्त किए जा सकते हैं। IPv4 (CIDR $1 से 32) और IPv6 (CIDR $2 से 128) समर्थित हैं।\nप्रदर्शन को ठीक रखने के लिए अधिकतम $3 संपादन लाए जाएँगे।\nइसका इस्तेमाल नीतियों के अनुसार करें।", + "checkuser-desc": "सदस्यों को दूसरे सदस्यों के IP पते के साथ दूसरी जानकारी देखने की अनुमति देता है", "checkuser": "सदस्य जाँच", "checkuserlog": "सदस्य जाँच लॉग", - "checkuser-contribs": "सदस्य आई॰पी पते जाँचें", - "checkuser-contribs-log": "हाल में हुई सदस्य जाँचें", - "group-checkuser": "सदस्य जाँचकर्ता", + "checkuser-contribs": "सदस्य के IP पते जाँचें", + "checkuser-contribs-log": "हाल में हुए सदस्य जाँच", + "checkuser-contribs-log-initiator": "इस सदस्य द्वारा किए गए सदस्य जाँच", + "group-checkuser": "सदस्य जाँचकर्ताएँ", "group-checkuser-member": "{{GENDER:$1|सदस्य जाँचकर्ता}}", - "right-checkuser": "सदस्य का आई॰पी पता एवं अन्य जानकारी जाँचें", - "right-checkuser-log": "सदस्य जाँच लॉग देखें", - "action-checkuser": "सदस्य के आई॰पी पते और अन्य जानकारी जाँचने", + "right-checkuser": "सदस्यों के IP पते और दूसरी जानकारी जाँचें", + "right-checkuser-log": "Checkuser लॉग देखें", + "action-checkuser": "सदस्यों के IP पते और दूसरी जानकारी जाँचने", "action-checkuser-log": "सदस्य जाँच लॉग देखने", - "grouppage-checkuser": "{{ns:project}}: सदस्य जाँचकर्ता", + "grouppage-checkuser": "{{ns:project}}:सदस्य जाँचकर्ता", "checkuser-reason": "कारण:", - "checkuser-reason-api": "ए॰पी॰आई: $1", - "checkuser-showlog": "सदस्यजाँच लॉग दिखायें", + "checkuser-reason-api": "API: $1", + "checkuser-showlog": "CheckUser लॉग देखें", "checkuser-query": "हाल में हुए बदलावों में खोजें", - "checkuser-target": "आई॰पी पता या सदस्यनाम:", + "checkuser-target": "IP पता या सदस्यनाम:", "checkuser-users": "सदस्य खोजें", "checkuser-edits": "सम्पादन खोजें", - "checkuser-ips": "आई॰पी पते खोजें", + "checkuser-ips": "IP पते खोजें", "checkuser-period": "अवधि:", - "checkuser-week-1": "पिछले सप्ताह", - "checkuser-week-2": "पिछले दो सप्ताह", - "checkuser-month": "पिछले तीस दिन", + "checkuser-week-1": "पिछला हफ़्ता", + "checkuser-week-2": "पिछले दो हफ़्ते", + "checkuser-month": "पिछले 30 दिन", + "checkuser-month-2": "पिछले 60 दिन", "checkuser-all": "सभी", - "checkuser-cidr-label": "आइ॰पी पतों की सूची के लिए कॉमन रेंज और प्रभावित आइ॰पी पते खोजें", - "checkuser-cidr-res": "समन्वय CIDR:", - "checkuser-empty": "इस लॉग में कोई प्रविष्टि नहीं है।", - "checkuser-nomatch": "कोई मेल खाते परिणाम नहीं मिले।", - "checkuser-nomatch-edits": "कोई मेल खाते परिणाम नहीं मिले।\nअंतिम सम्पादन $1 को $2 बजे हुआ था।", + "checkuser-cidr-label": "IP पतों की सूची के लिए साँझित रेंज और प्रभावित IP पते खोजें", + "checkuser-cidr-res": "साँझित CIDR:", + "checkuser-cidr-affected-ips": "प्रभावित IP पते:", + "checkuser-cidr-too-small": "रेंज कुछ ज़्यादा ही बड़ा है", + "checkuser-range-outside-limit": "रेंज $1 अनुमत सीमा के बाहर है।", + "checkuser-empty": "इस लॉग में कोई आयटम नहीं है।", + "checkuser-nomatch": "कोई मेल खाता परिणाम नहीं मिला।", + "checkuser-nomatch-edits": "कोई मेल खाता परिणाम नहीं मिला।\nआखिरी संपादन $1 को $2 बजे हुआ था।", "checkuser-check": "जाँचें", - "checkuser-log-fail": "लॉग प्रविष्टि जोड़ नहीं पाये", - "checkuser-nolog": "कोई लॉग फ़ाइल नहीं मिली।", - "checkuser-blocked": "अवरुद्ध", - "checkuser-gblocked": "वैश्विक रूप से अवरुद्ध", + "checkuser-check-this-user": "इस सदस्य को जाँचें", + "checkuser-investigate-this-user": "इस सदस्य की जाँच करें", + "checkuser-recent-checks": "इस सदस्य के लिए हाल में हुए जाँच", + "checkuser-log-fail": "लॉग एंट्री जोड़ी न जा सकी", + "checkuser-log-checks-by": "जाँचकर्ता", + "checkuser-log-checks-on": "जाँच का लक्ष्य", + "checkuser-blocked": "अवरोधित", + "checkuser-gblocked": "ग्लोबल रूप से अवरोधित", "checkuser-locked": "लॉक किया हुआ", - "checkuser-wasblocked": "पहले भी अवरुद्ध", + "checkuser-wasblocked": "पहले अवरोधित", "checkuser-localonly": "एकीकृत नहीं", "checkuser-massblock": "चयनित सदस्यों को अवरोधित करें", - "checkuser-massblock-text": "चुने गये खाते अनिश्चितकालीन रूप से अवरोधित कर दिये जाएँगे। आई॰पी पतों का स्वचालित रूप से अवरोधन सक्षम होगा और खाता निर्माण अक्षम होगा।\nआई॰पी पते अनामक सदस्यों के लिये एक सप्ताह तक अवरोधित कर दिये जाएँगे और खाता निर्माण अक्षम होगा।", - "checkuser-blocktag": "सदस्य पृष्ठ को इस पाठ से बदलें:", - "checkuser-blocktag-talk": "सदस्य वार्ता पृष्ठ को इस पाठ से बदलें:", + "checkuser-massblock-text": "चुने हुए खातों को हमेशा के लिए अवरोधित कर दिया जाएगा, जिसमें IP पतों को अपने आप अवरोधित किया जाएगा और खाते का निर्माण अक्षम होगा।\nIP पतों को गुमनाम सदस्यों के लिए एक हफ़्ते तक अवरोधित किया जाएगा और सिर्फ खाते का निर्माण अक्षम होगा।", + "checkuser-blockemail": "ईमेल भेजने से रोकें", + "checkuser-blocktalk": "अवरोधित होने पर अपने वार्ता पृष्ठ को संपादित करने से रोकें", + "checkuser-blocktag": "सदस्य पृष्ठों को इससे बदलें:", + "checkuser-blocktag-talk": "सदस्य वार्ता पृष्ठों को इससे बदलें:", + "checkuser-reblock": "मौजूदा अवरोधों को ओवर्राइड करें", "checkuser-massblock-commit": "चयनित सदस्यों को अवरोधित करें", - "checkuser-block-success": "'''$1 {{PLURAL:$2|सदस्य}} अब अवरुद्ध {{PLURAL:$2|है|हैं}}।'''", - "checkuser-block-failure": "'''कोई सदस्य अवरुद्ध नहीं किये गये।'''", - "checkuser-block-limit": "बहुत ज़्यादा सदस्य चुने हैं।", + "checkuser-block-success": "'''$1 सदस्य अब अवरोधित {{PLURAL:$2|है|हैं}}।'''", + "checkuser-block-failure": "'''कोई सदस्य अवरुद्ध नहीं किए गए।'''", + "checkuser-block-limit": "बहुत ज़्यादा सदस्य चुने गए हैं।", "checkuser-block-noreason": "आपको अवरोध का कारण देना होगा।", - "checkuser-noreason": "आपको इस खोज का कारण देना होगा।", - "checkuser-too-many": "बहुत सारे परिणाम (खोज अंदाज़े अनुसार)। कृपया CIDR छोटा करें।\nनीचे प्रयुक्त आई॰पी पतों की सूची हैं (अधिकतम पाँच हज़ार, अनुक्रम में):", + "checkuser-centralauth-multilock": "चयनित खातों को साथ लॉक करें", + "checkuser-noreason": "आपको इस क्वेरी का एक कारण देना होगा।", + "checkuser-too-many": "बहुत सारे परिणाम आए (क्वेरी के अनुमान के अनुसार), कृपया CIDR को छोटा करें।\nये रहे उपयुक्त IP पते (अधिकतम $1, पते के अनुसार छाँटे गए):", "checkuser-user-nonexistent": "निर्दिष्ट सदस्य मौजूद नहीं है।", - "checkuser-search": "खोजें", + "checkuser-target-nonexistent": "निर्दिष्ट लक्ष्य मौजूद नहीं है।", + "checkuser-initiator-nonexistent": "निर्दिष्ट कर्ता मौजूद नहीं है।", + "checkuser-search": "सदस्य जाँच लॉग की एंट्रियाँ खोजें", "checkuser-search-submit": "खोजें", "checkuser-search-initiator": "कर्ता", "checkuser-search-target": "लक्ष्य", "checkuser-log-search-target": "लक्ष्य:", - "checkuser-ipeditcount": "~$1 सभी सदस्यों से", - "checkuser-showmain": "सदस्य जाँच मुख्य फ़ॉर्म पर वापिस जायें", - "checkuser-limited": "'''प्रदर्शन कारणों की वजह से केवल सीमित परिणाम दिखाये जा रहे हैं।'''", - "checkuser-autocreate-action": "स्वचालित रूप से निर्मित हुआ था", - "checkuser-create-action": "बनाया गया था", - "checkuser-email-action": "सदस्य \"$1\" को ई-मेल भेजा गया", - "checkuser-reset-action": "\"$1\" के लिए पासवर्ड रीसेट करें", - "group-checkuser.css": "/* यहाँ पर दी सी॰एस॰एस केवल सदस्य जाँचकर्ताओं के लिये होगी */", - "group-checkuser.js": "/* यहाँ पर दी जावास्क्रिप्ट केवल सदस्य जाँचकर्ताओं के लिए होगी */", - "checkuser-link-investigate-label": "नया इस्तमाल करने वाला उपकरण आज़माएं", + "checkuser-log-search-initiator": "कर्ता:", + "checkuser-log-search-type": "खोजकर्ता:", + "checkuser-ipeditcount": "सभी सदस्यों से ~$1", + "checkuser-showmain": "CheckUser के मुख्य फ़ॉर्म पर जाएँ", + "checkuser-show-investigate": "जाँच के मुख्य फ़ॉर्म पर जाएँ", + "checkuser-limited": "'''प्रदर्शन को ठीक रखने के लिए सीमित परिणाम दिखाए जा रहे हैं।'''", + "checkuser-log-entry-userips": "$3, $1 ने $2 के IP पते प्राप्त किए", + "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-log-entry-investigate": "$3, $1 ने $2 की जानकारी को जाँचा", + "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 के रूप में सफलतापूर्वक लॉग-इन किया गया", + "group-checkuser.css": "/* यहाँ पर दी गई CSS सिर्फ checkuser पर प्रभाव डालेगी */", + "group-checkuser.js": "/* यहाँ पर दी गई जावास्क्रिप्ट सिर्फ checkuser पर प्रभाव डालेगी */", + "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 अब अवरोधित {{PLURAL:$2|है|हैं}}।", + "checkuser-investigateblock-notices-failed": "कुछ सूचनाओं को सदस्य पृष्ठों या सदस्य वार्ता पृष्ठों पर जोड़ना न जा सका।", + "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-subtitle-continue-button-label": "जारी रखें", + "checkuser-investigate-subtitle-show-checkuser": "CheckUser पर जाएँ", + "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": "पिछले 2 हफ़्ते", + "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": "कोई परिणाम नहीं है: आखिरी 90 दिनों में इन सदस्यों या IP पतों द्वारा कोई कार्य नहीं किया गया है", + "checkuser-investigate-timeline-notice-no-results-filters": "इन मानदंडों से मेल खाने वाले कोई परिणाम नहीं हैं। खोज को बड़ा करने के लिए कुछ फ़िल्टर हटाएँ।", + "checkuser-investigate-compare-copy-button-label": "विकिटेक्स्ट दिखाएँ", + "checkuser-investigate-compare-copy-button-label-hide": "विकिटेक्स्ट छिपाएँ", + "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": "सदस्य एजेंट", + "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/hif-latn.json b/CheckUser/i18n/hif-latn.json index 1f8c6795..d508e2ca 100644 --- a/CheckUser/i18n/hif-latn.json +++ b/CheckUser/i18n/hif-latn.json @@ -28,7 +28,6 @@ "checkuser-nomatch": "Koi match nai mila", "checkuser-check": "Check karo", "checkuser-log-fail": "Log antry me jorre nai sakaa", - "checkuser-nolog": "Koi log file nai mila", "checkuser-blocked": "Block karaa gais", "checkuser-gblocked": "Globally block karaa gais", "checkuser-locked": "lock karaa gais", diff --git a/CheckUser/i18n/hr.json b/CheckUser/i18n/hr.json index f02cd897..e7bd664c 100644 --- a/CheckUser/i18n/hr.json +++ b/CheckUser/i18n/hr.json @@ -13,7 +13,6 @@ }, "checkuser-summary": "Ovaj alat pretražuje nedavne promjene i pronalazi IP adrese suradnika ili prikazuje uređivanja/ime suradnika ako je zadana IP adresa. Suradnici i uređivanja mogu biti dobiveni po XFF zaglavljima dodavanjem \"/xff\" na kraj IP adrese. Podržane su IPv4 (CIDR $1-32) i IPv6 (CIDR $2-128) adrese. Rezultat ima maksimalno 5.000 zapisa iz tehničkih razloga. Rabite ovaj alat u skladu s pravilima.", "checkuser-desc": "Daje suradniku pravo za provjeriti IP adrese suradnika i druge informacije", - "checkuser-logcase": "Pretraživanje evidencije razlikuje velika i mala slova", "checkuser": "Provjeri suradnika", "checkuserlog": "Evidencija provjere suradnika", "checkuser-contribs": "provjeri suradničke IP adrese", @@ -45,7 +44,6 @@ "checkuser-nomatch-edits": "Nema poklapanja.\nPosljednja izmjena je bila $1 u $2.", "checkuser-check": "Provjeri", "checkuser-log-fail": "Ne mogu dodati zapis", - "checkuser-nolog": "Evidencijska datoteka nije nađena", "checkuser-blocked": "Blokiran", "checkuser-gblocked": "Globalno blokiran", "checkuser-locked": "Zaključan", diff --git a/CheckUser/i18n/hsb.json b/CheckUser/i18n/hsb.json index a4024780..fd29142a 100644 --- a/CheckUser/i18n/hsb.json +++ b/CheckUser/i18n/hsb.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "Tutón nastroj přepytuje aktualne změny, zo by IP-adresy wužiwarja zwěsćił abo změny abo wužiwarske daty za IP pokazał.\nWužiwarjo a změny IP-adresy dadźa so přez XFF-hłowy wotwołać, připowěšo \"/xff\" na IP-adresu. IPv4 (CIDR $1-32) a IPv6 (CIDR $2-128) so podpěrujetej.", "checkuser-desc": "Dawa wužiwarjam z trěbnym prawom móžnosć IP-adresy a druhe informacije wužiwarja kontrolować", - "checkuser-logcase": "Pytanje w protokolu rozeznawa mjez wulko- a małopisanjom.", "checkuser": "Wužiwarja kontrolować", "checkuserlog": "Protokol wužiwarskeje kontrole", "checkuser-contribs": "Wužiwarske IP přepruwować", @@ -38,7 +37,6 @@ "checkuser-nomatch-edits": "Žane wotpowědowanja namakane.\nPoslednja změna bě $1 $2.", "checkuser-check": "Pruwować", "checkuser-log-fail": "Njemóžno protokolowy zapisk přidać.", - "checkuser-nolog": "Žadyn protokol namakany.", "checkuser-blocked": "Zablokowany", "checkuser-gblocked": "Globalnje zablokowany", "checkuser-locked": "Zawrjeny", diff --git a/CheckUser/i18n/hu.json b/CheckUser/i18n/hu.json index e0d86e13..dc2a5f94 100644 --- a/CheckUser/i18n/hu.json +++ b/CheckUser/i18n/hu.json @@ -12,6 +12,7 @@ "Grin", "Hunyadym", "KossuthRad", + "Tacsipacsi", "Terik", "Tgr", "Wolf Rex" @@ -19,7 +20,6 @@ }, "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.", "checkuser-desc": "Lehetővé teszi olyan felhasználói jogok kiosztását, mely segítségével megtekinthetőek a felhasználók IP-címei és más adatok", - "checkuser-logcase": "A kereső kis- és nagybetűérzékeny.", "checkuser": "IP-ellenőr", "checkuserlog": "IP-ellenőr-napló", "checkuser-contribs": "a szerkesztő IP-ellenőrzése", @@ -53,7 +53,6 @@ "checkuser-check-this-user": "Felhasználó ellenőrzése", "checkuser-recent-checks": "Ezen szerkesztő legutóbbi ellenőrzései", "checkuser-log-fail": "Nem sikerült az elem hozzáadása", - "checkuser-nolog": "A naplófájl nem található.", "checkuser-blocked": "Blokkolva", "checkuser-gblocked": "Globálisan blokkolva", "checkuser-locked": "Zárva", @@ -65,13 +64,14 @@ "checkuser-blocktalk": "Saját vitalap szerkeszthetőségének megakadályozása, mialatt a felhasználó blokkolva van", "checkuser-blocktag": "Szerkesztői lapok cseréje erre:", "checkuser-blocktag-talk": "Vitalapok cseréje erre:", + "checkuser-reblock": "Jelenlegi blokkok felülírása", "checkuser-massblock-commit": "Kiválasztott szerkesztők blokkolása", "checkuser-block-success": "'''A következő {{PLURAL:$2|szerkesztő|szerkesztők}} blokkolva {{PLURAL:$2|lett|lettek}}: $1.'''", "checkuser-block-failure": "'''Nem lettek szerkesztők blokkolva.'''", "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-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-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 $1, cím alapján rendezve):", "checkuser-user-nonexistent": "A megadott szerkesztő nem létezik.", "checkuser-search": "Keresés a naplófájlokban", "checkuser-search-submit": "Keresés", @@ -80,7 +80,7 @@ "checkuser-log-search-target": "Cél:", "checkuser-log-search-type": "Keresés a következő alapján:", "checkuser-ipeditcount": "~$1 az összes szerkesztő által", - "checkuser-showmain": "Vissza az IP-ellenőri oldalra", + "checkuser-showmain": "Váltás a fő IP-ellenőri űrlapra", "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 <bdi>$2</bdi> szerkesztéseit", @@ -91,9 +91,28 @@ "checkuser-autocreate-action": "automatikusan létrehozva", "checkuser-create-action": "készült", "checkuser-email-action": "e-mailt küldött „$1” szerkesztőnek", - "checkuser-reset-action": "lecserélte „$1” jelszavát", + "checkuser-reset-action": "jelszóemlékeztetőt kért „$1” nevében", "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", - "checkuser-investigate-preliminary-table-header-blocked": "Állapot" + "checkuser-investigateblock": "Felhasználók blokkolása", + "checkuser-investigateblock-target": "Felhasználói nevek és IP-címek", + "checkuser-investigateblock-reason": "Ok", + "checkuser-investigateblock-options": "További lehetőségek", + "checkuser-investigateblock-reblock-label": "Jelenlegi blokkok felülírása", + "checkuser-investigate-subtitle-cancel-button-label": "Mégse", + "checkuser-investigate-tab-timeline": "Idővonal", + "checkuser-investigate-duration-label": "Időtartam", + "checkuser-investigate-duration-option-1w": "Múlt héten", + "checkuser-investigate-duration-option-2w": "Az előző két hét", + "checkuser-investigate-duration-option-30d": "Az előző harminc nap", + "checkuser-investigate-reason-label": "Ok", + "checkuser-investigate-preliminary-table-cell-blocked": "Blokkolva", + "checkuser-investigate-preliminary-table-cell-unblocked": "Nincs blokkolva", + "checkuser-investigate-preliminary-table-header-blocked": "Állapot", + "checkuser-investigate-preliminary-table-header-editcount": "Szerkesztések", + "checkuser-investigate-preliminary-table-header-name": "Felhasználói név", + "checkuser-investigate-filters-legend": "Szűrők", + "checkuser-investigate-compare-table-header-username": "Felhasználói név", + "checkuser-investigate-compare-table-header-ip": "IP" } diff --git a/CheckUser/i18n/hyw.json b/CheckUser/i18n/hyw.json index e8c292a9..fa4cef72 100644 --- a/CheckUser/i18n/hyw.json +++ b/CheckUser/i18n/hyw.json @@ -1,8 +1,10 @@ { "@metadata": { "authors": [ + "Azniv Stepanian", "Շահէն" ] }, + "checkuser-investigate-preliminary-table-header-groups": "Խումբեր", "checkuser-investigate-compare-table-button-contribs-label": "Ներդրումներ" } diff --git a/CheckUser/i18n/ia.json b/CheckUser/i18n/ia.json index 4c9428ec..bddafe01 100644 --- a/CheckUser/i18n/ia.json +++ b/CheckUser/i18n/ia.json @@ -4,13 +4,13 @@ "McDutchie" ] }, - "checkuser-summary": "Iste instrumento analysa le modificationes recente pro recuperar le adresses IP usate per un usator o pro monstrar le datos de modificationes e de usatores pro un adresse IP.\nLe usatores e modificationes facite desde un adresse IP de cliente pote esser recuperate via capites XFF per appender \"/xff\" al IP.\nEs supportate le adresses IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128).\nNon plus de 5000 modificationes essera retornate pro non supercargar le systema.\nTote uso de iste instrumento debe esser conforme al politicas in vigor.", + "checkuser-summary": "Iste instrumento analysa le modificationes recente pro recuperar le adresses IP que un usator usa, o pro monstrar le datos de modificationes e de usatores pro un adresse IP.\nLe usatores e modificationes facite desde un adresse IP de cliente pote esser recuperate via capites XFF; adjunge \"/xff\" al adresse IP pro facer lo.\nEs supportate le adresses IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128).\nNon plus de $3 modificationes essera retornate pro evitar de supercargar le systema.\nTote uso de iste instrumento debe esser conforme al politicas in vigor.", "checkuser-desc": "Concede al usatores con le autorisation appropriate le capabilitate de verificar le adresses IP e altere informationes de usatores", - "checkuser-logcase": "Le recerca del registros distingue inter majusculas e minusculas.", "checkuser": "Verification de usator", "checkuserlog": "Registro de verification de usatores", "checkuser-contribs": "verification de adresses IP de usatores", "checkuser-contribs-log": "verificationes recente de usatores", + "checkuser-contribs-log-initiator": "verificationes de usatores facite per iste usator", "group-checkuser": "Verificatores de usatores", "group-checkuser-member": "{{GENDER:$1|verificator|verificatrice}} de usatores", "right-checkuser": "Verificar le adresses IP e altere informationes del usator", @@ -30,17 +30,23 @@ "checkuser-week-1": "ultime septimana", "checkuser-week-2": "ultime duo septimanas", "checkuser-month": "ultime 30 dies", + "checkuser-month-2": "ultime 60 dies", "checkuser-all": "totes", "checkuser-cidr-label": "Cercar le gamma commun e le adresses IP afficite pro un lista de adresses IP", "checkuser-cidr-res": "CIDR commun:", + "checkuser-cidr-affected-ips": "Adresses IP concernite:", + "checkuser-cidr-too-small": "Le gamma es troppo large", + "checkuser-range-outside-limit": "Le gamma $1 es foras del limites permittite.", "checkuser-empty": "Le registro non contine entratas.", "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-investigate-this-user": "Investigar 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-log-checks-by": "verificationes facite per", + "checkuser-log-checks-on": "verificationes de", "checkuser-blocked": "Blocate", "checkuser-gblocked": "Globalmente blocate", "checkuser-locked": "Serrate", @@ -52,23 +58,30 @@ "checkuser-blocktalk": "Impedir de modificar le proprie pagina de discussion durante le blocada", "checkuser-blocktag": "Reimplaciar paginas de usatores con:", "checkuser-blocktag-talk": "Reimplaciar le paginas de discussion per:", + "checkuser-reblock": "Reimplaciar le blocadas existente", "checkuser-massblock-commit": "Blocar usatores seligite", "checkuser-block-success": "'''Le {{PLURAL:$2|usator|usatores}} $1 es ora blocate.'''", "checkuser-block-failure": "'''Nulle usator blocate.'''", "checkuser-block-limit": "Troppo de usatores seligite.", "checkuser-block-noreason": "Tu debe indicar un motivo pro le blocadas.", "checkuser-centralauth-multilock": "Multi-blocar le contos seligite", + "checkuser-centralauth-multilock-list": "Multi-serra le contos seligite usante le ligamines:", + "checkuser-centralauth-multilock-list-item": "Ligamine $1", "checkuser-noreason": "Tu debe dar un motivo pro iste consulta.", - "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-too-many": "Troppo de resultatos (per estimation del consulta). Per favor, specifica un CIDR plus stricte.\nEcce le IPs usate (max. $1, ordinate per adresse):", "checkuser-user-nonexistent": "Le usator specificate non existe.", + "checkuser-target-nonexistent": "Le destination specificate non existe.", + "checkuser-initiator-nonexistent": "Le initiator specificate non existe.", "checkuser-search": "Cercar entratas de registro CheckUser", "checkuser-search-submit": "Cercar", "checkuser-search-initiator": "initiator", "checkuser-search-target": "objectivo", "checkuser-log-search-target": "Objectivo:", + "checkuser-log-search-initiator": "Initiator:", "checkuser-log-search-type": "Cercar per:", "checkuser-ipeditcount": "~$1 de tote le usatores", "checkuser-showmain": "Cambiar al formulario principal del verification de usatores", + "checkuser-show-investigate": "Passar al formulario principal de investigation", "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 <bdi>$2</bdi>", @@ -76,11 +89,101 @@ "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-log-entry-investigate": "$3, $1 cercava information sur $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-reset-action": "ha reinitialisate le contrasigno del usator $1", "checkuser-token-fail": "Session fallite. Per favor, essaya de novo.", "checkuser-login-failure": "Fallimento de aperir session in {{SITENAME}} como $1", - "checkuser-login-success": "Session aperite in {{SITENAME}} como $1" + "checkuser-login-failure-with-good-password": "Fallimento de aperir session a {{SITENAME}} como $1, benque le contrasigno es correcte", + "checkuser-login-success": "Session aperite in {{SITENAME}} como $1", + "checkuser-link-investigate-label": "Proba le nove instrumento de verification de usatores", + "checkuser-investigateblock": "Blocar usatores", + "checkuser-investigateblock-target": "Nomines de usator e adresses IP", + "checkuser-investigateblock-actions": "Actiones a blocar", + "checkuser-investigateblock-reason": "Motivo", + "checkuser-investigateblock-options": "Optiones additional", + "checkuser-investigateblock-email-label": "Impedir de inviar e-mail", + "checkuser-investigateblock-usertalk-label": "Impedir de modificar le proprie pagina de discussion durante le blocada", + "checkuser-investigateblock-reblock-label": "Reimplaciar le blocadas existente", + "checkuser-investigateblock-notice-user-page-label": "Lassar un nota sur le pagina de usator", + "checkuser-investigateblock-notice-talk-page-label": "Lassar un nota sur le pagina de discussion de usator", + "checkuser-investigateblock-notice-position-label": "Position", + "checkuser-investigateblock-notice-text-label": "Wikitexto", + "checkuser-investigateblock-notice-append": "Adjunger al pagina", + "checkuser-investigateblock-notice-prepend": "Prefixar al pagina", + "checkuser-investigateblock-notice-replace": "Reimplaciar pagina", + "checkuser-investigateblock-failure": "Nulle usator ha essite blocate. Pro reimplaciar le blocadas existente, marca: \"{{int:checkuser-investigateblock-reblock-label}}\". Un blocada non essera reimplaciate si le nove blocada es identic al blocada existente.", + "checkuser-investigateblock-success": "Le {{PLURAL:$2|usator|usatores}} $1 es ora blocate.", + "checkuser-investigateblock-notices-failed": "Alcun notas non poteva esser addite al paginas de usator o de discussion usator.", + "checkuser-investigate": "Investigar", + "checkuser-investigate-page-subtitle": "Investigation actual pro $1", + "checkuser-investigate-subtitle-block-button-label": "Blocar", + "checkuser-investigate-subtitle-cancel-button-label": "Cancellar", + "checkuser-investigate-subtitle-continue-button-label": "Continuar", + "checkuser-investigate-subtitle-show-checkuser": "Passar a CheckUser", + "checkuser-investigate-indicator-new-investigation": "Nove investigation", + "checkuser-investigate-indicator-logs": "Registros", + "checkuser-investigate-legend": "Cercar nomines de usator, adresses IP o gammas IP", + "checkuser-investigate-notice-no-results": "Il non ha resultatos.", + "checkuser-investigate-tab-preliminary-check": "Informationes del conto", + "checkuser-investigate-tab-compare": "Adresses IP e agentes usator", + "checkuser-investigate-tab-timeline": "Chronologia", + "checkuser-investigate-targets-label": "Nomines de usator e adresses IP:", + "checkuser-investigate-targets-placeholder": "NomineDeUsator o 1.1.1.1", + "checkuser-investigate-duration-label": "Durata", + "checkuser-investigate-duration-option-all": "Totes", + "checkuser-investigate-duration-option-1w": "Ultime septimana", + "checkuser-investigate-duration-option-2w": "Ultime 2 septimanas", + "checkuser-investigate-duration-option-30d": "Ultime 30 dies", + "checkuser-investigate-reason-label": "Motivo", + "checkuser-investigate-preliminary-notice-ip-targets": "Le scheda de information de conto non include information sur adresses IP. Vide le <span class=\"plainlinks\">[$1 scheda IPs & Agentes usator]</span> pro ille detalios.", + "checkuser-investigate-preliminary-table-cell-blocked": "Blocate", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|modification|modificationes}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Non blocate", + "checkuser-investigate-preliminary-table-header-blocked": "Stato", + "checkuser-investigate-preliminary-table-header-editcount": "Modificationes", + "checkuser-investigate-preliminary-table-header-groups": "Gruppos", + "checkuser-investigate-preliminary-table-header-name": "Nomine de usator", + "checkuser-investigate-preliminary-table-header-registration": "Data de ligation", + "checkuser-investigate-preliminary-table-header-wiki": "Wiki", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki non trovate", + "checkuser-investigate-filters-legend": "Filtros", + "checkuser-investigate-filters-exclude-targets-label": "Celar le sequente usatores o adresses IP", + "checkuser-investigate-timeline-notice-no-results": "Il non ha resultatos: il non ha activitate registrate de iste usatores o adresses IP in le ultime 90 dies.", + "checkuser-investigate-timeline-notice-no-results-filters": "Il non ha resultatos que corresponde a iste criterios de filtration. Tenta remover alcun filtros pro allargar le recerca.", + "checkuser-investigate-compare-copy-button-label": "Monstrar wikitexto", + "checkuser-investigate-compare-copy-button-label-hide": "Celar wikitexto", + "checkuser-investigate-compare-toollinks-ipcheck": "Verification de proxy", + "checkuser-investigate-compare-copy-message-label": "Vole tu copiar iste information in forma de tabella wikitexto?", + "checkuser-investigate-compare-notice-exceeded-limit": "A causa de limitationes technic nos ha attingite le numero maxime de entratas que pote esser monstrate. Le datos restituite pro le sequente objectivos es incomplete: $1. Per favor tenta usar minus objectivos, reducer le fenestra de tempore, o restringer le gamma de adresses IP.", + "checkuser-investigate-compare-notice-no-results": "Nulle resultato: iste usatores o adresses IP non ha facite alcun modificationes in le ultime 90 dies.", + "checkuser-investigate-compare-notice-no-results-filters": "Il non ha resultatos que corresponde a iste criterios de filtration. Tenta remover alcun filtros pro allargar le recerca.", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Monstrar tote le adresses IP de iste usator", + "checkuser-investigate-compare-table-button-add-user-targets-label": "Monstrar tote le usatores sur iste adresse IP", + "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Adder iste adresse IP al investigation", + "checkuser-investigate-compare-table-button-checks-label": "Verificationes", + "checkuser-investigate-compare-table-button-contribs-label": "Contributiones", + "checkuser-investigate-compare-table-button-filter-label": "Filtrar del resultatos", + "checkuser-investigate-compare-table-cell-unregistered": "Non registrate", + "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|modification/action|modificationes/actiones}}]</b>", + "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 de tote le usatores)</i>", + "checkuser-investigate-compare-table-header-username": "Nomine de usator", + "checkuser-investigate-compare-table-header-activity": "Intervallo de datas", + "checkuser-investigate-compare-table-header-ip": "IP", + "checkuser-investigate-compare-table-header-useragent": "Agente usator", + "checkuser-investigate-subtitle-link-restart-tour": "Recomenciar le visita guidate", + "checkuser-investigate-tour-targets-title": "Verificar plure usatores e adresses IP?", + "checkuser-investigate-tour-targets-desc": "Adde usque a $1 nomine{{PLURAL:$1||s}} de usator o adresse{{PLURAL:$1||s}} IP e obtene tote le informationes in un sol loco. Non te inquieta, nos va crear un registro CheckUser separate pro cata un de illos.", + "checkuser-investigate-tour-useragents-title": "Agentes usator correspondente?", + "checkuser-investigate-tour-useragents-desc": "Passa supra un cellula pro emphasar tote le lineas que ha le mesme datos. Clicca sur le icone de spinula pro mantener iste emphase durante que tu percurre le datos.", + "checkuser-investigate-tour-addusertargets-title": "Require plus contexto?", + "checkuser-investigate-tour-addusertargets-desc": "Clicca pro vider tote le altere usatores sur le adresse IP. Tu pote tamben facer isto pro usatores e examinar tote le adresses IP que illes usa. Nos te creara automaticamente un entrata de registro CheckUser.", + "checkuser-investigate-tour-filterip-title": "Restringer tu investigation?", + "checkuser-investigate-tour-filterip-desc": "Elimina le disordine filtrante nomines de usator, adresses IP o agentes usator. Vole restaurar le datos? Usa le pannello Filtros in alto pro remover le filtros.", + "checkuser-investigate-tour-block-title": "Vole blocar?", + "checkuser-investigate-tour-block-desc": "Permitte seliger le usatores que tu vole blocar e pois te porta al formulario de blocada pro eliger le blocada appropriate.", + "checkuser-investigate-tour-copywikitext-title": "Vole copiar le datos?", + "checkuser-investigate-tour-copywikitext-desc": "Copia le tabella de comparation con un sol clic e porta lo a CUWiki. Nota ben que tu copia solmente lo que es visibile e non tote le paginas del investigation." } diff --git a/CheckUser/i18n/id.json b/CheckUser/i18n/id.json index 3e775e84..5b280ed2 100644 --- a/CheckUser/i18n/id.json +++ b/CheckUser/i18n/id.json @@ -5,7 +5,10 @@ "Arief", "Bennylin", "Borgx", + "DARMAS BUDI SANTOSO", + "Daud I.F. Argana", "Farras", + "Hidayatsrf", "Irwangatot", "IvanLanin", "Iwan Novirion", @@ -19,40 +22,43 @@ }, "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.", "checkuser-desc": "Memberikan fasilitas bagi pengguna yang memiliki hak akses untuk memeriksa alamat IP dan informasi lain dari pengguna", - "checkuser-logcase": "Log ini bersifat sensitif terhadap kapitalisasi.", "checkuser": "Pemeriksaan pengguna", "checkuserlog": "Catatan pemeriksaan pengguna", - "checkuser-contribs": "memeriksa IP pengguna", + "checkuser-contribs": "periksa IP pengguna", "checkuser-contribs-log": "pemeriksaan pengguna terbaru", "group-checkuser": "Pemeriksa", "group-checkuser-member": "{{GENDER:$1|pemeriksa}}", - "right-checkuser": "Memeriksa alamat IP pengguna dan informasi lainnya", - "right-checkuser-log": "Melihat log pemeriksa", - "action-checkuser": "memeriksa alamat IP pengguna dan informasi lainnya", + "right-checkuser": "Periksa alamat IP pengguna dan informasi lainnya", + "right-checkuser-log": "Lihat log pemeriksa", + "action-checkuser": "periksa alamat IP pengguna dan informasi lainnya", "action-checkuser-log": "lihat log pemeriksa", "grouppage-checkuser": "{{ns:project}}:Pemeriksa", "checkuser-reason": "Alasan:", "checkuser-reason-api": "API: $1", - "checkuser-showlog": "beralih ke Log Pemeriksaan Pengguna", + "checkuser-showlog": "Beralih ke Log Pemeriksa", "checkuser-query": "Kueri perubahan terbaru", "checkuser-target": "Alamat IP atau nama pengguna:", "checkuser-users": "Cari pengguna", "checkuser-edits": "Cari suntingan", "checkuser-ips": "Cari IP", "checkuser-period": "Jangka waktu:", - "checkuser-week-1": "minggu lalu", - "checkuser-week-2": "dua minggu terakhir", + "checkuser-week-1": "pekan lalu", + "checkuser-week-2": "dua pekanterakhir", "checkuser-month": "30 hari terakhir", + "checkuser-month-2": "60 hari terakhir", "checkuser-all": "semua", "checkuser-cidr-label": "Mencari jangkauan umum dan alamat yang dipengaruhi dari sebuah daftar IP", "checkuser-cidr-res": "CIDR umum:", + "checkuser-range-outside-limit": "The range $1 is outside the allowed limits.", "checkuser-empty": "Log kosong.", "checkuser-nomatch": "Tidak ditemukan data yang cocok.", "checkuser-nomatch-edits": "Tidak ditemukan hasil sesuai kriteria yang diberikan.\nSuntingan terakhir dilakukan pada $1 $2.", "checkuser-check": "Periksa", + "checkuser-check-this-user": "Periksa pengguna ini", + "checkuser-investigate-this-user": "Selidiki pengguna ini", + "checkuser-recent-checks": "Pemeriksaan terbaru kepada pengguna ini", "checkuser-log-fail": "Entri log tidak dapat ditambahkan", - "checkuser-nolog": "Berkas log tidak ditemukan.", - "checkuser-blocked": "Diblok", + "checkuser-blocked": "Diblokir", "checkuser-gblocked": "Diblokir secara global", "checkuser-locked": "Terkunci", "checkuser-wasblocked": "Telah diblokir sebelumnya", @@ -63,6 +69,7 @@ "checkuser-blocktalk": "Cegah pengguna ini untuk menyunting halaman pembicaraannya saat diblokir", "checkuser-blocktag": "Ganti halaman pengguna dengan:", "checkuser-blocktag-talk": "Ganti halaman pembicaraan dengan:", + "checkuser-reblock": "Timpa pemblokiran yang ada", "checkuser-massblock-commit": "Blokir pengguna yang dipilih", "checkuser-block-success": "'''{{PLURAL:$2|Pengguna|Pengguna}} $1 berhasil diblokir.'''", "checkuser-block-failure": "'''Tidak ada pengguna yang diblokir.'''", @@ -70,16 +77,17 @@ "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-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-too-many": "Terlalu banyak hasil (menurut perkiraan kueri), mohon persempit CIDR.\nBerikut adalah alamat IP yang digunakan (maks $1, diurutkan berdasarkan alamat):", "checkuser-user-nonexistent": "Pengguna yang dimaksud tidak ditemukan", "checkuser-search": "Cari entri log pengguna", "checkuser-search-submit": "Cari", "checkuser-search-initiator": "pemeriksa", "checkuser-search-target": "target", "checkuser-log-search-target": "Target", - "checkuser-log-search-type": "Bar pencarian", - "checkuser-ipeditcount": "~$1 dari seluruh pengguna", + "checkuser-log-search-type": "Cari menurut:", + "checkuser-ipeditcount": "~$1 dari semua pengguna", "checkuser-showmain": "Beralih ke bentuk utama Pemeriksa", + "checkuser-show-investigate": "Beralih ke formulir utama investigasi", "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 <bdi>$2</bdi>", @@ -87,11 +95,102 @@ "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-log-entry-investigate": "$3, $1 memeriksa informasi 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-reset-action": "Reset kata sandi pengguna \"$1\"", "checkuser-token-fail": "Kegagalan sesi. Silakan coba kembali.", + "checkuser-login-failure": "Gagal masuk ke {{SITENAME}} sebagai $1", + "checkuser-login-success": "Berhasil masuk ke {{SITENAME}} sebagai $1", + "group-checkuser.css": "/* CSS yang ditempatkan di sini hanya akan mempengaruhi checkuser */", + "group-checkuser.js": "/* JS yang ditempatkan di sini hanya akan mempengaruhi checkuser */", + "checkuser-link-investigate-label": "Coba alat Pemeriksa baru", + "checkuser-investigateblock": "Blokir pengguna", + "checkuser-investigateblock-target": "Nama pengguna dan alamat IP", + "checkuser-investigateblock-actions": "Tindakan untuk memblokir", + "checkuser-investigateblock-reason": "Alasan", + "checkuser-investigateblock-options": "Opsi tambahan", + "checkuser-investigateblock-email-label": "Cegah pengguna mengirimkan surel", + "checkuser-investigateblock-usertalk-label": "Cegah pengguna ini untuk menyunting halaman pembicaraannya saat diblokir", + "checkuser-investigateblock-reblock-label": "Timpa pemblokiran yang ada", + "checkuser-investigateblock-notice-user-page-label": "Tinggalkan pemberitahuan di halaman Pengguna", + "checkuser-investigateblock-notice-talk-page-label": "Tinggalkan pemberitahuan di halaman Pembicaraan Pengguna", + "checkuser-investigateblock-notice-position-label": "Posisi", + "checkuser-investigateblock-notice-text-label": "Teks wiki", + "checkuser-investigateblock-notice-append": "Sisipkan ke akhir halaman", + "checkuser-investigateblock-notice-prepend": "Sisipkan ke awal halaman", + "checkuser-investigateblock-notice-replace": "Ganti halaman", + "checkuser-investigateblock-failure": "Tidak ada pengguna yang diblokir. Untuk mengganti pemblokiran yang ada, periksa: \"{{int:checkuser-investigateblock-reblock-label}}\". Sebuah pemblokiran tidak akan ditimpa jika pemblokiran baru identik dengan pemblokiran yang ada.", + "checkuser-investigateblock-success": "{{PLURAL:$2|Pengguna}} $1 {{PLURAL:$2|sekarang}} diblokir.", + "checkuser-investigateblock-notices-failed": "Beberapa pemberitahuan tidak dapat ditambahkan ke halaman pengguna atau halaman pembicaraan pengguna.", + "checkuser-investigate": "Investigasi", + "checkuser-investigate-page-subtitle": "Investigasi terkini untuk $1", + "checkuser-investigate-subtitle-block-button-label": "Blokir", + "checkuser-investigate-subtitle-cancel-button-label": "Batalkan", + "checkuser-investigate-subtitle-continue-button-label": "Lanjutkan", + "checkuser-investigate-subtitle-show-checkuser": "Beralih ke Pemeriksaan Pengguna", + "checkuser-investigate-indicator-new-investigation": "Investigasi baru", + "checkuser-investigate-indicator-logs": "Log", + "checkuser-investigate-legend": "Cari nama pengguna, alamat IP, atau rentang IP", + "checkuser-investigate-notice-no-results": "Tidak ada hasil.", "checkuser-investigate-tab-preliminary-check": "Informasi akun", - "checkuser-investigate-subtitle-link-restart-tour": "Mulai Ulang Tur" + "checkuser-investigate-tab-compare": "IP & Agen pengguna", + "checkuser-investigate-tab-timeline": "Linimasa", + "checkuser-investigate-targets-label": "Nama pengguna dan alamat IP:", + "checkuser-investigate-targets-placeholder": "NamaPengguna atau 1.1.1.1", + "checkuser-investigate-duration-label": "Durasi", + "checkuser-investigate-duration-option-all": "Semua", + "checkuser-investigate-duration-option-1w": "Pekan lalu", + "checkuser-investigate-duration-option-2w": "2 Pekan lalu", + "checkuser-investigate-duration-option-30d": "30 hari terakhir", + "checkuser-investigate-reason-label": "Alasan", + "checkuser-investigate-preliminary-notice-ip-targets": "Tab Informasi akun tidak menyertakan informasi apa pun tentang IP. Lihat <span class=\"plainlinks\">[tab IP & Agen pengguna $1]</span> untuk detail tersebut.", + "checkuser-investigate-preliminary-table-cell-blocked": "Diblokir", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|suntingan}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Tidak diblokir", + "checkuser-investigate-preliminary-table-header-blocked": "Status", + "checkuser-investigate-preliminary-table-header-editcount": "Suntingan", + "checkuser-investigate-preliminary-table-header-groups": "Kelompok", + "checkuser-investigate-preliminary-table-header-name": "Nama pengguna", + "checkuser-investigate-preliminary-table-header-registration": "Tanggal terlampir", + "checkuser-investigate-preliminary-table-header-wiki": "Wiki", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki tak ditemukan", + "checkuser-investigate-filters-legend": "Penyaring", + "checkuser-investigate-filters-exclude-targets-label": "Sembunyikan pengguna atau IP berikut", + "checkuser-investigate-timeline-notice-no-results": "Tidak ada hasil: tidak ada aktivitas yang tercatat dari pengguna atau IP ini dalam 90 hari terakhir", + "checkuser-investigate-timeline-notice-no-results-filters": "Tidak ada hasil yang cocok dengan kriteria pemfilteran ini. Coba hapus beberapa filter untuk memperluas pencarian.", + "checkuser-investigate-compare-copy-button-label": "Tampilkan tekswiki", + "checkuser-investigate-compare-toollinks-whois": "WHOIS", + "checkuser-investigate-compare-toollinks-ipcheck": "Periksa proksi", + "checkuser-investigate-compare-copy-message-label": "Apakah Anda ingin menyalin informasi ini sebagai tabel teks Wiki?", + "checkuser-investigate-compare-notice-exceeded-limit": "Karena keterbatasan teknis kami telah mencapai jumlah catatan yang dapat disajikan. Data yang dihasilkan untuk target berikut tidak lengkap: $1. Coba gunakan target yang lebih sedikit, jangka waktu yang lebih kecil, atau rentang IP yang lebih sempit.", + "checkuser-investigate-compare-notice-no-results": "Tidak ada hasil: tidak ada suntingan dari pengguna atau IP ini dalam 90 hari terakhir", + "checkuser-investigate-compare-notice-no-results-filters": "Tidak ada hasil yang cocok dengan kriteria peyaringan ini. Coba hapus beberapa penyaring untuk memperluas pencarian.", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Tampilkan semua IP pengguna ini", + "checkuser-investigate-compare-table-button-add-user-targets-label": "Tampilkan semua pengguna di IP ini", + "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Tambahkan IP ini ke investigasi", + "checkuser-investigate-compare-table-button-checks-label": "Periksa", + "checkuser-investigate-compare-table-button-contribs-label": "Kontribusi", + "checkuser-investigate-compare-table-button-filter-label": "Filter dari hasil", + "checkuser-investigate-compare-table-cell-unregistered": "Tidak terdaftar", + "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|suntingan}}]</b>", + "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 dari semua pengguna)</i>", + "checkuser-investigate-compare-table-header-username": "Nama pengguna", + "checkuser-investigate-compare-table-header-activity": "Rentang tanggal", + "checkuser-investigate-compare-table-header-ip": "IP", + "checkuser-investigate-compare-table-header-useragent": "Agen pengguna", + "checkuser-investigate-subtitle-link-restart-tour": "Mulai Ulang Tur", + "checkuser-investigate-tour-targets-title": "Periksa beberapa pengguna dan IP sekaligus?", + "checkuser-investigate-tour-targets-desc": "Tambahkan hingga $1 {{PLURAL:$1|Nama pengguna atau IP}} dan dapatkan semua informasi di satu tempat. Jangan khawatir, kami akan membuat log Pemeriksa terpisah untuk tiap akun atau IP.", + "checkuser-investigate-tour-useragents-title": "Cocokkan Agen Pengguna?", + "checkuser-investigate-tour-useragents-desc": "Arahkan kursor ke sel untuk menyorot semua baris lain yang memiliki data yang sama. Klik ikon pin agar sorotan tetap menyala saat Anda menelusuri data.", + "checkuser-investigate-tour-addusertargets-title": "Perlu lebih banyak konteks?", + "checkuser-investigate-tour-addusertargets-desc": "Klik untuk melihat semua pengguna lain di IP. Anda juga dapat melakukan ini untuk Pengguna, dan melihat semua IP yang telah mereka gunakan. Kami akan secara otomatis membuat item log Pemeriksa untuk Anda.", + "checkuser-investigate-tour-filterip-title": "Mempersempit investigasi Anda?", + "checkuser-investigate-tour-filterip-desc": "Hapus kekacauan dengan memfilter nama pengguna, IP, atau agen pengguna. Ingin kembali melihat data awal? Gunakan panel penyaring di atas untuk menghapus penyaring.", + "checkuser-investigate-tour-block-title": "Ingin memblokir?", + "checkuser-investigate-tour-block-desc": "Memungkinkan Anda memilih pengguna yang ingin Anda blokir dan kemudian membawa Anda ke formulir pemblokiran untuk memilih jenis pemblokiran yang sesuai.", + "checkuser-investigate-tour-copywikitext-title": "Ingin menyalin data?", + "checkuser-investigate-tour-copywikitext-desc": "Salin tabel perbandingan dengan sekali klik dan bawa ke CUWiki. Perhatikan bahwa Anda hanya menyalin apa yang terlihat dan tidak semua halaman investigasi." } diff --git a/CheckUser/i18n/ie.json b/CheckUser/i18n/ie.json index c388cc82..6cb1d87b 100644 --- a/CheckUser/i18n/ie.json +++ b/CheckUser/i18n/ie.json @@ -1,8 +1,151 @@ { "@metadata": { "authors": [ - "OIS" + "OIS", + "Renan" ] }, - "checkuser-investigate-tab-compare": "Comparar" + "checkuser": "Verification de usatores", + "checkuserlog": "Diarium de verification de usatores", + "checkuser-contribs": "verificar adresses de IP de usator", + "checkuser-contribs-log": "verificationes de usatores recent", + "group-checkuser": "Verificatores de usatores", + "group-checkuser-member": "{{GENDER:$1|verificator de usator}}", + "right-checkuser": "Verificar adresses de IP de usatores e altri informationes", + "right-checkuser-log": "Vider li diarium de verification de usatores", + "action-checkuser": "verificar adresses de IP de usatores e altri informationes", + "action-checkuser-log": "vider li diarium de verification de usatores", + "grouppage-checkuser": "{{ns:project}}:Verificator de usator", + "checkuser-reason": "Rason:", + "checkuser-reason-api": "API: $1", + "checkuser-query": "Consultar nov changes", + "checkuser-target": "Adresse de IP o nómine de usator:", + "checkuser-users": "Obtener usatores", + "checkuser-edits": "Obtener redactiones", + "checkuser-ips": "Obtener adresses de IP", + "checkuser-period": "Duration:", + "checkuser-week-1": "ultim semane", + "checkuser-week-2": "ultim du semanes", + "checkuser-month": "ultim 30 dies", + "checkuser-all": "omni", + "checkuser-cidr-res": "CIDR comun:", + "checkuser-empty": "Li diarium ne contene partes.", + "checkuser-nomatch": "Nequant resultates constatat.", + "checkuser-nomatch-edits": "Nequant resultates constatat.\nUltim redaction esset in $1 ye $2.", + "checkuser-check": "Verificar", + "checkuser-check-this-user": "Verificar ti usator", + "checkuser-investigate-this-user": "Investigar ti usator", + "checkuser-recent-checks": "Recent verificationes por ti usator", + "checkuser-blocked": "Blocat", + "checkuser-gblocked": "Blocat globalmen", + "checkuser-wasblocked": "Blocat anteriorimen", + "checkuser-massblock": "Blocar usatores selectet", + "checkuser-blockemail": "Impedir de inviar missage electronic", + "checkuser-blocktalk": "Impedir de redacter lor propri págine de discussion durante que blocat", + "checkuser-blocktag": "Substituer págines de usator che:", + "checkuser-blocktag-talk": "Substituer págines de discussion che:", + "checkuser-reblock": "Substituer blocadas existent", + "checkuser-massblock-commit": "Blocar usatores selectet", + "checkuser-block-success": "'''Li {{PLURAL:$2|usator|usatores}} $1 es nu blocat.'''", + "checkuser-block-failure": "'''Nequant usatores blocat.'''", + "checkuser-block-limit": "Mult usatores selectet.", + "checkuser-block-noreason": "Vu deve dar un rason por li blocadas.", + "checkuser-noreason": "Vu deve dar un rason por ti consultation.", + "checkuser-user-nonexistent": "Li usator specificat ne existe.", + "checkuser-search": "Serchar intradas in diarium de verification de usatores", + "checkuser-search-submit": "Serchar", + "checkuser-search-initiator": "initiator", + "checkuser-search-target": "cible", + "checkuser-log-search-target": "Cible:", + "checkuser-log-search-type": "Sercha per:", + "checkuser-ipeditcount": "~$1 de omni usatores", + "checkuser-showmain": "Comutar por formul principal de Verification de usatores", + "checkuser-show-investigate": "Comutar por formul principal de Investigar", + "checkuser-log-entry-userips": "$3, $1 obtenet adresses de IP por $2", + "checkuser-log-entry-ipedits": "$3, $1 obtenet redactiones por <bdi>$2</bdi>", + "checkuser-log-entry-ipusers": "$3, $1 obtenet usatores por <bdi>$2</bdi>", + "checkuser-log-entry-ipedits-xff": "$3, $1 obtenet redactiones por XFF <bdi>$2</bdi>", + "checkuser-log-entry-ipusers-xff": "$3, $1 obtenet usatores por XFF <bdi>$2</bdi>", + "checkuser-log-entry-useredits": "$3, $1 obtenet redactiones por $2", + "checkuser-log-entry-investigate": "$3, $1 procurat information por $2", + "checkuser-autocreate-action": "esset automaticmen creat", + "checkuser-create-action": "esset creat", + "checkuser-email-action": "inviat un missage electronic a usator \"$1\"", + "checkuser-reset-action": "redefinir parol-passe por usator \"$1\"", + "checkuser-token-fail": "Defecte in session. Pleser provar denov.", + "checkuser-link-investigate-label": "Prova li nov utensile Verification de usatores", + "checkuser-investigateblock": "Blocar usatores", + "checkuser-investigateblock-target": "Nómines de usatores e adresses de IP", + "checkuser-investigateblock-actions": "Actiones por blocar", + "checkuser-investigateblock-reason": "Rason", + "checkuser-investigateblock-options": "Optiones additional", + "checkuser-investigateblock-email-label": "Impedir de inviar missage electronic", + "checkuser-investigateblock-usertalk-label": "Impedir de redacter lor propri págine de discussion durante que blocat", + "checkuser-investigateblock-reblock-label": "Substituer blocadas existent", + "checkuser-investigateblock-notice-user-page-label": "Inviar un notification in págine de usator", + "checkuser-investigateblock-notice-talk-page-label": "Inviar un notification in págine de discussion del usator", + "checkuser-investigateblock-notice-position-label": "Position", + "checkuser-investigateblock-notice-text-label": "Textu wiki", + "checkuser-investigateblock-notice-append": "Anexer al págine", + "checkuser-investigateblock-notice-prepend": "Prefixar al págine", + "checkuser-investigateblock-notice-replace": "Substituer págine", + "checkuser-investigateblock-success": "Li {{PLURAL:$2|usator|usatores}} $1 es nu blocat.", + "checkuser-investigateblock-notices-failed": "Alcun notificationes ne posset esser addit a págines de usatores o págines de discussion de usatores.", + "checkuser-investigate": "Investigar", + "checkuser-investigate-page-subtitle": "Actual investigation por $1", + "checkuser-investigate-subtitle-block-button-label": "Blocar", + "checkuser-investigate-subtitle-cancel-button-label": "Anullar", + "checkuser-investigate-subtitle-continue-button-label": "Continuar", + "checkuser-investigate-subtitle-show-checkuser": "Comutar por Verification de usator", + "checkuser-investigate-indicator-new-investigation": "Nov investigation", + "checkuser-investigate-indicator-logs": "Diariumes", + "checkuser-investigate-legend": "Serchar por nómines de usatores, adresses de IP o ranges de IP", + "checkuser-investigate-notice-no-results": "Hay nequant resultates.", + "checkuser-investigate-tab-preliminary-check": "Information de conto", + "checkuser-investigate-tab-compare": "IPs & Agentes de usator", + "checkuser-investigate-tab-timeline": "Linea cronologic", + "checkuser-investigate-targets-label": "Nómines de usatores e adresses de IP", + "checkuser-investigate-targets-placeholder": "Nómine de usator o 1.1.1.1", + "checkuser-investigate-duration-label": "Duration", + "checkuser-investigate-duration-option-all": "Omni", + "checkuser-investigate-duration-option-1w": "Ultim semane", + "checkuser-investigate-duration-option-2w": "Ultim 2 semanes", + "checkuser-investigate-duration-option-30d": "Ultim 30 dies", + "checkuser-investigate-reason-label": "Rason", + "checkuser-investigate-preliminary-notice-ip-targets": "Li bord Information de conto ne include qualcunc information in IPs. Vider li <span class=\"plainlinks\">[$1 bord IPs & Agentes de usator]</span> por tis detallies.", + "checkuser-investigate-preliminary-table-cell-blocked": "Blocat", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|redaction|redactiones}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Non-blocat", + "checkuser-investigate-preliminary-table-header-blocked": "Statu", + "checkuser-investigate-preliminary-table-header-editcount": "Redactiones", + "checkuser-investigate-preliminary-table-header-groups": "Gruppes", + "checkuser-investigate-preliminary-table-header-name": "Nómine de usator", + "checkuser-investigate-preliminary-table-header-registration": "Date fixat", + "checkuser-investigate-preliminary-table-header-wiki": "Wiki", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki ne constatat", + "checkuser-investigate-filters-legend": "Filtres", + "checkuser-investigate-filters-exclude-targets-label": "Ocultar li sequent usatores o IPs", + "checkuser-investigate-compare-copy-button-label": "Monstrar textu wiki", + "checkuser-investigate-compare-toollinks-whois": "WHOIS", + "checkuser-investigate-compare-toollinks-ipcheck": "Verificar surogate", + "checkuser-investigate-compare-copy-message-label": "Vu vell desirar copiar ti information quam un tabelle textu wiki?", + "checkuser-investigate-compare-notice-no-results": "Hay nequant resultates: ta have esset nequant redactiones de tis usatores o IPs in li ultim 90 dies", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Monstrar omni IPs de ti-ci usator", + "checkuser-investigate-compare-table-button-add-user-targets-label": "Monstrar omni usatores in ti-ci IP", + "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Addir ti IP por investigation", + "checkuser-investigate-compare-table-button-checks-label": "Verificationes", + "checkuser-investigate-compare-table-button-contribs-label": "Contributiones", + "checkuser-investigate-compare-table-button-filter-label": "Filtar del resultates", + "checkuser-investigate-compare-table-cell-unregistered": "Non-registrat", + "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|redaction|redactiones}}]</b>", + "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 de omni usatores)</i>", + "checkuser-investigate-compare-table-header-username": "Nómine de usator", + "checkuser-investigate-compare-table-header-activity": "Range de date", + "checkuser-investigate-compare-table-header-ip": "IP", + "checkuser-investigate-compare-table-header-useragent": "Agente de usator", + "checkuser-investigate-subtitle-link-restart-tour": "Recomensar tur", + "checkuser-investigate-tour-targets-title": "Verificar multiplica usatores e IPs?", + "checkuser-investigate-tour-filterip-title": "Restricter tui investigation?", + "checkuser-investigate-tour-block-title": "Vu desira blocar?", + "checkuser-investigate-tour-copywikitext-title": "Vu desira copiar li data?" } diff --git a/CheckUser/i18n/ig.json b/CheckUser/i18n/ig.json index b00d1367..976c84cf 100644 --- a/CheckUser/i18n/ig.json +++ b/CheckUser/i18n/ig.json @@ -1,6 +1,8 @@ { "@metadata": { "authors": [ + "Okenwa", + "Timzy D'Great", "Ukabia" ] }, @@ -10,7 +12,7 @@ "checkuser-reason": "Mgbághapụtà:", "checkuser-showlog": "Zí ndétu nchétá", "checkuser-users": "Nàta òjìème", - "checkuser-edits": "Gá nwèté orü shí IP", + "checkuser-edits": "Nweta ndezi", "checkuser-ips": "Gá nwèté ónúọgụgụ IP", "checkuser-period": "Ógè ȯ wèrè:", "checkuser-week-1": "izù nke gáráni", @@ -19,6 +21,7 @@ "checkuser-check": "Lechányá", "checkuser-blocked": "Kwàchịrị", "checkuser-locked": "Gbàchịrị", + "checkuser-centralauth-multilock-list-item": "Njikọ $1", "checkuser-search": "Chọwa", "checkuser-search-submit": "Tùwe", "checkuser-search-initiator": "onyé bịdòrò", diff --git a/CheckUser/i18n/ilo.json b/CheckUser/i18n/ilo.json index c5f21bb6..1d495007 100644 --- a/CheckUser/i18n/ilo.json +++ b/CheckUser/i18n/ilo.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "Daytoy a ramit ket agiskan kadagiti kaudian a balbaliw tapno agala kadagiti adres ti IP nga inus-usar ti agar-aramat wenno agiparang ti inurnos/datos ti agar-aramat para iti maysa nga adres ti IP.\nDagiti agar-aramat ken dagiti inurnos babaen ti kliente ti adres ti IP ket maala babaen dagiti paulo ti XFF babaen ti panagala ti adres ti IP nga agraman iti \"/xff\". Nasuportaran ti IPv4 (CIDR $1-32) ken IPv6 (CIDR $2-128) .\n\nUsaren daytoy babaen ti annuroten.", "checkuser-desc": "Agited kadagiti agar-aramat ti maibagay a pammalubos ti abilidad nga agkita kadagiti adres ti IP ti agar-aramat ken sabsabali pay a pakaammo", - "checkuser-logcase": "Ti panagbiruk ti listaan ket sensitibo ti kadakkel ti letra.", "checkuser": "Kitaen ti agar-aramat", "checkuserlog": "Kitaen ti listaan ti agar-aramat", "checkuser-contribs": "kitaen ti adres ti IP ti agar-aramat", @@ -38,7 +37,6 @@ "checkuser-nomatch-edits": "Awan ti nabirukan a kapadpada.\nTi naudi a naurnos ket idi $1 iti oras a $2.", "checkuser-check": "Kitaen", "checkuser-log-fail": "Saan a makanayon idiay listaan", - "checkuser-nolog": "Awan ti listaan a papeles ti nabirukan.", "checkuser-blocked": "Naserraan", "checkuser-gblocked": "Sangalubongan a naserraan", "checkuser-locked": "Napengdan", diff --git a/CheckUser/i18n/inh.json b/CheckUser/i18n/inh.json index 0c5d27aa..9b500e7a 100644 --- a/CheckUser/i18n/inh.json +++ b/CheckUser/i18n/inh.json @@ -6,5 +6,5 @@ }, "group-checkuser": "Доакъашхой тохкараш", "checkuser-search": "Доакъашхочун тохкама тептара чу лахар", - "checkuser-search-submit": "Хьалáха" + "checkuser-search-submit": "Лаха" } diff --git a/CheckUser/i18n/io.json b/CheckUser/i18n/io.json index 623f7fb5..b82161c7 100644 --- a/CheckUser/i18n/io.json +++ b/CheckUser/i18n/io.json @@ -20,16 +20,19 @@ "checkuser-all": "omna", "checkuser-cidr-res": "Komuna CIDR:", "checkuser-blocked": "Blokusita", - "checkuser-gblocked": "Blokusita globale", + "checkuser-gblocked": "Blokusita en omna Wiki", "checkuser-wasblocked": "Antee blokusita", "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-search-target": "emo", + "checkuser-log-search-target": "Emo:", "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-cancel-button-label": "Nuligez", "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", diff --git a/CheckUser/i18n/is.json b/CheckUser/i18n/is.json index 9f21a35c..8f7edf67 100644 --- a/CheckUser/i18n/is.json +++ b/CheckUser/i18n/is.json @@ -27,7 +27,6 @@ "checkuser-all": "allt", "checkuser-nomatch": "Engin samsvörun fannst.", "checkuser-check": "Athuga", - "checkuser-nolog": "Engin skrá fundin.", "checkuser-blocked": "Bannaður", "checkuser-locked": "Læstur", "checkuser-search": "Leita", diff --git a/CheckUser/i18n/it.json b/CheckUser/i18n/it.json index f2e12767..aceed6b2 100644 --- a/CheckUser/i18n/it.json +++ b/CheckUser/i18n/it.json @@ -2,6 +2,7 @@ "@metadata": { "authors": [ ".anaconda", + "Ajeje Brazorf", "Ask21", "Aushulz", "Beta16", @@ -23,19 +24,19 @@ "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.", + "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 $3 modifiche, per ragioni di prestazioni. Usa questo strumento in stretta conformità alle policy.", "checkuser-desc": "Consente agli utenti con le opportune autorizzazioni di sottoporre a verifica gli indirizzi IP e altre informazioni relative agli utenti", - "checkuser-logcase": "La ricerca nei log è ''case sensitive'' (distingue fra maiuscole e minuscole).", "checkuser": "Controllo utenze", "checkuserlog": "Registro dei controlli utente", "checkuser-contribs": "controlla gli indirizzi IP dell'utente", "checkuser-contribs-log": "controlli utente recenti", + "checkuser-contribs-log-initiator": "controlli effettuati dall'utente", "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 registro dei checkuser", "action-checkuser": "controllare gli indirizzi IP dell'utente e altre informazioni", - "action-checkuser-log": "vedere il log dei checkuser", + "action-checkuser-log": "vedere il registro dei checkuser", "grouppage-checkuser": "{{ns:project}}:Check user", "checkuser-reason": "Motivo:", "checkuser-reason-api": "API: $1", @@ -49,6 +50,7 @@ "checkuser-week-1": "settimana scorsa", "checkuser-week-2": "ultime due settimane", "checkuser-month": "ultimi 30 giorni", + "checkuser-month-2": "ultimi 60 giorni", "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:", @@ -57,16 +59,18 @@ "checkuser-nomatch-edits": "Nessun risultato trovato.\nUltimo edit risalente alle $2 del $1.", "checkuser-check": "Controlla", "checkuser-check-this-user": "Controlla questo utente", + "checkuser-investigate-this-user": "Investiga su questo utente", "checkuser-recent-checks": "Controlli recenti per questo utente", - "checkuser-log-fail": "Impossibile aggiungere la voce al log", - "checkuser-nolog": "Non è stato trovato alcun file di log.", + "checkuser-log-fail": "Impossibile aggiungere la voce al registro", + "checkuser-log-checks-by": "controlli eseguiti", + "checkuser-log-checks-on": "controlli subiti", "checkuser-blocked": "Bloccato", "checkuser-gblocked": "Bloccato globalmente", "checkuser-locked": "Disabilitato", "checkuser-wasblocked": "Bloccato precedentemente", "checkuser-localonly": "Non unificato", "checkuser-massblock": "Blocca utenti selezionati", - "checkuser-massblock-text": "Gli utenti selezionati saranno bloccati infinito, con il blocco automatico attivato e la registrazione disattivata.\nGli indirizzi IP saranno bloccati per una settimana solo per gli utenti anonimi e con la registrazione disattivata.", + "checkuser-massblock-text": "Gli utenti selezionati saranno bloccati infinito con blocco automatico attivato e registrazione disattivata.\nGli indirizzi IP saranno bloccati per una settimana solo per gli utenti anonimi e con la registrazione disattivata.", "checkuser-blockemail": "Impedisci l'invio di email", "checkuser-blocktalk": "Impedisci di modificare la propria pagina di discussioni mentre è bloccato", "checkuser-blocktag": "Sostituisci pagine utente con:", @@ -78,6 +82,7 @@ "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-centralauth-multilock-list-item": "Collegamento $1", "checkuser-noreason": "È necessario fornire una motivazione per questa query.", "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.", @@ -86,9 +91,11 @@ "checkuser-search-initiator": "richiedente", "checkuser-search-target": "obiettivo", "checkuser-log-search-target": "Obiettivo:", + "checkuser-log-search-initiator": "Richiedente:", "checkuser-log-search-type": "Ricerca per:", "checkuser-ipeditcount": "~$1 da tutti gli utenti", "checkuser-showmain": "Passa al modulo principale CheckUser", + "checkuser-show-investigate": "Passa al modulo principale Investiga", "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 <bdi>$2</bdi>", @@ -96,10 +103,11 @@ "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-log-entry-investigate": "$3, $1 ha ottenuto informazioni su $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-reset-action": "reimposta password per l'utente $1", "checkuser-token-fail": "Errore di sessione. Riprova ancora.", "checkuser-login-failure": "Errore nell'effettuare l'accesso su {{SITENAME}} come $1", "checkuser-login-success": "Accesso effettuato su {{SITENAME}} come $1", @@ -122,15 +130,12 @@ "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-subtitle-show-checkuser": "Passa al modulo CheckUser", "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", @@ -138,7 +143,7 @@ "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-label": "Nomi utente e indirizzi IP:", "checkuser-investigate-targets-placeholder": "Nome utente o 1.1.1.1", "checkuser-investigate-duration-label": "Durata", "checkuser-investigate-duration-option-all": "Tutto", @@ -162,7 +167,8 @@ "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-copy-button-label-hide": "Nascondi wikitesto", + "checkuser-investigate-compare-toollinks-whois": "WHOIS", "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.", @@ -175,7 +181,7 @@ "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-edits": "<b>[$1 {{PLURAL:$1|modifica/azione|modifiche/azioni}}]</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", diff --git a/CheckUser/i18n/ja.json b/CheckUser/i18n/ja.json index fe8b0289..861ec3e4 100644 --- a/CheckUser/i18n/ja.json +++ b/CheckUser/i18n/ja.json @@ -3,6 +3,7 @@ "authors": [ "129femtoseconds", "2nd-player", + "A2y4", "Aotake", "Azeha", "Bonfire12", @@ -15,6 +16,7 @@ "Kanjy", "Kkairri", "Marine-Blue", + "MathXplore", "Mirinano", "Muttley", "Otokoume", @@ -22,6 +24,7 @@ "Rxy", "Schu", "Shirayuki", + "Siglite3", "Suisui", "Sujiniku", "Tmv", @@ -32,13 +35,13 @@ "青子守歌" ] }, - "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パフォーマンス上の理由により、最大$3件の編集しか表示できません。\n方針に従って使用してください。", "checkuser-desc": "利用者の IP アドレスなどの情報を、適切な権限を持つ利用者が調査できるようにする", - "checkuser-logcase": "記録の検索では大文字/小文字を区別します。", "checkuser": "利用者の調査", "checkuserlog": "利用者調査の記録", "checkuser-contribs": "利用者のIPアドレスを調査", "checkuser-contribs-log": "最近の調査記録", + "checkuser-contribs-log-initiator": "この利用者が実施した調査記録", "group-checkuser": "利用者調査者", "group-checkuser-member": "{{GENDER:$1|利用者調査者}}", "right-checkuser": "利用者のIPアドレスやその他の情報を調査", @@ -48,7 +51,7 @@ "grouppage-checkuser": "{{ns:project}}:利用者調査者", "checkuser-reason": "理由:", "checkuser-reason-api": "API: $1", - "checkuser-showlog": "チェックユーザー記録に切り替え", + "checkuser-showlog": "利用者調査の記録に切り替え", "checkuser-query": "最近の更新の照会", "checkuser-target": "IPアドレスまたは利用者名:", "checkuser-users": "利用者名を取得", @@ -58,17 +61,22 @@ "checkuser-week-1": "過去 1 週間", "checkuser-week-2": "過去 2 週間", "checkuser-month": "過去 30 日間", + "checkuser-month-2": "過去 60 日間", "checkuser-all": "すべて", "checkuser-cidr-label": "IPアドレス一覧から共通範囲と影響を受けるアドレスを見つける", "checkuser-cidr-res": "共通CIDR:", + "checkuser-cidr-affected-ips": "影響を受けるIPアドレス:", + "checkuser-cidr-too-small": "範囲が広すぎます", "checkuser-empty": "記録内に項目がありません。", "checkuser-nomatch": "該当するものはありません。", "checkuser-nomatch-edits": "該当するものはありません。\n最終編集は $1 $2 です。", "checkuser-check": "調査", "checkuser-check-this-user": "この利用者を調査", - "checkuser-recent-checks": "この利用者の最近の調査", + "checkuser-investigate-this-user": "この利用者を調査する", + "checkuser-recent-checks": "この利用者に対する最近の調査記録", "checkuser-log-fail": "ログに追加できません", - "checkuser-nolog": "ログファイルが見つかりません。", + "checkuser-log-checks-by": "調査記録", + "checkuser-log-checks-on": "被調査記録", "checkuser-blocked": "ブロック済", "checkuser-gblocked": "グローバルブロック済", "checkuser-locked": "ロック済", @@ -90,14 +98,18 @@ "checkuser-noreason": "照会理由の記入が必要です。", "checkuser-too-many": "(クエリを見積もったところ) 検索結果が多すぎます。CIDRの指定を小さく絞り込んでください。\n使用したIPアドレスは以下の通り (上限 $1 件、並び順はアドレス順):", "checkuser-user-nonexistent": "指定された利用者は存在しません。", + "checkuser-target-nonexistent": "指定された利用者名は存在しません。", + "checkuser-initiator-nonexistent": "指定された調査実行者は存在しません。", "checkuser-search": "利用者調査のログ項目を検索", "checkuser-search-submit": "検索", "checkuser-search-initiator": "調査実行者", "checkuser-search-target": "調査対象者", "checkuser-log-search-target": "利用者名:", + "checkuser-log-search-initiator": "調査実行者", "checkuser-log-search-type": "検索:", "checkuser-ipeditcount": "全利用者による編集 ~$1回", - "checkuser-showmain": "利用者調査のメインフォームに切り替える", + "checkuser-showmain": "利用者調査のメインフォームに切り替え", + "checkuser-show-investigate": "詳細調査のメインフォームに切り替え", "checkuser-limited": "'''パフォーマンス上の理由で、結果は省略されています。'''", "checkuser-log-entry-userips": "$3 $1 は $2 が使用したIPアドレスを取得", "checkuser-log-entry-ipedits": "$3 $1 は <bdi>$2</bdi> からの編集を取得", @@ -105,29 +117,57 @@ "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-log-entry-investigate": "$3 $1 は $2 の情報を調査", "checkuser-autocreate-action": "自動的に作成", "checkuser-create-action": "作成済", "checkuser-email-action": "利用者「$1」にメールを送信", "checkuser-reset-action": "利用者「$1」のパスワードをリセット", "checkuser-token-fail": "セッション失敗。もう一度やり直してください。", - "checkuser-login-failure": "$1として{{SITENAME}}にログインできませんでした", - "checkuser-login-success": "$1として{{SITENAME}}にログインしました", + "checkuser-login-failure": "$1として{{SITENAME}}にログインするのに失敗", + "checkuser-login-success": "$1として{{SITENAME}}にログインするのに成功", "group-checkuser.css": "/* ここに記述したCSSは利用者調査者のみに影響します */", "group-checkuser.js": "/* ここに記述したJSは利用者調査者のみに影響します */", - "checkuser-investigateblock-actions": "ブロック操作", + "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": "詳細調査", + "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-subtitle-show-checkuser": "通常の利用者調査に切り替え", + "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-label": "利用者名とIPアドレス", "checkuser-investigate-targets-placeholder": "利用者名 or 1.1.1.1", + "checkuser-investigate-duration-label": "期間", + "checkuser-investigate-duration-option-all": "すべて", + "checkuser-investigate-duration-option-1w": "過去 1 週間", + "checkuser-investigate-duration-option-2w": "過去 2 週間", + "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": "ブロックされていない", @@ -135,19 +175,44 @@ "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": "結果がありませんでした: 直近90日以内の利用者またはIPアドレスからの活動は記録されていません。", "checkuser-investigate-timeline-notice-no-results-filters": "これらのフィルタ―条件に合致する結果はありません。フィルターの一部を解除して、検索範囲を拡大してみてください。", + "checkuser-investigate-compare-copy-button-label": "ウィキテキストを表示", + "checkuser-investigate-compare-copy-button-label-hide": "ウィキテキストを非表示", + "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": "この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アドレス", "checkuser-investigate-compare-table-header-useragent": "ユーザーエージェント", - "checkuser-investigate-tour-filterip-desc": "ユーザー名、IPアドレスまたはエージェント情報を除外してスッキリさせましょう。元へ戻したい?上部にある絞り込みパネルを使って絞り込み条件を削除して下さい。" + "checkuser-investigate-subtitle-link-restart-tour": "解説をもう一度表示する", + "checkuser-investigate-tour-targets-title": "複数の利用者やIPアドレスを調査するには?", + "checkuser-investigate-tour-targets-desc": "最大 $1 個の{{PLURAL:$1|利用者名またはIPアドレス}}を対象に、すべての情報を1つの表として表示します。調査記録一覧には各対象が別々の記録として残ります。", + "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/jut.json b/CheckUser/i18n/jut.json index 8f803615..14e7dd32 100644 --- a/CheckUser/i18n/jut.json +++ b/CheckUser/i18n/jut.json @@ -7,7 +7,6 @@ }, "checkuser-summary": "Detj wärktye scanne Siensti øndrenge for å finj IP'e brugtj å i bestemtj bruge, elle for å wis redigiirengs- elle brugedata for i IP.\nBruge å redigiirenge fra i klient-IP kan hentjs via XFF-headers we å tilfye \"/xff\" te IP'i. Ipv4 (CIRD $1-32) å IPv6 (CIDR $2-128) ä unjestøtten.\nFor å siker programmes ye-ewn kan maksimalt 5000 redigiirenge djenförs.\nBrug kons detj wärktye i öwe-iensstæmmels mä djäljenje politike på {{SITENAME}}.", "checkuser-desc": "Djie bruga mä den rett guetjennels mulihede for å tjekk brugaris IP-adresse å ånj informasjon", - "checkuser-logcase": "Loggsyegneng djör forskell på stuer å små buegstawe.", "checkuser": "Tjekkbruge", "checkuserlog": "Tjekkbrugelogg", "group-checkuser": "Tjekkbruga", @@ -24,7 +23,6 @@ "checkuser-nomatch": "Ien öwe-iensstæmmenje resultate bløw funjen.", "checkuser-check": "Tjekk", "checkuser-log-fail": "Ku ett tilfye loggpost", - "checkuser-nolog": "Loggfili bløw ett funjen.", "checkuser-blocked": "Blokiirtj", "checkuser-too-many": "For mange resultater, gør CIDR'en smallere. Her er de brugte IP'er (max 5000, sorteret efter adresse):", "checkuser-user-nonexistent": "Ånförtje brugari eksistiire ett.", diff --git a/CheckUser/i18n/jv.json b/CheckUser/i18n/jv.json index 8686d1e8..141cf8ea 100644 --- a/CheckUser/i18n/jv.json +++ b/CheckUser/i18n/jv.json @@ -10,7 +10,6 @@ }, "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 naraguna", "checkuserlog": "Log pamriksan naraguna", "checkuser-contribs": "priksa alamat IP naraguna", @@ -42,7 +41,6 @@ "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.", "checkuser-blocked": "Diblokir", "checkuser-gblocked": "Diblokir sacara global", "checkuser-locked": "Dikunci", diff --git a/CheckUser/i18n/ka.json b/CheckUser/i18n/ka.json index 6ca2db24..e649d4ad 100644 --- a/CheckUser/i18n/ka.json +++ b/CheckUser/i18n/ka.json @@ -40,7 +40,6 @@ "checkuser-nomatch-edits": "დამთხვევა ვერ მოიძებნა.\nბოლო ცვლილება მოხდა $1-ზე $2-ზე.", "checkuser-check": "შემოწმება", "checkuser-log-fail": "ჟურნალის ჩანაწერის დამატება შეუძლებელია", - "checkuser-nolog": "ჟურნალის ფაილი ვერ მოიძებნა.", "checkuser-blocked": "დაბლოკილია", "checkuser-gblocked": "გლობალურად ბლოკირებული", "checkuser-locked": "დახურვა", diff --git a/CheckUser/i18n/kaa.json b/CheckUser/i18n/kaa.json new file mode 100644 index 00000000..18988dc5 --- /dev/null +++ b/CheckUser/i18n/kaa.json @@ -0,0 +1,11 @@ +{ + "@metadata": { + "authors": [ + "Ajiniyaz Nurniyazov", + "Nurlan" + ] + }, + "group-checkuser": "Paydalanıwshılardı tekseriwshiler", + "checkuser-centralauth-multilock-list-item": "Silteme $1", + "checkuser-login-failure-with-good-password": "{{SITENAME}} saytına $1 retinde kirip bolmadı, lekin parol tuwrı edi" +} diff --git a/CheckUser/i18n/kk-arab.json b/CheckUser/i18n/kk-arab.json index c256cdda..7213ea57 100644 --- a/CheckUser/i18n/kk-arab.json +++ b/CheckUser/i18n/kk-arab.json @@ -3,7 +3,6 @@ "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": "قاتىسۋشىنى سىناۋ", "checkuserlog": "قاتىسۋشى سىناۋ جۋرنالى", "group-checkuser": "قاتىسۋشى سىناۋشىلار", @@ -20,7 +19,6 @@ "checkuser-nomatch": "سايكەس تابىلمادى.", "checkuser-check": "سىناۋ", "checkuser-log-fail": "جۋرنالعا جازبا ۇستەلىنبەدى", - "checkuser-nolog": "جۋرنال فايلى تابىلمادى.", "checkuser-blocked": "بۇعاتتالعان", "checkuser-too-many": "تىم كوپ ناتىيجە كەلتىرىلدى, CIDR دەگەندى تارىلتىپ كورىڭىز. مىندا پايدالانىلعان IP جايلار كورسەتىلگەن (بارىنشا 5000, جايىمەن سۇرىپتالعان):", "checkuser-user-nonexistent": "ەنگىزىلگەن قاتىسۋشى جوق.", diff --git a/CheckUser/i18n/kk-cyrl.json b/CheckUser/i18n/kk-cyrl.json index f2e61761..a147bc3a 100644 --- a/CheckUser/i18n/kk-cyrl.json +++ b/CheckUser/i18n/kk-cyrl.json @@ -1,11 +1,11 @@ { "@metadata": { "authors": [ - "Arystanbek" + "Arystanbek", + "U.ayaao.p" ] }, "checkuser-summary": "Бұл құрал пайдаланушы қолданған IP жайлар үшін, немесе IP жай түзету/пайдаланушы деректерін көрсету үшін жуықтағы өзгерістерді қарап шығады.\n\tПайдаланушыларды мен түзетулерді XFF IP арқылы IP жайға «/xff» дегенді қосып келтіруге болады. IPv4 (CIDR $1-32) және IPv6 (CIDR $2-128) арқауланады.\n\tОрындаушылық себептерімен 5000 түзетуден артық қайтарылмайды. Бұны ережелерге сәйкес пайдаланыңыз.", - "checkuser-logcase": "Журналдан іздеу әріп бас-кішілігін айырады.", "checkuser": "Қатысушыны сынау", "checkuserlog": "Қатысушы сынау журналы", "checkuser-contribs-log": "соңғы қатысушы тексерулері", @@ -28,7 +28,6 @@ "checkuser-nomatch": "Сәйкес табылмады.", "checkuser-check": "Сынау", "checkuser-log-fail": "Журналға жазба үстелінбеді", - "checkuser-nolog": "Журнал файлы табылмады.", "checkuser-blocked": "Бұғатталған", "checkuser-gblocked": "ғалам бойынша бұғатталған", "checkuser-locked": "Құлыпталған", @@ -50,7 +49,8 @@ "checkuser-search-target": "нысана", "checkuser-ipeditcount": "Барлық қатысушылардан ~$1", "checkuser-showmain": "Қатысушыларды тексеру басты пішініне ауысу", - "checkuser-autocreate-action": "автоматты түрде басталды", + "checkuser-autocreate-action": "аутоматты түрде басталды", "checkuser-create-action": "басталды", - "checkuser-email-action": "«$1» деген қатысушыға электронды хат жіберу" + "checkuser-email-action": "«$1» деген қатысушыға электронды хат жіберу", + "checkuser-investigate-compare-copy-button-label-hide": "Уикимәтінді жасыру" } diff --git a/CheckUser/i18n/kk-latn.json b/CheckUser/i18n/kk-latn.json index 6ce95bf5..1f96bfdb 100644 --- a/CheckUser/i18n/kk-latn.json +++ b/CheckUser/i18n/kk-latn.json @@ -3,7 +3,6 @@ "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", "checkuserlog": "Qatıswşı sınaw jwrnalı", "group-checkuser": "Qatıswşı sınawşılar", @@ -20,7 +19,6 @@ "checkuser-nomatch": "Säýkes tabılmadı.", "checkuser-check": "Sınaw", "checkuser-log-fail": "Jwrnalğa jazba üstelinbedi", - "checkuser-nolog": "Jwrnal faýlı tabılmadı.", "checkuser-blocked": "Buğattalğan", "checkuser-too-many": "Tım köp nätïje keltirildi, CIDR degendi tarıltıp köriñiz. Mında paýdalanılğan IP jaýlar körsetilgen (barınşa 5000, jaýımen surıptalğan):", "checkuser-user-nonexistent": "Engizilgen qatıswşı joq.", diff --git a/CheckUser/i18n/km.json b/CheckUser/i18n/km.json index b16ea982..d83475f9 100644 --- a/CheckUser/i18n/km.json +++ b/CheckUser/i18n/km.json @@ -9,7 +9,6 @@ ] }, "checkuser-desc": "ផ្ដល់ឱ្យអ្នកប្រើប្រាស់នូវការអនុញ្ញាតសមគួរដើម្បីទទួលបាននូវសមត្ថភាពក្នុងការត្រួតពិនិត្យអាសយដ្ឋាន IP របស់អ្នកប្រើប្រាស់និងព័ត៌មានផ្សេងៗទៀត", - "checkuser-logcase": "ការស្វែងរកកំណត់ហេតុដោយបែងចែកអក្សរធំ អក្សរតូច។", "checkuser": "ត្រួតពិនិត្យអ្នកប្រើប្រាស់", "checkuserlog": "កំណត់ហេតុនៃការត្រួតពិនិត្យអ្នកប្រើប្រាស់", "checkuser-contribs": "ត្រួតពិនិត្យ IP របស់អ្នកប្រើប្រាស់", @@ -38,7 +37,6 @@ "checkuser-empty": "មិនមានអ្វីនៅក្នុងកំណត់ហេតុនេះទេ។", "checkuser-nomatch": "មិនមានការគូផ្គងដូចគ្នាត្រូវបានរកឃើញទេ។", "checkuser-check": "ត្រួតពិនិត្យ", - "checkuser-nolog": "ឯកសារកំណត់ហេតុមិនត្រូវបានរកឃើញទេ។", "checkuser-blocked": "បានហាមឃាត់", "checkuser-gblocked": "ត្រូវបានរាំងខ្ទប់ជាសាកល", "checkuser-locked": "បានចាក់សោ", diff --git a/CheckUser/i18n/ko.json b/CheckUser/i18n/ko.json index 5ab09a53..9849fc1f 100644 --- a/CheckUser/i18n/ko.json +++ b/CheckUser/i18n/ko.json @@ -2,6 +2,7 @@ "@metadata": { "authors": [ "Albamhandae", + "Bluehill", "Ellif", "Ficell", "IRTC1015", @@ -16,12 +17,12 @@ "ToePeu", "Ykhwong", "관인생략", + "렌즈", "아라" ] }, - "checkuser-summary": "이 도구는 최근의 변경 사항을 검사하여 특정 사용자가 이용한 IP 주소를 검색하거나 특정 IP 주소에 대한 편집/사용자 정보를 보여줍니다.\n클라이언트 IP를 통한 사용자와 편집은 IP 주소 뒤에 \"/xff\"를 추가함으로써 XFF 헤더를 통해 조사할 수 있습니다. IPv4 (CIDR $1-32)와 IPv6 (CIDR $2-128)을 지원합니다.\n성능 상의 이유로 최대 5,000개의 편집만 반환됩니다.\n이 도구는 정책에 맞게 사용하십시오.", + "checkuser-summary": "이 도구는 최근의 변경 사항을 검사하여 특정 사용자가 이용한 IP 주소를 검색하거나 특정 IP 주소에 대한 편집/사용자 정보를 보여줍니다.\n클라이언트 IP를 통한 사용자와 편집은 IP 주소 뒤에 \"/xff\"를 추가함으로써 XFF 헤더를 통해 조사할 수 있습니다. IPv4 (CIDR $1-32)와 IPv6 (CIDR $2-128)을 지원합니다.\n성능상의 이유로 최대 $3개의 편집만 반환됩니다.\n이 도구는 정책에 맞게 사용하십시오.", "checkuser-desc": "사용자의 IP 주소 등의 정보를 조사할 수 있는 적절한 권한을 특정한 사용자에게 줍니다", - "checkuser-logcase": "기록 검색은 대소문자를 구분합니다.", "checkuser": "사용자 검사", "checkuserlog": "사용자 검사 기록", "checkuser-contribs": "사용자 IP를 확인", @@ -45,17 +46,20 @@ "checkuser-week-1": "지난 1주일", "checkuser-week-2": "지난 2주일", "checkuser-month": "지난 30일", + "checkuser-month-2": "지난 60일", "checkuser-all": "모두", "checkuser-cidr-label": "IP 주소의 공통 범위와 영향을 받는 주소 목록 찾기", "checkuser-cidr-res": "공통 CIDR:", + "checkuser-cidr-affected-ips": "영향을 받는 IP 주소:", + "checkuser-cidr-too-small": "범위가 너무 큽니다", "checkuser-empty": "기록이 없습니다.", "checkuser-nomatch": "일치하는 결과가 없습니다.", "checkuser-nomatch-edits": "일치하는 결과가 없습니다.\n마지막 편집은 $1 $2에 있었습니다.", "checkuser-check": "확인", "checkuser-check-this-user": "이 사용자 검사", + "checkuser-investigate-this-user": "이 사용자를 조사하기", "checkuser-recent-checks": "이 사용자의 최근 검사", "checkuser-log-fail": "기록을 남길 수 없습니다", - "checkuser-nolog": "기록 파일이 없습니다.", "checkuser-blocked": "차단됨", "checkuser-gblocked": "전체 위키에서 차단됨", "checkuser-locked": "잠김", @@ -67,6 +71,7 @@ "checkuser-blocktalk": "차단된 동안 자신의 사용자 토론 문서를 편집하지 못하도록 막기", "checkuser-blocktag": "사용자 문서를 다음 내용으로 바꾸기:", "checkuser-blocktag-talk": "토론 문서를 다음 내용으로 바꾸기:", + "checkuser-reblock": "기존 차단을 대체하기", "checkuser-massblock-commit": "선택한 사용자를 차단", "checkuser-block-success": "'''$1 {{PLURAL:$2|사용자}}가 성공적으로 차단{{PLURAL:$2|되었습니다}}.'''", "checkuser-block-failure": "'''차단된 사용자가 없습니다.'''", @@ -84,6 +89,7 @@ "checkuser-log-search-type": "검색 종류:", "checkuser-ipeditcount": "모든 사용자로부터 편집 $1개", "checkuser-showmain": "사용자검사 기본 양식으로 돌아가기", + "checkuser-show-investigate": "조사 기본 양식으로 전환", "checkuser-limited": "'''성능 상의 이유로 결과 중 일부만 보여줍니다.'''", "checkuser-log-entry-userips": "$3, $1님이 $2의 IP 주소를 조회했습니다", "checkuser-log-entry-ipedits": "$3, $1님이 <bdi>$2</bdi>의 편집을 조회했습니다", @@ -91,6 +97,7 @@ "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-log-entry-investigate": "$3에, $1님이 $2에 대한 정보를 조회했습니다", "checkuser-autocreate-action": "자동으로 만들어졌습니다", "checkuser-create-action": "만들어졌습니다", "checkuser-email-action": "\"$1\" 사용자에게 이메일을 보냈습니다", @@ -100,53 +107,80 @@ "checkuser-login-success": "{{SITENAME}}에 $1님으로 성공적으로 로그인했습니다", "group-checkuser.css": "/* 이 CSS 설정은 검사관에만 적용됩니다 */", "group-checkuser.js": "/* 이 자바스크립트 설정은 검사관에만 적용됩니다 */", - "checkuser-investigateblock": "사용자 차단", + "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-investigate": "조사하기", + "checkuser-investigate-subtitle-block-button-label": "차단하기", "checkuser-investigate-subtitle-cancel-button-label": "취소", "checkuser-investigate-subtitle-continue-button-label": "계속", + "checkuser-investigate-subtitle-show-checkuser": "사용자 검사로 전환하기", + "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-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": "지난 2주", + "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": "결과가 없습니다: 최근 90일 내에 이 사용자 또는 IP의 활동 기록이 없습니다", "checkuser-investigate-timeline-notice-no-results-filters": "이 필터 조건에 일치하는 결과가 없습니다. 일부 필터를 제거하여 검색 범위를 확대해 보십시오.", "checkuser-investigate-compare-copy-button-label": "위키텍스트 보기", + "checkuser-investigate-compare-copy-button-label-hide": "위키텍스트 숨기기", "checkuser-investigate-compare-toollinks-ipcheck": "프록시 검사", "checkuser-investigate-compare-copy-message-label": "이 정보를 위키텍스트 표로 복사하시겠습니까?", + "checkuser-investigate-compare-notice-no-results": "결과가 없습니다: 최근 90일동안 이 사용자나 IP 대역에서의 편집이 없습니다.", "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-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-useragents-title": "사용자 에이전트가 일치합니까?", + "checkuser-investigate-tour-filterip-title": "조사 범위를 더 좁힐까요?", + "checkuser-investigate-tour-block-title": "차단을 원하십니까?", "checkuser-investigate-tour-copywikitext-title": "데이터를 복사하시겠습니까?" } diff --git a/CheckUser/i18n/ks-arab.json b/CheckUser/i18n/ks-arab.json new file mode 100644 index 00000000..ec50993e --- /dev/null +++ b/CheckUser/i18n/ks-arab.json @@ -0,0 +1,17 @@ +{ + "@metadata": { + "authors": [ + "Teashae" + ] + }, + "checkuser": "صٲرِف چَک", + "checkuser-reason": "وَضاحَت:", + "checkuser-search-submit": "ژھانٛڈُن", + "checkuser-investigateblock-reason": "وَضاحَت", + "checkuser-investigate-subtitle-block-button-label": "بُلاک", + "checkuser-investigate-subtitle-cancel-button-label": "مَنسوٗخ", + "checkuser-investigate-duration-option-all": "سٲری", + "checkuser-investigate-reason-label": "وَضاحَت", + "checkuser-investigate-preliminary-table-header-name": "صٲرِف ناو:", + "checkuser-investigate-preliminary-table-header-wiki": "وِکی" +} diff --git a/CheckUser/i18n/ksh.json b/CheckUser/i18n/ksh.json index 5ce3a3d5..ebaa0e07 100644 --- a/CheckUser/i18n/ksh.json +++ b/CheckUser/i18n/ksh.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "Met däm Werkzüch he kam_mer de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße fun Metmaacher fenge, di en de {{lcfirst:{{int:Recentchanges}}}} schtonn, un mer kann de Metmaacher iehr Dahte un Änderonge fenge för en beschtemmpte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß.\n\nMetmaacher un ier Änderong för en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß uss ener <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"X-Forwarded-For\">XFF</i>-Kopp_Reih wähde jezeich, wam_mer aan di <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß en „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"X-Forwarded-For\">/xff</code>“ aanhängk. \n\nDobei wäde <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"et Internet Protocol en dä Väsjohn 4\">IPv4</i> (<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätt $1-32) un <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"et Internet Protocol en dä Väsjohn 6\">IPv6</i> (<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätt $2-128) ongerschtöz. Leßte jon beß 5000 Änderonge, öm der ẞööver nit zoh doll ze beschäfteje.\n\nDonn op de Räjelle för dat Werrkzüsch obach jävve, un donn et nit bruche, wann De dat nit darrefs.", "checkuser-desc": "Metmaacher met däm Rääsch dozoh könne de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße un annder Dahte fun de Metmaacher övverpröhfe.", - "checkuser-logcase": "Dat Söhke em Logbohch deit zwesche jruhße un kleine Bohchshtave ongerscheide.", "checkuser": "Metmaacher övverpröhfe", "checkuserlog": "Logbohch fum Metmaacher-Övverpröhfe", "checkuser-contribs": "Metmaacher ier <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße övverpröhfe", @@ -38,7 +37,6 @@ "checkuser-nomatch-edits": "Nix zopaß jefonge. De letzte Änderong wohr aam $1 öm $2 Uhr.", "checkuser-check": "Lohß jonn!", "checkuser-log-fail": "Kann em Logbohch nix dobei schrihve", - "checkuser-nolog": "Kein Logbohch jefonge.", "checkuser-blocked": "Jeschpächt", "checkuser-gblocked": "En alle Wikis jeschpächt", "checkuser-locked": "Zohjemaat un afjeschloße", diff --git a/CheckUser/i18n/ksw.json b/CheckUser/i18n/ksw.json new file mode 100644 index 00000000..0db38f95 --- /dev/null +++ b/CheckUser/i18n/ksw.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "SawJaemin" + ] + }, + "checkuser-all": "ခဲလၢာ်" +} diff --git a/CheckUser/i18n/ku-latn.json b/CheckUser/i18n/ku-latn.json index 01a3bfaa..257d4946 100644 --- a/CheckUser/i18n/ku-latn.json +++ b/CheckUser/i18n/ku-latn.json @@ -12,7 +12,7 @@ "checkuser-month": "30 rojên dawî", "checkuser-all": "hemû", "checkuser-block-noreason": "Tu divê bo astengkirinan sedemekê bidî.", - "checkuser-search": "Lêbigere", + "checkuser-search": "Li qeydên têkitinên bikarhênerên kontrolê bigere", "checkuser-search-submit": "Lêbigere", "checkuser-ipeditcount": "~$1 ji hemû bikarhêneran", "checkuser-create-action": "hat afirandin", diff --git a/CheckUser/i18n/lb.json b/CheckUser/i18n/lb.json index 6b40938a..0cb45ccd 100644 --- a/CheckUser/i18n/lb.json +++ b/CheckUser/i18n/lb.json @@ -6,9 +6,8 @@ "Soued031" ] }, - "checkuser-summary": "Dës Funktioun scannt déi rezent Ännerunge fir d'Ip-Adressen, déi vun engem Benotzer benotzt goufen, ze fannen, repektiv d'Ännerunge pro Benotzer fir eng IP.\nBenotzer an Ännerunge vun enger IP-Adress kënnen och iwwer den XFF header gesicht ginn andeems hanner d'IP-Adress \"/xff\" hannendrugehaange gëtt. IPv4 (CIDR $1-32) an IPv6 (CIDR $2-128) ginn ënnerstëtzt.\nNet méi wéi 5000 Ännerunge ginn aus Performancegrënn zréckgeschéckt.\nBenotzt dës Funktioun am Aklang mat den Direktiven.", + "checkuser-summary": "Dës Funktioun scannt déi rezent Ännerunge fir d'IP-Adressen, déi vun engem Benotzer benotzt goufen, ze fannen, respektiv d'Ännerunge pro Benotzer fir eng IP.\nBenotzer an Ännerunge vun enger IP-Adress kënnen och iwwer den XFF header gesicht ginn andeems hanner d'IP-Adress \"/xff\" hannendrugehaange gëtt. IPv4 (CIDR $1-32) an IPv6 (CIDR $2-128) ginn ënnerstëtzt.\nNet méi wéi $3 Ännerunge ginn aus Performancegrënn zréckgeschéckt.\nBenotzt dës Funktioun am Aklang mat den Direktiven.", "checkuser-desc": "Gëtt Benotzer mat den néidege Rechter d'Méiglechkeet d'IP-Adresse sou wéi aner Informatiounen iwwer d'Benotzer z'iwwerpréiwen", - "checkuser-logcase": "D'Sichen am Logbuch mécht en Ënnerscheed tëscht grouss a kleng Buschtawen", "checkuser": "Benotzer-Check", "checkuserlog": "Lëscht vun de Benotzerkontrollen", "checkuser-contribs": "De Benotzer hir Ip-Adrssen iwwerpréifen", @@ -32,6 +31,7 @@ "checkuser-week-1": "lescht Woch", "checkuser-week-2": "lescht 2 Wochen", "checkuser-month": "lescht 30 Deeg", + "checkuser-month-2": "lescht 60 Deeg", "checkuser-all": "all", "checkuser-cidr-label": "Gemeinsamen Adressberäich a betraffen Adressen fir eng Lëscht vun IP-Adresse fannen", "checkuser-cidr-res": "Gemeinsam CIDR:", @@ -40,9 +40,9 @@ "checkuser-nomatch-edits": "Et gouf näischt sou fonnt.\nDéi lescht Ännerung war de() $1 ëm $2.", "checkuser-check": "Kontrolléieren", "checkuser-check-this-user": "Dëse Benotzer iwwerpréiwen", + "checkuser-investigate-this-user": "Dëse Benotzer ënnersichen", "checkuser-recent-checks": "Rezent Iwwerpréiwunge fir dëse Benotzer", "checkuser-log-fail": "D'Aschreiwung an d'Logbuch konnt net gemaach ginn", - "checkuser-nolog": "D'Logbuch gouf net fonnt.", "checkuser-blocked": "Gespaart", "checkuser-gblocked": "global gespaart", "checkuser-locked": "Gespaart", @@ -60,8 +60,10 @@ "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-centralauth-multilock": "Méi erausgesicht Benotzerkonte spären", + "checkuser-centralauth-multilock-list-item": "Link $1", "checkuser-noreason": "Dir musst e Grond fir dës Ufro uginn.", - "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-too-many": "Ze vill Resultater (am Vergläich zu der Schätzung vun der Ufro), reduzéiert wgl. de Beräich vum CIDR.\nHei sinn déi benotzten IP-Adressen (max $1, 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", @@ -71,17 +73,23 @@ "checkuser-log-search-type": "Sichen no:", "checkuser-ipeditcount": "~$1 vun alle Benotzer", "checkuser-showmain": "Op den Haaptformulaire vun CheckUser wiesselen", + "checkuser-show-investigate": "Op den Haaptformulaire fir z'ënnersiche wiesselen", "checkuser-limited": "'''Dës Lëscht gouf aus Grënn vun der performance vun de Servere gekierzt.'''", + "checkuser-log-entry-userips": "$3, $1 huet d'IP-Adresse fir $2 kritt", "checkuser-log-entry-ipedits": "$3, $1 huet d'Ännerunge vun <bdi>$2</bdi> kritt", + "checkuser-log-entry-ipusers": "$3, $1 huet d'Benotzer fir <bdi>$2</bdi> kritt", + "checkuser-log-entry-ipedits-xff": "$3, $1 huet d'Ännerunge fir XFF <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-reset-action": "setzt d'Passwuert fir de Benotzer \"$1\" zréck", "checkuser-token-fail": "Sessiouns-Feeler.Probéiert wgl. nach eng Kéier.", + "checkuser-login-failure": "Konnt sech net alogge op {{SITENAME}} als $1", "checkuser-login-success": "Op {{SITENAME}} ageloggt als $1", "checkuser-link-investigate-label": "Probéiert dat neit CheckUser-Geschier", "checkuser-investigateblock": "Benotzer spären", "checkuser-investigateblock-target": "Benotzernimm an IP-Adressen", + "checkuser-investigateblock-actions": "Aktiounen déi gespaart solle ginn", "checkuser-investigateblock-reason": "Grond", "checkuser-investigateblock-options": "Zousätzlech Optiounen", "checkuser-investigateblock-email-label": "Verhënnere fir E-Mailen ze verschécken", @@ -90,16 +98,19 @@ "checkuser-investigateblock-notice-position-label": "Positioun", "checkuser-investigateblock-notice-text-label": "Wikitext", "checkuser-investigateblock-notice-replace": "Säit ersetzen", + "checkuser-investigate": "Ënnersichen", + "checkuser-investigate-page-subtitle": "Aktuell Ënnersichung fir $1", "checkuser-investigate-subtitle-block-button-label": "Spären", "checkuser-investigate-subtitle-cancel-button-label": "Ofbriechen", "checkuser-investigate-subtitle-continue-button-label": "Virufueren", + "checkuser-investigate-subtitle-show-checkuser": "Op CheckUser wiesselen", "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-label": "Benotzernimm an IP-Adressen:", "checkuser-investigate-targets-placeholder": "Benotzernumm oder 1.1.1.1", "checkuser-investigate-duration-label": "Dauer", "checkuser-investigate-duration-option-all": "All", @@ -107,17 +118,32 @@ "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-blocked": "Gespaart", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|Ännerung|Ännerungen}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Net gespaart", + "checkuser-investigate-preliminary-table-header-blocked": "Status", + "checkuser-investigate-preliminary-table-header-editcount": "Ännerungen", + "checkuser-investigate-preliminary-table-header-groups": "Gruppen", + "checkuser-investigate-preliminary-table-header-name": "Benotzernumm", + "checkuser-investigate-preliminary-table-header-wiki": "Wiki", "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-checks-label": "Kontrolléieren", + "checkuser-investigate-compare-table-button-contribs-label": "Kontributiounen", "checkuser-investigate-compare-table-button-filter-label": "Aus de Resultater filteren", "checkuser-investigate-compare-table-cell-unregistered": "Net-ugemellt", + "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|Ännerung|Ännerungen}}]</b>", "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?" + "checkuser-investigate-compare-table-header-useragent": "Browser", + "checkuser-investigate-subtitle-link-restart-tour": "Tour nei starten", + "checkuser-investigate-tour-addusertargets-title": "Braucht Dir méi Kontext?", + "checkuser-investigate-tour-block-title": "Spären?", + "checkuser-investigate-tour-copywikitext-title": "Wëllt Dir d'Date kopéieren?" } diff --git a/CheckUser/i18n/li.json b/CheckUser/i18n/li.json index 06a00016..23ccfbda 100644 --- a/CheckUser/i18n/li.json +++ b/CheckUser/i18n/li.json @@ -8,7 +8,6 @@ }, "checkuser-summary": "Dit hölpmiddel bekiek recènte verangeringe óm IP-adresse die 'ne gebroeker haet gebroek te achterhaole of toeantj de bewèrkings- en gebroekersgegaeves veur 'n IP-adres.\nGebroekers en bewèrkinge van 'n IP-adres van 'ne cliënt kinne achterhaoldj waere via XFF-headers door \"/xff\" achter 't IP-adres toe te voege. IPv4 (CIDR $1-32) en IPv6 (CIDR $2-128) waere óngersteundj.\nÓm prestatiereej waere neet mieë es 5.000 bewèrkinge getoeantj. Gebroek dit hölpmiddel volges 't vasgesteldje beleid.", "checkuser-desc": "Läöt geautproseerde gebroekers IP-adresse en angere informatie van gebroekers achterhaole", - "checkuser-logcase": "Zeuke in 't logbook is huidlèttergeveulig.", "checkuser": "Konterleer gebroeker", "checkuserlog": "Logbook KonterleerGebroeker", "checkuser-contribs": "Controleer gebroekers-IP", @@ -42,7 +41,6 @@ "checkuser-check-this-user": "Controleer deze gebroeker", "checkuser-recent-checks": "Recènte controles veur deze gebroeker", "checkuser-log-fail": "Logbookregel toevoege neet meugelik", - "checkuser-nolog": "Gein logbook gevónje.", "checkuser-blocked": "Geblokkeerdj", "checkuser-gblocked": "Globaal vas", "checkuser-locked": "Aafgeslaote", diff --git a/CheckUser/i18n/lld.json b/CheckUser/i18n/lld.json index 29562f22..c80f1463 100644 --- a/CheckUser/i18n/lld.json +++ b/CheckUser/i18n/lld.json @@ -1,9 +1,11 @@ { "@metadata": { "authors": [ + "Asenoner", "Starladin" ] }, "checkuser-investigate-notice-no-results": "Degügn resultac.", - "checkuser-investigate-preliminary-table-header-blocked": "Status" + "checkuser-investigate-preliminary-table-header-blocked": "Status", + "checkuser-investigate-compare-copy-button-label-hide": "Nascuend l wikitest" } diff --git a/CheckUser/i18n/lmo.json b/CheckUser/i18n/lmo.json new file mode 100644 index 00000000..5a974548 --- /dev/null +++ b/CheckUser/i18n/lmo.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Salvemm el lombard" + ] + }, + "group-checkuser": "Controlloeur" +} diff --git a/CheckUser/i18n/lt.json b/CheckUser/i18n/lt.json index c4dab124..83a7e5d8 100644 --- a/CheckUser/i18n/lt.json +++ b/CheckUser/i18n/lt.json @@ -34,7 +34,6 @@ "checkuser-nomatch-edits": "Nerasta jokiu atitikmenų\nPaskutini karta redaguota $1 $2.", "checkuser-check": "Tikrinti", "checkuser-log-fail": "Neįmanoma pridėti žurnalo įrašo", - "checkuser-nolog": "Nerastas žurnalo failas", "checkuser-blocked": "Užblokuotas", "checkuser-gblocked": "Užblokuotas globaliai", "checkuser-locked": "Užrakintas", diff --git a/CheckUser/i18n/lv.json b/CheckUser/i18n/lv.json index 955eaa09..f54f1a28 100644 --- a/CheckUser/i18n/lv.json +++ b/CheckUser/i18n/lv.json @@ -12,7 +12,7 @@ }, "checkuser-desc": "Atļauj lietotājiem ar attiecīgām pilnvarām pārbaudīt lietotāja IP adresi un citu informāciju.", "checkuser": "Pārbaudīt lietotāju", - "checkuser-contribs": "pārbaudīt lietotāja IP adreses", + "checkuser-contribs": "pārbaudīt dalībnieka IP adreses", "group-checkuser": "Pārbaudītāji", "group-checkuser-member": "{{GENDER:$1|pārbaudīt lietotāju}}", "right-checkuser": "Pārbaudīt lietotāja IP adreses un citu informāciju", diff --git a/CheckUser/i18n/mai.json b/CheckUser/i18n/mai.json index 74f4a969..c1e3247c 100644 --- a/CheckUser/i18n/mai.json +++ b/CheckUser/i18n/mai.json @@ -35,7 +35,6 @@ "checkuser-nomatch": "कोनो मेल खाएत परिणाम नै भेटल।", "checkuser-check": "जाँचु", "checkuser-log-fail": "लॉग प्रविष्टि जोड़ नै सकलिए", - "checkuser-nolog": "कुनो लॉग फ़ाइल नैं मिल्ल।", "checkuser-blocked": "अवरुद्ध", "checkuser-gblocked": "विश्वव्यापी रूपसँ अवरुद्ध", "checkuser-locked": "बंद भेल", diff --git a/CheckUser/i18n/mg.json b/CheckUser/i18n/mg.json index f7555643..61c8e329 100644 --- a/CheckUser/i18n/mg.json +++ b/CheckUser/i18n/mg.json @@ -4,6 +4,5 @@ "Jagwar" ] }, - "checkuser-nolog": "Tsy nahitana rakitra laogy.", "checkuser-search-submit": "Hikaroka" } diff --git a/CheckUser/i18n/mk.json b/CheckUser/i18n/mk.json index aa8a6b6b..f44e98d4 100644 --- a/CheckUser/i18n/mk.json +++ b/CheckUser/i18n/mk.json @@ -8,13 +8,13 @@ "Vlad5250" ] }, - "checkuser-summary": "Оваа алатка врши преглед на скорешни промени за да ги добие IP-адресите користени од некој корисник или да ги прикаже податоците за уредувања/корисници за некоја IP-адреса.\nКорисниците и уредувањата од клиентска IP-адреса можат да се добијат преку XFF наслови со додавање на „/xff“ на IP-адресата. Поддржани се IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128).\nЌе се прикажат највеќе до 5000 уредувања од функционални причини.\nКористете го ова во согласност со правилата.", + "checkuser-summary": "Оваа алатка врши преглед на скорешни промени за да ги добие IP-адресите користени од некој корисник или да ги прикаже податоците за уредувања/корисници за некоја IP-адреса.\nКорисниците и уредувањата од клиентска IP-адреса можат да се добијат преку XFF наслови со додавање на „/xff“ на IP-адресата. Поддржани се IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128).\nЌе се прикажат највеќе до $3 уредувања од функционални причини.\nКористете го ова во согласност со правилата.", "checkuser-desc": "Доделува право за проверка на кориснички IP-адреси и други информации", - "checkuser-logcase": "Пребарувањето на дневникот разликува големи и букви.", "checkuser": "Провери корисник", "checkuserlog": "Дневник на проверки", "checkuser-contribs": "провери IP-адреси на корисникот", "checkuser-contribs-log": "скорешни проверки", + "checkuser-contribs-log-initiator": "кориснички проверки напраевни од овој корисник", "group-checkuser": "Проверувачи", "group-checkuser-member": "{{GENDER:$1|проверувач}}", "right-checkuser": "Проверување на корисничка IP-адреса и други информации", @@ -34,17 +34,23 @@ "checkuser-week-1": "последна седмица", "checkuser-week-2": "последни две седмици", "checkuser-month": "последни 30 дена", + "checkuser-month-2": "последните 60 дена", "checkuser-all": "сите", "checkuser-cidr-label": "Најди заедничка низа и погодени адреси за список на IP-адреси", "checkuser-cidr-res": "Заеднички CIDR:", + "checkuser-cidr-affected-ips": "Засегната IP-адреса:", + "checkuser-cidr-too-small": "Опсегот е преголем", + "checkuser-range-outside-limit": "Опсегот $1 е вон дозволените граници.", "checkuser-empty": "Дневникот не содржи записи.", "checkuser-nomatch": "Нема совпаѓања.", "checkuser-nomatch-edits": "Нема совпаѓања.\nПоследното уредување се случило на $1 во $2.", "checkuser-check": "Провери", "checkuser-check-this-user": "Провери го корисников", + "checkuser-investigate-this-user": "Иследи го корисников", "checkuser-recent-checks": "Скорешни проверки на корисникот", "checkuser-log-fail": "Не можам да додадам ставка во дневникот", - "checkuser-nolog": "Дневникот не е пронајден.", + "checkuser-log-checks-by": "проверки од", + "checkuser-log-checks-on": "проверки на", "checkuser-blocked": "Блокиран", "checkuser-gblocked": "Блокиран глобално", "checkuser-locked": "Заклучено", @@ -63,17 +69,23 @@ "checkuser-block-limit": "Избравте премногу корисници.", "checkuser-block-noreason": "Мора да наведете причина за блокирањата.", "checkuser-centralauth-multilock": "Повеќекратно заклучување на сметки", + "checkuser-centralauth-multilock-list": "Заклучете ги следниве сметки наеднаш користејќи ги врските:", + "checkuser-centralauth-multilock-list-item": "Врска $1", "checkuser-noreason": "Мора да наведете причина за ова барање.", "checkuser-too-many": "Премногу ставки (според процената на барањето). Уточнете го CIDR.\nЕве ги користените IP-адреси (највеќе $1, подредени по адреса):", "checkuser-user-nonexistent": "Наведениот корисник не постои.", + "checkuser-target-nonexistent": "Укажаната цел не постои.", + "checkuser-initiator-nonexistent": "Укажаниот покренувач не постои", "checkuser-search": "Пребарај по ставките од дневникот на проверки", "checkuser-search-submit": "Пребарај", "checkuser-search-initiator": "покренувач", "checkuser-search-target": "цел", "checkuser-log-search-target": "Цел:", + "checkuser-log-search-initiator": "Покренувач:", "checkuser-log-search-type": "Пребарај по:", "checkuser-ipeditcount": "~$1 од сите корисници", "checkuser-showmain": "Префрли ме на главниот образец за проверување корисници", + "checkuser-show-investigate": "Префрли се на главниот иследувачки образец", "checkuser-limited": "'''Исходов е скратен од делотворрни причини.'''", "checkuser-log-entry-userips": "$3, $1 доби IP-адреси за $2", "checkuser-log-entry-ipedits": "$3, $1 доби уредувања за <bdi>$2</bdi>", @@ -81,12 +93,14 @@ "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-log-entry-investigate": "$3, $1 побара информации за $2", "checkuser-autocreate-action": "беше автоматски создадена", "checkuser-create-action": "е создаден", "checkuser-email-action": "му испрати е-пошта на корисникот „$1“", "checkuser-reset-action": "смени лозинка за корисникот „$1“", "checkuser-token-fail": "Седницата не успеа. Обидете се повторно.", "checkuser-login-failure": "Не успеав да ве најавам на {{SITENAME}} како $1", + "checkuser-login-failure-with-good-password": "Не успеав да ве најавам на {{SITENAME}} како $1, но лозинката беше исправна", "checkuser-login-success": "Успешно ве најавив на {{SITENAME}} како $1", "group-checkuser.css": "/* Тука поставениот CSS ќе се применува само врз проверувачи */", "group-checkuser.js": "/* Тука поставениот JS ќе се применува само врз проверувачи */", @@ -109,15 +123,12 @@ "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-subtitle-show-checkuser": "Префрли на Проверка на корисник", "checkuser-investigate-indicator-new-investigation": "Ново иследување", "checkuser-investigate-indicator-logs": "Дневници", "checkuser-investigate-legend": "Пребсрајте кориснички имиња, IP-адреси или IP-опсези", @@ -125,7 +136,7 @@ "checkuser-investigate-tab-preliminary-check": "Информации за сметката", "checkuser-investigate-tab-compare": "IP-адреса и кориснички застапници", "checkuser-investigate-tab-timeline": "Времеслед", - "checkuser-investigate-targets-label": "Кориснички имиња и IP-адреси", + "checkuser-investigate-targets-label": "Кориснички имиња и IP-адреси:", "checkuser-investigate-targets-placeholder": "Корисничко име или 1.1.1.1", "checkuser-investigate-duration-label": "Траење", "checkuser-investigate-duration-option-all": "Сите", @@ -149,6 +160,7 @@ "checkuser-investigate-timeline-notice-no-results": "Нема исход: нема заведена активност од овие корисници или IP-адреси во последниве 90 дена", "checkuser-investigate-timeline-notice-no-results-filters": "Нема исход што одговара на филтрираното. Отстранете некои филтри за да го проширите пребарувањето.", "checkuser-investigate-compare-copy-button-label": "Прик. викитекст", + "checkuser-investigate-compare-copy-button-label-hide": "Скриј викитекст", "checkuser-investigate-compare-toollinks-ipcheck": "Проверка на застапник", "checkuser-investigate-compare-copy-message-label": "Дали би сакале да ги прекопирате овие информации како викитекстна табела?", "checkuser-investigate-compare-notice-exceeded-limit": "Поради технички ограничувања, прикажан е најголемиот можен број на записи. Податоците дадени за следниве цели се непотполни: $1. Обидете се со помалку цели, помал временски опсег или потесни IP-опсези.", @@ -161,7 +173,7 @@ "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-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": "Датумски опсег", diff --git a/CheckUser/i18n/ml.json b/CheckUser/i18n/ml.json index 74c3cdbe..98443e48 100644 --- a/CheckUser/i18n/ml.json +++ b/CheckUser/i18n/ml.json @@ -9,7 +9,6 @@ }, "checkuser-summary": "ഈ ഉപകരണം സമീപകാലമാറ്റങ്ങൾ പരിശോധിക്കുകയും, ഒരുപയോക്താവ് ഉപയോഗിച്ച ഐ.പി. വിലാസങ്ങൾ ശേഖരിക്കുകയോ അല്ലെങ്കിൽ തിരുത്തലിന്റെ/ഉപയോക്താവിന്റെ വിവരങ്ങൾ പ്രദർശിപ്പിക്കുകയോ ചെയ്യുന്നു.\nഒരു ക്ലയന്റ് ഐ.പി. വിലാസത്തിൽ നിന്നുള്ള ഉപയോക്താക്കളേയും തിരുത്തലുകളേയും കുറിച്ചുള്ള വിവരങ്ങൾ എക്സ്.എഫ്.എഫ്. (XFF) വഴി ശേഖരിക്കാൻ, ഐ.പി. വിലാസത്തിനൊടുവിൽ \"/xff\" എന്നു ചേർത്ത് സാധിക്കുന്നതാണ്. IPv4 (CIDR $1-32) ഒപ്പം IPv6 (CIDR $2-128) എന്നിവ പിന്തുണയ്ക്കുന്നു.\nപ്രവർത്തനക്ഷമത സംബന്ധിച്ച കാരണങ്ങളാൽ 5,000 തിരുത്തുകളിലധികം ശേഖരിക്കുന്നതല്ല.\nഈ സൗകര്യം നയങ്ങൾക്കനുസരിച്ചു മാത്രം ഉപയോഗിക്കേണ്ടതാകുന്നു.", "checkuser-desc": "ഉപയോക്താക്കൾ ഉപയോഗിച്ച ഐ.പി. വിലാസവും മറ്റുവിവരങ്ങളും പരിശോധിക്കുവാനുള്ള അവകാശം കൊടുക്കാൻ പ്രാപ്തമാക്കുന്നു", - "checkuser-logcase": "പ്രവർത്തന രേഖകൾക്കു വേണ്ടിയുള്ള തിരച്ചിൽ കേസ് സെൻസിറ്റീവ് ആണ്.", "checkuser": "ചെക്ക് യൂസർ", "checkuserlog": "ചെക്ക് യൂസർ പ്രവർത്തനരേഖ", "checkuser-contribs": "ഉപയോക്തൃ ഐ.പി. വിലാസങ്ങൾ പരിശോധിക്കുക", @@ -41,7 +40,6 @@ "checkuser-nomatch-edits": "ഒത്തുപോകുന്നവ കണ്ടെത്താനായില്ല.\nഅവസാന തിരുത്തൽ $2 $1-നു ആണ് നടന്നത്.", "checkuser-check": "പരിശോധിക്കുക", "checkuser-log-fail": "പ്രവർത്തനരേഖയിൽ ഇനം ചേർക്കുന്നതിനു കഴിഞ്ഞില്ല", - "checkuser-nolog": "പ്രവർത്തനരേഖ പ്രമാണം കണ്ടില്ല.", "checkuser-blocked": "തടയപ്പെട്ടിരിക്കുന്നു", "checkuser-gblocked": "ആഗോളമായി തടയപ്പെട്ടിരിക്കുന്നു", "checkuser-locked": "പൂട്ടിയിരിക്കുന്നു", diff --git a/CheckUser/i18n/mr.json b/CheckUser/i18n/mr.json index 3fb4be43..2cf57397 100644 --- a/CheckUser/i18n/mr.json +++ b/CheckUser/i18n/mr.json @@ -10,7 +10,6 @@ }, "checkuser-summary": "हे उपकरण अलीकडील बदलांमधून एखाद्या सदस्याने वापरलेले अंकपत्ते किंवा एखाद्या अंकपत्त्याची संपादने/सदस्य दाखविते.\nक्लायंट अंकपत्त्यावरील सदस्य अथवा संपादने पाहण्यासाठी अंकपत्त्यानंतर \"/xff\" द्यावे लागेल.\nIPv4 (CIDR $1-32) आणि IPv6 (CIDR $2-128) वापरता येऊ शकेल.\nएका वेळी ५००० पेक्षा जास्त संपादने दाखविली जाणार नाहीत. हे उपकरण पॉलिसीच्या नियमांना धरून वापरावे.", "checkuser-desc": "सदस्याला इतर सदस्यांचे आंतरजाल अंकपत्ते (आयपी) तपासण्याची तसेच इतर माहिती पाहण्याची परवानगी देतो.", - "checkuser-logcase": "लॉगमधील शोध हा लिपीशी संबंधित (case-sensitive) आहे.", "checkuser": "सदस्य तपासा", "checkuserlog": "सदस्यतपास नोंदी", "checkuser-contribs": "सदस्याचा अंकपत्ता तपासा", @@ -40,7 +39,6 @@ "checkuser-nomatch-edits": "काहीच अनुरुपन सापडले नाही.\nशेवटले संपादन $2ला $1वर होते.", "checkuser-check": "पडताळा", "checkuser-log-fail": "लॉगमध्ये नोंद वाढविता आलेली नाही.", - "checkuser-nolog": "लॉग संचिका सापडलेली नाही.", "checkuser-blocked": "प्रतिबंधित", "checkuser-gblocked": "वैश्विकरित्या प्रतिबंधित", "checkuser-locked": "कुलुपबंद", diff --git a/CheckUser/i18n/mrh.json b/CheckUser/i18n/mrh.json index 9679c6f1..85cb3e7e 100644 --- a/CheckUser/i18n/mrh.json +++ b/CheckUser/i18n/mrh.json @@ -4,5 +4,6 @@ "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):" + "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-reset-action": "Hmâhtuhpa $1 châta bieruchâ sohpathi" } diff --git a/CheckUser/i18n/ms-arab.json b/CheckUser/i18n/ms-arab.json new file mode 100644 index 00000000..212598da --- /dev/null +++ b/CheckUser/i18n/ms-arab.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Tofeiku" + ] + }, + "checkuser-investigate-compare-table-button-contribs-label": "سومبڠن" +} diff --git a/CheckUser/i18n/ms.json b/CheckUser/i18n/ms.json index e765b8e4..ef693d0b 100644 --- a/CheckUser/i18n/ms.json +++ b/CheckUser/i18n/ms.json @@ -10,7 +10,6 @@ }, "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.", "checkuser-desc": "Melantik pengguna dengan keizinan untuk membongkar alamat IP pengguna tertentu berserta maklumat-maklumat sulit lain", - "checkuser-logcase": "Carian log ini sensitif huruf (mengambil kisah kecil besar huruf).", "checkuser": "Periksa pengguna", "checkuserlog": "Log pemeriksa", "checkuser-contribs": "periksa alamat IP pengguna", @@ -42,7 +41,6 @@ "checkuser-nomatch-edits": "Tiada padanan. Suntingan terakhir ialah pada $1, $2.", "checkuser-check": "Periksa", "checkuser-log-fail": "Daftar log tidak dapat ditambah", - "checkuser-nolog": "Fail log tiada.", "checkuser-blocked": "Disekat", "checkuser-gblocked": "Disekat secara sejagat", "checkuser-locked": "Dikunci", diff --git a/CheckUser/i18n/mt.json b/CheckUser/i18n/mt.json index e882b22d..c7bb773c 100644 --- a/CheckUser/i18n/mt.json +++ b/CheckUser/i18n/mt.json @@ -8,7 +8,6 @@ }, "checkuser-summary": "Din l-għodda tanalizza t-tibdil riċenti sabiex tikseb l-indirizzi IP użati minn utent jew turi modifiki u informazzjoni ta' indirizz IP. Utenti u modifiki minn indirizz IP ta' klijent jista' jinkiseb permezz ta' ''headers'' XFF billi iżżid is-suff \"/xff\" mal-IP. IPv4 (CIDR $1-32) and IPv6 (CIDR $2-128) huma sostnuti. Mhux iktar minn 5,000 modifika se jiġu ritornati lura għal raġunijiet ta' prestazzjoni. Uża din l-għodda skont il-politika.", "checkuser-desc": "Tagħti l-utenti bil-permess xieraq li jiċċekkjaw l-indirizzi IP u informazzjoni oħra tal-utenti", - "checkuser-logcase": "It-tfittxija fir-reġistru hija sensittiva għall-ittri kbar u żgħar.", "checkuser": "Iċċekkja l-utent", "checkuserlog": "Reġistru tal-kontrolli fuq l-utenti", "checkuser-contribs": "ikkontrolla l-indirizzi IP tal-utent", @@ -40,7 +39,6 @@ "checkuser-nomatch-edits": "L-ebda riżultat ma nstab.\nL-aħħar modifika saret fil-$1 fil-$2.", "checkuser-check": "Iċċekkja", "checkuser-log-fail": "Huwa impossibbli li tiġi miżjuda d-daħla fir-reġistru", - "checkuser-nolog": "L-ebda fajl ta' reġistru ma nstab.", "checkuser-blocked": "Imblukkat", "checkuser-gblocked": "Imblukkat globalment", "checkuser-locked": "Imsakkar", diff --git a/CheckUser/i18n/mwl.json b/CheckUser/i18n/mwl.json deleted file mode 100644 index 6b6d0be5..00000000 --- a/CheckUser/i18n/mwl.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "@metadata": { - "authors": [ - "MokaAkashiyaPT" - ] - }, - "checkuser-userlinks": "([[User_talk:$1|cumbersa]] | [[Special:Contributions/$1|cuntribuiçones]] | [[Special:Block/$1|bloquiar]])" -} diff --git a/CheckUser/i18n/nah.json b/CheckUser/i18n/nah.json index 9bc19b99..1443ff3d 100644 --- a/CheckUser/i18n/nah.json +++ b/CheckUser/i18n/nah.json @@ -3,10 +3,11 @@ "authors": [ "Akapochtli", "Fluence", + "Languaeditor", "Teòtlalili" ] }, "checkuser-reason": "Īxtlamatiliztli:", "checkuser-search": "Motemoz icalaquiyan CheckUser", - "checkuser-search-submit": "Tlatemoliztli" + "checkuser-search-submit": "Xiktemo" } diff --git a/CheckUser/i18n/nap.json b/CheckUser/i18n/nap.json deleted file mode 100644 index 2588419c..00000000 --- a/CheckUser/i18n/nap.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "@metadata": { - "authors": [ - "Ruthven" - ] - }, - "checkuser-search": "Ascia" -} diff --git a/CheckUser/i18n/nb.json b/CheckUser/i18n/nb.json index e23a0e85..da4949c6 100644 --- a/CheckUser/i18n/nb.json +++ b/CheckUser/i18n/nb.json @@ -3,6 +3,7 @@ "authors": [ "Audun", "Danmichaelo", + "EdoAug", "Finnrind", "Jon Harald Søby", "Laaknor", @@ -10,9 +11,8 @@ "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.", + "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 $3 {{PLURAL:$3|redigering|redigeringer}}. Bruk dette verktøyet i samsvar med retningslinjene.", "checkuser-desc": "Gir brukere med de tilhørende rettighetene muligheten til å sjekke brukeres IP-adresser og annen informasjon", - "checkuser-logcase": "Loggsøket er sensitivt for store/små bokstaver.", "checkuser": "Brukersjekk", "checkuserlog": "Brukersjekkingslogg", "checkuser-contribs": "kontroller brukerens IP-adresser", @@ -36,17 +36,21 @@ "checkuser-week-1": "forrige uke", "checkuser-week-2": "siste to uker", "checkuser-month": "siste måned", + "checkuser-month-2": "de siste 60 dagene", "checkuser-all": "alle", "checkuser-cidr-label": "Finn felles adresseområde og påvirkede adresser for en liste over IP-adresser", "checkuser-cidr-res": "Felles CIDR:", + "checkuser-cidr-affected-ips": "Påvirkede IP-adresser:", + "checkuser-cidr-too-small": "Intervallet er for stort", + "checkuser-range-outside-limit": "Intervallet $1 er utenfor de tillatte grensene.", "checkuser-empty": "Loggen inneholder ingen elementer.", "checkuser-nomatch": "Ingen treff.", "checkuser-nomatch-edits": "Ingen treff.\nSiste redigering var $2 $1.", "checkuser-check": "Sjekk", "checkuser-check-this-user": "Kontroller denne brukeren", + "checkuser-investigate-this-user": "Undersøk denne brukeren", "checkuser-recent-checks": "Nylige kontroller av denne brukeren", "checkuser-log-fail": "Kunne ikke legge til loggelement.", - "checkuser-nolog": "Ingen loggfil funnet.", "checkuser-blocked": "Blokkert", "checkuser-gblocked": "Blokkert globalt", "checkuser-locked": "Låst", @@ -68,6 +72,7 @@ "checkuser-noreason": "Du må oppgi en grunn for denne spørringen.", "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-target-nonexistent": "Det gitte målet finnes ikke.", "checkuser-search": "Søk i IP-kontroll-loggoppføringer", "checkuser-search-submit": "Søk", "checkuser-search-initiator": "IP-kontrolløren", @@ -76,6 +81,7 @@ "checkuser-log-search-type": "Søk etter:", "checkuser-ipeditcount": "~$1 fra alle brukere", "checkuser-showmain": "Gå til hovedskjemaet for CheckUser", + "checkuser-show-investigate": "Bytt til hovedskjema for undersøkelse", "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 <bdi>$2</bdi>", @@ -83,10 +89,11 @@ "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-log-entry-investigate": "$3, $1 sjekket informasjon for $2", "checkuser-autocreate-action": "ble automatisk opprettet", "checkuser-create-action": "ble opprettet", "checkuser-email-action": "sendte e-post til «$1»", - "checkuser-reset-action": "nullstilte passord for «$1»", + "checkuser-reset-action": "nullstilte passord for brukeren $1", "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", @@ -111,10 +118,6 @@ "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", @@ -127,7 +130,7 @@ "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-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", @@ -151,6 +154,7 @@ "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-copy-button-label-hide": "Skjul 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.", @@ -163,7 +167,7 @@ "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-edits": "<b>[$1 {{PLURAL:$1|redigering/handling|redigeringer/handlinger}}]</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", diff --git a/CheckUser/i18n/nds-nl.json b/CheckUser/i18n/nds-nl.json index a0bd19e7..ebe259ec 100644 --- a/CheckUser/i18n/nds-nl.json +++ b/CheckUser/i18n/nds-nl.json @@ -6,12 +6,11 @@ }, "checkuser-summary": "Dit hulpmiddel bekik de leste wiezigingen um IP-adressen weerumme te haolen die gebruukt bin deur n gebruker of gif de bewarkings-/gebrukersgegevens weer veur n IP-adres. Gebrukers en bewarkingen kunnen weerummehaold wörden mit n XFF-IP deur \"/xff\" an t IP-adres toe te voegen. IPv4 (CIDR $1-32) en IPv6 (CIDR $2-128) wörden ondersteund. Wie laoten niet meer as 5.000 bewarkingen zien vanwegen prestasieredens. Gebruuk dit in overeenstemming mit t beleid.", "checkuser-desc": "Laot gebrukers mit de beneudigen rechten IP-adressen en aandere informasie van gebrukers achterhaolen.", - "checkuser-logcase": "De zeukfunksie van t logboek is heufdlettergeveulig", "checkuser": "Gebruker naokieken", "checkuserlog": "Logboek gebrukersscheumers", "group-checkuser": "gebrukers nåkyken", - "group-checkuser-member": "{{GENDER:$1|gebrukerkontrolöör}}", - "grouppage-checkuser": "{{ns:project}}:Gebrukerkontrolöör", + "group-checkuser-member": "{{GENDER:$1|gebrukerskontrolöör}}", + "grouppage-checkuser": "{{ns:project}}:Gebrukerskontrolöör", "checkuser-reason": "Reden:", "checkuser-showlog": "Logboek bekieken", "checkuser-query": "Zeukopdrachte leste wiezigingen", @@ -23,7 +22,6 @@ "checkuser-nomatch": "Gien overeenkomsten evunnen.", "checkuser-check": "Naokieken", "checkuser-log-fail": "Kon gien logboekantekeningen maken", - "checkuser-nolog": "Gien logboek evunnen.", "checkuser-blocked": "Eblokkeerd", "checkuser-too-many": "Te veule resultaoten (volgens de schatting). Maakt de IP-reeks kleinder:\nHieronder staon de gebruken IP-aderssen (maximaal 5.000, op IP-adres ekontroleerd):", "checkuser-user-nonexistent": "De op-egeven gebruker besteet niet.", diff --git a/CheckUser/i18n/nds.json b/CheckUser/i18n/nds.json index 35392bba..fe7b7ac3 100644 --- a/CheckUser/i18n/nds.json +++ b/CheckUser/i18n/nds.json @@ -7,7 +7,6 @@ }, "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.", "checkuser-desc": "Verlöövt Brukers mit de nödigen Rechten, de IP-Adressen un annere Infos vun Brukers natokieken", - "checkuser-logcase": "De Logbook-Söök maakt en Ünnerscheed twischen grote un lütte Bookstaven.", "checkuser": "Bruker nakieken", "checkuserlog": "Checkuser-Logbook", "checkuser-contribs": "IP-Adressen vun Bruker prüfen", @@ -35,7 +34,6 @@ "checkuser-nomatch-edits": "Nix funnen.\nLest Ännern weer an’n $1 üm $2.", "checkuser-check": "Los", "checkuser-log-fail": "Kunn keen Logbook-Indrag tofögen", - "checkuser-nolog": "Keen Loogbook funnen.", "checkuser-blocked": "Sperrt", "checkuser-gblocked": "global sperrt", "checkuser-locked": "slaten", diff --git a/CheckUser/i18n/ne.json b/CheckUser/i18n/ne.json index e6b47836..7d02c17a 100644 --- a/CheckUser/i18n/ne.json +++ b/CheckUser/i18n/ne.json @@ -1,16 +1,18 @@ { "@metadata": { "authors": [ + "Bada Kaji", "Bhawani Gautam", "Bhawani Gautam Rhk", "NehalDaveND", "Nirajan pant", "पर्वत सुबेदी", + "बडा काजी", "बिप्लब आनन्द" ] }, "checkuser": "प्रयोगकर्ता जाँच", - "checkuserlog": "प्रयोगकर्ता जाँच लग", + "checkuserlog": "प्रयोगकर्ता जाँच अभिलेख", "checkuser-contribs": "प्रयोगकर्ताको आइपी ठेगानाहरू जाँच्ने", "checkuser-contribs-log": "हालैका प्रयोगकर्ता जाँचहरू", "group-checkuser": "प्रयोगकर्ताहरू जाँच्ने", @@ -40,14 +42,14 @@ "checkuser-nomatch-edits": "खोजिएको परिणाम भेटिएन।\nअन्तिम सम्पादन $1 मा $2।", "checkuser-check": "जाँच्ने", "checkuser-log-fail": "लग इन्ट्री जोड्न असफल", - "checkuser-nolog": "कुनै लग फाइल भेटिएन।", "checkuser-blocked": "निषेधित", - "checkuser-gblocked": "वैश्विक निषेधित", + "checkuser-gblocked": "विश्वव्यापी निषेधित", "checkuser-locked": "प्रतिबन्धित", "checkuser-wasblocked": "पछिल्लो निषेधित", "checkuser-localonly": "एकीकृत छैन", - "checkuser-search": "खोज्ने", - "checkuser-search-submit": "खोज", + "checkuser-search": "खोज्नुहोस्", + "checkuser-search-submit": "खोज्नुहोस्", + "checkuser-investigate-subtitle-cancel-button-label": "रद्द गर्नुहोस्", "checkuser-investigate-notice-no-results": "कुनैपनि नतिजाहरू भेटिएनन्", "checkuser-investigate-tab-compare": "आइपी तथा प्रयोगकर्ता एजेन्टहरू", "checkuser-investigate-tab-timeline": "समयरेखा", diff --git a/CheckUser/i18n/nl.json b/CheckUser/i18n/nl.json index 6965ed26..3a5250ca 100644 --- a/CheckUser/i18n/nl.json +++ b/CheckUser/i18n/nl.json @@ -2,25 +2,30 @@ "@metadata": { "authors": [ "Akoopal", + "Aranka", "Dutchy45", "Elroy", "Erwin", "Mainframe98", + "McDutchie", "Nieuwsgierige Gebruiker", "PonkoSasuke", "SPQRobin", "Siebrand", "Sjoerddebruin", - "Troefkaart" + "Trijnstel", + "Troefkaart", + "Vistaus", + "Xbaked potatox" ] }, - "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.", + "checkuser-summary": "Dit hulpmiddel doorzoekt de recente wijzigingen om de IP-adressen van een gebruiker te achterhalen, of om voor een IP-adres de bewerkings- en gebruikersgegegevens weer te geven.\nDe met een bepaald IP-adres in verband staande gebruikers en bewerkingen kunnen via XFF-headers achterhaald worden door \"/xff\" achter het IP-adres toe te voegen. Daarbij worden zowel IPv4 (CIDR $1-32) als IPv6 (CIDR $2-128) ondersteund.\nOm prestatieredenen worden niet meer dan $3 bewerkingen weergegeven.\nGebruik dit hulpmiddel alleen in overeenstemming met het vastgestelde beleid.", "checkuser-desc": "Laat bevoegde gebruikers IP-adressen en andere gegevens van gebruikers achterhalen", - "checkuser-logcase": "Zoeken in het logboek is hoofdlettergevoelig.", "checkuser": "Gebruiker controleren", "checkuserlog": "Logboek controleren gebruikers", "checkuser-contribs": "IP-adressen van gebruiker controleren", "checkuser-contribs-log": "recente gebruikerscontroles", + "checkuser-contribs-log-initiator": "uitgevoerde gebruikerscontroles door deze gebruiker", "group-checkuser": "controlegebruikers", "group-checkuser-member": "{{GENDER:$1|controlegebruiker}}", "right-checkuser": "IP-adressen en andere gegevens van gebruikers bekijken", @@ -37,20 +42,23 @@ "checkuser-edits": "Bewerkingen opvragen", "checkuser-ips": "IP-adressen opvragen", "checkuser-period": "Duur:", - "checkuser-week-1": "laatste week", - "checkuser-week-2": "laatste twee weken", + "checkuser-week-1": "afgelopen week", + "checkuser-week-2": "afgelopen twee weken", "checkuser-month": "laatste 30 dagen", + "checkuser-month-2": "laatste 60 dagen", "checkuser-all": "alle", "checkuser-cidr-label": "Gemeenschappelijke range en getroffen adressen zoeken uit een lijst van IP-adressen", "checkuser-cidr-res": "Gemeenschappelijke CIDR:", + "checkuser-cidr-affected-ips": "Getroffen IP-adressen:", + "checkuser-cidr-too-small": "Bereik is te groot", "checkuser-empty": "Het logboek bevat geen regels.", "checkuser-nomatch": "Geen overeenkomsten gevonden.", "checkuser-nomatch-edits": "Niets gevonden.\nDe laatste bewerking was op $1 om $2.", "checkuser-check": "Controleren", "checkuser-check-this-user": "Deze gebruiker controleren", + "checkuser-investigate-this-user": "Deze gebruiker onderzoeken", "checkuser-recent-checks": "Recente controles voor deze gebruiker", "checkuser-log-fail": "Logboekregel toevoegen niet mogelijk", - "checkuser-nolog": "Geen logboek gevonden.", "checkuser-blocked": "Geblokkeerd", "checkuser-gblocked": "Globaal geblokkeerd", "checkuser-locked": "Afgesloten", @@ -62,6 +70,7 @@ "checkuser-blocktalk": "Voorkomen dat deze gebruiker tijdens de blokkade de eigen overlegpagina kan bewerken", "checkuser-blocktag": "Gebruikerspagina's vervangen door:", "checkuser-blocktag-talk": "Overlegpagina's vervangen door:", + "checkuser-reblock": "Bestaande blokkeringen overschrijven", "checkuser-massblock-commit": "Geselecteerde gebruikers blokkeren", "checkuser-block-success": "'''De {{PLURAL:$2|gebruiker|gebruikers}} $1 {{PLURAL:$2|is|zijn}} geblokkeerd.'''", "checkuser-block-failure": "'''Geen gebruikers geblokkeerd.'''", @@ -79,6 +88,7 @@ "checkuser-log-search-type": "Zoeken op:", "checkuser-ipeditcount": "~$1 van alle gebruikers", "checkuser-showmain": "Naar het hoofdformulier van GebruikerControleren gaan", + "checkuser-show-investigate": "Overschakelen naar hoofdformulier Onderzoeken", "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 <bdi>$2</bdi>", @@ -86,26 +96,45 @@ "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-log-entry-investigate": "$3, $1 zocht informatie op over $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-reset-action": "heeft het wachtwoord voor gebruiker $1 opnieuw ingesteld", "checkuser-token-fail": "Sessie is mislukt. Probeer het opnieuw.", "checkuser-login-failure": "Kon niet als $1 inloggen op {{SITENAME}}", "checkuser-login-success": "Succesvol als $1 op {{SITENAME}} ingelogd", + "checkuser-investigateblock": "Gebruikers blokkeren", "checkuser-investigateblock-target": "Gebruikersnaam en IP-adressen", + "checkuser-investigateblock-actions": "Te blokkeren handelingen", + "checkuser-investigateblock-reason": "Reden", "checkuser-investigateblock-options": "Verdere opties", + "checkuser-investigateblock-email-label": "Weerhouden van het versturen van e-mail", + "checkuser-investigateblock-usertalk-label": "Voorkomen dat de eigen overlegpagina tijdens de blokkade bewerkt kan worden", + "checkuser-investigateblock-reblock-label": "Bestaande blokkeringen overschrijven", + "checkuser-investigateblock-notice-user-page-label": "Een bericht op de gebruikerspagina achterlaten", + "checkuser-investigateblock-notice-talk-page-label": "Een bericht op de overlegpagina achterlaten", "checkuser-investigateblock-notice-position-label": "Positie", "checkuser-investigateblock-notice-text-label": "Wikitext", + "checkuser-investigateblock-notice-append": "Aan de pagina toevoegen", + "checkuser-investigateblock-notice-prepend": "Aan het begin van de pagina toevoegen", "checkuser-investigateblock-notice-replace": "Vervang pagina", + "checkuser-investigateblock-failure": "Geen gebruikers geblokkeerd. Om bestaande blokkades te overschrijven, vink: \"{{int:checkuser-investigateblock-reblock-label}}\" aan. Een blokkade wordt niet overschreven als de nieuwe blokkade gelijk is aan de oude.", + "checkuser-investigateblock-success": "De {{PLURAL:$2|gebruiker|gebruikers}} $1 {{PLURAL:$2|is|zijn}} nu geblokkeerd.", + "checkuser-investigateblock-notices-failed": "Sommige berichten konden niet toegevoegd worden aan gebruikers- of overlegpagina's.", "checkuser-investigate": "Onderzoeken", + "checkuser-investigate-page-subtitle": "Lopend onderzoek voor $1", "checkuser-investigate-subtitle-block-button-label": "Blokkeren", + "checkuser-investigate-subtitle-cancel-button-label": "Annuleren", + "checkuser-investigate-subtitle-continue-button-label": "Doorgaan", + "checkuser-investigate-indicator-new-investigation": "Nieuw onderzoek", "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-preliminary-check": "Accountgegevens", + "checkuser-investigate-tab-compare": "IP's & User agents", "checkuser-investigate-tab-timeline": "Tijdlijn", - "checkuser-investigate-targets-label": "Gebruikersnaam of IP-adres", + "checkuser-investigate-targets-label": "Gebruikersnamen en IP-adressen:", "checkuser-investigate-targets-placeholder": "Gebruikersnaam of 1.1.1.1", "checkuser-investigate-duration-label": "Duur", "checkuser-investigate-duration-option-all": "Alle", @@ -113,6 +142,7 @@ "checkuser-investigate-duration-option-2w": "Afgelopen twee weken", "checkuser-investigate-duration-option-30d": "Laatste 30 dagen", "checkuser-investigate-reason-label": "Reden", + "checkuser-investigate-preliminary-notice-ip-targets": "De accountgegevenstab bevat geen informatie over IP-adressen.\nZie de <span class=\"plainlinks\">[$1 tab IP's & User agents]</span> voor deze gegevens.", "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", @@ -123,11 +153,26 @@ "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-filters-legend": "Filters", + "checkuser-investigate-filters-exclude-targets-label": "De volgende gebruikers of IP's verbergen", + "checkuser-investigate-timeline-notice-no-results": "Er zijn geen resultaten: deze gebruikers of IP-adressen hebben de afgelopen 90 dagen geen veranderingen doorgevoerd", + "checkuser-investigate-compare-copy-button-label": "Toon wikitekst", + "checkuser-investigate-compare-toollinks-ipcheck": "Proxycontrole", + "checkuser-investigate-compare-copy-message-label": "Wil je deze informatie kopiëren als een Wikitekst-tabel?", "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-button-add-ip-targets-label": "Alle IP's van deze gebruiker tonen", + "checkuser-investigate-compare-table-button-add-user-targets-label": "Alle gebruikers op dit IP tonen", + "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Dit IP aan het onderzoek toevoegen", + "checkuser-investigate-compare-table-button-checks-label": "Controles", + "checkuser-investigate-compare-table-button-contribs-label": "Bijdragen", + "checkuser-investigate-compare-table-button-filter-label": "Filter de resultaten", "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-edits": "<b>[$1 {{PLURAL:$1|bewerking/handeling|bewerkingen/handelingen}}]</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" + "checkuser-investigate-compare-table-header-activity": "Periode", + "checkuser-investigate-compare-table-header-ip": "IP-adres", + "checkuser-investigate-compare-table-header-useragent": "User agent", + "checkuser-investigate-subtitle-link-restart-tour": "Herstart toer" } diff --git a/CheckUser/i18n/nn.json b/CheckUser/i18n/nn.json index e579c409..997ad52e 100644 --- a/CheckUser/i18n/nn.json +++ b/CheckUser/i18n/nn.json @@ -9,7 +9,6 @@ }, "checkuser-summary": "Dette verktøyet går gjennom siste endringar for å henta IP-ane som er nytta av ein brukar, eller syner endrings- eller brukarinformasjon for ein IP.\n\nBrukarar og endringar frå ein klient-IP kan verta henta gjennom XFF ved å leggja til «/xff» bak IP-en. IPv4 (CIDR $1-32) og IPv6 (CIDR $2-128) er støtta.\n\nAv yteårsaker vert høgst 5000 endringar viste.\nNytt dette verktøyet i samsvar med retningsliner.", "checkuser-desc": "Gjev brukarar med dei rette rettane moglegheita til å sjekka IP-adressene til og annan informasjon om brukarar.", - "checkuser-logcase": "Loggsøket tek omsyn til små og store bokstavar.", "checkuser": "Brukarsjekk", "checkuserlog": "Logg over brukarkontrollering", "checkuser-contribs": "finn brukaren sine IP-adresser", @@ -41,7 +40,6 @@ "checkuser-nomatch-edits": "Ingen treff.\nSiste endringar skjedde $1 $2.", "checkuser-check": "Sjekk", "checkuser-log-fail": "Kunne ikkje leggja til loggelement.", - "checkuser-nolog": "Fann inga loggfil.", "checkuser-blocked": "Blokkert", "checkuser-gblocked": "Blokkert globalt", "checkuser-locked": "Låst", diff --git a/CheckUser/i18n/nqo.json b/CheckUser/i18n/nqo.json new file mode 100644 index 00000000..905b06b8 --- /dev/null +++ b/CheckUser/i18n/nqo.json @@ -0,0 +1,12 @@ +{ + "@metadata": { + "authors": [ + "Aboubacar.banamoridou.toure", + "Lancine.kounfantoh.fofana" + ] + }, + "checkuser-month-2": "ߞߐߟߊ߫ ߕߟߋ߫ ߆߀ ߟߎ߫", + "checkuser-investigate-this-user": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߌ߬ߟߊ ߣߌ߲߬ ߢߊߢߌߣߌ߲߫", + "checkuser-log-checks-on": "ߝߛߍ߬ߝߛߍ߬ ߘߊ߫", + "checkuser-show-investigate": "ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߫ ߞߊ߬ ߢߊߢߌߣߌ߲ߠߌ߲ ߠߊߕߊ߯ ߦߌ߬ߘߊ߬ߥߟߊ ߓߊߖߎߡߊ ߘߐ߫" +} diff --git a/CheckUser/i18n/oc.json b/CheckUser/i18n/oc.json index 7e51baf3..2f62b92a 100644 --- a/CheckUser/i18n/oc.json +++ b/CheckUser/i18n/oc.json @@ -8,7 +8,6 @@ }, "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.", "checkuser-desc": "Balha la possibilitat a las personas exprèssament autorizadas de verificar las adreças IP dels utilizaires e mai d’autras entresenhas los concernent", - "checkuser-logcase": "La recèrca dins lo Jornal es sensibla a la cassa.", "checkuser": "Verificator d’utilizaire", "checkuserlog": "Notacion de Verificator d'utilizaire", "checkuser-contribs": "verificar las adreças IP", @@ -37,7 +36,6 @@ "checkuser-nomatch-edits": "Cap d'ocurréncia pas trobada.\nLa darrièra modificacion èra lo $1 a $2.", "checkuser-check": "Recèrca", "checkuser-log-fail": "Impossible d'apondre l'entrada del jornal.", - "checkuser-nolog": "Cap de fichièr jornal pas trobat.", "checkuser-blocked": "Blocat", "checkuser-gblocked": "Globalament blocat", "checkuser-locked": "Verrolhat", diff --git a/CheckUser/i18n/or.json b/CheckUser/i18n/or.json index f10f6eb8..cda44bc9 100644 --- a/CheckUser/i18n/or.json +++ b/CheckUser/i18n/or.json @@ -39,7 +39,6 @@ "checkuser-nomatch-edits": "କିଛି ବି ମେଳ ଖାଇଲା ନାହିଁ ।\nଶେଷ ବଦଳଟି $1 ଦିନ $2 ବେଳେ ହୋଇଥିଲା ।", "checkuser-check": "ଯାଞ୍ଚ କରିବା", "checkuser-log-fail": "ଇତିହାସ ନିବେଶ କରିବାକୁ ଅକ୍ଷମ", - "checkuser-nolog": "ଇତିହାସ ଫାଇଲ ମିଳିଲା ନାହିଁ ।", "checkuser-blocked": "ଅଟକାଯାଇଥିବା", "checkuser-gblocked": "ଜଗତସାରା ଅଟକାଯାଇଛି", "checkuser-locked": "କିଳାଯାଇଅଛି", diff --git a/CheckUser/i18n/pl.json b/CheckUser/i18n/pl.json index 4dcd4c19..efe17743 100644 --- a/CheckUser/i18n/pl.json +++ b/CheckUser/i18n/pl.json @@ -10,6 +10,7 @@ "Krottyianock", "Leinad", "Matma Rex", + "Msz2001", "Rail", "Railfail536", "Saper", @@ -20,18 +21,18 @@ "Zero" ] }, - "checkuser-summary": "Narzędzie pozwala na ustalenie adresów IP, z których\nkorzystał użytkownik lub pokazać edycje i nazwy użytkowników edytujących z zadanego adresu IP.\n\nDodając parameter \"/xff\" do adresu IP można odnaleźć użytkowników i edycje przeszukując zapisane nagłówki XFF (X-Forwarded-For).\n\nObsługiwane są zakresy adresów IPv4 (maska CIDR $1-32) i IPv6 (CIDR $2-128).\n\nNarzędzie ze względów wydajnościowych pokazuje co najwyżej 5000 edycji.\n\nPamiętaj o korzystaniu z narzędzia zgodnie z zasadami.", + "checkuser-summary": "Narzędzie pozwala na ustalenie adresów IP, z których\nkorzystał użytkownik lub pokazać edycje i nazwy użytkowników edytujących z zadanego adresu IP.\n\nDodając parametr „/xff” do adresu IP można odnaleźć użytkowników i edycje przeszukując zapisane nagłówki XFF (X-Forwarded-For).\n\nObsługiwane są zakresy adresów IPv4 (maska CIDR $1-32) i IPv6 (CIDR $2-128).\n\nNarzędzie ze względu na wydajność pokazuje maksymalnie {{formatnum:$3}} {{PLURAL:$3|edycję|edycje|edycji}}.\n\nPamiętaj o korzystaniu z narzędzia zgodnie z zasadami.", "checkuser-desc": "Umożliwia uprawnionym użytkownikom sprawdzenie adresów IP użytkowników oraz innych informacji", - "checkuser-logcase": "Podczas przeszukiwania rejestru rozróżniane są małe/wielkie litery", "checkuser": "Sprawdź IP użytkownika", "checkuserlog": "Rejestr sprawdzeń CheckUser", "checkuser-contribs": "sprawdź adresy IP", "checkuser-contribs-log": "rejestr sprawdzeń checkuser", + "checkuser-contribs-log-initiator": "sprawdzenia użytkowników wykonane przez tego użytkownika", "group-checkuser": "Checkuserzy", "group-checkuser-member": "{{GENDER:$1|checkuser|checkuserka}}", "right-checkuser": "Sprawdzanie adresów IP oraz innych informacji o użytkownikach", "right-checkuser-log": "Przeglądanie rejestru checkuser", - "action-checkuser": "sprawdzania adresów IP uzytkowników i innych informacji", + "action-checkuser": "sprawdzania adresów IP użytkowników i innych informacji", "action-checkuser-log": "przeglądania rejestru checkuser", "grouppage-checkuser": "{{ns:project}}:Checkuser", "checkuser-reason": "Powód", @@ -46,17 +47,23 @@ "checkuser-week-1": "ostatni tydzień", "checkuser-week-2": "ostatnie dwa tygodnie", "checkuser-month": "ostatnie 30 dni", + "checkuser-month-2": "ostatnie 60 dni", "checkuser-all": "wszystkie", "checkuser-cidr-label": "Znajdź wspólny zakres i wpływ na adresy IP z listy", "checkuser-cidr-res": "Wspólny CIDR:", + "checkuser-cidr-affected-ips": "Liczba adresów:", + "checkuser-cidr-too-small": "Zakres jest za duży", + "checkuser-range-outside-limit": "Zakres $1 jest poza dozwolonymi limitami.", "checkuser-empty": "Rejestr nie zawiera żadnych wpisów.", "checkuser-nomatch": "Brak wyników.", "checkuser-nomatch-edits": "Brak wyników.\nOstatnia edycja została wykonana $1 o $2.", "checkuser-check": "sprawdź", "checkuser-check-this-user": "Sprawdź tego użytkownika", + "checkuser-investigate-this-user": "Sprawdź tego użytkownika", "checkuser-recent-checks": "Ostatnie sprawdzenia dla tego użytkownika", "checkuser-log-fail": "Nie udało się dodać wpisu do rejestru", - "checkuser-nolog": "Nie znaleziono pliku rejestru.", + "checkuser-log-checks-by": "sprawdzone adresy IP", + "checkuser-log-checks-on": "sprawdzenia adresów IP", "checkuser-blocked": "Zablokowany", "checkuser-gblocked": "Zablokowany globalnie", "checkuser-locked": "Zablokowany", @@ -75,17 +82,22 @@ "checkuser-block-limit": "Wybrano zbyt wielu użytkowników.", "checkuser-block-noreason": "Należy podać powód blokad.", "checkuser-centralauth-multilock": "Zablokuj wybrane konta", + "checkuser-centralauth-multilock-list": "Multizablokuj wybrane konta za pomocą linków:", "checkuser-noreason": "Musisz podać powód wykonania zapytania.", "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-target-nonexistent": "Podany obiekt sprawdzenia nie istnieje.", + "checkuser-initiator-nonexistent": "Podany sprawdzający nie istnieje.", "checkuser-search": "Szukaj w rejestrze checkuserów", "checkuser-search-submit": "Szukaj", "checkuser-search-initiator": "sprawdzającym", "checkuser-search-target": "sprawdzanym", "checkuser-log-search-target": "Cel:", + "checkuser-log-search-initiator": "Sprawdzający:", "checkuser-log-search-type": "Szukaj według:", "checkuser-ipeditcount": "~$1 od wszystkich użytkowników", "checkuser-showmain": "Przejdź do głównego formularza CheckUser", + "checkuser-show-investigate": "Przejdź do głównego formularza sprawdzania", "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 <bdi>$2</bdi>", @@ -93,13 +105,17 @@ "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-log-entry-investigate": "$3, $1 sprawdził(a) informacje o $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-reset-action": "reset hasła dla {{GENDER:$1|użytkownika|użytkowniczki}} „$1”", "checkuser-token-fail": "Awaria sesji. Spróbuj jeszcze raz.", "checkuser-login-failure": "Logowanie do {{GRAMMAR:D.lp|{{SITENAME}}}} jako $1 nie powiodło się", + "checkuser-login-failure-with-good-password": "Nie udało się zalogować do {{GRAMMAR:D.lp|{{SITENAME}}}} jako $1 mimo posiadania poprawnego hasła", "checkuser-login-success": "Pomyślnie zalogowano do {{GRAMMAR:D.lp|{{SITENAME}}}} jako $1", + "group-checkuser.css": "/* Umieszczony tutaj kod CSS dotyczyć będzie tylko checkuserów */", + "group-checkuser.js": "/* Umieszczony tutaj kod JS dotyczyć będzie tylko checkuserów */", "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", @@ -119,15 +135,12 @@ "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-subtitle-show-checkuser": "Przejdź do CheckUser", "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", @@ -135,9 +148,9 @@ "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-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-label": "Okres", "checkuser-investigate-duration-option-all": "Wszystko", "checkuser-investigate-duration-option-1w": "Ostatni tydzień", "checkuser-investigate-duration-option-2w": "Ostatnie dwa tygodnie", @@ -157,13 +170,14 @@ "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-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-copy-button-label-hide": "Ukryj 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-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-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", @@ -171,7 +185,7 @@ "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-edits": "<b>[$1 {{PLURAL:$1|edycja/akcja|edycje/akcje|edycji/akcji}}]</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", @@ -181,13 +195,13 @@ "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-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-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-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-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 f47b1a75..60c430d4 100644 --- a/CheckUser/i18n/pms.json +++ b/CheckUser/i18n/pms.json @@ -8,7 +8,6 @@ }, "checkuser-summary": "St'utiss-sì as passa j'ùltime modìfiche për tiré sù j'adrësse IP dovra da n'utent ò pura mostré lòn ch'as fa da n'adrëssa IP e che dat utent ch'a l'abia associà.\n\tJ'utent ch'a deuvro n'adrëssa IP e le modìfiche faite d'ambelelì as peulo tiresse sù ën dovrand j'antestassion XFF, për felo tache-ie dapress l'adrëssa e \"/xff\". A marcia tant con la forma IPv4 (CIDR $1-32) che con cola IPv6 (CIDR $2-128).\n\tPër na question ëd caria ëd travaj a tira nen sù pì che 5000 modìfiche. A va dovrà conforma ai deuit për ël process ëd contròl.", "checkuser-desc": "A dà a j'utent con ij përmess aproprià la possibilità ëd controlé j'adrësse IP dj'utent e àutre anformassion", - "checkuser-logcase": "L'arsërca ant ël registr a conta ëdcò maiùscole e minùscole.", "checkuser": "Contròl dj'utent", "checkuserlog": "Registr dël contròl dj'utent", "checkuser-contribs": "contròla l'adrëssa IP ëd l'utent", @@ -40,7 +39,6 @@ "checkuser-nomatch-edits": "Gnun arzultà trovà.\nL'ùltima modìfica a l'era ël $1 a $2.", "checkuser-check": "Contròl", "checkuser-log-fail": "I-i la fom nen a gionte-ie na riga ant sël registr", - "checkuser-nolog": "Pa gnun registr ch'a sia trovasse.", "checkuser-blocked": "Blocà", "checkuser-gblocked": "Blocà globalment", "checkuser-locked": "Sarà", diff --git a/CheckUser/i18n/pnb.json b/CheckUser/i18n/pnb.json new file mode 100644 index 00000000..3cf1bccd --- /dev/null +++ b/CheckUser/i18n/pnb.json @@ -0,0 +1,15 @@ +{ + "@metadata": { + "authors": [ + "Abbas dhothar" + ] + }, + "group-checkuser": "توثیق شدہ ورتنوالے", + "checkuser-reason": "وجہ:", + "checkuser-month": "پچھلے 30 دن", + "checkuser-investigateblock-notice-replace": "بدلے صفحے", + "checkuser-investigate-subtitle-cancel-button-label": "رد کرو", + "checkuser-investigate-duration-option-30d": "پچھلے 30 دن", + "checkuser-investigate-compare-table-button-contribs-label": "شراکتاں", + "checkuser-investigate-compare-table-cell-unregistered": "غیر رجسٹرڈ" +} diff --git a/CheckUser/i18n/ps.json b/CheckUser/i18n/ps.json index 6c98ffa0..90eb2efe 100644 --- a/CheckUser/i18n/ps.json +++ b/CheckUser/i18n/ps.json @@ -21,7 +21,6 @@ "checkuser-month": "تېرې ۳۰ ورځې", "checkuser-all": "ټول", "checkuser-check": "کره کتل", - "checkuser-nolog": "يادښت دوتنه و نه موندل شوه.", "checkuser-blocked": "بنديز لگېدلی", "checkuser-gblocked": "نړېواله بنديز لگېدلی", "checkuser-locked": "تړل شوی", diff --git a/CheckUser/i18n/pt-br.json b/CheckUser/i18n/pt-br.json index decc58b4..ae828805 100644 --- a/CheckUser/i18n/pt-br.json +++ b/CheckUser/i18n/pt-br.json @@ -1,14 +1,17 @@ { "@metadata": { "authors": [ + "Albertoleoncio", "Amgauna", "Ankry", "Araceletorres", "Cainamarques", "Chaduvari", "Dicionarista", + "Duke of Wikipädia", "Eduardo Addad de Oliveira", "Eduardo.mps", + "Eduardoaddad", "Felipe L. Ewald", "Giro720", "He7d3r", @@ -23,12 +26,12 @@ "Pedroca cerebral", "RadiX", "Rodrigo codignoli", + "YuriNikolai", 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.", + "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 $3 edições por motivos de desempenho. O uso desta ferramenta deverá estar de acordo com as políticas.", "checkuser-desc": "Concede a usuários com a permissão apropriada a possibilidade de verificar os endereços IP de um usuário e outras informações", - "checkuser-logcase": "As buscas nos registros são sensíveis a letras maiúsculas ou minúsculas.", "checkuser": "Verificar usuário", "checkuserlog": "Registros de verificação de usuários", "checkuser-contribs": "verificar IPs do usuário", @@ -60,12 +63,12 @@ "checkuser-nomatch-edits": "Nenhum resultado encontrado.\nA última edição foi em $1 às $2.", "checkuser-check": "Verificar", "checkuser-check-this-user": "Verificar este usuário", + "checkuser-investigate-this-user": "Investigar esse usuário", "checkuser-recent-checks": "Verificações recentes para este usuário", "checkuser-log-fail": "Não foi possível adicionar entradas ao registro", - "checkuser-nolog": "Não foi encontrado um arquivo de registros.", "checkuser-blocked": "Bloqueado", "checkuser-gblocked": "Bloqueado globalmente", - "checkuser-locked": "bloqueada", + "checkuser-locked": "Travado", "checkuser-wasblocked": "Previamente bloqueado", "checkuser-localonly": "Não unificada", "checkuser-massblock": "Bloquear usuários selecionados", @@ -92,6 +95,7 @@ "checkuser-log-search-type": "Pesquisa para:", "checkuser-ipeditcount": "~$1 de todos os usuários", "checkuser-showmain": "Retornar ao formulário principal de CheckUser", + "checkuser-show-investigate": "Mudar para o formulário principal de investigação", "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 <bdi>$2</bdi>", @@ -99,10 +103,11 @@ "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-log-entry-investigate": "$3, $1 procurou informações de $2", "checkuser-autocreate-action": "foi automaticamente criada", "checkuser-create-action": "foi criada", "checkuser-email-action": "enviou email para o(a) usuário(a) \"$1\"", - "checkuser-reset-action": "suprimir a senha do usuário \"$1\"", + "checkuser-reset-action": "redefinir a senha do usuário \"$1\"", "checkuser-token-fail": "Falha na sessão. Por favor, tente novamente.", "checkuser-login-failure": "Não foi possível entrar em {{SITENAME}} como $1", "checkuser-login-success": "Entrou em {{SITENAME}} como $1", @@ -127,15 +132,12 @@ "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-subtitle-show-checkuser": "Mudar para CheckUser", "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", @@ -143,7 +145,7 @@ "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-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", @@ -179,7 +181,7 @@ "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-edits": "<b>[$1 {{PLURAL:$1|edição/ação|edições/açõ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", diff --git a/CheckUser/i18n/pt.json b/CheckUser/i18n/pt.json index ea231ff5..c0e2bee6 100644 --- a/CheckUser/i18n/pt.json +++ b/CheckUser/i18n/pt.json @@ -19,13 +19,13 @@ 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-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. Sã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 $3 edições.\nO uso desta ferramenta deverá respeitar as normas e recomendações.", "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", "checkuser-contribs": "verificar endereços IP do utilizador", "checkuser-contribs-log": "verificações de utilizador recentes", + "checkuser-contribs-log-initiator": "verificações de utilizadores feitas por este utilizador", "group-checkuser": "Verificadores de utilizadores", "group-checkuser-member": "{{GENDER:$1|verificador|verificadora}} de utilizadores", "right-checkuser": "Verificar os endereços IP e outras informações de um utilizador", @@ -45,17 +45,23 @@ "checkuser-week-1": "última semana", "checkuser-week-2": "últimas duas semanas", "checkuser-month": "últimos 30 dias", + "checkuser-month-2": "últimos 60 dias", "checkuser-all": "todos", "checkuser-cidr-label": "Encontrar intervalo comum e endereços afetados para uma lista de IPs", "checkuser-cidr-res": "CIDR comum:", + "checkuser-cidr-affected-ips": "Endereços IP afetados:", + "checkuser-cidr-too-small": "A gama é demasiado grande", + "checkuser-range-outside-limit": "A gama $1 está fora dos limites permitidos.", "checkuser-empty": "O registo não contém entradas.", "checkuser-nomatch": "Não foram encontrados resultados.", "checkuser-nomatch-edits": "Não foi encontrado nenhum resultado.\nA última edição foi a $1 às $2.", "checkuser-check": "Verificar", "checkuser-check-this-user": "Verificar este utilizador", + "checkuser-investigate-this-user": "Investigar este utilizador", "checkuser-recent-checks": "Verificações recentes para este utilizador", "checkuser-log-fail": "Não foi possível adicionar entradas ao registo", - "checkuser-nolog": "Não foi encontrado nenhum ficheiro de registos.", + "checkuser-log-checks-by": "verificações por", + "checkuser-log-checks-on": "verificações de", "checkuser-blocked": "Bloqueado", "checkuser-gblocked": "Bloqueado globalmente", "checkuser-locked": "Bloqueado", @@ -67,23 +73,30 @@ "checkuser-blocktalk": "Impedir de editar a sua própria página de discussão enquanto estiver bloqueado", "checkuser-blocktag": "Substituir páginas de utilizador por:", "checkuser-blocktag-talk": "Substituir páginas de discussão por:", + "checkuser-reblock": "Contornar bloqueios existentes", "checkuser-massblock-commit": "Bloquear utilizadores selecionados", "checkuser-block-success": "'''{{PLURAL:$2|O utilizador|Os utilizadores}} $1 {{PLURAL:$2|está agora bloqueado|estão agora bloqueados}}.'''", "checkuser-block-failure": "'''Não há utilizadores bloqueados.'''", "checkuser-block-limit": "Há demasiados utilizadores selecionados.", "checkuser-block-noreason": "Tem de especificar um motivo para os bloqueios.", "checkuser-centralauth-multilock": "Bloquear contas globais selecionadas", + "checkuser-centralauth-multilock-list": "Bloquear as contas globais selecionadas usando as hiperligações:", + "checkuser-centralauth-multilock-list-item": "Hiperligação $1", "checkuser-noreason": "Tem de fornecer um motivo para esta pesquisa.", - "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-too-many": "Há demasiados resultados (segundo estimativa da pesquisa); por favor, restrinja o CIDR.\nAqui estão os endereços IP utilizados ($1 no máximo, ordenados por endereço):", "checkuser-user-nonexistent": "O utilizador especificado não existe.", + "checkuser-target-nonexistent": "O destinatário especificado não existe.", + "checkuser-initiator-nonexistent": "O iniciador especificado não existe.", "checkuser-search": "Pesquisar entradas do registo de verificações de utilizadores", "checkuser-search-submit": "Pesquisar", "checkuser-search-initiator": "iniciador", "checkuser-search-target": "alvo", "checkuser-log-search-target": "Destinatário:", + "checkuser-log-search-initiator": "Iniciador:", "checkuser-log-search-type": "Pesquisar por:", "checkuser-ipeditcount": "~$1 de todos os utilizadores", "checkuser-showmain": "Mudar para o formulário principal da verificação de utilizadores", + "checkuser-show-investigate": "Mudar para o formulário principal de investigação", "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 <bdi>$2</bdi>", @@ -91,20 +104,56 @@ "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-log-entry-investigate": "$3, $1 procurou informação sobre $2", "checkuser-autocreate-action": "foi criada automaticamente", "checkuser-create-action": "foi criada", "checkuser-email-action": "correio eletrónico enviado para o utilizador \"$1\"", - "checkuser-reset-action": "foi reiniciada a palavra-passe do utilizador \"$1\"", + "checkuser-reset-action": "foi reiniciada a palavra-passe do utilizador $1", "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-failure-with-good-password": "Não conseguiu autenticar-se na wiki {{SITENAME}} como $1, mas tinha a palavra-passe correta", "checkuser-login-success": "Entrou na wiki {{SITENAME}} como $1", + "checkuser-link-investigate-label": "Tente a nova ferramenta de verificação de utilizadores", + "checkuser-investigateblock": "Bloquear utilizadores", + "checkuser-investigateblock-target": "Nomes de utilizador e endereços IP", + "checkuser-investigateblock-actions": "Operações a bloquear", + "checkuser-investigateblock-reason": "Motivo", + "checkuser-investigateblock-options": "Opções adicionais", + "checkuser-investigateblock-email-label": "Impedir envio de correio eletrónico", + "checkuser-investigateblock-usertalk-label": "Impedir de editar a sua própria página de discussão enquanto estiver bloqueado", + "checkuser-investigateblock-reblock-label": "Contornar bloqueios existentes", + "checkuser-investigateblock-notice-user-page-label": "Deixar um aviso na página do utilizador", + "checkuser-investigateblock-notice-talk-page-label": "Deixar um aviso na página de discussão do utilizador", + "checkuser-investigateblock-notice-position-label": "Posição", + "checkuser-investigateblock-notice-text-label": "Texto wiki", + "checkuser-investigateblock-notice-append": "Acrescentar ao fim da página", + "checkuser-investigateblock-notice-prepend": "Acrescentar ao início da página", + "checkuser-investigateblock-notice-replace": "Substituir a página", + "checkuser-investigateblock-failure": "Não foi bloqueado nenhum utilizador. Para contornar bloqueios existentes, consulte: \"{{int:checkuser-investigateblock-reblock-label}}\". Um bloqueio não será contornado se o bloqueio novo for igual ao bloqueio existente.", + "checkuser-investigateblock-success": "{{PLURAL:$2|O utilizador $1 está agora bloqueado|Os utilizadores $1 estão agora bloqueados}}.", + "checkuser-investigateblock-notices-failed": "Alguns avisos não foram acrescentados às páginas dos utilizadores ou às páginas de discussão dos utilizadores.", "checkuser-investigate": "Investigar", + "checkuser-investigate-page-subtitle": "Investigação corrente sobre $1", + "checkuser-investigate-subtitle-block-button-label": "Bloquear", + "checkuser-investigate-subtitle-cancel-button-label": "Cancelar", + "checkuser-investigate-subtitle-continue-button-label": "Continuar", + "checkuser-investigate-subtitle-show-checkuser": "Mudar para verificação de utilizadores", + "checkuser-investigate-indicator-new-investigation": "Investigação nova", "checkuser-investigate-indicator-logs": "Registos", "checkuser-investigate-legend": "Pesquisar nomes de utilizador, endereços IP ou gamas IP", + "checkuser-investigate-notice-no-results": "Não foram produzidos resultados.", + "checkuser-investigate-tab-preliminary-check": "Informação da conta", + "checkuser-investigate-tab-compare": "Endereços IP e agentes do utilizador", "checkuser-investigate-tab-timeline": "Linha cronológica", - "checkuser-investigate-targets-label": "Nomes de utilizador e endereços IP", + "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-duration-label": "Duração", + "checkuser-investigate-duration-option-all": "Todas", + "checkuser-investigate-duration-option-1w": "Última semana", + "checkuser-investigate-duration-option-2w": "Últimas 2 semanas", + "checkuser-investigate-duration-option-30d": "Últimos 30 dias", "checkuser-investigate-reason-label": "Motivo", + "checkuser-investigate-preliminary-notice-ip-targets": "O separador de informação da conta não inclui informação sobre endereços IP. Para obter esses detalhes consulte o <span class=\"plainlinks\">[$1 separador \"Endereços IP e agentes do utilizador\"]</span>.", "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", @@ -114,13 +163,42 @@ "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-preliminary-table-cell-wiki-nowiki": "A wiki não foi encontrada", "checkuser-investigate-filters-legend": "Filtros", "checkuser-investigate-filters-exclude-targets-label": "Ocultar os seguintes utilizadores ou IPs", + "checkuser-investigate-timeline-notice-no-results": "Não foram produzidos resultados: não existe atividade registada destes utilizadores e endereços IP nos últimos 90 dias", + "checkuser-investigate-timeline-notice-no-results-filters": "Não foram produzidos resultados que correspondam a estes critérios de filtragem. Tente remover alguns filtros para ampliar o universo da pesquisa.", "checkuser-investigate-compare-copy-button-label": "Mostrar texto wiki", + "checkuser-investigate-compare-copy-button-label-hide": "Ocultar texto wiki", + "checkuser-investigate-compare-toollinks-ipcheck": "Verificação de proxies", + "checkuser-investigate-compare-copy-message-label": "Quer copiar esta informação na forma de tabela em texto wiki?", + "checkuser-investigate-compare-notice-exceeded-limit": "Devido a limitações técnicas foi atingido o número de registos que podem ser apresentados. Os dados recebidos para os seguintes alvos estão incompletos: $1. Tente usar menos alvos, uma janela temporal mais pequena ou gamas mais estreitas de endereços IP.", + "checkuser-investigate-compare-notice-no-results": "Não foram produzidos resultados: estes utilizadores ou endereços IP não realizaram edições nos últimos 90 dias", + "checkuser-investigate-compare-notice-no-results-filters": "Não foram produzidos resultados que correspondam a estes critérios de filtragem. Tente remover alguns filtros para ampliar o universo da pesquisa", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Mostrar todos os endereços IP deste utilizador", + "checkuser-investigate-compare-table-button-add-user-targets-label": "Mostrar todos os utilizadores deste 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 dos resultados", "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-edits": "<b>[$1 {{PLURAL:$1|edição ou operação|edições e operaçõ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" + "checkuser-investigate-compare-table-header-ip": "IP", + "checkuser-investigate-compare-table-header-useragent": "Agente do utilizador", + "checkuser-investigate-subtitle-link-restart-tour": "Recomeçar a visita guiada", + "checkuser-investigate-tour-targets-title": "A verificar vários utilizadores e endereços IP?", + "checkuser-investigate-tour-targets-desc": "Adicione até $1 {{PLURAL:$1|nome de utilizador ou IP|nomes de utilizador ou endereços IP}} e obtenha toda a informação num único sítio. Não se preocupe, criaremos um registo de verificação de utilizadores separado para cada um deles.", + "checkuser-investigate-tour-useragents-title": "Agentes de utilizador coincidentes?", + "checkuser-investigate-tour-useragents-desc": "Coloque o ponteiro do rato sobre uma célula para destacar todas as outras linhas que contêm os mesmos dados. Clique o alfinete para manter os destaques fixos à medida que percorre os dados.", + "checkuser-investigate-tour-addusertargets-title": "Precisa de mais contexto?", + "checkuser-investigate-tour-addusertargets-desc": "Clique para ver todos os outros utilizadores do IP. Também pode fazer o mesmo aos utilizadores e ver todos os endereços IP que estes têm utilizado. Criaremos uma entrada automática por si no registo de verificação de utilizadores.", + "checkuser-investigate-tour-filterip-title": "Afinar a sua investigação?", + "checkuser-investigate-tour-filterip-desc": "Remova dados desnecessários suprimindo, por filtragem, nomes de utilizador, endereços IP ou agentes de utilizador. Quer recuperar estes dados? Use o painel Filtros no topo para remover os filtros.", + "checkuser-investigate-tour-block-title": "Quer fazer bloqueios?", + "checkuser-investigate-tour-block-desc": "Permite-lhe selecionar os utilizadores que pretende bloquear e depois leva-o ao formulário de bloqueio para escolher o bloqueio apropriado.", + "checkuser-investigate-tour-copywikitext-title": "Quer copiar os dados?", + "checkuser-investigate-tour-copywikitext-desc": "Copie a tabela de comparação com um clique e leve-a para a CUWiki. Repare que só está a copiar aquilo que é visível e não todas as páginas da investigação." } diff --git a/CheckUser/i18n/qqq.json b/CheckUser/i18n/qqq.json index 0ea07fc8..8b9b2918 100644 --- a/CheckUser/i18n/qqq.json +++ b/CheckUser/i18n/qqq.json @@ -6,6 +6,7 @@ "Catrope", "Darth Kule", "Dferg", + "Dreamy Jazz", "FF11", "Fryed-peach", "Jon Harald Søby", @@ -30,16 +31,18 @@ "Slomox", "Tgr", "The Evil IP address", - "Umherirrender" + "Umherirrender", + "Verdy p", + "Xiplus" ] }, - "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", + "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\n* $3 - the maximum number of results returned as set in the wiki global CheckUserMaximumRowCount. default value: 5000", "checkuser-desc": "{{desc|name=Check User|url=https://www.mediawiki.org/wiki/Extension:CheckUser}}", - "checkuser-logcase": "Unused at this time.", "checkuser": "Check user extension.\n{{doc-special|CheckUser}}\nIn the special page, checkusers can check the IP addresses of users.\n{{Identical|Check user}}", "checkuserlog": "{{doc-special|CheckUserLog}}\nIn the special page, checkusers can look at a log of past checkuser actions.", "checkuser-contribs": "This is a link anchor used in [[Special:Contributions]]/''name'' to link to [[Special:CheckUser]].", "checkuser-contribs-log": "This is a link anchor used in [[Special:Contributions]]/''name'' to link to recent entries in the CheckUser log regarding the user. Displayed only when user viewing the page has the right to view the CheckUser log ('''checkuser-log''' permission).", + "checkuser-contribs-log-initiator": "This is a link anchor used in [[Special:Contributions]]/''name'' to link to recent check users made by this user. Displayed only when user viewing the page has the right to view the CheckUser log ('''checkuser-log''' permission).", "group-checkuser": "{{doc-group|checkuser}}\ncheck is a noun, not a verb here\n\n{{Identical|Check user}}", "group-checkuser-member": "{{doc-group|checkuser|member}}\n{{Identical|Check user}}", "right-checkuser": "{{doc-right|checkuser}}", @@ -59,17 +62,23 @@ "checkuser-week-1": "Option in drop-down input box \"Duration\" on CheckUser Special page. See screenshot '[[mw:Extension:CheckUser#Basic_interface|Basic CheckUser interface]]'.\n{{Identical|Last week}}", "checkuser-week-2": "Option in drop-down input box \"Duration\" on CheckUser Special page. See screenshot '[[mw:Extension:CheckUser#Basic_interface|Basic CheckUser interface]]'.", "checkuser-month": "Option in drop-down input box \"Duration\" on CheckUser Special page. See screenshot '[[mw:Extension:CheckUser#Basic_interface|Basic CheckUser interface]]'.", + "checkuser-month-2": "Option in drop-down input box \"Duration\" on CheckUser Special page. See screenshot '[[mw:Extension:CheckUser#Basic_interface|Basic CheckUser interface]]'.", "checkuser-all": "Option in drop-down input box \"Duration\" on CheckUser Special page. See screenshot '[[mw:Extension:CheckUser#Basic_interface|Basic CheckUser interface]]'.\n{{Identical|All}}", - "checkuser-cidr-label": "[[File:Checkuser find common range form (example).png|thumb|Form where string is used with sample data.]]Used as the fieldset label in [[Special:CheckUser]].", + "checkuser-cidr-label": "[[File:Checkuser find common range form ooui (example).png|thumb|Form where string is used with sample data.]]Used as the fieldset label in [[Special:CheckUser]].", "checkuser-cidr-res": "For an explanation of CIDR see [[WikiPedia:CIDR]].", + "checkuser-cidr-affected-ips": "The prefix text for the number of affected IP addresses in the CheckUser CIDR form.", + "checkuser-cidr-too-small": "The error message shown when the calculated CIDR is too large.", + "checkuser-range-outside-limit": "Used on Special:CheckUser if the range is outside the allowed limit.", "checkuser-empty": "Used in [[Special:CheckUserLog]], if the CheckUser log is empty.", "checkuser-nomatch": "Used in [[Special:CheckUser]].\n\nSee also:\n* {{msg-mw|Checkuser-nomatch-edits}}", "checkuser-nomatch-edits": "Parameters:\n* $1 - date, localized\n* $2 - time, localized\nSee also:\n* {{msg-mw|Checkuser-nomatch}}", "checkuser-check": "Button label on CheckUser Special page. See screenshot '[[mw:Extension:CheckUser#Basic_interface|Basic CheckUser interface]]'.\n\nAlso appears to be used as link to new CheckUser check from the results page of a CheckUser check - see screenshot \"Example IP check\".\n{{Identical|Check}}", - "checkuser-check-this-user": "Label for the link shown in the subtitle", + "checkuser-check-this-user": "Label for a link shown in Special:CheckUserLog's subtitle. Links to Special:CheckUser. See also {{msg-mw|checkuser-investigate-this-user}}.", + "checkuser-investigate-this-user": "Label for a link shown in Special:CheckUserLog's subtitle. Links to Special:Investigate. See also {{msg-mw|checkuser-check-this-user}}.", "checkuser-recent-checks": "Label for the link shown in the subtitle", "checkuser-log-fail": "Used as failure message in [[Special:CheckUser]].", - "checkuser-nolog": "Unused at this time.", + "checkuser-log-checks-by": "Tool link used in the CheckUserLog that links to the checks performed by a CheckUser.", + "checkuser-log-checks-on": "Tool link used in the CheckUserLog that links to checks performed on a user / IP.", "checkuser-blocked": "Used as link text in [[Special:CheckUser]].\n\nThe link points to [[Special:Log]] or [[Special:BlockList]].\n\nSee also:\n* {{msg-mw|Checkuser-gblocked}}\n* {{msg-mw|Checkuser-wasblocked}}\n{{Identical|Blocked}}", "checkuser-gblocked": "Used a flag in [[Special:CheckUser]].\n\nSee also:\n* {{msg-mw|Checkuser-blocked}}\n* {{msg-mw|Checkuser-wasblocked}}", "checkuser-locked": "Used as a flag in [[Special:CheckUser]].\n{{Identical|Locked}}", @@ -88,17 +97,23 @@ "checkuser-block-limit": "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-noreason}}", "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-centralauth-multilock-list": "Label of the list of links to Special:MultiLock shown on Special:CheckUser's block form. This is shown if a single link would be too long for the browser and thus multiple links shown in a list format are needed.\n\nSee also {{msg-mw|checkuser-centralauth-multilock}}", + "checkuser-centralauth-multilock-list-item": "Label for a link in a list of links to Special:MultiLock for the selected accounts in Special:CheckUser\n\n$1 - The index of the link starting from 1", "checkuser-noreason": "Used as error message in [[Special:CheckUser]].", "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-target-nonexistent": "Used as error message in [[Special:CheckUserLog]].", + "checkuser-initiator-nonexistent": "Used as error message in [[Special:CheckUserLog]].\n\n\"Initiator\" is {{msg-mw|Checkuser-search-initiator}}.", "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}}", "checkuser-search-initiator": "This message is an option in a radio button on the search form for the checkuser log.\n\nSee screenshot \"[[mw:Extension:CheckUser#Basic_interface|Example log]]\".\n\nInitiator means the CheckUser who checks someone's information.\n{{Identical|Initiator}}", "checkuser-search-target": "This message is used in an option in a radio button on the search form for the checkuser log. The target of the check means the user which was checked.\n{{Identical|Target}}", "checkuser-log-search-target": "Label of form field on Special:CheckUserLog's search form. Valid values in the field can be either an IP address or an IP address range or a username.\n{{Identical|Target}}", + "checkuser-log-search-initiator": "Label of form field on Special:CheckUserLog's search form. Valid values in the field can be a username.\n\nThe word \"Initiator\" should be the same as in {{msg-mw|Checkuser-search-initiator}}.\n\n{{Identical|Initiator}}", "checkuser-log-search-type": "Label of form field on Special:CheckUserLog's search form. This corresponds to the radio buttons for the search type. See {{msg-mw|checkuser-search-initiator}} and {{msg-mw|checkuser-log-search-target}}.", - "checkuser-ipeditcount": "This information is shown on the result page of [[mw:Extension:CheckUser#Basic_interface|Special:CheckUser]] (when doing the ''{{int:Checkuser-users}}'' check), next to the individual listed IPs.\n\nSee [[mw:Extension:CheckUser#Basic_interface|screenshot]] \"Example user name check\").\n\nParameters:\n* $1 - an estimate of the total number of edits from the respective IP (i.e. the number of edits by all users, not only by the requested user). As the comment in the code says: ''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\"…''", + "checkuser-ipeditcount": "This information is shown on the result page of [[mw:Extension:CheckUser#Basic_interface|basic CheckUser interface]] on [[Special:CheckUser]] when doing the ''{{int:Checkuser-users}}'' check), next to the individual listed IPs. Its appearance is similar to that of edit summaries.\n\n[[File:CheckUser3.png|thumb|screenshot]]\n\nParameters:\n* $1 - an estimate of the total number of edits from the respective IP (i.e. the number of edits by all users, not only by the requested user). As the comment in the code says: ''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\"…''", "checkuser-showmain": "Link label on Special:CheckUserLog's subtitle. Links to Special:CheckUser. See also {{msg-mw|checkuser-showlog}}.", + "checkuser-show-investigate": "Link label on Special:CheckUserLog's subtitle. Links to Special:Investigate. See also {{msg-mw|checkuser-showmain}}.", "checkuser-limited": "A message shown above CheckUser results if the result list would be longer than the specified limit (5000 entries), and has been truncated.", "checkuser-log-entry-userips": "This is an entry in the checkuser log when a checkuser checks from which IP addresses a user has edited.\n\nParameters:\n* $1 - the user who did the check\n* $2 - the user that was checked, with links to talk page, contributions, and block (like this: [[User:Username|Username]] ( [[User talk|Talk]] | [[Special:Contributions/Username|contribs]] | [[Special:Blockip|block]]) )\n* $3 - a formatted timestamp of the event\n* $4 - a formatted date of the event\n* $5 - a formatted time of the event\n\nSee screenshot \"[[mw:Extension:CheckUser#Basic_interface|Example log]]\".\n{{Related|Checkuser-log}}", "checkuser-log-entry-ipedits": "This is an entry in the checkuser log when a checkuser checks which edits have been done from an IP address.\n\nParameters:\n* $1 - the user who did the check\n* $2 - the IP address that was checked\n* $3 - a formatted timestamp of the event\n* $4 - a formatted date of the event\n* $5 - a formatted time of the event\n\nSee screenshot \"[[mw:Extension:CheckUser#Basic_interface|Example log]]\".\n{{Related|Checkuser-log}}", @@ -106,6 +121,7 @@ "checkuser-log-entry-ipedits-xff": "This is an entry in the checkuser log when a checkuser checks which edits have been done from an XFF IP address (XFF means X-Forwarded-For. Some providers use proxies to forward user requests. This effectively means anonymization of requests. To make the requesting user identifiable again, the original requesting IP is transmitted in a separate HTTP header, the XFF header.).\n\nParameters:\n* $1 - the user who did the check\n* $2 - the IP address that was checked\n* $3 - a formatted timestamp of the event\n* $4 - a formatted date of the event\n* $5 - a formatted time of the event\n\nSee screenshot \"[[mw:Extension:CheckUser#Basic_interface|Example log]]\".\n{{Related|Checkuser-log}}", "checkuser-log-entry-ipusers-xff": "This is an entry in the checkuser log when a checkuser checks which users have used an XFF IP address (XFF means X-Forwarded-For. Some providers use proxies to forward user requests. This effectively means anonymization of requests. To make the requesting user identifiable again, the original requesting IP is transmitted in a separate HTTP header, the XFF header.).\n\nParameters:\n* $1 - the user who did the check\n* $2 - the IP address\n* $3 - a formatted timestamp of the event\n* $4 - a formatted date of the event\n* $5 - a formatted time of the event\n\nSee screenshot \"[[mw:Extension:CheckUser#Basic_interface|Example log]]\".\n{{Related|Checkuser-log}}", "checkuser-log-entry-useredits": "This is an entry in the checkuser log when a checkuser checks which edits have been done from an IP address.\n\nParameters:\n* $1 - name of checkuser\n* $2 - name of user whose edits were inspected\n* $3 - a formatted timestamp of the event\n* $4 - a formatted date of the event\n* $5 - a formatted time of the event\n\nSee screenshot \"[[mw:Extension:CheckUser#Basic_interface|Example log]]\".\n{{Related|Checkuser-log}}", + "checkuser-log-entry-investigate": "This is an entry in the checkuser log when a checkuser investigates a target using [[Special:Investigate]].\n\nParameters:\n* $1 - name of checkuser\n* $2 - name of target\n* $3 - a formatted timestamp of the event\n* $4 - a formatted date of the event\n* $5 - a formatted time of the event\n\n{{Related|Checkuser-log}}", "checkuser-autocreate-action": "Text of the event displayed in the CheckUser results, corresponding to the automatic creation of a new user account (by CentralAuth).", "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", @@ -113,7 +129,8 @@ "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-failure": "Log entry shown in CheckUser logs for failed login attempts", + "checkuser-login-failure-with-good-password": "Log entry shown in CheckUser logs for failed login attempts which had the correct password for the account but failed for any other reason", "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}}", @@ -136,17 +153,14 @@ "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-subtitle-show-checkuser": "Label for a button linking to [[Special:CheckUser]].", "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-indicator-logs": "Label for a button linking to [[Special:CheckUserLog]].", "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.", @@ -165,10 +179,10 @@ "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-editcount": "Label for a table header in [[Special:Investigate]].\n\n{{identical|Edit}}", "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-registration": "Label for a table header in [[Special:Investigate]]. Means \"the day on which (the account) was attached\".\n\nSee also:\n* {{msg-mw|Centralauth-admin-list-attached-on}}", "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]].", @@ -176,11 +190,12 @@ "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-copy-button-label-hide": "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-exceeded-limit": "Warning shown in [[Special:Investigate]].\n\nParameters:\n* $1 - invalid usernames", "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]]", @@ -190,8 +205,8 @@ "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-cell-edits": "Entry for a table cell in [[Special:Investigate]].\n\nParameters:\n* $1 - total number of edits and actions 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 and actions 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]].", diff --git a/CheckUser/i18n/qu.json b/CheckUser/i18n/qu.json index 0e0bf9f4..ef7183ce 100644 --- a/CheckUser/i18n/qu.json +++ b/CheckUser/i18n/qu.json @@ -5,7 +5,6 @@ ] }, "checkuser-summary": "Kay llamk'anaqa ñaqha hukchasqakunapim maskaykun huk ruraqpa llamk'achisqan IP huchhakunata chaskinapaq icha huk IP huchhap llamk'apusqamanta/ruraqmanta willankunata rikuchinapaq.\nRuraqkunata icha mink'akuq IP huchhap rurasqankunatapas XFF uma siq'iwanmi chaskiyta atinki IP huchhata \"/xff\" nisqawan yapaspa. IPv4 (CIDR $1-32), IPv6 (CIDR $2-128) nisqakunam llamk'akun.\nPichqa waranqamanta aswan llamk'apusqakunaqa manam kutimunqachu, allin rikuchinarayku. Kay llamk'anataqa kawpayllakama rurachiy.", - "checkuser-logcase": "Hallch'a maskaqqa hatun sananchata uchuy sananchamantam sapaqchan.", "checkuser": "Ruraqta llanchiy", "checkuserlog": "Ruraq llanchiy hallch'a", "group-checkuser": "Ruraqkunata llanchiy", @@ -27,7 +26,6 @@ "checkuser-nomatch": "Manam imapas taripasqachu.", "checkuser-check": "Llanchiy", "checkuser-log-fail": "Manam atinichu hallch'aman yapayta", - "checkuser-nolog": "Manam hallch'ayta tarinichu", "checkuser-blocked": "Hark'asqa", "checkuser-gblocked": "Sapsintinpi hark'asqa", "checkuser-locked": "Wichq'asqa", diff --git a/CheckUser/i18n/rki.json b/CheckUser/i18n/rki.json new file mode 100644 index 00000000..68e5e9fc --- /dev/null +++ b/CheckUser/i18n/rki.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Ven Suvannalinkara" + ] + }, + "checkuser-login-failure-with-good-password": "$1အဖြိုက် {{SITENAME}}ဒို့ အကောင့်ဝင်ဖို့ မအောင်မြင်ဂေလေ့ မှန်ကန်ရေ စကားဝှက်ဟိရေ" +} diff --git a/CheckUser/i18n/ro.json b/CheckUser/i18n/ro.json index 23306845..61445fb9 100644 --- a/CheckUser/i18n/ro.json +++ b/CheckUser/i18n/ro.json @@ -8,12 +8,12 @@ "KlaudiuMihaila", "Memo18", "Mihai", - "Minisarm" + "Minisarm", + "NGC 54" ] }, "checkuser-summary": "Acestă unealtă scanează schimbările recente pentru a regăsi adresele IP folosite de un utilizator sau arată modificările/utilizatorul pentru o anumită adresă IP.\nUtilizatorii și modificările efectuate de un client IP pot fi regăsite prin antetele XFF atașând adresa IP prin intermediul „/xff”. IPv4 (CIDR $1-32) și IPv6 (CIDR $2-128) sunt acceptate.\nNu mai mult de 5000 de modificări vor fi returnate din motive de performanță.\nUtilizați unealta în concordanță cu politica proiectului.", "checkuser-desc": "Autorizează utilizatorii cu drepturile specifice să poată verifica adresele IP și alte informații", - "checkuser-logcase": "Căutarea în jurnal este sensibilă la majuscule - minuscule", "checkuser": "Verifică utilizatorul", "checkuserlog": "Jurnal verificare utilizator", "checkuser-contribs": "verifică IP-urile utilizatorilor", @@ -45,7 +45,6 @@ "checkuser-nomatch-edits": "Niciun rezultat.\nUltima modificare a fost efectuată pe $1 la ora $2.", "checkuser-check": "Verifică", "checkuser-log-fail": "Imposibil de adăugat intrări în jurnal", - "checkuser-nolog": "Nu a fost găsit un jurnal.", "checkuser-blocked": "Blocat", "checkuser-gblocked": "Blocat global", "checkuser-locked": "Blocat", @@ -61,7 +60,7 @@ "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-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-too-many": "Prea multe rezultate (conform estimării interogării), vă rugăm să limitați CIDR.\nIată IP-urile folosite (maxim $1, sortate după adresă):", "checkuser-user-nonexistent": "Utilizatorul specificat nu există.", "checkuser-search": "Caută înregistrări din jurnalul check user", "checkuser-search-submit": "Caută", diff --git a/CheckUser/i18n/roa-tara.json b/CheckUser/i18n/roa-tara.json index ac428695..a1501b64 100644 --- a/CheckUser/i18n/roa-tara.json +++ b/CheckUser/i18n/roa-tara.json @@ -7,7 +7,6 @@ }, "checkuser-summary": "'Stù strumènde condrolle le cangiaminde recende pe' recuperà le 'nderizze IP ausate da 'nu utinde o pe' mostrà le date cangiaminde/utinde dape' 'nu inderizze IP.\nLe utinde e le cangiaminde pòtene essere recuperate da 'nu inderizze IP d'u client ausanne l'indestazione XFF sckaffanne a le 'nderizze IP \"/xff\". IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128) sonde supportate.\nNo cchiù de 5,000 cangiaminde honne a essere restituite pe' motive de prestazione.\nAuse quiste d'accorde c'a polìteche.", "checkuser-desc": "Congede a le utinde cu l'autorizzazzione appropriate 'a capacetata de condrollà le 'nderizze IP de l'utinde e otre 'mbormazzione", - "checkuser-logcase": "L'archivije de ricerche jè sensibbele a le maiuscole e minuscole.", "checkuser": "Utende verificatore", "checkuserlog": "Archivije de le CheckUser", "checkuser-contribs": "condrolle le 'nderizze IP de le utinde", @@ -39,9 +38,9 @@ "checkuser-nomatch-edits": "Non g'agghie acchiate ninde.<br />\nL'urteme cangiamende ha state fatte 'u $1 a le $2.", "checkuser-check": "Verifiche", "checkuser-check-this-user": "Condrolle stu utende", + "checkuser-investigate-this-user": "Investighe sus a stu utende", "checkuser-recent-checks": "Urteme condrolle sus a stu utende", "checkuser-log-fail": "'Mbossibbele aggiungiere 'a vôsce d'u reggistre", - "checkuser-nolog": "Nisciune archivije de file acchiate.", "checkuser-blocked": "Bloccate", "checkuser-gblocked": "Bloccate globbalmende", "checkuser-locked": "Bloccate", @@ -53,6 +52,7 @@ "checkuser-blocktalk": "Non ge face cangià a stu utende 'a pàgena de le 'ngazzaminde sue fine ca jè bloccate", "checkuser-blocktag": "Sostituisce le pàggene utinde cu:", "checkuser-blocktag-talk": "Sostituisce le pàggene de le 'ngazzaminde cu:", + "checkuser-reblock": "Cange 'u blocche esistende", "checkuser-massblock-commit": "Bluecche l'utinde scacchiate", "checkuser-block-success": "'''L'{{PLURAL:$2|utende|utinde}} $1 {{PLURAL:$2|è|sonde}} bloccate.'''", "checkuser-block-failure": "'''Nisciune utende blccate.'''", @@ -70,6 +70,7 @@ "checkuser-log-search-type": "Cirche pe:", "checkuser-ipeditcount": "~$1 da tutte l'utinde", "checkuser-showmain": "Veje sus a 'u module prengepàle de CheckUser", + "checkuser-show-investigate": "Passe a 'u module prengepàle investige", "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 <bdi>$2</bdi>", @@ -77,6 +78,7 @@ "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-log-entry-investigate": "$3, $1 ave avute 'mbormaziune sus a $2", "checkuser-autocreate-action": "ha state ccrejete automaticamende", "checkuser-create-action": "ha state ccrejate", "checkuser-email-action": "mannate 'na mail a l'utende \"$1\"", @@ -84,12 +86,91 @@ "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", + "checkuser-link-investigate-label": "Pruève 'u strumende nuève CheckUser", "checkuser-investigateblock": "Bluècche l'utinde", "checkuser-investigateblock-target": "Nome de le utinde e indirizze IP", + "checkuser-investigateblock-actions": "Aziune da bloccà", + "checkuser-investigateblock-reason": "Mutive", + "checkuser-investigateblock-options": "Opziune in aggiunde", + "checkuser-investigateblock-email-label": "No fà mannà email a l'utinde", + "checkuser-investigateblock-usertalk-label": "Non ge face cangià a stu utende 'a pàgena de le 'ngazzaminde sue fine ca jè bloccate", + "checkuser-investigateblock-reblock-label": "Cange 'u blocche esistende", + "checkuser-investigateblock-notice-user-page-label": "Lasse 'nu avvise jndr'à pàgene utende", + "checkuser-investigateblock-notice-talk-page-label": "Lasse 'nu avvise jndr'à pàgene de le 'ngazzaminde de l'utende", + "checkuser-investigateblock-notice-position-label": "Posizione", + "checkuser-investigateblock-notice-text-label": "Uicchiteste", + "checkuser-investigateblock-notice-append": "Appinne jndr'à pàgene", + "checkuser-investigateblock-notice-prepend": "Mitte 'ngape 'a pàgene", + "checkuser-investigateblock-notice-replace": "Sostituisce 'a pàgene", + "checkuser-investigateblock-failure": "Nisciune utende ha state bloccate. Pe sovrascrivere le blocche ca stonne ggià, condrolle \"{{int:checkuser-investigateblock-reblock-label}}\". 'Nu blocche non ge avène applecate ce jè uguale a quidde ggià esistende.", + "checkuser-investigateblock-success": "{{PLURAL:$2|L'utende|le utinde}} $1 {{PLURAL:$2|jè|sò}} bloccate.", + "checkuser-investigateblock-notices-failed": "Non g'ha state possibbele aggiungere de le avvise a le pàggene utende o a le paggène de le 'ngazzaminde de l'utende.", "checkuser-investigate": "Investighe", + "checkuser-investigate-page-subtitle": "Recerche de mò pe $1", + "checkuser-investigate-subtitle-block-button-label": "Blocche", + "checkuser-investigate-subtitle-cancel-button-label": "Annulle", + "checkuser-investigate-subtitle-continue-button-label": "Condinue", + "checkuser-investigate-subtitle-show-checkuser": "Vèje sus a CheckUser", + "checkuser-investigate-indicator-new-investigation": "Recerca nove", + "checkuser-investigate-indicator-logs": "Archivije", "checkuser-investigate-legend": "Cirche nome utinde, indirizze IP o 'ndervalle IP", + "checkuser-investigate-notice-no-results": "Non ge stonne resultate.", + "checkuser-investigate-tab-preliminary-check": "'Mbormaziune d'u cunde", + "checkuser-investigate-tab-compare": "IP e user agent", + "checkuser-investigate-tab-timeline": "Linèe d'u tiembe", "checkuser-investigate-targets-label": "Nome de le utinde e indirizze IP", "checkuser-investigate-targets-placeholder": "Nome utende o 1.1.1.1", + "checkuser-investigate-duration-label": "Durate", + "checkuser-investigate-duration-option-all": "Tutte", + "checkuser-investigate-duration-option-1w": "Urtema sumàne", + "checkuser-investigate-duration-option-2w": "Urteme 2 sumàne", + "checkuser-investigate-duration-option-30d": "Urteme 30 giurne", "checkuser-investigate-reason-label": "Mutive", - "checkuser-investigate-preliminary-table-header-blocked": "State" + "checkuser-investigate-preliminary-notice-ip-targets": "Le 'mbormaziune sus a 'u cunde non ge tènene nisciuna 'mbormazione sus a le IP. 'Ndruche <span class=\"plainlinks\">[$1 IPs e user agent]</span> pe ste dettaglie.", + "checkuser-investigate-preliminary-table-cell-blocked": "Bloccate", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|cangiamende|cangiaminde}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Non bloccate", + "checkuser-investigate-preliminary-table-header-blocked": "State", + "checkuser-investigate-preliminary-table-header-editcount": "Cangiaminde", + "checkuser-investigate-preliminary-table-header-groups": "Gruppe", + "checkuser-investigate-preliminary-table-header-name": "Nome utende", + "checkuser-investigate-preliminary-table-header-registration": "Date de collegamende", + "checkuser-investigate-preliminary-table-header-wiki": "Uicchi", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Uicchi non acchiate", + "checkuser-investigate-filters-legend": "Filtre", + "checkuser-investigate-filters-exclude-targets-label": "Scunne ste utinde o IP", + "checkuser-investigate-timeline-notice-no-results": "Non ge stonne resultate: non ge onne state reggistrate attività da ste utinde o IP jndr'à le urteme 90 sciurne.", + "checkuser-investigate-timeline-notice-no-results-filters": "Non ge stonne resultate ca s'accocchiane a ste criterie de filtre. Pruève a luà de le filtre pe allarià 'a recerche", + "checkuser-investigate-compare-copy-button-label": "'Ndruche 'u uicchiteste", + "checkuser-investigate-compare-toollinks-ipcheck": "Proxy check", + "checkuser-investigate-compare-copy-message-label": "Vuè ccu copie sta 'mbormazione jndr'à 'na tabbelle de uicchiteste?", + "checkuser-investigate-compare-notice-exceeded-limit": "Pe mutive tecnice, amme raggiunde 'u numere massime de vôsce 'ndrucabbele. Le date sus a ste destinaziune sò 'ngomblete: $1. Pruève arrete indicanne mene destinaziune, 'na finestre temborale cchiù piccenne o 'nu indervalle de IP mene larie.", + "checkuser-investigate-compare-notice-no-results": "Non ge stonne resultate: ste utinde o IP non ge onne fatte cangiaminde jndr'à le urteme 90 sciurne", + "checkuser-investigate-compare-notice-no-results-filters": "Non ge stonne resultate ca s'accocchiane a ste criterie. Live quacche filtre e pruève arrete.", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "'Ndruche tutte le IP de stu utende", + "checkuser-investigate-compare-table-button-add-user-targets-label": "'Ndruche tutte le utinde de stu IP", + "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Aggiunge stu IP a 'a recerche", + "checkuser-investigate-compare-table-button-checks-label": "Verifiche", + "checkuser-investigate-compare-table-button-contribs-label": "Condrebbute", + "checkuser-investigate-compare-table-button-filter-label": "Filtre da le resultate", + "checkuser-investigate-compare-table-cell-unregistered": "None reggistrate", + "checkuser-investigate-compare-table-cell-edits": "<b>$1 {{PLURAL:$1|cangiamende|cangiaminde}}</b>", + "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 da tutte le utinde)</i>", + "checkuser-investigate-compare-table-header-username": "Nome utende", + "checkuser-investigate-compare-table-header-activity": "Indervalle de date", + "checkuser-investigate-compare-table-header-ip": "IP", + "checkuser-investigate-compare-table-header-useragent": "Utende agente", + "checkuser-investigate-subtitle-link-restart-tour": "Accuminze arrete 'u gire", + "checkuser-investigate-tour-targets-title": "Condrolle cchiù utinde e IP?", + "checkuser-investigate-tour-targets-desc": "Aggiunge 'nzigne a $1 {{PLURAL:$1|nome}} utende o IP e 'ndruhce tutte le 'mbormaziune 'nzieme. No te preoccupà: ccrejame 'na vôsce de reggistre separate pe ognune de lore.", + "checkuser-investigate-tour-useragents-title": "User Agent uguale?", + "checkuser-investigate-tour-useragents-desc": "Vèje cu 'u sciorge sus a 'na celle pe evidenzià tutte le righe cu le stesse date. Cazze sus a l'icone d'u spille pe mandenè fisse l'evidenziazione mendre analizze le otre date.", + "checkuser-investigate-tour-addusertargets-title": "Abbesogne de maggiore condeste?", + "checkuser-investigate-tour-addusertargets-desc": "Cazze pe 'ndrucà tutte le otre utinde cu stu IP. Puè farle pure cu le utinde e 'ndrucà le IP ca onne ausate. Ccrejame 'na vôsce de reggistre pe ogne richieste.", + "checkuser-investigate-tour-filterip-title": "Accoricame 'a recerche?", + "checkuser-investigate-tour-filterip-desc": "Live 'a 'mbormazione de cchiù filtranne le nome de l'utinde, l'IP o User Agent. Puè 'ndrucà arrete le date luanne filtre da l'elenghe de sus.", + "checkuser-investigate-tour-block-title": "Appleche 'u blocche?", + "checkuser-investigate-tour-block-desc": "Permette de scacchià le utinde da bloccà e pò iapre 'u module de blocche pe scacchià 'u blocche satte.", + "checkuser-investigate-tour-copywikitext-title": "Vuè ccu copie le date?", + "checkuser-investigate-tour-copywikitext-desc": "Recopie 'a tabbelle de combronde cazzanne e carresciannele sus a CUUicchi. Ue, ca ste copie sulamende quidde ca jè 'ndrucabbele e none tutte le pàggene d'a recerche." } diff --git a/CheckUser/i18n/ru.json b/CheckUser/i18n/ru.json index 24e1d70c..31cd6120 100644 --- a/CheckUser/i18n/ru.json +++ b/CheckUser/i18n/ru.json @@ -11,14 +11,19 @@ "Express2000", "Facenapalm", "Ferrer", + "Gulka.nik", "Ilya Voyager", + "Iniquity", "Kaganer", + "Kareyac", "Kent73", "Kv75", "Lockal", "Mailman", "MaksimPinigin", "Mariya", + "Megakott", + "MirandaBlack", "Mouse21", "NBS", "Okras", @@ -26,15 +31,16 @@ "Pacha Tchernof", "Prima klasy4na", "Putnik", + "Rubin16", "Silence", "Teretalexev", + "UniCollab", "Александр Сигачёв", "Ядерный Трамвай" ] }, - "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Используйте эту страницу '''только в соответствии с правилами'''.", + "checkuser-summary": "Данный инструмент может быть использован, чтобы получить IP-адреса, использовавшиеся участником, либо чтобы показать правки/участников, работавших с IP-адреса.\nПравки и пользователи, которые правили с определённого IP-адреса, указанного в X-Forwarded-For, можно получить, добавив постфикс <code>/xff</code> к IP-адресу. Поддерживаемые версии IP: 4 (CIDR $1—32) и 6 (CIDR $2—128).\nИз соображений производительности будут показаны только первые $3 правок.\nИспользуйте эту страницу '''только в соответствии с правилами'''.", "checkuser-desc": "Предоставляет возможность проверять IP-адреса и дополнительную информацию участников", - "checkuser-logcase": "Поиск по журналу чувствителен к регистру.", "checkuser": "Проверить участника", "checkuserlog": "Журнал проверки участников", "checkuser-contribs": "проверить IP-адреса участника", @@ -61,14 +67,15 @@ "checkuser-all": "все", "checkuser-cidr-label": "Найти общий диапазон и затрагиваемые адреса для списка IP", "checkuser-cidr-res": "Общая CIDR:", + "checkuser-range-outside-limit": "Диапазон $1 выходит за допустимые пределы.", "checkuser-empty": "Журнал пуст.", "checkuser-nomatch": "Совпадений не найдено.", "checkuser-nomatch-edits": "Совпадений не найдено.\nПоследняя правка сделана $1 в $2.", "checkuser-check": "Проверить", "checkuser-check-this-user": "Проверить этого участника", + "checkuser-investigate-this-user": "Исследовать этого пользователя", "checkuser-recent-checks": "Недавние проверки этого пользователя", "checkuser-log-fail": "Невозможно добавить запись в журнал", - "checkuser-nolog": "Файл журнала не найден.", "checkuser-blocked": "Заблокирован", "checkuser-gblocked": "Заблокирован глобально", "checkuser-locked": "Заблокирован", @@ -80,6 +87,7 @@ "checkuser-blocktalk": "Запретить редактировать свою страницу обсуждения во время блокировки", "checkuser-blocktag": "Заменить страницы участников на:", "checkuser-blocktag-talk": "Заменить страницы обсуждения на:", + "checkuser-reblock": "Переписать существующие блокировки", "checkuser-massblock-commit": "Заблокировать выбранных участников", "checkuser-block-success": "'''Сейчас {{PLURAL:$2|заблокирован $1 участник|заблокированы $1 участника|заблокированы $1 участников}}.'''", "checkuser-block-failure": "'''Нет заблокированных участников.'''", @@ -87,51 +95,84 @@ "checkuser-block-noreason": "Вы должны указать причину блокировок.", "checkuser-centralauth-multilock": "Глобально заблокировать выбранные учётные записи", "checkuser-noreason": "Вы должны указать причину для этого запроса.", - "checkuser-too-many": "Слишком много результатов (согласно оценке запроса), пожалуйста, сузьте CIDR.\nИспользованные IP (максимум 5000, отсортировано по адресу):", + "checkuser-too-many": "Слишком много результатов (согласно оценке запроса), пожалуйста, сузьте CIDR.\nИспользованные IP (максимум $1, отсортировано по адресу):", "checkuser-user-nonexistent": "Указанного участника не существует", + "checkuser-target-nonexistent": "Указанный целевой объект не существует.", + "checkuser-initiator-nonexistent": "Указанный инициатор не существует.", "checkuser-search": "Поиск по записям журнала проверки пользователя", "checkuser-search-submit": "Найти", "checkuser-search-initiator": "инициатор", "checkuser-search-target": "цель", "checkuser-log-search-target": "Цель:", + "checkuser-log-search-initiator": "Инициатор:", "checkuser-log-search-type": "Поиск по", "checkuser-ipeditcount": "~$1 от всех участников", "checkuser-showmain": "Перейти к странице проверки участников", + "checkuser-show-investigate": "Переключиться на главную форму исследования", "checkuser-limited": "'''Результаты были усечены чтобы не создавать дополнительной нагрузки на сервер.'''", - "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-userips": "$3 $1 {{GENDER:$1|получил|получила}} IP-адреса для $2", + "checkuser-log-entry-ipedits": "$3 $1 {{GENDER:$1|получил|получила}} правки для <bdi>$2</bdi>", + "checkuser-log-entry-ipusers": "$3 $1 {{GENDER:$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-log-entry-ipusers-xff": "$3 $1 {{GENDER:$1|получил|получила}} учётные записи для XFF <bdi>$2</bdi>", + "checkuser-log-entry-useredits": "$3 $1 {{GENDER:$1|получил|получила}} правки для $2", + "checkuser-log-entry-investigate": "$3, $1 {{GENDER:$1|искал|искала}} информацию о $2", "checkuser-autocreate-action": "был создан автоматически", "checkuser-create-action": "создан", "checkuser-email-action": "отправил письмо участнику «$1»", - "checkuser-reset-action": "сбросил пароль для участника $1", + "checkuser-reset-action": "сбросил пароль для {{GENDER:$1|участника|участницы|участника_цы}} $1", "checkuser-token-fail": "Сеанс прерван. Пожалуйста, попробуйте ещё раз.", "checkuser-login-failure": "Не удалось войти в {{SITENAME}} в качестве $1", - "checkuser-login-success": "Успешно вошел в систему {{SITENAME}} как $1", + "checkuser-login-success": "Успешно вошёл в систему {{SITENAME}} как $1", + "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 участника|заблокированы $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-investigateblock-notices-failed": "Некоторые уведомления не могли быть добавлены на страницы участников или страницы обсуждения участников.", + "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-subtitle-show-checkuser": "Перейти на проверку участников", + "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": "Последние 2 недели", + "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": "Фильтры", @@ -139,15 +180,36 @@ "checkuser-investigate-timeline-notice-no-results": "Нет результатов: за последние 90 дней не было зарегистрировано активности этих участников или IP-адресов.", "checkuser-investigate-timeline-notice-no-results-filters": "Нет результатов, соответствующих этим критериям фильтрации. Попробуйте удалить некоторые фильтры, чтобы расширить поиск.", "checkuser-investigate-compare-copy-button-label": "Показать вики-текст", + "checkuser-investigate-compare-copy-button-label-hide": "Скрыть викитекст", + "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-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-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/rue.json b/CheckUser/i18n/rue.json index c4b2473b..cf2312d3 100644 --- a/CheckUser/i18n/rue.json +++ b/CheckUser/i18n/rue.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "Тот інштрумент бадать послїднї зміны і уможнює здобыти IP адресы хоснователїв або указати едітованя і хоснователя з даной IP адресы.\nХоснователї і едітованя з кліентской IP адресы ся дають здобыти з головок XFF приданём „/xff“ ку IP. Є підпороване IPv4 (CIDR $1–32) і IPv6 (CIDR $2-128).\nЗ огляду на выкон ся дасть указати максімално 5000 едітовань. Хоснуйте тот інштрумент в згодї з правилами.", "checkuser-desc": "Додавать хоснователям з одповідаючіма правами можность здобывати IP адресы хоснователїв і далшы повязаны інформації", - "checkuser-logcase": "Гляданя в записах чутливе на великость букв.", "checkuser": "Перевірити хоснователя", "checkuserlog": "Лоґ перевіркы хоснователїв", "checkuser-contribs": "перевірити IP адресы хоснователя", @@ -35,7 +34,6 @@ "checkuser-nomatch-edits": "Згода ненайджена.\nОстатнє едітованя зроблене $1 о $2.", "checkuser-check": "Перевірити", "checkuser-log-fail": "Не подарило ся записати до лоґу", - "checkuser-nolog": "Файл лоґованя ся не нашов.", "checkuser-blocked": "Заблокованый", "checkuser-gblocked": "Заблокованый ґлобално", "checkuser-locked": "Замкнуто", diff --git a/CheckUser/i18n/rw.json b/CheckUser/i18n/rw.json new file mode 100644 index 00000000..2bb4c91f --- /dev/null +++ b/CheckUser/i18n/rw.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Germain92" + ] + }, + "checkuser-range-outside-limit": "urutonde $1 ruri hanze yimipaka yemewe. is outside." +} diff --git a/CheckUser/i18n/ryu.json b/CheckUser/i18n/ryu.json index efea48dd..55df55c0 100644 --- a/CheckUser/i18n/ryu.json +++ b/CheckUser/i18n/ryu.json @@ -1,9 +1,10 @@ { "@metadata": { "authors": [ + "ChoiChong", "Tmv" ] }, "checkuser-investigate-subtitle-block-button-label": "ブロック", - "checkuser-investigate-subtitle-cancel-button-label": "ヰーヰー" + "checkuser-investigate-subtitle-cancel-button-label": "とぅりちゃーすん" } diff --git a/CheckUser/i18n/sah.json b/CheckUser/i18n/sah.json index 4a811af2..e2967ca3 100644 --- a/CheckUser/i18n/sah.json +++ b/CheckUser/i18n/sah.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "Бу үстүрүмүөнү кыттааччы IP-ларын көрөргө, эбэтэр IP-аадырыһы туһаммыт хас да кыттааччы уларытыыларын көрөргө туттуохха сөп.\nБиир IP-аадырыстан оҥоһуллубут көннөрүүлэри, эбэтэр ону туһаммыт X-Forwarded-For ыйыллыбыт кыттааччылары көрөргө, бу префиксы IP-га туруоран биэр: <code>/xff</code>. Поддерживаемые версии IP: 4 (CIDR $1—32) и 6 (CIDR $2-128).\nСистиэмэни ноҕуруускалаамаары бастакы 5000 көннөрүү эрэ көрдөрүллүөҕэ. Бу сирэйи '''сиэрдээхтик''' тутун.", "checkuser-desc": "Кыттаачылар IP-ларын уонна кинилэр тустарынан атын сибидиэнньэлэри көрөр кыаҕы биэрии.", - "checkuser-logcase": "Сурунаалга көрдөөһүн улахан/кыра буукубалары араарар.", "checkuser": "Кыттааччыны бэрэбиэркэлээ", "checkuserlog": "Кыттаачылары бэрэбиэркэлээһин сурунаала", "checkuser-contribs": "кыттааччы IP-тын тургутуу", @@ -34,7 +33,6 @@ "checkuser-nomatch-edits": "Сөп түбэһии көстубэтэ.\nБүтэһик көннөрүү $1, $2 оҥоһуллубут.", "checkuser-check": "Бэрэбиэркэлээ", "checkuser-log-fail": "Сурунаалга сурук эбэр табыллыбат(а)", - "checkuser-nolog": "Сурунаал билэтэ көстүбэтэ", "checkuser-blocked": "Тугу эмэ гынара бобуллубут", "checkuser-gblocked": "Төгүрүччү хааччахтаммыт", "checkuser-locked": "Эбии кыахтара сабыллыбыт", diff --git a/CheckUser/i18n/scn.json b/CheckUser/i18n/scn.json index b170ce35..f6563877 100644 --- a/CheckUser/i18n/scn.json +++ b/CheckUser/i18n/scn.json @@ -1,15 +1,15 @@ { "@metadata": { "authors": [ + "Ajeje Brazorf", "Melos", "Pippinu", "Santu", "Sarvaturi" ] }, - "checkuser-summary": "Stu strummentu analizza li canciamenti fatti di picca p'arripigghiari li nnirizzi IP adupirati di n'utenti, o p'ammustrari li canciamenti e l'utenti assuciati a nu nnirizzu IP.\nAgghiuncennu ô nnirizzu IP lu suffissu \"/xff\" s'arrintràccianu l'utenti e li canciamenti ca vèninu di nu nnirizzu IP clienti tinennu cuntu dâ ntistazzioni XFF. Sunnu suppurtati l'IPv4 (CIDR $1-32) e l'IPv6 (CIDR $2-128).\nNun vèninu turnati chiossai di 5.000 canciamenti, pi mutivi di pristazzioni.\nAdupirari stu strummentu rispittannu lu rigulamentu.", + "checkuser-summary": "Stu strummentu analizza li canciamenti fatti di picca p'arripigghiari li nnirizzi IP adupirati di n'utenti, o p'ammustrari li canciamenti e l'utenti assuciati a nu nnirizzu IP.\nAgghiuncennu ô nnirizzu IP lu suffissu \"/xff\" s'arrintràccianu l'utenti e li canciamenti ca vèninu d'un nnirizzu IP clienti tinennu cuntu dâ ntistazzioni XFF. Sunnu suppurtati l'IPv4 (CIDR $1-32) e l'IPv6 (CIDR $2-128).\nNun vèninu turnati chiossai di 5 000 canciamenti, pi mutivi di pristazzioni.\nAdupirari stu strummentu rispittannu lu rigulamentu.", "checkuser-desc": "Pirmetti a l'utenti ca hannu la spicìfica auturizzazzioni di cuntrullari li nnirizzi IP e àutri nfurmazzioni di l'àutri utenti", - "checkuser-logcase": "L'arricerca ntô riggistru fa diffirenza tra maiùsculu e minùsculu.", "checkuser": "Cuntrollu di l'utenti", "checkuserlog": "Riggistru dî cuntrolli di l'utenti", "checkuser-contribs": "cuntrolla li nnirizzi IP di l'utenti", @@ -33,6 +33,7 @@ "checkuser-week-1": "ùrtima simana", "checkuser-week-2": "ùrtimi dui simani", "checkuser-month": "ùrtimi 30 jorna", + "checkuser-month-2": "ùrtimi 60 jorna", "checkuser-all": "sempri", "checkuser-cidr-label": "Attrova lu ntirvallu cumuni e li nnirizzi ntirissati partennu di na lista di nnirizzi IP", "checkuser-cidr-res": "CIDR cumuni:", @@ -41,7 +42,6 @@ "checkuser-nomatch-edits": "Nuddu risurtatu attruvatu.\nL'ùrtimu canciamentu fu fattu a li $2 di lu $1.", "checkuser-check": "Cuntrolla", "checkuser-log-fail": "Nun fu pussìbbili agghiùnciri la vuci ô riggistru", - "checkuser-nolog": "Nun fu attruvatu lu file dû riggistru.", "checkuser-blocked": "Bluccatu", "checkuser-gblocked": "Bluccatu glubbalmenti", "checkuser-locked": "Chiusu", @@ -55,7 +55,7 @@ "checkuser-block-success": "'''{{PLURAL:$2|L'utenti}} $1 ora {{PLURAL:$2|è bluccatu|sunnu bluccati}}.'''", "checkuser-block-failure": "'''Nuddu utenti bluccatu.'''", "checkuser-block-limit": "Troppu assai utenti scigghiuti.", - "checkuser-block-noreason": "S'havi a dari nu mutivu pi li blocchi.", + "checkuser-block-noreason": "S'havi a dari nu mutivu pî blocchi.", "checkuser-noreason": "S'havi a dari nu mutivu pi sta ntirrugazzioni.", "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.", @@ -70,5 +70,28 @@ "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." + "checkuser-token-fail": "Erruri di sissioni. Pi favuri prova n'àutra vota.", + "checkuser-investigateblock-reason": "Mutivu", + "checkuser-investigateblock-notice-text-label": "Wikitestu", + "checkuser-investigate-subtitle-cancel-button-label": "Annulla", + "checkuser-investigate-indicator-logs": "Riggistri", + "checkuser-investigate-targets-placeholder": "Nomu utentu o 1.1.1.1", + "checkuser-investigate-duration-option-all": "Tuttu", + "checkuser-investigate-duration-option-1w": "Ùrtima simana", + "checkuser-investigate-duration-option-2w": "Ùrtimi 2 simani", + "checkuser-investigate-duration-option-30d": "Ùrtimi 30 jorna", + "checkuser-investigate-reason-label": "Mutivu", + "checkuser-investigate-preliminary-table-cell-blocked": "Bluccatu", + "checkuser-investigate-preliminary-table-cell-edits": "{{PLURAL:$1|canciamentu|canciamenti}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Nun bluccatu", + "checkuser-investigate-preliminary-table-header-blocked": "Statu", + "checkuser-investigate-preliminary-table-header-editcount": "Canciamenti", + "checkuser-investigate-preliminary-table-header-groups": "Gruppi", + "checkuser-investigate-preliminary-table-header-name": "Nomu utenti", + "checkuser-investigate-preliminary-table-header-wiki": "Wiki", + "checkuser-investigate-filters-legend": "Filtri", + "checkuser-investigate-compare-copy-button-label": "Ammustra wikitestu", + "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|canciamentu|canciamenti}}]</b>", + "checkuser-investigate-compare-table-header-username": "Nomu utenti", + "checkuser-investigate-compare-table-header-ip": "IP" } diff --git a/CheckUser/i18n/sd.json b/CheckUser/i18n/sd.json index cc907bfb..8002ea97 100644 --- a/CheckUser/i18n/sd.json +++ b/CheckUser/i18n/sd.json @@ -7,10 +7,12 @@ ] }, "group-checkuser": "واپرائيندڙ چڪاسڪار", - "checkuser-target": "آئي پي پتو يا واپرائيندڙ نانءُ", + "checkuser-target": "آئپي پتو يا واپرائيندڙنانءُ:", "checkuser-edits": "سنوارون وٺو", "checkuser-month": "گذريل 30 ڏينھن", "checkuser-all": "سڀ", - "checkuser-check-this-user": "هن واپرائيندڙ جي جانچ ڪيو (Check this user)", - "checkuser-blocktag-talk": "بحث صفحن کي سان مٽايو:" + "checkuser-check-this-user": "هن واپرائيندڙ کي چڪاسيو", + "checkuser-blocktag-talk": "بحث صفحن کي سان مٽايو:", + "checkuser-investigate-preliminary-table-header-editcount": "سنوارون", + "checkuser-investigate-filters-legend": "ڇاڻيون" } diff --git a/CheckUser/i18n/se.json b/CheckUser/i18n/se.json new file mode 100644 index 00000000..c343b591 --- /dev/null +++ b/CheckUser/i18n/se.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Yupik" + ] + }, + "checkuser-all": "buot", + "checkuser-search-submit": "Oza" +} diff --git a/CheckUser/i18n/sgs.json b/CheckUser/i18n/sgs.json deleted file mode 100644 index acff3410..00000000 --- a/CheckUser/i18n/sgs.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "@metadata": { - "authors": [ - "Hugo.arg" - ] - }, - "checkuser-search": "Ėiškuotė" -} diff --git a/CheckUser/i18n/sh.json b/CheckUser/i18n/sh.json index 2e5e1ccb..1a7527d8 100644 --- a/CheckUser/i18n/sh.json +++ b/CheckUser/i18n/sh.json @@ -5,13 +5,13 @@ "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-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 $3 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-logcase": "Pretraga evidencije razlikuje mala i velika slova.", "checkuser": "Provjera korisnika / Провера корисника", "checkuserlog": "Evidencija čekjuzera", "checkuser-contribs": "Proveri korisnikove IP adrese", "checkuser-contribs-log": "skorašnje provere", + "checkuser-contribs-log-initiator": "korisničke provjere koje je izvršio ovaj korisnik", "group-checkuser": "Čekjuzeri", "group-checkuser-member": "{{GENDER:$1|čekjuzer}}", "right-checkuser": "Provera korisničkih IP adresa i ostale informacije", @@ -31,6 +31,7 @@ "checkuser-week-1": "poslednja nedelja", "checkuser-week-2": "poslednje dve nedelje", "checkuser-month": "poslednjih 30 dana", + "checkuser-month-2": "poslednjih 60 dana", "checkuser-all": "sve", "checkuser-cidr-label": "Nađi zajedničku nizu i zahvaćene adrese za spisak IP adresa", "checkuser-cidr-res": "Zajednički CIDR:", @@ -39,9 +40,9 @@ "checkuser-nomatch-edits": "Nema pogodaka.\nPoslednja izmena je urađena $1 u $2.", "checkuser-check": "Proveri", "checkuser-check-this-user": "Proveri ovog korisnika", + "checkuser-investigate-this-user": "Istraži 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", "checkuser-locked": "Zaključan", @@ -59,17 +60,22 @@ "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-centralauth-multilock-list-item": "Link $1", "checkuser-noreason": "Morate da navedete razlog za ovaj upit.", - "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-too-many": "Previše stavki (prema procjeni upita). Molimo Vas da suzite CIDR.\nOvdje su korišćene IP adrese (najviše $1, poredane po adresi):", "checkuser-user-nonexistent": "Navedeni korisnik ne postoji.", + "checkuser-target-nonexistent": "Navedena cilj ne postoji.", + "checkuser-initiator-nonexistent": "Navedeni inicijator ne postoji.", "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-initiator": "Pokretač:", "checkuser-log-search-type": "Pretraži prema:", "checkuser-ipeditcount": "~$1 od svih korisnika", "checkuser-showmain": "Prebaci me na glavni obrazac za proveravanje korisnika", + "checkuser-show-investigate": "Prijeđi na glavni obrazac Istražite", "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>", @@ -80,8 +86,58 @@ "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štio/la je 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" + "checkuser-login-success": "Uspješno sam prijavio na {{SITENAME}} kao $1", + "checkuser-investigateblock": "Blokiraj korisnike", + "checkuser-investigateblock-target": "Korisnička imena i IP adrese", + "checkuser-investigateblock-reason": "Razlog", + "checkuser-investigateblock-options": "Dodatne mogućnosti", + "checkuser-investigateblock-email-label": "Onemogući slanje e-pošte", + "checkuser-investigateblock-usertalk-label": "Spriječi uređivanje vlastite stranice za razgovor za vrijeme blokiranja", + "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-position-label": "Pozicija", + "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-investigateblock-failure": "Nijedan korisnik nije blokiran. Za nadjačavanje postojećih blokada označite: \"{{int:checkuser-investigateblock-reblock-label}}\". Blokada neće biti zamjenjena ako je nova blokada identična postojećoj.", + "checkuser-investigateblock-success": "{{PLURAL:$2|Korisnik|Korisnici}} $1 {{PLURAL:$2|je sada blokiran|su sada blokirani}}.", + "checkuser-investigate-subtitle-block-button-label": "Blokiraj", + "checkuser-investigate-subtitle-cancel-button-label": "Otkaži", + "checkuser-investigate-subtitle-continue-button-label": "Nastavi", + "checkuser-investigate-subtitle-show-checkuser": "Prebaci na CheckUser", + "checkuser-investigate-indicator-logs": "Evidencije", + "checkuser-investigate-legend": "Pretraga korisničkih imena, IP adresa ili IP opsega", + "checkuser-investigate-notice-no-results": "Nema rezultata.", + "checkuser-investigate-tab-preliminary-check": "Informacije o računu", + "checkuser-investigate-tab-timeline": "Vremenska crta", + "checkuser-investigate-targets-label": "Korisnička imena i IP adrese:", + "checkuser-investigate-duration-label": "Trajanje", + "checkuser-investigate-duration-option-all": "Sve", + "checkuser-investigate-duration-option-1w": "Prošla sedmica", + "checkuser-investigate-duration-option-30d": "Poslednjih 30 dana", + "checkuser-investigate-reason-label": "Razlog", + "checkuser-investigate-preliminary-table-cell-blocked": "Blokiran", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|izmjena|izmjene|izmjena}}", + "checkuser-investigate-preliminary-table-header-blocked": "Status", + "checkuser-investigate-preliminary-table-header-editcount": "Izmjene", + "checkuser-investigate-preliminary-table-header-groups": "Grupe", + "checkuser-investigate-preliminary-table-header-name": "Korisničko ime", + "checkuser-investigate-preliminary-table-header-wiki": "Wiki", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki nije pronađen", + "checkuser-investigate-filters-legend": "Filtri", + "checkuser-investigate-compare-copy-button-label": "Pokaži wikitekst", + "checkuser-investigate-compare-copy-button-label-hide": "Sakrij wikitekst", + "checkuser-investigate-compare-toollinks-ipcheck": "Provjera proksija", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Prikaži sve IP adrese ovog korisnika", + "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": "Korisničko ime", + "checkuser-investigate-compare-table-header-activity": "Datumski raspon", + "checkuser-investigate-compare-table-header-ip": "IP", + "checkuser-investigate-compare-table-header-useragent": "Korisnički agent" } diff --git a/CheckUser/i18n/si.json b/CheckUser/i18n/si.json index 3d8dedf9..4b3bdaec 100644 --- a/CheckUser/i18n/si.json +++ b/CheckUser/i18n/si.json @@ -6,7 +6,6 @@ "බිඟුවා" ] }, - "checkuser-logcase": "ලඝු සෙවීම අවස්ථා සංවේදියි.", "checkuser": "පරීක්ෂක නිළධරයා", "checkuserlog": "පරිශීලක ලඝු සටහන පිරික්සන්න", "checkuser-contribs": "පරිශීලකයාගේ අයිපී ලිපිනය පරික්ෂා කරන්න", @@ -37,7 +36,6 @@ "checkuser-nomatch-edits": "කිසිදු ගැලපුමක් සමුනොවිනි.\nඅවසන් සංස්කරණය $1 ට $2 හීදී සිදුකොට තිබිණි.", "checkuser-check": "පරික්ෂා කරන්න", "checkuser-log-fail": "ලඝු-සටහනක් එකතු කිරීමට නොහැක", - "checkuser-nolog": "ලඝු-සටහන් ගොනුවක් හමු නොවිණි.", "checkuser-blocked": "ඇහිරීම", "checkuser-gblocked": "ගෝලීය වශයෙන් වාරණය කරන ලද", "checkuser-locked": "අගුළුලා ඇත", diff --git a/CheckUser/i18n/sje.json b/CheckUser/i18n/sje.json new file mode 100644 index 00000000..83eb55e1 --- /dev/null +++ b/CheckUser/i18n/sje.json @@ -0,0 +1,12 @@ +{ + "@metadata": { + "authors": [ + "Olve Utne" + ] + }, + "checkuser-blocked": "Buđđusum", + "checkuser-investigateblock": "Buđđusä adnejijt", + "checkuser-investigate-subtitle-block-button-label": "Buđđusä", + "checkuser-investigate-indicator-logs": "Låggå", + "checkuser-investigate-preliminary-table-cell-blocked": "Buđđusum" +} diff --git a/CheckUser/i18n/sk.json b/CheckUser/i18n/sk.json index 74063ff9..869ae245 100644 --- a/CheckUser/i18n/sk.json +++ b/CheckUser/i18n/sk.json @@ -11,7 +11,6 @@ }, "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.", "checkuser-desc": "Dáva používateľom s príslušným oprávnením možnosť overovať IP adresu a iné informácie o používateľovi", - "checkuser-logcase": "Vyhľadávanie v zázname zohľadňuje veľkosť písmen.", "checkuser": "Overiť používateľa", "checkuserlog": "Záznam kontroly používateľov", "checkuser-contribs": "skontrolovať IP používateľa", @@ -44,7 +43,6 @@ "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ý", "checkuser-gblocked": "Globálne zablokovaný", "checkuser-locked": "Zamknutý", diff --git a/CheckUser/i18n/skr-arab.json b/CheckUser/i18n/skr-arab.json index 0f661989..1a08080a 100644 --- a/CheckUser/i18n/skr-arab.json +++ b/CheckUser/i18n/skr-arab.json @@ -4,6 +4,7 @@ "Saraiki" ] }, + "checkuser-centralauth-multilock-list-item": "لنک $1", "checkuser-investigate-indicator-logs": "لاگ", "checkuser-investigate-duration-option-all": "یکے", "checkuser-investigate-duration-option-1w": "پچھلا ہفتہ", diff --git a/CheckUser/i18n/sl.json b/CheckUser/i18n/sl.json index 17bbc930..8a9adae5 100644 --- a/CheckUser/i18n/sl.json +++ b/CheckUser/i18n/sl.json @@ -2,23 +2,25 @@ "@metadata": { "authors": [ "Dbc334", - "Janezdrilc" + "Eleassar", + "Janezdrilc", + "MrJaroslavik" ] }, - "checkuser-summary": "To orodje naredi pregled zadnjih sprememb, da pridobi IP-naslove, ki jih uporablja uporabnik, ali prikaže podatke urejanja/uporabniške podatke IP-naslova.\nUporabniki in urejanja odjemalčevega IP-naslova se lahko pridobijo preko glav XFF tako, da se IP-naslovu pripne »/xff«. Podprta sta IPv4 (CIDR $1-32) in IPv6 (CIDR $2-128).\nZaradi zmogljivostnih razlogov je prikazanih največ 5.000 urejanj.\nOrodje uporabljajte v skladu s pravili.", - "checkuser-desc": "Uporabnikom z ustreznimi dovoljenji omogoči preverjanje uporabnikovih IP-naslovov in druge informacije", - "checkuser-logcase": "Iskanje po dnevniku je občutljivo na velikost črk.", + "checkuser-summary": "To orodje prečeše zadnje spremembe, da pridobi IP-naslove, ki jih uporablja uporabnik, ali prikaže podatke urejanja/uporabniške podatke IP-naslova.\nUporabniki in urejanja odjemalčevega IP-naslova se lahko pridobijo prek glav XFF tako, da se IP-naslovu pripne »/xff«. Podprta sta IPv4 (CIDR $1-32) in IPv6 (CIDR $2-128).\nIz razlogov zmogljivosti je prikazanih največ $3 urejanj.\nOrodje uporabljajte v skladu s pravili.", + "checkuser-desc": "Uporabnikom z ustreznim dovoljenjem omogoča preverjanje uporabniških IP-naslovov in drugih podatkov", "checkuser": "Preveri uporabnika", "checkuserlog": "Dnevnik preverjanj uporabnikov", "checkuser-contribs": "preveri uporabnikove IP-naslove", "checkuser-contribs-log": "nedavna preverjanja uporabnikov", + "checkuser-contribs-log-initiator": "uporabniški pregledi, ki jih je opravil ta uporabnik", "group-checkuser": "Preverjevalci uporabnikov", "group-checkuser-member": "{{GENDER:$1|preverjevalec|preverjevalka}} uporabnikov", - "right-checkuser": "Preverjanje uporabnikovih IP-naslovov in drugih informacij", - "right-checkuser-log": "Prikaži dnevnik preverjanj uporabnikov", - "action-checkuser": "preverjanje uporabnikovih IP-naslovov in drugih informacij", - "action-checkuser-log": "prikaži dnevnik preverjanj uporabnikov", - "grouppage-checkuser": "{{ns:project}}:Preveri uporabnika", + "right-checkuser": "Preverjanje uporabnikovih IP-naslovov in drugih podatkov", + "right-checkuser-log": "Dostop do dnevnika preverjanj uporabnikov", + "action-checkuser": "preverjati uporabnikovih IP-naslovov in drugih podatkov", + "action-checkuser-log": "dostopati do dnevnika preverjanj uporabnikov", + "grouppage-checkuser": "{{ns:project}}:Preverjevalci uporabnikov", "checkuser-reason": "Razlog:", "checkuser-reason-api": "API: $1", "checkuser-showlog": "Preklopi na dnevnik preverjanj uporabnikov", @@ -30,58 +32,164 @@ "checkuser-period": "Trajanje:", "checkuser-week-1": "pretekli teden", "checkuser-week-2": "pretekla dva tedna", - "checkuser-month": "preteklih 30 dni", + "checkuser-month": "zadnjih 30 dni", + "checkuser-month-2": "zadnjih 60 dni", "checkuser-all": "vse", "checkuser-cidr-label": "Poišči skupni razpon in dotaknjene IP-naslove za seznam IP-naslovov", "checkuser-cidr-res": "Pogost CIDR:", + "checkuser-cidr-affected-ips": "Zadevni IP-naslovi:", + "checkuser-cidr-too-small": "Razpon je prevelik", + "checkuser-range-outside-limit": "Razpon $1 je zunaj dovoljenih meja.", "checkuser-empty": "Dnevnik ne vsebuje vnosov.", "checkuser-nomatch": "Ni zadetkov.", "checkuser-nomatch-edits": "Ni zadetkov.\nZadnje urejanje je bilo dne $1 ob $2.", "checkuser-check": "Preveri", "checkuser-check-this-user": "Preveri tega uporabnika", + "checkuser-investigate-this-user": "Preišči tega uporabnika", "checkuser-recent-checks": "Zadnja preverjanja za tega uporabnika", "checkuser-log-fail": "Ni mogoče dodati vnosa v dnevnik", - "checkuser-nolog": "Ne najdem datoteke dnevnika.", + "checkuser-log-checks-by": "preverjanja uporabnika/ce", + "checkuser-log-checks-on": "preverjanja uporabnika/ce", "checkuser-blocked": "Blokiran", "checkuser-gblocked": "Blokiran globalno", "checkuser-locked": "Zaklenjeno", "checkuser-wasblocked": "Predhodno blokiran", "checkuser-localonly": "Ni enoten", "checkuser-massblock": "Blokiraj izbrane uporabnike", - "checkuser-massblock-text": "Izbrani računi bodo blokirani za nedoločen čas, z omogočenim samodejnim blokiranjem IP-naslovov in onemogočenim ustvarjanjem računov.\nIP-naslovi brezimnih uporabnikov bodo blokirani samo za en teden in ustvarjanje računov bo nemogočeno.", + "checkuser-massblock-text": "Izbrani računi bodo blokirani za nedoločen čas, z omogočenim samodejnim blokiranjem IP-naslovov in onemogočenim ustvarjanjem računov.\nIP-naslovi bodo za en teden blokirani samo za anonimne uporabnike, pri čemer bo onemogočeno tudi ustvarjanje računov.", "checkuser-blockemail": "Prepreči pošiljanje e-pošte", "checkuser-blocktalk": "Prepreči urejanje lastne pogovorne strani v času blokiranosti", "checkuser-blocktag": "Zamenjaj uporabniške strani z:", "checkuser-blocktag-talk": "Zamenjaj pogovorne strani z:", + "checkuser-reblock": "Preglasi obstoječa blokiranja", "checkuser-massblock-commit": "Blokiraj izbrane uporabnike", "checkuser-block-success": "'''{{PLURAL:$2|Uporabnik|Uporabnika|Uporabniki|Uporabnikov}} $1 {{PLURAL:$2|je zdaj blokiran|sta zdaj blokirana|so zdaj blokirani|je zdaj blokiranih}}.'''", "checkuser-block-failure": "'''Noben uporabnik ni blokiran.'''", "checkuser-block-limit": "Izbranih je preveč uporabnikov.", - "checkuser-block-noreason": "Potrebno je navesti razlog blokiranj.", + "checkuser-block-noreason": "Navesti morate razlog za blokiranja.", "checkuser-centralauth-multilock": "Zakleni izbrane račune", - "checkuser-noreason": "Potrebno je navesti razlog za to poizvedbo.", - "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-centralauth-multilock-list": "Večkratno zaklepanje izbranih računov s povezavami:", + "checkuser-centralauth-multilock-list-item": "Povezava $1", + "checkuser-noreason": "Navesti morate razlog za to poizvedbo.", + "checkuser-too-many": "Preveč zadetkov (glede na oceno poizvedbe); prosimo, zožite CIDR.\nTu so navedeni uporabljeni IP-naslovi (največ $1, razvrščeni po naslovu):", "checkuser-user-nonexistent": "Navedeni uporabnik ne obstaja.", + "checkuser-target-nonexistent": "Navedeni cilj ne obstaja.", + "checkuser-initiator-nonexistent": "Navedeni vršilec ne obstaja.", "checkuser-search": "Iskanje vnosov v dnevniku preverjanj uporabnikov", "checkuser-search-submit": "Išči", "checkuser-search-initiator": "pobudnik", "checkuser-search-target": "cilj", "checkuser-log-search-target": "Cilj:", + "checkuser-log-search-initiator": "Vršilec:", "checkuser-log-search-type": "Iskanje od:", "checkuser-ipeditcount": "~$1 od vseh uporabnikov", "checkuser-showmain": "Preklopi na glavni obrazec za preverjanje uporabnikov", - "checkuser-limited": "'''Rezultati so bili okrnjeni iz zmogljivostnih razlogov.'''", + "checkuser-show-investigate": "Preklopi na glavni obrazec Preišči", + "checkuser-limited": "'''Zadetki so iz zmogljivostnih razlogov okrnjeni.'''", "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 <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-log-entry-investigate": "$3, $1 je poiskal informacije za $2", "checkuser-autocreate-action": "je bil samodejno ustvarjen", "checkuser-create-action": "je bil ustvarjen", "checkuser-email-action": "pošlji e-pošto uporabniku »$1«", - "checkuser-reset-action": "ponastavi geslo uporabnika »$1«", - "checkuser-token-fail": "Seja je spodletela. Poskusi ponovno.", + "checkuser-reset-action": "ponastavitev gesla {{GENDER:$1|uporabnika|uporabnice}} »$1«", + "checkuser-token-fail": "Seja je spodletela. Poskusite znova.", "checkuser-login-failure": "Prijava na {{SITENAME}} kot $1 je spodletela", - "checkuser-login-success": "Uspešna prijava na {{SITENAME}} kot $1" + "checkuser-login-failure-with-good-password": "Prijava v projekt {{SITENAME}} kot $1 ni uspela, vendar je bilo geslo pravilno", + "checkuser-login-success": "Uspešna prijava na {{SITENAME}} kot $1", + "group-checkuser.css": "/* Tukaj postavljeni CSS bo vplival samo na preverjevalce uporabnikov */", + "group-checkuser.js": "/* Tukaj postavljeni JS bo vplival samo na preverjevalce uporabnikov */", + "checkuser-link-investigate-label": "Preizkusite novo orodje CheckUser", + "checkuser-investigateblock": "Blokiraj uporabnike", + "checkuser-investigateblock-target": "Uporabniška imena in IP-naslovi", + "checkuser-investigateblock-actions": "Dejanja za blokiranje", + "checkuser-investigateblock-reason": "Razlog", + "checkuser-investigateblock-options": "Dodatne možnosti", + "checkuser-investigateblock-email-label": "Prepreči pošiljanje e-pošte", + "checkuser-investigateblock-usertalk-label": "Prepreči urejanje lastne pogovorne strani v času blokiranosti", + "checkuser-investigateblock-reblock-label": "Preglasi obstoječa blokiranja", + "checkuser-investigateblock-notice-user-page-label": "Pusti obvestilo na uporabniški strani", + "checkuser-investigateblock-notice-talk-page-label": "Pusti obvestilo na uporabniški pogovorni strani", + "checkuser-investigateblock-notice-position-label": "Položaj", + "checkuser-investigateblock-notice-text-label": "Vikibesedilo", + "checkuser-investigateblock-notice-append": "Dodaj na konec strani", + "checkuser-investigateblock-notice-prepend": "Dodaj na začetek strani", + "checkuser-investigateblock-notice-replace": "Zamenjaj stran", + "checkuser-investigateblock-failure": "Noben uporabnik ni bil blokiran. Če želite preglasiti obstoječa blokiranja, označite: »{{int:checkuser-investigateblock-reblock-label}}«. Blokiranje ne bo preglašeno, če je novo blokiranje enako obstoječemu.", + "checkuser-investigateblock-success": "Zdaj {{PLURAL:$2|je blokiran|sta blokirana|so blokirani|je blokiranih}} $1 {{PLURAL:$2|uporabnik|uporabnika|uporabniki|uporabnikov}}.", + "checkuser-investigateblock-notices-failed": "Nekaterih obvestil ni bilo mogoče dodati na uporabniške strani ali uporabniške pogovorne strani.", + "checkuser-investigate": "Preišči", + "checkuser-investigate-page-subtitle": "Trenutna preiskava za $1", + "checkuser-investigate-subtitle-block-button-label": "Blokiraj", + "checkuser-investigate-subtitle-cancel-button-label": "Prekliči", + "checkuser-investigate-subtitle-continue-button-label": "Nadaljuj", + "checkuser-investigate-subtitle-show-checkuser": "Preklopi na CheckUser", + "checkuser-investigate-indicator-new-investigation": "Nova preiskava", + "checkuser-investigate-indicator-logs": "Dnevniki", + "checkuser-investigate-legend": "Iskanje uporabniških imen, IP-naslovov ali IP-obsegov", + "checkuser-investigate-notice-no-results": "Ni zadetkov.", + "checkuser-investigate-tab-preliminary-check": "Podatki o računu", + "checkuser-investigate-tab-compare": "IP-ji in uporabniški agenti", + "checkuser-investigate-tab-timeline": "Časovnica", + "checkuser-investigate-targets-label": "Uporabniška imena in IP-naslovi:", + "checkuser-investigate-targets-placeholder": "Uporabniško ime ali 1.1.1.1", + "checkuser-investigate-duration-label": "Trajanje", + "checkuser-investigate-duration-option-all": "Vse", + "checkuser-investigate-duration-option-1w": "Zadnji teden", + "checkuser-investigate-duration-option-2w": "Zadnja 2 tedna", + "checkuser-investigate-duration-option-30d": "Zadnjih 30 dni", + "checkuser-investigate-reason-label": "Razlog", + "checkuser-investigate-preliminary-notice-ip-targets": "Zavihek Podatki o računu ne vključuje nobenih informacij o IP-jih. Za te podatke glejte <span class=\"plainlinks\">[$1 zavihek IP-ji in uporabniški agenti]</span>.", + "checkuser-investigate-preliminary-table-cell-blocked": "Blokiran/a", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|urejanhe|urejanji|urejanja|urejanj}}", + "checkuser-investigate-preliminary-table-cell-unblocked": "Ni blokiran/a", + "checkuser-investigate-preliminary-table-header-blocked": "Stanje", + "checkuser-investigate-preliminary-table-header-editcount": "Urejanja", + "checkuser-investigate-preliminary-table-header-groups": "Skupine", + "checkuser-investigate-preliminary-table-header-name": "Uporabniško ime", + "checkuser-investigate-preliminary-table-header-registration": "Datum priložitve", + "checkuser-investigate-preliminary-table-header-wiki": "Viki", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Viki ni najden", + "checkuser-investigate-filters-legend": "Filtri", + "checkuser-investigate-filters-exclude-targets-label": "Skrij naslednje uporabnike ali IP-je", + "checkuser-investigate-timeline-notice-no-results": "Ni zadetkov: V zadnjih 90 dneh ni bila zabeležena nobena aktivnost teh uporabnikov ali IP-jev.", + "checkuser-investigate-timeline-notice-no-results-filters": "Ni zadetkov, ki bi ustrezali tem merilom filtriranja. Poskusite odstraniti nekaj filtrov, da razširite iskanje.", + "checkuser-investigate-compare-copy-button-label": "Pokaži vikibesedilo", + "checkuser-investigate-compare-copy-button-label-hide": "Skrij vikibesedilo", + "checkuser-investigate-compare-toollinks-whois": "WHOIS", + "checkuser-investigate-compare-toollinks-ipcheck": "Preverjanje posrednika", + "checkuser-investigate-compare-copy-message-label": "Ali želite te podatke kopirati v obliki vikitabele?", + "checkuser-investigate-compare-notice-exceeded-limit": "Zaradi tehničnih omejitev smo dosegli število zapisov, ki jih je mogoče predstaviti. Podatki, vrnjeni za naslednje cilje, so nepopolni: $1. Poskusite uporabiti manj ciljev, krajše časovno okno ali ožje IP-razpone.", + "checkuser-investigate-compare-notice-no-results": "Ni zadetkov: V zadnjih 90 dneh ni bilo zabeleženo nobeno urejanje teh uporabnikov ali IP-jev.", + "checkuser-investigate-compare-notice-no-results-filters": "Ni zadetkov, ki bi ustrezali tem merilom filtriranja. Poskusite odstraniti nekaj filtrov, da razširite iskanje.", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Prikaži vse IP-je tega uporabnika", + "checkuser-investigate-compare-table-button-add-user-targets-label": "Prikaži vse uporabnike s tem IP-jem", + "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Dodaj ta IP k preiskavi", + "checkuser-investigate-compare-table-button-checks-label": "Preverjanja", + "checkuser-investigate-compare-table-button-contribs-label": "Prispevki", + "checkuser-investigate-compare-table-button-filter-label": "Filtriraj iz zadetkov", + "checkuser-investigate-compare-table-cell-unregistered": "Neregistrirani", + "checkuser-investigate-compare-table-cell-edits": "<b>[ $1 {{PLURAL:$1| urejanje/dejanje|urejanji/dejanji|urejanja/dejanja|urejanj/dejanj}}]</b>", + "checkuser-investigate-compare-table-cell-other-edits": "<i>(~ $1 od vseh uporabnikov)</i>", + "checkuser-investigate-compare-table-header-username": "Uporabniško ime", + "checkuser-investigate-compare-table-header-activity": "Datumski razpon", + "checkuser-investigate-compare-table-header-ip": "IP", + "checkuser-investigate-compare-table-header-useragent": "Uporabniški agent", + "checkuser-investigate-subtitle-link-restart-tour": "Znova zaženite ogled", + "checkuser-investigate-tour-targets-title": "Preverjate več uporabnikov in IP-jev?", + "checkuser-investigate-tour-targets-desc": "Dodajte do $1 {{PLURAL:$1|uporabniško ime ali IP|uporabniški imeni ali IP-ja|uporabniška imena ali IP-je|uporabniških imen ali IP-jev}} in pridobite vse podatke na enem mestu. Ne skrbite, za vsakega od njih bomo ustvarili ločen CheckUser dnevniški zapis.", + "checkuser-investigate-tour-useragents-title": "Se ujemajo uporabniški agenti?", + "checkuser-investigate-tour-useragents-desc": "Premaknite miškin kazalec nad celico, da označite vse druge vrstice z enakimi podatki. Kliknite ikono žebljička, da med pregledovanjem podatkov ohranite označenost.", + "checkuser-investigate-tour-addusertargets-title": "Potrebujete več konteksta?", + "checkuser-investigate-tour-addusertargets-desc": "Kliknite za ogled vseh drugih uporabnikov s tem IP-jem. To lahko storite tudi za uporabnike in si ogledate vse IP-je, ki so jih uporabljali. Za vas bomo samodejno ustvarili dnevniški vnos CheckUser.", + "checkuser-investigate-tour-filterip-title": "Želite zožati preiskavo?", + "checkuser-investigate-tour-filterip-desc": "Odstranite nepotrebne podatke tako, da izfiltrirate uporabniška imena, IP-je ali uporabniške agente. Želite podatke znova prikazati? Za odstranitev filtrov uporabite panel Filtri na vrhu.", + "checkuser-investigate-tour-block-title": "Želite blokirati?", + "checkuser-investigate-tour-block-desc": "Omogoča vam, da izberete uporabnike, ki jih želite blokirati, nato pa vas popelje do obrazca za blokiranje, da izberete ustrezno blokiranje.", + "checkuser-investigate-tour-copywikitext-title": "Želite kopirati podatke?", + "checkuser-investigate-tour-copywikitext-desc": "Kopirajte primerjalno tabelo z enim klikom in jo prenesite v CUWiki. Upoštevajte, da kopirate samo tisto, kar je vidno, in ne vseh strani preiskave." } diff --git a/CheckUser/i18n/smj.json b/CheckUser/i18n/smj.json new file mode 100644 index 00000000..195de48d --- /dev/null +++ b/CheckUser/i18n/smj.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Yupik" + ] + }, + "checkuser-search-submit": "Åtså" +} diff --git a/CheckUser/i18n/smn.json b/CheckUser/i18n/smn.json new file mode 100644 index 00000000..c87890ec --- /dev/null +++ b/CheckUser/i18n/smn.json @@ -0,0 +1,17 @@ +{ + "@metadata": { + "authors": [ + "Seipinne", + "Yupik" + ] + }, + "checkuser-reason": "Suijâ:", + "checkuser-all": "puoh", + "checkuser-search-submit": "Uusâ", + "checkuser-investigate-subtitle-block-button-label": "Eesti", + "checkuser-investigate-subtitle-cancel-button-label": "Jooskâ", + "checkuser-investigate-reason-label": "Suijâ", + "checkuser-investigate-preliminary-table-header-name": "Kevtteenommâ", + "checkuser-investigate-filters-legend": "Silleeh", + "checkuser-investigate-compare-table-button-contribs-label": "Hammiimeh" +} diff --git a/CheckUser/i18n/sms.json b/CheckUser/i18n/sms.json new file mode 100644 index 00000000..e44485dc --- /dev/null +++ b/CheckUser/i18n/sms.json @@ -0,0 +1,28 @@ +{ + "@metadata": { + "authors": [ + "Yupik" + ] + }, + "checkuser-reason": "Mäinn:", + "checkuser-query": "Ooʒʒ ođđsumus muttsid", + "checkuser-target": "IP-addrõs leʹbe õõʹnninõmm:", + "checkuser-period": "Pââʹjj:", + "checkuser-all": "puk", + "checkuser-nomatch": "Ni mâiʹd ij käunnʼjam.", + "checkuser-nomatch-edits": "Ni mâiʹd ij käunnʼjam.\nMââimõs muuttâs leäi $1 čiâss $2.", + "checkuser-search-submit": "Ooʒʒ", + "checkuser-investigateblock-reason": "Mäinn", + "checkuser-investigate-subtitle-cancel-button-label": "Jõõsk", + "checkuser-investigate-notice-no-results": "Ni mâiʹd ij käunnʼjam.", + "checkuser-investigate-targets-placeholder": "Õõʹnninõmm leʹbe 1.1.1.1", + "checkuser-investigate-duration-label": "Pââʹjj", + "checkuser-investigate-reason-label": "Mäinn", + "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|muuttâs|muttâz|muttsed}}", + "checkuser-investigate-preliminary-table-header-editcount": "Muttâz", + "checkuser-investigate-preliminary-table-header-name": "Õõʹnninõmm", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki ij käunnʼjam", + "checkuser-investigate-compare-copy-button-label": "Čuäʹjet wikiteeʹkst", + "checkuser-investigate-compare-table-button-contribs-label": "Muttâz", + "checkuser-investigate-compare-table-header-username": "Õõʹnninõmm" +} diff --git a/CheckUser/i18n/sq.json b/CheckUser/i18n/sq.json index ca878b15..9eaa21a3 100644 --- a/CheckUser/i18n/sq.json +++ b/CheckUser/i18n/sq.json @@ -3,7 +3,8 @@ "authors": [ "Ammartivari", "Dori", - "Toplove12" + "Toplove12", + "Vanished 456321456" ] }, "checkuser": "Kontrollo përdoruesin", diff --git a/CheckUser/i18n/sr-ec.json b/CheckUser/i18n/sr-ec.json index 94cdba8d..d976d88a 100644 --- a/CheckUser/i18n/sr-ec.json +++ b/CheckUser/i18n/sr-ec.json @@ -19,9 +19,8 @@ "Сербијана" ] }, - "checkuser-summary": "Ова алатка врши преглед скорашњих измена и проналази корисничке IP адресе или приказује податке о кориснику/изменама поједине IP адресе.\nКорисници и измене IP адресе клијента могу се добавити преко XFF заглавља додавањем ознаке <code>/xff</code> иза IP адресе. Формати IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128) су подржани.\nЗбог перформанси, неће бити враћено више од 5.000 измена.\nКористите алатку у складу с правилима.", + "checkuser-summary": "Ова алатка врши преглед скорашњих измена и проналази корисничке IP адресе или приказује податке о кориснику/изменама поједине IP адресе.\nКорисници и измене IP адресе клијента могу се добавити преко XFF заглавља додавањем ознаке <code>/xff</code> иза IP адресе. Формати IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128) су подржани.\nЗбог перформанси, неће бити враћено више од $3 измена.\nКористите алатку у складу с правилима.", "checkuser-desc": "Даје корисницима са одговарајућим правима могућност провере IP адреса и других информација", - "checkuser-logcase": "Претрага дневника разликује мала и велика слова.", "checkuser": "Провера корисника", "checkuserlog": "Дневник провере корисника", "checkuser-contribs": "провери корисничке IP адресе", @@ -55,7 +54,6 @@ "checkuser-check-this-user": "Провери корисника", "checkuser-recent-checks": "Недавне провере овог корисника", "checkuser-log-fail": "Није могуће додати унос у дневник", - "checkuser-nolog": "Датотека дневника није пронађена.", "checkuser-blocked": "Блокиран", "checkuser-gblocked": "Глобално блокиран", "checkuser-locked": "Закључан", @@ -94,7 +92,7 @@ "checkuser-autocreate-action": "је аутоматски отворен", "checkuser-create-action": "је отворен", "checkuser-email-action": "имејл је послат кориснику „$1”", - "checkuser-reset-action": "ресетуј лозинку корисника „$1”", + "checkuser-reset-action": "ресетуј лозинку {{GENDER:$1|корисника|кориснице}} $1", "checkuser-token-fail": "Сесија је отказана. Покушајте поново.", "checkuser-login-failure": "Пријављивање на пројекат као $1 није успело", "checkuser-login-success": "Успешто пријављивање на пројекат као $1", @@ -110,7 +108,7 @@ "checkuser-investigate": "Испитивање", "checkuser-investigate-legend": "Тражење корисничких имена, IP адреса или опсега", "checkuser-investigate-notice-no-results": "Нема резултата.", - "checkuser-investigate-targets-label": "Корисничко име или IP адреса", + "checkuser-investigate-targets-label": "Корисничко име и IP адреса:", "checkuser-investigate-targets-placeholder": "Корисничко име или 1.1.1.1", "checkuser-investigate-reason-label": "Разлог", "checkuser-investigate-preliminary-table-cell-blocked": "Блокиран", diff --git a/CheckUser/i18n/sr-el.json b/CheckUser/i18n/sr-el.json index 2be28843..6eb5d53d 100644 --- a/CheckUser/i18n/sr-el.json +++ b/CheckUser/i18n/sr-el.json @@ -10,7 +10,6 @@ }, "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-logcase": "Pretraga dnevnika je osetljiva na mala i velika slova.", "checkuser": "Proveri korisnika", "checkuserlog": "Dnevnik čekjuzera", "checkuser-contribs": "Proveri korisnikove IP adrese", @@ -41,7 +40,6 @@ "checkuser-nomatch-edits": "Nisu nađena poklapanja.\nPoslednja izmena je bila na $1 u $2.", "checkuser-check": "Provera", "checkuser-log-fail": "Ne mogu da dodam stavku u dnevnik", - "checkuser-nolog": "Dnevnik nije pronađen.", "checkuser-blocked": "Blokiran", "checkuser-gblocked": "Blokiran globalno", "checkuser-locked": "Zaključano", diff --git a/CheckUser/i18n/st.json b/CheckUser/i18n/st.json new file mode 100644 index 00000000..05a1dc8e --- /dev/null +++ b/CheckUser/i18n/st.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Amire80" + ] + }, + "checkuser-reason": "Lebaka:", + "checkuser-block-success": "'''{{PLURAL:$2|Mosebelisi $2 o thibetsoe|Basebelisi $1 ba thibetsoe}}'''" +} diff --git a/CheckUser/i18n/stq.json b/CheckUser/i18n/stq.json index 4ac953e8..fc58eab1 100644 --- a/CheckUser/i18n/stq.json +++ b/CheckUser/i18n/stq.json @@ -8,7 +8,6 @@ }, "checkuser-summary": "Disse Reewe truchsäkt do lääste Annerengen, uum ju IP-Adresse fon n Benutser\n\tblw. do Beoarbaidengen/Benutsernoomen foar ne IP-Adresse fäästtoustaalen. Benutsere un\nBeoarbaidengen fon ne IP-Adresse konnen uk ätter Informatione uut do XFF-Headere\n\toufräiged wäide, as an ju IP-Adresse n „/xff“ anhonged wäd. (CIDR $1-32) un IPv6 (CIDR $2-128) wäide unnerstutsed.\n\tUut Perfomance-Gruunde wäide maximoal 5000 Beoarbaidengen uutroat. Benutsje CheckUser bloot in Uureenstämmenge mäd do Doatenskutsgjuchtlienjen.", "checkuser-desc": "Ferlööwet Benutsere mäd do äntspreekende Gjuchte do IP-Adressen as uk wiedere Informatione fon Benutsere tou wröigjen.", - "checkuser-logcase": "Ju Säike in dät Logbouk unnerskat twiske Groot- un Littikskrieuwen.", "checkuser": "Checkuser", "checkuserlog": "Checkuser-Logbouk", "checkuser-contribs": "IP-Adrässen Benutser wröigje", @@ -36,7 +35,6 @@ "checkuser-nomatch-edits": "Neen Uureenstimmengen fuunen. Lääste Beoarbaidenge waas an n $1 uum $2.", "checkuser-check": "Uutfiere", "checkuser-log-fail": "Logbouk-Iendraach kon nit bietouföiged wäide.", - "checkuser-nolog": "Neen Logbouk fuunen.", "checkuser-blocked": "speerd", "checkuser-gblocked": "globoal speerd", "checkuser-locked": "sleeten", diff --git a/CheckUser/i18n/su.json b/CheckUser/i18n/su.json index df2ffeaa..4df3683e 100644 --- a/CheckUser/i18n/su.json +++ b/CheckUser/i18n/su.json @@ -7,7 +7,6 @@ ] }, "checkuser-desc": "Leler kawenangan pikeun mariksa alamat IP jeung émbaran lianna ti hiji pamaké", - "checkuser-logcase": "Panyungsi log ngabédakeun kapitalisasi.", "checkuser": "Pamaké pamariksa", "checkuserlog": "Log PamakéPamariksa", "group-checkuser": "Pamaké pamariksa", @@ -23,7 +22,6 @@ "checkuser-nomatch": "Euweuh nu cocog.", "checkuser-check": "Pariksa", "checkuser-log-fail": "Teu bisa nambahkeun kana log", - "checkuser-nolog": "Log berkas teu kapanggih.", "checkuser-blocked": "Dipeungpeuk", "checkuser-too-many": "Hasilna loba teuing, heureutan CIDR-na.\nDi handap ieu béréndélan IP nu dipaké (paling loba 5000, disusun dumasar alamat):", "checkuser-user-nonexistent": "Euweuh pamaké nu cocog jeung pamundut.", diff --git a/CheckUser/i18n/sv.json b/CheckUser/i18n/sv.json index 7c0fb00a..f22c94f8 100644 --- a/CheckUser/i18n/sv.json +++ b/CheckUser/i18n/sv.json @@ -5,6 +5,7 @@ "Bengtsson96", "Boivie", "Hangsna", + "JRyan", "Jenniesarina", "Jopparn", "Lejonel", @@ -16,12 +17,12 @@ "Najami", "Per", "Sabelöga", + "Smetanakaviar", "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.", "checkuser-desc": "Ger möjlighet för användare med speciell behörighet att kontrollera användares IP-adresser och viss annan information", - "checkuser-logcase": "Loggsökning är skiftlägeskänslig.", "checkuser": "Kontrollera användare", "checkuserlog": "Logg över användarkontroller", "checkuser-contribs": "kontrollera användarens IP-adresser", @@ -53,9 +54,9 @@ "checkuser-nomatch-edits": "Fick ingen träff.\nSenaste redigering var $1 kl $2.", "checkuser-check": "Kontrollera", "checkuser-check-this-user": "Granska den här användaren", + "checkuser-investigate-this-user": "Undersök denna användare", "checkuser-recent-checks": "Senaste kontroller för denna användare", "checkuser-log-fail": "Loggposten kunde inte läggas i loggfilen.", - "checkuser-nolog": "Hittade ingen loggfil.", "checkuser-blocked": "Blockerad", "checkuser-gblocked": "Blockerad globalt", "checkuser-locked": "Låst", @@ -85,6 +86,7 @@ "checkuser-log-search-type": "Sök efter:", "checkuser-ipeditcount": "~$1 från alla användare", "checkuser-showmain": "Växla till CheckUser huvudformulär", + "checkuser-show-investigate": "Byt till \"Undersök huvudformuläret\"", "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 <bdi>$2</bdi>", @@ -92,6 +94,7 @@ "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-log-entry-investigate": "$3,$1 kollade upp information för $2", "checkuser-autocreate-action": "skapades automatiskt", "checkuser-create-action": "skapades", "checkuser-email-action": "skickade ett mejl till användare \"$1\"", @@ -118,15 +121,12 @@ "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-subtitle-show-checkuser": "Byt till CheckUser", "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", @@ -158,6 +158,7 @@ "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-copy-button-label-hide": "Dölj 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.", diff --git a/CheckUser/i18n/ta.json b/CheckUser/i18n/ta.json index 988c461d..3aca5ef2 100644 --- a/CheckUser/i18n/ta.json +++ b/CheckUser/i18n/ta.json @@ -39,7 +39,6 @@ "checkuser-nomatch-edits": "பொருத்தங்கள் கண்டறியப்படவில்லை.\nகடைசி திருத்தம் $1 ல் $2 மணிக்கு.", "checkuser-check": "சரிபார்க்கவும்", "checkuser-log-fail": "குறிப்பேடு உள்ளீட்டைச் சேர்க்க இயலவில்லை", - "checkuser-nolog": "குறிப்பேடு கோப்பு காணப்படவில்லை.", "checkuser-blocked": "தடுக்கப்பட்டது", "checkuser-gblocked": "உலக அளவில் தடை செய்யப்பட்டுள்ளது", "checkuser-locked": "மூடப்பட்டது", diff --git a/CheckUser/i18n/te.json b/CheckUser/i18n/te.json index 4ff87727..ca319d71 100644 --- a/CheckUser/i18n/te.json +++ b/CheckUser/i18n/te.json @@ -11,7 +11,6 @@ }, "checkuser-summary": "ఈ పరికరం ఓ వాడుకరి వాడిన ఐపీలను, లేదా ఒక ఐపీకి చెందిన దిద్దుబాట్లు, వాడుకరుల డేటాను చూపిస్తుంది.\nక్లయంటు ఐపీకి చెందిన వాడుకరులు, దిద్దుబాట్లను ఐపీకి /xff అని చేర్చి, XFF హెడర్ల ద్వారా వెలికితీయవచ్చు. IPv4 (CIDR $1-32) and IPv6 (CIDR $2-128) లు పనిచేస్తాయి.\nపనితనపు కారణాల వలన 5000 దిద్దుబాట్లకు మించి చూపించము. విధానాల కనుగుణంగా దీన్ని వాడండి.", "checkuser-desc": "వాడుకరి ఐపీ అడ్రసు, ఇతర సమాచారాన్ని చూడగలిగే అనుమతులను వాడుకరులకు ఇస్తుంది", - "checkuser-logcase": "చిచ్చా అన్వేషణ కోసం ఇంగ్లీషు అన్వేషకం ఇస్తే, అది కేస్ సెన్సిటివ్.", "checkuser": "వాడుకరి తనిఖీ", "checkuserlog": "వాడుకరిపరిశీలనల చిట్టా", "checkuser-contribs": "వాడుకరి ఐపీ అడ్రసులను పరిశీలించు", @@ -38,7 +37,6 @@ "checkuser-nomatch-edits": "సరిపోయేవేమీ కనిపించలేదు.\nచివరి దిద్దుబాటు $1 న $2 కు జరిగింది.", "checkuser-check": "తనిఖీ", "checkuser-log-fail": "చిట్టాలో పద్దుని చేర్చలేకపోయాం", - "checkuser-nolog": "చిట్టా ఫైలేమీ కనపడలేదు.", "checkuser-blocked": "నిరోధించాం", "checkuser-gblocked": "సార్వత్రికంగా నిరోధించారు", "checkuser-locked": "తాళం వెయ్యబడింది", diff --git a/CheckUser/i18n/tg-cyrl.json b/CheckUser/i18n/tg-cyrl.json index 15049132..4588266c 100644 --- a/CheckUser/i18n/tg-cyrl.json +++ b/CheckUser/i18n/tg-cyrl.json @@ -7,7 +7,6 @@ }, "checkuser-summary": "Ин абзор тағйироти охирро барои ба даст овардани нишонаҳои интернетӣ IP истифода шуда тавассути як корбар ё таъйини вироишҳои анчом шуда тариқи як нишонаи интернетӣ IP, ҷустуҷӯ мекунад.\nКорбарон ва вироишҳои як нишонаи интернетии IP-ро метавон бо таваҷҷӯҳ ба иттилоот сар оянд тариқи XFF бо афзудан нишонаи интернетӣ IP бо \"/xff\" пайдо кард. Ҳар ду протокол IPv4 (CIDR $1-32) ва IPv6 (CIDR $2-128) тавассути ин абзор пуштибонӣ мешаванд.\nНа беш аз 5000 вироиш бо далелҳои зудкорӣ баргардонида хоҳанд шуд. Бо мувофиқи сиёсат ва қоидаҳо инро истода кунед.", "checkuser-desc": "Ба корбарон ихтиёроти лозимиро барои баррасии нишонаҳои интернетӣ IP корбарон ва иттилооти дигар, иҷозат медиҳад", - "checkuser-logcase": "Ҷустуҷӯи гузориш ба хурд ё бузрг будани ҳарфҳо ҳасос аст.", "checkuser": "Бозрасии корбар", "checkuserlog": "БозрасиКорбар гузориш", "group-checkuser": "Бозрасии корбарон", @@ -31,7 +30,6 @@ "checkuser-nomatch-edits": "Ҳеҷ мутобиқате ёфт нашуд.\nОхирин вироиш дар $1 соати $2 буд.", "checkuser-check": "Барраси", "checkuser-log-fail": "Имкони афзудани иттилоот ба гузориш вуҷуд надорад", - "checkuser-nolog": "Парвандаи гузориш пайдо нашуд.", "checkuser-blocked": "Дастрасӣ қатъ шуд", "checkuser-gblocked": "Басташуда сартосарӣ", "checkuser-wasblocked": "Қаблан баста шуда", diff --git a/CheckUser/i18n/tg-latn.json b/CheckUser/i18n/tg-latn.json index 3c9b2df5..dfd8d318 100644 --- a/CheckUser/i18n/tg-latn.json +++ b/CheckUser/i18n/tg-latn.json @@ -6,7 +6,6 @@ }, "checkuser-summary": "In abzor taƣjiroti oxirro baroi ba dast ovardani nişonahoi internetī IP istifoda şuda tavassuti jak korbar jo ta'jini viroişhoi ancom şuda tariqi jak nişonai internetī IP, çustuçū mekunad.\nKorbaron va viroişhoi jak nişonai internetiji IP-ro metavon bo tavaççūh ba ittiloot sar ojand tariqi XFF bo afzudan nişonai internetī IP bo \"/xff\" pajdo kard. Har du protokol IPv4 (CIDR $1-32) va IPv6 (CIDR $2-128) tavassuti in abzor puştibonī meşavand.\nNa beş az 5000 viroiş bo dalelhoi zudkorī bargardonida xohand şud. Bo muvofiqi sijosat va qoidaho inro istoda kuned.", "checkuser-desc": "Ba korbaron ixtijoroti lozimiro baroi barrasiji nişonahoi internetī IP korbaron va ittilooti digar, içozat medihad", - "checkuser-logcase": "Çustuçūi guzoriş ba xurd jo buzrg budani harfho hasos ast.", "checkuser": "Bozrasiji korbar", "checkuserlog": "BozrasiKorbar guzoriş", "group-checkuser": "Bozrasiji korbaron", @@ -29,7 +28,6 @@ "checkuser-nomatch-edits": "Heç mutobiqate joft naşud.\nOxirin viroiş dar $1 soati $2 bud.", "checkuser-check": "Barrasi", "checkuser-log-fail": "Imkoni afzudani ittiloot ba guzoriş vuçud nadorad", - "checkuser-nolog": "Parvandai guzoriş pajdo naşud.", "checkuser-blocked": "Dastrasī qat' şud", "checkuser-gblocked": "Bastaşuda sartosarī", "checkuser-wasblocked": "Qablan basta şuda", diff --git a/CheckUser/i18n/tg.json b/CheckUser/i18n/tg.json deleted file mode 100644 index d6259e21..00000000 --- a/CheckUser/i18n/tg.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "@metadata": { - "authors": [ - "Ibrahim" - ] - }, - "right-checkuser-log": "Мушоҳидаи гузоришҳои бозрасии корбарӣ" -}
\ No newline at end of file diff --git a/CheckUser/i18n/th.json b/CheckUser/i18n/th.json index fa5d43bf..1d4ecace 100644 --- a/CheckUser/i18n/th.json +++ b/CheckUser/i18n/th.json @@ -11,7 +11,6 @@ }, "checkuser-summary": "เครื่องมือนี้สแกนการเปลี่ยนแปลงล่าสดเพื่อให้ได้มาซึ่งเลขที่อยู่ไอพีที่ผู้ใช้ใช้หรือแสดงข้อมูลการแก้ไข/ผู้ใช้เพื่อให้ได้มาซึ่งเลขที่อยู่ไอพี\nผู้ใช้และการแก้ไขโดยเลขที่อยู่ไอพีรับบริการสามารถได้มาผ่านตัวนำหน้า XFF โดยการผนวกเลขที่อยู่ไอพีกับ \"/xff\" เครื่องมือนี้รองรับ IPv4 (CIDR $1-32) และ IPv6 (CIDR $2-128)\nจะไม่คืนเกินกว่า 5,000 การแก้ไข ด้วยเหตุผลด้านสมรรถนะ\nใช้เครื่องมือนี้ตามนโยบาย", "checkuser-desc": "อนุญาตอย่างเหมาะสมให้ผู้ใช้สามารถตรวจสอบเลขที่อยู่ไอพีและสารสนเทศอื่นของผู้ใช้", - "checkuser-logcase": "การค้นหารายการบันทึกไวต่ออักษรใหญ่เล็ก", "checkuser": "ตรวจสอบผู้ใช้", "checkuserlog": "ปูมการตรวจสอบผู้ใช้", "checkuser-contribs": "ตรวจสอบหมายเลขไอพีของผู้ใช้", @@ -43,9 +42,9 @@ "checkuser-nomatch-edits": "ไม่พบรายการที่ตรงกัน\nแก้ไขล่าสุดเมื่อ $1 ณ เวลา $2", "checkuser-check": "ตรวจสอบ", "checkuser-check-this-user": "ตรวจสอบผู้ใช้นี้", + "checkuser-investigate-this-user": "สืบสวนผู้ใช้คนนี้", "checkuser-recent-checks": "การตรวจสอบล่าสุดสำหรับผู้ใช้นี้", "checkuser-log-fail": "ไม่สามารถเพิ่มหน่วยรายการบันทึกได้", - "checkuser-nolog": "ไม่พบไฟล์รายการบันทึก", "checkuser-blocked": "ถูกบล็อก", "checkuser-gblocked": "ถูกบล็อกทั่วโลก", "checkuser-locked": "ถูกล็อก", @@ -57,30 +56,122 @@ "checkuser-blocktalk": "ป้องกันไม่ให้แก้ไขหน้าพูดคุยของตนเองขณะถูกบล็อก", "checkuser-blocktag": "แทนที่หน้าผู้ใช้ด้วย:", "checkuser-blocktag-talk": "แทนที่หน้าคุยด้วย:", + "checkuser-reblock": "ยกเลิกบล็อกที่มีอยู่เดิม", "checkuser-massblock-commit": "บล็อกผู้ใช้ที่เลือก", "checkuser-block-success": "'''{{PLURAL:$2|ผู้ใช้|ผู้ใช้}} $1 {{PLURAL:$2|ได้ถูก|ได้ถูก}}บล็อกแล้ว'''", "checkuser-block-failure": "'''ไม่มีผู้ใช้ที่ถูกบล็อก'''", "checkuser-block-limit": "เลือกผู้ใช้มากเกินไป", "checkuser-block-noreason": "คุณต้องให้เหตุผลในการบล็อก", + "checkuser-centralauth-multilock": "ล็อกหลายบัญชีที่เลือก", "checkuser-noreason": "คุณต้องให้เหตุผลสำหรับการสอบถามนี้", - "checkuser-too-many": "มีผลลัพธ์มากเกินไป (จากการคาดคะเนของแบบสอบถาม) กรุณาทำให้ CIDR เฉพาะเจาะจงมากขึ้น\nนี่คือหมายเลขไอพีที่ถูกใช้ (สูงสุด 5000 เรียงตามหมายเลขไอพี)", + "checkuser-too-many": "มีผลลัพธ์มากเกินไป (จากการคาดคะเนของแบบสอบถาม) กรุณาทำให้ CIDR เฉพาะเจาะจงมากขึ้น\nนี่คือหมายเลขไอพีที่ถูกใช้ (สูงสุด $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-showmain": "สลับไปยังแบบฟอร์มหลักการตรวจสอบผู้ใช้", + "checkuser-show-investigate": "สลับไปที่แบบคำขอสืบสวนหลัก", "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-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-log-entry-investigate": "$3, $1 ค้นหาข้อมูลจาก $2", "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 สำเร็จแล้ว" + "checkuser-login-success": "เข้าสู่ระบบ {{SITENAME}} ในชื่อ $1 สำเร็จแล้ว", + "group-checkuser.css": "/* CSS ในที่นี้จะมีผลต่อผู้ตรวจสอบผู้ใช้เท่านั้น */", + "group-checkuser.js": "/* JS ในที่นี้จะมีผลต่อผู้ตรวจสอบผู้ใช้เท่านั้น */", + "checkuser-link-investigate-label": "ลองใช้เครื่องมือตรวจสอบผู้ใช้ตัวใหม่", + "checkuser-investigateblock": "บล็อกผู้ใช้ (สืบสวน)", + "checkuser-investigateblock-target": "ชื่อผู้ใช้และเลขที่อยู่ไอพี", + "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": "สืบสวน", + "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-subtitle-show-checkuser": "สลับไปยังตรวจสอบผู้ใช้", + "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-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": "2 สัปดาห์ที่แล้ว", + "checkuser-investigate-duration-option-30d": "30 วันที่แล้ว", + "checkuser-investigate-reason-label": "เหตุผล", + "checkuser-investigate-preliminary-notice-ip-targets": "แถบข้อมูลบัญชีไม่มีข้อมูลใด ๆ เกี่ยวกับไอพี ดู<span class=\"plainlinks\">[$1 แถบตัวแทนไอพีและผู้ใช้]</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": "ซ่อนผู้ใช้หรือไอพีต่อไปนี้", + "checkuser-investigate-timeline-notice-no-results": "ไม่มีผลลัพธ์: ไม่มีกิจกรรมที่บันทึกไว้จากผู้ใช้หรือไอพีเหล่านี้ในระยะเวลา 90 วันที่ผ่านมา", + "checkuser-investigate-timeline-notice-no-results-filters": "ไม่มีผลลัพธ์ที่ตรงกับเงื่อนไขตัวกรองเหล่านี้ ลองนำตัวกรองบางตัวออกเพื่อขยายขอบเขตการค้นหา", + "checkuser-investigate-compare-copy-button-label": "แสดงข้อความวิกิ", + "checkuser-investigate-compare-toollinks-whois": "WHOIS", + "checkuser-investigate-compare-toollinks-ipcheck": "ตรวจพร็อกซี", + "checkuser-investigate-compare-copy-message-label": "คุณต้องการคัดลอกข้อมูลนี้เป็นตารางข้อความวิกิหรือไม่", + "checkuser-investigate-compare-notice-exceeded-limit": "เนื่องจากข้อจำกัดทางเทคนิค เราถึงขีดจำกัดของจำนวนบันทึกที่สามารถนำเสนอได้แล้ว ข้อมูลที่ส่งกลับสำหรับเป้าหมายต่อไปนี้ไม่สมบูรณ์: $1 โปรดลองลดจำนวนเป้าหมาย ระยะเวลาหรือช่วงไอพีให้แคบลง", + "checkuser-investigate-compare-notice-no-results": "ไม่มีผลลัพธ์: ไม่มีการแก้ไขจากผู้ใช้หรือไอพีเหล่านี้ใน 90 วันที่ผ่านมา", + "checkuser-investigate-compare-notice-no-results-filters": "ไม่มีผลลัพธ์ที่ตรงกับเงื่อนไขตัวกรองเหล่านี้ ลองนำตัวกรองบางตัวออกเพื่อขยายขอบเขตการค้นหา", + "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-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": "ตัวแทนผู้ใช้", + "checkuser-investigate-subtitle-link-restart-tour": "เริ่มการเที่ยวชมใหม่", + "checkuser-investigate-tour-targets-title": "ตรวจสอบผู้ใช้หลาบบัญชีและไอพีหรือไม่", + "checkuser-investigate-tour-useragents-title": "ตรงกับตัวแทนผู้ใช้หรือไม่", + "checkuser-investigate-tour-addusertargets-title": "ต้องการบริบทเพิ่มเติมหรือไม่", + "checkuser-investigate-tour-filterip-title": "จำกัดการสืบสวนของคุณหรือไม่", + "checkuser-investigate-tour-block-title": "ต้องการบล็อกหรือไม่", + "checkuser-investigate-tour-copywikitext-title": "ต้องการคัดลอกข้อมูลหรือไม่" } diff --git a/CheckUser/i18n/ti.json b/CheckUser/i18n/ti.json index 8bf88263..16d57950 100644 --- a/CheckUser/i18n/ti.json +++ b/CheckUser/i18n/ti.json @@ -4,5 +4,6 @@ "Joanmp17" ] }, - "checkuser-investigate-preliminary-table-header-editcount": "ምምዕርራያት" + "checkuser-investigate-preliminary-table-header-editcount": "ኣርትዖታት", + "checkuser-investigate-compare-table-button-contribs-label": "ኣበርክቶታት" } diff --git a/CheckUser/i18n/tk.json b/CheckUser/i18n/tk.json index 87aae8bf..e40129b1 100644 --- a/CheckUser/i18n/tk.json +++ b/CheckUser/i18n/tk.json @@ -5,7 +5,6 @@ ] }, "checkuser-desc": "Ulanyjylaryň IP adreslerini we beýleki maglumatlaryny barlamak hukugy üçin degişli rugsatlary ulanyjylara berýär", - "checkuser-logcase": "Gündelik gözlegi baş-setir harpa duýgurdyr.", "checkuser": "Ulanyjy barla", "checkuserlog": "Ulanyjy barlaýjysy gündeligi", "checkuser-contribs": "ulanyjy IP adreslerini barla", @@ -32,7 +31,6 @@ "checkuser-nomatch-edits": "Gabat gelýän zat tapylmady.\nSoňky özgerdiş $2, $1 senesinde.", "checkuser-check": "Barla", "checkuser-log-fail": "Gündelik girişini goşup bolmaýar", - "checkuser-nolog": "Hiç hili gündelik faýly tapylmady.", "checkuser-blocked": "Blokirlendi", "checkuser-gblocked": "Global blokirlendi", "checkuser-locked": "Gulply", diff --git a/CheckUser/i18n/tl.json b/CheckUser/i18n/tl.json index 50fd2296..b8eefd9a 100644 --- a/CheckUser/i18n/tl.json +++ b/CheckUser/i18n/tl.json @@ -8,7 +8,6 @@ }, "checkuser-summary": "Nagmamasid ng kamakailang mga pagbabago ang kasangkapang ito upang makuhang muli ang ginamit na mga IP ng tagagamit o ipakita ang dato ng pagbabago/tagagamit para sa isang IP.\nAng mga tagagamit at mga pagbabagong ginawa ng isang IP ng kliyente ay maaaring kuhaning muli sa pamamagitan ng paggamit ng mga paulong XFF sa pamamagitan ng pagkakabit ng \"/xff\" sa IP.\nSinusuportahan ang IPv4 (CIDR $1-32) at ang IPv6 (CIDR $2-128).\nWalang mas mataas sa 5000 mga pagbabago ang ibabalik dahil sa mga kadahilanang pangpagsasagawa.\nGamitin ito ayon sa patakaran.", "checkuser-desc": "Nagbibigay sa mga tagagamit ng naaangkop na pahintulot ang kakayahang suriin ang mga adres ng IP ng tagagamit at iba pang kabatiran (impormasyon)", - "checkuser-logcase": "May kaselanan sa pagmamakinilya ng panitik ang paghahanap ng talaan.", "checkuser": "Suriin ang tagagamit", "checkuserlog": "Talaang SuriinTagagamit", "checkuser-contribs": "suriin ang mga adres ng IP ng tagagamit", @@ -40,7 +39,6 @@ "checkuser-nomatch-edits": "Walang natagpuang mga pagtutugma.\nAng huling pagbabago ay noong $1 sa $2.", "checkuser-check": "Suriin", "checkuser-log-fail": "Hindi nagawang idagdag ang ipinasok sa talaan", - "checkuser-nolog": "Walang natagpuang talaksan ng talaan.", "checkuser-blocked": "Hinadlangan", "checkuser-gblocked": "Hinadlangan na pandaigdigan", "checkuser-locked": "Ikinandado", diff --git a/CheckUser/i18n/tr.json b/CheckUser/i18n/tr.json index 74a54e89..0b05bf16 100644 --- a/CheckUser/i18n/tr.json +++ b/CheckUser/i18n/tr.json @@ -12,25 +12,26 @@ "McDutchie", "MuratTheTurkish", "Sadrettin", + "SaldırganSincap", "Sayginer", "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-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 nedenleriyle $3 düzenlemeden fazla geri almayacaktır.", + "checkuser-desc": "Uygun izne sahip kullanıcılara, kullanıcıların IP adreslerini ve diğer bilgileri kontrol etme yeteneği verir.", "checkuser": "Denetçi", "checkuserlog": "Denetçi günlüğü", - "checkuser-contribs": "kullanıcı IP'lerini kontrol et", + "checkuser-contribs": "kullanıcı IP adreslerini kontrol et", "checkuser-contribs-log": "son kullanıcı kontrolleri", + "checkuser-contribs-log-initiator": "bu kullanıcı tarafından yapılan 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": "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", + "action-checkuser-log": "denetçi günlüğünü görme", "grouppage-checkuser": "{{ns:project}}:Denetçi", "checkuser-reason": "Gerekçe:", "checkuser-reason-api": "API: $1", @@ -39,22 +40,28 @@ "checkuser-target": "IP adresi veya kullanıcı adı:", "checkuser-users": "Kullanıcıları bulup getir", "checkuser-edits": "Değişiklikleri al", - "checkuser-ips": "IP'leri bulup getir", + "checkuser-ips": "IP adresleri bulup getir", "checkuser-period": "Süre:", "checkuser-week-1": "geçen hafta", "checkuser-week-2": "son iki hafta", "checkuser-month": "son 30 gün", + "checkuser-month-2": "son 60 gün", "checkuser-all": "hepsi", "checkuser-cidr-label": "Bir IP adresi listesi için genel aralığı ve etkilenen adresleri bul", "checkuser-cidr-res": "Genel CIDR:", + "checkuser-cidr-affected-ips": "Etkilenen IP adresleri:", + "checkuser-cidr-too-small": "Aralık çok büyük", + "checkuser-range-outside-limit": "$1 aralığı izin verilen sınırların dışındadır.", "checkuser-empty": "Günlükte başka öğe yok.", "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-investigate-this-user": "Bu kullanıcıyı araştır", "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-log-checks-by": "kontrol eden", + "checkuser-log-checks-on": "kontrol edilmesi", "checkuser-blocked": "Engellendi", "checkuser-gblocked": "Küresel olarak engellendi", "checkuser-locked": "Kilitli", @@ -63,7 +70,7 @@ "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": "Engellenirken kendi tartışma sayfalarını düzenlemeyi önle", + "checkuser-blocktalk": "Engellenirken kendi mesaj 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", @@ -73,30 +80,38 @@ "checkuser-block-limit": "Çok fazla kullanıcı seçildi.", "checkuser-block-noreason": "Engellemeler için bir neden belirtmelisiniz.", "checkuser-centralauth-multilock": "Seçili hesapları toplu kilitle", + "checkuser-centralauth-multilock-list": "Bağlantıları kullanarak seçilen hesapları çoklu kilitleyin:", + "checkuser-centralauth-multilock-list-item": "$1 bağlantısı", "checkuser-noreason": "Bu sorgu için bir gerekçe göstermelisiniz.", - "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-too-many": "Çok fazla sonuç (sorgu tahminine göre), lütfen CIDR'yi daraltın.\nİşte kullanılan IP adresleri (maksimum $1, adrese göre sıralı):", "checkuser-user-nonexistent": "Belirtilen kullanıcı mevcut değil.", + "checkuser-target-nonexistent": "Belirtilen hedef mevcut değil.", + "checkuser-initiator-nonexistent": "Belirtilen başlatı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-log-search-target": "Hedef:", + "checkuser-log-search-initiator": "Başlatıcı:", "checkuser-log-search-type": "Arama ölçütü:", "checkuser-ipeditcount": "tüm kullanıcılardan ~$1", "checkuser-showmain": "Denetçi ana formuna değiştir", - "checkuser-limited": "'''Performans nedeniyle sonuçlar kırpıldı.'''", + "checkuser-show-investigate": "Ana formu araştırmaya geç", + "checkuser-limited": "'''Bu sonuçlar performans nedenleriyle kısaltılmıştır.'''", "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-log-entry-investigate": "$3, $1, $2 için bilgi aradı", "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ıya parolayı sıfırla", + "checkuser-reset-action": "$1 kullanıcısı için 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-failure-with-good-password": "{{SITENAME}} sitesinde $1 olarak oturum açılamadı, ancak doğru parolayı sahipti", "checkuser-login-success": "$1 olarak {{SITENAME}} sitesinde oturum başarıyla açıldı", "checkuser-link-investigate-label": "Yeni Denetçi aracını deneyin", "checkuser-investigateblock": "Kullanıcıları engelle", @@ -117,15 +132,12 @@ "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-page-subtitle": "$1 için mevcut soruşturma", "checkuser-investigate-subtitle-block-button-label": "Engelle", "checkuser-investigate-subtitle-cancel-button-label": "İptal", "checkuser-investigate-subtitle-continue-button-label": "Devam et", + "checkuser-investigate-subtitle-show-checkuser": "Denetçi olarak değiştir", "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", @@ -133,7 +145,7 @@ "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-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", @@ -157,6 +169,7 @@ "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-copy-button-label-hide": "Viki metni gizle", "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.", @@ -169,7 +182,7 @@ "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-edits": "<b>[$1 {{PLURAL:$1|düzenleme/eylem}}]</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ığı", diff --git a/CheckUser/i18n/ug-arab.json b/CheckUser/i18n/ug-arab.json index ab91297b..4ae60ced 100644 --- a/CheckUser/i18n/ug-arab.json +++ b/CheckUser/i18n/ug-arab.json @@ -4,7 +4,6 @@ "Sahran" ] }, - "checkuser-logcase": "خاتىرە ئىزدەشتە چوڭ كىچىك ھەرپنى پەرقلەندۈرىدۇ.", "checkuser": "ئىشلەتكۈچى تەكشۈرۈش", "checkuserlog": "ئىشلەتكۈچى خاتىرىسىنى تەكشۈرۈش", "checkuser-contribs": "ئىشلەتكۈچى IP ئادرېسىنى تەكشۈرۈش", @@ -35,7 +34,6 @@ "checkuser-nomatch-edits": "ماس كەلگەن تۈر تېپىلمىدى.\nئاخىرقى تەھرىرلەش $1 $2.", "checkuser-check": "تەكشۈر", "checkuser-log-fail": "خاتىرە تۈرىنى قوشالمايدۇ", - "checkuser-nolog": "خاتىرە ھۆججەت تېپىلمىدى.", "checkuser-blocked": "توسۇلغان", "checkuser-gblocked": "ئومۇمىيەت توسۇلغان", "checkuser-locked": "قۇلۇپلانغان", diff --git a/CheckUser/i18n/uk.json b/CheckUser/i18n/uk.json index 2ddb7e0f..4cabd55b 100644 --- a/CheckUser/i18n/uk.json +++ b/CheckUser/i18n/uk.json @@ -5,7 +5,9 @@ "Ahonc", "Alex Khimich", "Base", + "DDPAT", "Dim Grits", + "Ice bulldog", "Movses", "NickK", "Piramidion", @@ -13,21 +15,22 @@ "Sodmy", "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Використовуйте цей засіб тільки відповідно до правил.", + "checkuser-summary": "Цей засіб переглядає нові редагування для отримання IP-адрес, які використовував певний користувач, або щоб знайти редагування/користувача за IP-адресою.\nРедагування і користувачів, що редагували з певної IP-адреси, зазначеної в X-Forwarded-For, можна отримати, додавши префікс <code>/xff</code> до IP-адреси. Підтримувані версії IP: 4 (CIDR $1—32) і 6 (CIDR $2-128).\nЗ огляду на продуктивність буде показано не більше {{PLURAL:$3|редагування|редагувань}}.\nВикористовуйте цей засіб тільки відповідно до правил.", "checkuser-desc": "Надання можливості перевіряти IP-адреси та іншу інформацію користувачів", - "checkuser-logcase": "Пошук у журналі чутливий до регістру.", "checkuser": "Перевірити користувача", "checkuserlog": "Журнал перевірки користувачів", "checkuser-contribs": "перевірити IP-адреси користувача", - "checkuser-contribs-log": "недавні перевірки користувача", + "checkuser-contribs-log": "останні перевірки користувача", + "checkuser-contribs-log-initiator": "перевірки користувачів здійснені користувачем", "group-checkuser": "Чек'юзери", "group-checkuser-member": "{{GENDER:$1|чек'юзер|чек'юзерка}}", "right-checkuser": "Перевірка IP-адрес та іншої інформації про користувачів", "right-checkuser-log": "Перегляд журналу перевірки користувачів", - "action-checkuser": "перевірку IP-адрес та іншої інформації про користувача", + "action-checkuser": "Перевірка IP-адрес користувачів та іншої інформації", "action-checkuser-log": "перегляд журналу перевірки користувачів", "grouppage-checkuser": "{{ns:project}}:Чек'юзери", "checkuser-reason": "Причина:", @@ -42,17 +45,22 @@ "checkuser-week-1": "останній тиждень", "checkuser-week-2": "останні два тижні", "checkuser-month": "останні 30 днів", + "checkuser-month-2": "останні 60 днів", "checkuser-all": "усі", "checkuser-cidr-label": "Знайти загальний діапазон і задіяні адреси для списку IP-адрес", "checkuser-cidr-res": "Спільний CIDR:", + "checkuser-cidr-affected-ips": "Охоплені IP-адреси:", + "checkuser-cidr-too-small": "Завеликий діапазон", "checkuser-empty": "Журнал порожній.", "checkuser-nomatch": "Не знайдено збігів.", "checkuser-nomatch-edits": "Збіги не знайдені.\nОстаннє редагування зроблене $1 о $2.", "checkuser-check": "Перевірити", "checkuser-check-this-user": "Перевірити цього користувача", + "checkuser-investigate-this-user": "Розслідувати цього користувача", "checkuser-recent-checks": "Останні перевірки цього користувача", "checkuser-log-fail": "Не в змозі додати запис до журналу", - "checkuser-nolog": "Файл журналу не знайдений.", + "checkuser-log-checks-by": "перевірки", + "checkuser-log-checks-on": "перевірки щодо", "checkuser-blocked": "Заблокований", "checkuser-gblocked": "Заблокований глобально", "checkuser-locked": "Закритий", @@ -71,17 +79,22 @@ "checkuser-block-limit": "Вибрано забагато користувачів.", "checkuser-block-noreason": "Ви повинні вказати причину блокувань.", "checkuser-centralauth-multilock": "Заблокувати вибрані облікові записи", + "checkuser-centralauth-multilock-list-item": "Посилання $1", "checkuser-noreason": "Вам необхідно зазначити причину цього запиту.", "checkuser-too-many": "Забагато результатів (згідно з оцінкою запиту), будь ласка, звузьте CIDR.\nВикористані IP (максимум $1, відсортовані за адресою):", "checkuser-user-nonexistent": "Зазначений користувач не існує.", + "checkuser-target-nonexistent": "Указана ціль не існує.", + "checkuser-initiator-nonexistent": "Указаний ініціатор не існує.", "checkuser-search": "Знайти записи в журналі перевірок", "checkuser-search-submit": "Знайти", "checkuser-search-initiator": "ініціатор", "checkuser-search-target": "ціль", "checkuser-log-search-target": "Ціль:", + "checkuser-log-search-initiator": "Ініціатор:", "checkuser-log-search-type": "Пошук за:", "checkuser-ipeditcount": "~$1 від усіх користувачів", "checkuser-showmain": "Перейти до головної сторінки перевірки", + "checkuser-show-investigate": "Перемкнути на основну форму розслідування", "checkuser-limited": "'''Результати урізано, щоб не обтяжувати сервер.'''", "checkuser-log-entry-userips": "$3, $1 отримав IP-адреси для $2", "checkuser-log-entry-ipedits": "$3, $1 отримав редагування для <bdi>$2</bdi>", @@ -89,10 +102,11 @@ "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-log-entry-investigate": "$3, $1 переглянув інформацію для $2", "checkuser-autocreate-action": "створений автоматично", "checkuser-create-action": "створено", "checkuser-email-action": "надіслав листа користувачеві «$1»", - "checkuser-reset-action": "скинув пароль для користувача $1", + "checkuser-reset-action": "скинув пароль користувачеві $1", "checkuser-token-fail": "Помилка сесії. Будь ласка, спробуйте знову.", "checkuser-login-failure": "Не вдалося увійти в систему на сайті {{SITENAME}} як $1", "checkuser-login-success": "Виконано вхід у систему на сайті {{SITENAME}} як $1", @@ -111,21 +125,18 @@ "checkuser-investigateblock-notice-talk-page-label": "Залишити сповіщення на сторінці обговорення користувача", "checkuser-investigateblock-notice-position-label": "Позиція", "checkuser-investigateblock-notice-text-label": "Вікітекст", - "checkuser-investigateblock-notice-append": "Додати укінці сторінки", + "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-subtitle-show-checkuser": "Перейти до перевірки користувачів", "checkuser-investigate-indicator-new-investigation": "Нове розслідування", "checkuser-investigate-indicator-logs": "Журнали", "checkuser-investigate-legend": "Пошук імен користувачів, IP-адрес чи IP-діапазонів", @@ -133,7 +144,7 @@ "checkuser-investigate-tab-preliminary-check": "Відомості облікового запису", "checkuser-investigate-tab-compare": "IP-адреси й агенти користувача", "checkuser-investigate-tab-timeline": "Хронологія", - "checkuser-investigate-targets-label": "Імена користувачів та IP-адреси", + "checkuser-investigate-targets-label": "Імена користувачів та IP-адреси:", "checkuser-investigate-targets-placeholder": "Ім'я користувача або 1.1.1.1", "checkuser-investigate-duration-label": "Тривалість", "checkuser-investigate-duration-option-all": "Усе", @@ -157,6 +168,8 @@ "checkuser-investigate-timeline-notice-no-results": "Немає результатів: у цих користувачів чи IP не було активності за останні 90 днів", "checkuser-investigate-timeline-notice-no-results-filters": "За цими критеріями нічого не знайдено. Спробуйте вилучити певні фільтри для розширення області пошуку.", "checkuser-investigate-compare-copy-button-label": "Показати вікітекст", + "checkuser-investigate-compare-copy-button-label-hide": "Сховати вікірозмітку", + "checkuser-investigate-compare-toollinks-whois": "WHOIS", "checkuser-investigate-compare-toollinks-ipcheck": "Перевірка проксі", "checkuser-investigate-compare-copy-message-label": "Хочете скопіювати цю інформацію у форматі вікітаблиці?", "checkuser-investigate-compare-notice-exceeded-limit": "Через технічні обмеження ми досягли максимальної кількості записів, які можна презентувати. Виведені для вказаних цілей дані є неповними: $1. Будь ласка, спробуйте використати менше цілей, коротше часове вікно, чи вужчі IP-діапазони.", @@ -169,13 +182,23 @@ "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-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-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 й отримайте всю інформацію в одному місці. Не переживайте, ми створимо окремий запис у журналі чек'юзерів для кожного з них." + "checkuser-investigate-tour-targets-desc": "Додайте до $1 {{PLURAL:$1|імені користувача|імен користувача}} чи IP й отримайте всю інформацію в одному місці. Не переживайте, ми створимо окремий запис у журналі чек'юзерів для кожного з них.", + "checkuser-investigate-tour-useragents-title": "Однакові User agent?", + "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-адреси та user agent. Хочете повернути дані? Використайте панель Фільтри угорі, щоб вилучити фільтри.", + "checkuser-investigate-tour-block-title": "Хочете заблокувати?", + "checkuser-investigate-tour-block-desc": "Дозволяє Вам обрати користувачів, що Ви б хотіли заблокувати та переводить Вас до форми блокування для обрання необхідного блоку.", + "checkuser-investigate-tour-copywikitext-title": "Хочете скопіювати дані?", + "checkuser-investigate-tour-copywikitext-desc": "Скопіюйте таблицю порівняння одним кліком й використайте на CU-вікі. Зауважте, однак, що Ви копіюєте лише те, що видно, а не всі сторінки розслідування." } diff --git a/CheckUser/i18n/ur.json b/CheckUser/i18n/ur.json index e74e3f97..3ec01d1a 100644 --- a/CheckUser/i18n/ur.json +++ b/CheckUser/i18n/ur.json @@ -6,7 +6,6 @@ "පසිඳු කාවින්ද" ] }, - "checkuser-logcase": "لاگ ان کریں تلاش کیس حساس ہے.", "checkuser": "صارف کو چیک کریں", "checkuserlog": "صارف لاگ ان کریں چیک کریں", "checkuser-contribs-log": "حال ہی میں صارف کي", diff --git a/CheckUser/i18n/uz.json b/CheckUser/i18n/uz.json index 2bf33a24..4aef76dd 100644 --- a/CheckUser/i18n/uz.json +++ b/CheckUser/i18n/uz.json @@ -2,10 +2,12 @@ "@metadata": { "authors": [ "CoderSI", + "Jamshiduralovofficial", "Sociologist" ] }, "group-checkuser": "Foydalanuvchilarni tekshiruvchilar", "checkuser-search-target": "chetlatiluvchi", - "checkuser-autocreate-action": "avtomatik ravishda yaratilgan" + "checkuser-autocreate-action": "avtomatik ravishda yaratilgan", + "checkuser-investigate-subtitle-show-checkuser": "Foydalanuvchini Tekshirishni yoqing" } diff --git a/CheckUser/i18n/vec.json b/CheckUser/i18n/vec.json index 998171ac..8e48f786 100644 --- a/CheckUser/i18n/vec.json +++ b/CheckUser/i18n/vec.json @@ -8,7 +8,6 @@ }, "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": "Ł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", @@ -36,7 +35,6 @@ "checkuser-nomatch-edits": "No xe stà catà nissun risultato.\nL'ultima modìfega la xe stà a le ore $2 del $1.", "checkuser-check": "Controla", "checkuser-log-fail": "Inpossibile zontar la voçe al registro", - "checkuser-nolog": "No xe stà catà nissun file de registro.", "checkuser-blocked": "Blocà", "checkuser-gblocked": "Blocà globalmente", "checkuser-locked": "Blocà", diff --git a/CheckUser/i18n/vi.json b/CheckUser/i18n/vi.json index 4bffff33..986b9cb5 100644 --- a/CheckUser/i18n/vi.json +++ b/CheckUser/i18n/vi.json @@ -9,7 +9,6 @@ }, "checkuser-summary": "Công cụ này sẽ quét các thay đổi gần đây để lấy ra các IP được một thành viên sử dụng hoặc hiển thị dữ liệu sửa đổi/tài khoản của một IP. Các tài khoản và sửa đổi của một IP có thể được trích ra từ tiêu đề XFF bằng cách thêm vào IP “/xff”. IPv4 (CIDR $1-32) và IPv6 (CIDR $2-128) đều được hỗ trợ. Không quá 5000 sửa đổi sẽ được trả về vì lý do hiệu suất. Hãy dùng công cụ này theo đúng quy định.", "checkuser-desc": "Cung cấp cho những người đủ tiêu chuẩn khả năng kiểm tra địa chỉ IP và thông tin khác của người dùng khác", - "checkuser-logcase": "Tìm kiếm nhật trình có phân biệt chữ hoa chữ thường", "checkuser": "Kiểm tra người dùng", "checkuserlog": "Nhật trình CheckUser", "checkuser-contribs": "kiểm tra IP của người dùng", @@ -40,8 +39,9 @@ "checkuser-nomatch": "Không tìm thấy kết quả.", "checkuser-nomatch-edits": "Không tìm thấy kết quả.\nLần sửa đổi cuối xảy ra $1 lúc $2.", "checkuser-check": "Kiểm tra", + "checkuser-check-this-user": "Kiểm tra người dùng này", + "checkuser-recent-checks": "Tác vụ kiểm tra gần đây về người dùng này", "checkuser-log-fail": "Không thể ghi vào nhật trình", - "checkuser-nolog": "Không tìm thấy tập tin nhật trình", "checkuser-blocked": "Đã cấm", "checkuser-gblocked": "Cấm toàn cục", "checkuser-locked": "Khóa", @@ -50,9 +50,10 @@ "checkuser-massblock": "Cấm các người dùng được chọn", "checkuser-massblock-text": "Các tài khoản được chọn sẽ bị cấm vô hạn, cũng cấm mở tài khoản và tự động cấm các địa chỉ IP. Những người dùng những địa chỉ IP này sẽ bị cấm một tuần và không được mở tài khoản.", "checkuser-blockemail": "Không cho gửi thư điện tử", - "checkuser-blocktalk": "Không cho người dùng này sửa trang thảo luận người dùng của họ khi bị cấm", + "checkuser-blocktalk": "Không cho thành viên này sửa trang thảo luận thành viên của họ khi bị cấm", "checkuser-blocktag": "Thay thế các trang cá nhân bằng:", "checkuser-blocktag-talk": "Thay các trang thảo luận bằng:", + "checkuser-reblock": "Ghi đè các tác vụ cấm hiện tại", "checkuser-massblock-commit": "Cấm những người dùng được chọn", "checkuser-block-success": "'''{{PLURAL:$2|Người|Những người}} dùng $1 mới bị cấm.'''", "checkuser-block-failure": "'''Không ai bị cấm.'''", @@ -60,7 +61,7 @@ "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-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-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 $1, 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", "checkuser-search-submit": "Tìm kiếm", @@ -70,6 +71,7 @@ "checkuser-log-search-type": "Tìm theo:", "checkuser-ipeditcount": "~$1 trong tất cả các thành viên", "checkuser-showmain": "Mở mẫu CheckUser chính", + "checkuser-show-investigate": "Chuyển sang biểu mẫu Điều tra", "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 <bdi>$2</bdi>", @@ -82,11 +84,86 @@ "checkuser-email-action": "gửi thư điện tử cho người dùng “$1”", "checkuser-reset-action": "tái tạo mật khẩu của người dùng “$1”", "checkuser-token-fail": "Phiên làm việc bị thất bại. Xin hãy thử lại.", + "checkuser-login-failure": "Thất bại khi đăng nhập vào {{SITENAME}} như $1", + "checkuser-login-success": "Đăng nhập thành công vào {{SITENAME}} như $1", "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 */", + "checkuser-link-investigate-label": "Hãy thử công cụ Kiểm tra người dùng mới", + "checkuser-investigateblock": "Cấm người dùng", + "checkuser-investigateblock-target": "Tên thành viên và địa chỉ IP", + "checkuser-investigateblock-actions": "Tác vụ bị cấm", + "checkuser-investigateblock-reason": "Lý do", + "checkuser-investigateblock-options": "Tùy chọn khác", + "checkuser-investigateblock-email-label": "Không cho gửi thư điện tử", + "checkuser-investigateblock-usertalk-label": "Không cho thành viên này sửa trang thảo luận thành viên của họ khi bị cấm", + "checkuser-investigateblock-reblock-label": "Ghi đè các tác vụ cấm hiện tại", + "checkuser-investigateblock-notice-user-page-label": "Nhắn tin vào trang cá nhân", + "checkuser-investigateblock-notice-talk-page-label": "Nhắn tin vào trang thảo luận cá nhân", + "checkuser-investigateblock-notice-position-label": "Vị trí", "checkuser-investigateblock-notice-text-label": "Wikitext", + "checkuser-investigateblock-notice-append": "Thêm vào cuối trang", + "checkuser-investigateblock-notice-prepend": "Thêm vào đầu trang", + "checkuser-investigateblock-notice-replace": "Thay thế trang", + "checkuser-investigateblock-failure": "Không người dùng nào bị cấm. Để ghi đè các tác vụ cấm hiện tại, đánh hộp kiểm: “{{int:checkuser-investigateblock-reblock-label}}”. Tác vụ cấm sẽ không bị ghi đè nếu tác vụ cấm mới giống hệt với tác vụ cấm hiện tại.", + "checkuser-investigateblock-success": "{{PLURAL:$2|Người dùng|Những người dùng}} $1 mới {{PLURAL:$2|bị|đều bị}} cấm.", + "checkuser-investigateblock-notices-failed": "Không thể thêm thông báo vào một số trang cá nhân hoặc trang thảo luận cá nhân.", + "checkuser-investigate": "Điều tra", + "checkuser-investigate-page-subtitle": "Cuộc điều tra hiện tại về $1", + "checkuser-investigate-subtitle-block-button-label": "Cấm", + "checkuser-investigate-subtitle-cancel-button-label": "Hủy bỏ", + "checkuser-investigate-subtitle-continue-button-label": "Tiếp tục", + "checkuser-investigate-indicator-new-investigation": "Cuộc điều tra mới", + "checkuser-investigate-indicator-logs": "Nhật trình", + "checkuser-investigate-legend": "Tìm tên thành viên, địa chỉ IP, hoặc dãy địa chỉ IP", + "checkuser-investigate-notice-no-results": "Không có kết quả.", + "checkuser-investigate-tab-preliminary-check": "Thông tin tài khoản", + "checkuser-investigate-tab-compare": "Địa chỉ IP và tác nhân người dùng", + "checkuser-investigate-tab-timeline": "Thời biểu", + "checkuser-investigate-targets-label": "Tên thành viên và địa chỉ IP", + "checkuser-investigate-targets-placeholder": "TênThànhViên hoặc 1.1.1.1", + "checkuser-investigate-duration-label": "Thời lượng", + "checkuser-investigate-duration-option-all": "Tất cả", + "checkuser-investigate-duration-option-1w": "Tuần qua", + "checkuser-investigate-duration-option-2w": "2 tuần qua", + "checkuser-investigate-duration-option-30d": "30 ngày qua", + "checkuser-investigate-reason-label": "Lý do", + "checkuser-investigate-preliminary-notice-ip-targets": "Thẻ Thông tin tài khoản không bao gồm thông tin nào về địa chỉ IP. Xem các chi tiết về địa chỉ IP trong <span class=\"plainlinks\">[$1 thẻ Địa chỉ IP và tác nhân người dùng]</span>.", + "checkuser-investigate-preliminary-table-cell-blocked": "Đã cấm", + "checkuser-investigate-preliminary-table-cell-edits": "$1 lần sửa đổi", + "checkuser-investigate-preliminary-table-cell-unblocked": "Không bị cấm", + "checkuser-investigate-preliminary-table-header-blocked": "Trạng thái", + "checkuser-investigate-preliminary-table-header-editcount": "Sửa đổi", + "checkuser-investigate-preliminary-table-header-groups": "Nhóm", + "checkuser-investigate-preliminary-table-header-name": "Tên thành viên", + "checkuser-investigate-preliminary-table-header-registration": "Ngày đính kèm", + "checkuser-investigate-preliminary-table-header-wiki": "Wiki", + "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Không tìm thấy wiki", + "checkuser-investigate-filters-legend": "Bộ lọc", + "checkuser-investigate-filters-exclude-targets-label": "Ẩn các thành viên hoặc địa chỉ IP sau", + "checkuser-investigate-timeline-notice-no-results": "Không có kết quả: các thành viên hoặc địa chỉ IP này không thực hiện tác vụ nào được ghi trong 90 ngày qua", + "checkuser-investigate-timeline-notice-no-results-filters": "Không có kết quả trùng với các điều kiện lọc này. Hãy thử bỏ một số bộ lọc để làm rộng truy vấn.", + "checkuser-investigate-compare-copy-button-label": "Hiện mã wiki", + "checkuser-investigate-compare-toollinks-ipcheck": "Kiểm tra máy chủ proxy", + "checkuser-investigate-compare-copy-message-label": "Bạn có muốn sao chép thông tin này dưới dạng bảng mã wiki?", + "checkuser-investigate-compare-notice-no-results": "Không có kết quả: các thành viên hoặc địa chỉ IP này không thực hiện sửa đổi nào trong 90 ngày qua", + "checkuser-investigate-compare-notice-no-results-filters": "Không có kết quả trùng với các điều kiện lọc này. Hãy thử bỏ một số bộ lọc để làm rộng truy vấn.", + "checkuser-investigate-compare-table-button-add-ip-targets-label": "Hiện các IP ứng với người dùng này", + "checkuser-investigate-compare-table-button-add-user-targets-label": "Hiện các người dùng ứng với IP này", + "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Thêm địa chỉ IP này vào cuộc điều tra", + "checkuser-investigate-compare-table-button-checks-label": "Tác vụ kiểm tra", + "checkuser-investigate-compare-table-button-contribs-label": "Đóng góp", + "checkuser-investigate-compare-table-button-filter-label": "Lọc ra khỏi các kết quả", + "checkuser-investigate-compare-table-cell-unregistered": "Vô danh", + "checkuser-investigate-compare-table-cell-edits": "<b>[$1 lần sửa đổi]</b>", + "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 bởi các người dùng)</i>", + "checkuser-investigate-compare-table-header-username": "Tên thành viên", + "checkuser-investigate-compare-table-header-activity": "Phạm vi ngày", + "checkuser-investigate-compare-table-header-ip": "Địa chỉ IP", + "checkuser-investigate-compare-table-header-useragent": "Tác nhân người dùng", "checkuser-investigate-tour-targets-title": "Kiểm tra nhiều người dùng và IP?", + "checkuser-investigate-tour-useragents-title": "Tác nhân người dùng khớp?", "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-title": "Cần thêm bối cảnh?", "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.", diff --git a/CheckUser/i18n/vo.json b/CheckUser/i18n/vo.json index 8d08f521..83b1fc7d 100644 --- a/CheckUser/i18n/vo.json +++ b/CheckUser/i18n/vo.json @@ -7,7 +7,6 @@ }, "checkuser-summary": "Stum at vestigon votükamis brefabüik ad dagetön ladetis-IP fa geban semik pagebölis, ud ad jonön redakama- u gebananünis tefü ladet-IP semik.\nGebans e redakams se dona-IP kanons pagetön de tiäds: XFF medä läükoy eli „/xff“ ladete-IP. Els IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128) kanons pagebön.\nRedakams no plu 5000 pejonons sekü kods kaenavik. Gebolös stumi at bai nomem.", "checkuser-desc": "Gevon gebanes labü däl zesüdik fägi ad vestigön ladeti(s)-IP gebana äsi nünis votik", - "checkuser-logcase": "Pö suk in registar mayuds e minuds padifükons.", "checkuser": "Vestigön gebani", "checkuserlog": "Vestigön gebani: jenotalised", "group-checkuser": "Gebanavestigans", @@ -32,7 +31,6 @@ "checkuser-nomatch-edits": "No petuvon.\nRedakam lätik ejenon ün $1, tü $2.", "checkuser-check": "Vestigön", "checkuser-log-fail": "No eplöpos ad laükön jenotalisede", - "checkuser-nolog": "Ragiv jenotaliseda no petuvon.", "checkuser-blocked": "Peblokon", "checkuser-gblocked": "Peblokon valöpo", "checkuser-locked": "Pelökofärmükon", diff --git a/CheckUser/i18n/wa.json b/CheckUser/i18n/wa.json index c3c714f8..35fbc960 100644 --- a/CheckUser/i18n/wa.json +++ b/CheckUser/i18n/wa.json @@ -1,16 +1,16 @@ { "@metadata": { "authors": [ + "Reptilien.19831209BE1", "Srtxg" ] }, "checkuser-summary": "Ciste usteye ci rwaite les dierins candjmints po trover les adresses IP eployeyes pa èn uzeu ou mostrer les dnêyes des candjmints/uzeus po ene adresse IP dnêye.\nLes uzeus et candjmints fwaits a pårti d' ene adresse IP polèt esse cwerous après viè les tiestires XFF tot radjoutant «/xff» al fén d' l' adresse IP.\nIPv4 (CIDR /$1 a /32) et IPv6 (CIDR /$2 a /128) sont ambedeus sopoirtés.\nPo des råjhons di performance i gn årè nén d' pus di 5000 responses di rtournêyes.\nEployîz ciste usteye tot shuvant les rîles.", "checkuser-desc": "Permete ås cis k' end ont les permissions di cweri les adresses IP et d' ôtès infôrmåcions so les uzeus.", - "checkuser-logcase": "Li cweraedje dins l' djournå fwait l' diferince etur grandes et petitès letes.", "checkuser": "Verifiaedje des uzeus", "checkuserlog": "Djournå des verifiaedjes d' uzeus", "checkuser-contribs": "cweri les adresses IP des uzeus", - "group-checkuser": "Verifieus d' uzeus", + "group-checkuser": "Verifieus d’ uzeus", "group-checkuser-member": "{{GENDER:$1|verifieu|verifieuse}} d' uzeus", "right-checkuser": "Cweri après les adresses IP et d' ôtès infôrmåcions d' èn uzeu", "right-checkuser-log": "Vey li djournå des verifiaedjes d' uzeus", @@ -37,7 +37,6 @@ "checkuser-nomatch-edits": "I n' a rén ki corespond.\nLi dierin candjmint a stî fwait l' $1 a $2.", "checkuser-check": "Cweri après", "checkuser-log-fail": "Dji n' a savou radjouter ene intrêye e djournå.", - "checkuser-nolog": "Nou fitchî djournå di trové.", "checkuser-blocked": "Bloké", "checkuser-gblocked": "Bloké totavå", "checkuser-locked": "Dismetou", diff --git a/CheckUser/i18n/yi.json b/CheckUser/i18n/yi.json index d32b8d05..fb11177d 100644 --- a/CheckUser/i18n/yi.json +++ b/CheckUser/i18n/yi.json @@ -1,6 +1,7 @@ { "@metadata": { "authors": [ + "Pacha Tchernof", "פוילישער" ] }, @@ -26,7 +27,6 @@ "checkuser-nomatch-edits": "נישט געטראפֿן קיין פאָרן.\nלעצטע רעדאַקטירונג געווען אום $1 אין $2.", "checkuser-check": "בודק זײַן", "checkuser-log-fail": "נישט מעגלעך צולייגן בײַשרײַבונג אין לאג-בוך.", - "checkuser-nolog": "נישט געפֿונען קיין לאג בוך.", "checkuser-blocked": "בלאקירט", "checkuser-gblocked": "בלאקירט גלאבאַליש", "checkuser-locked": "פֿאַרשלאסן", @@ -40,5 +40,6 @@ "checkuser-ipeditcount": "~$1 פון אלע באניצער", "checkuser-create-action": "איז געווארן געשאפן", "checkuser-email-action": "געשיקט א בליצבריוו צו באניצער \"$1\"", - "checkuser-reset-action": "צוריקשטעלן פאסווארט פאר באניצער \"$1\"" + "checkuser-reset-action": "צוריקשטעלן פאסווארט פאר באניצער \"$1\"", + "checkuser-investigate-subtitle-cancel-button-label": "אַנולירן" } diff --git a/CheckUser/i18n/yue.json b/CheckUser/i18n/yue.json index b9d07cb1..a8cf34a7 100644 --- a/CheckUser/i18n/yue.json +++ b/CheckUser/i18n/yue.json @@ -7,7 +7,6 @@ }, "checkuser-summary": "呢個工具會響最近更改度掃瞄對一位用戶用過嘅IP地址,或者係睇一個IP嘅用戶資料同埋佢嘅編輯記錄。\n\t響用戶同埋用戶端IP嘅編輯係可幾經由XFF頭,加上 \"/xff\" 就可以拎到。呢個工具係支援 IPv4 (CIDR $1-32) 同埋 IPv6 (CIDR $2-128)。\n\t由於為咗效能方面嘅原因,將唔會顯示多過5000次嘅編輯。請跟源政策去用呢個工具。", "checkuser-desc": "畀有合適權限嘅用戶查其他用戶嘅IP地址同其他資料", - "checkuser-logcase": "搵呢個日誌係有分大細楷嘅。", "checkuser": "核對用戶", "checkuserlog": "稽查用戶日誌", "group-checkuser": "稽查員", @@ -25,7 +24,6 @@ "checkuser-nomatch": "搵唔到符合嘅資訊。", "checkuser-check": "检查", "checkuser-log-fail": "唔能夠加入日誌項目", - "checkuser-nolog": "搵唔到日誌檔。", "checkuser-blocked": "已經封鎖", "checkuser-too-many": "太多結果,請收窄個CIDR。\n呢度係個用過嘅IP (最多5000個,按地址排):", "checkuser-user-nonexistent": "指定嘅用戶唔存在。", diff --git a/CheckUser/i18n/zgh.json b/CheckUser/i18n/zgh.json new file mode 100644 index 00000000..b3cb7700 --- /dev/null +++ b/CheckUser/i18n/zgh.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Hakim1bal" + ] + }, + "checkuser-search-submit": "ⵔⵣⵓ", + "checkuser-investigate-preliminary-table-header-editcount": "ⵉⵙⵏⴼⵍⵏ" +} diff --git a/CheckUser/i18n/zh-hans.json b/CheckUser/i18n/zh-hans.json index a09ff0d6..6557a4c3 100644 --- a/CheckUser/i18n/zh-hans.json +++ b/CheckUser/i18n/zh-hans.json @@ -1,9 +1,13 @@ { "@metadata": { "authors": [ + ")8", "Anakmalaysia", "Bencmq", + "Diskdance", + "FakeGreenHand", "Gaoxuewei", + "GuoPC", "Gzdavidwong", "Hydra", "Jimmy xu wrk", @@ -12,35 +16,42 @@ "Mywood", "PhiLiP", "Shirayuki", + "Shizhao", "Shuiwater", "SomeyaMako", "Ssc", + "Stang", + "Tr jason", + "Tranve", "WhitePhosphorus", "Wmr", "Wmr89502270", + "Wzl19371", "Xiaomingyan", + "Xzonn", "Yfdyh000", "乌拉跨氪", "列维劳德", + "星海", "沈澄心", "白布飘扬", "铁桶" ] }, - "checkuser-summary": "本工具会从最近更改中获取用户使用过的IP地址,可使用XFF头信息来获取同一客户端IP地址下的用户和编辑,即在IP地址后方附加“/xff”。本工具支持IPv4(CIDR $1-32)和IPv6(CIDR $2-128)。由于效率原因,本工具只能查询最近5000笔编辑次数。请确保您的操作符合方针。", - "checkuser-desc": "令已授权用户可以核查用户的IP地址及其他信息", - "checkuser-logcase": "日志搜索是区分大小写的。", + "checkuser-summary": "本工具会从最近更改中获取某个用户使用过的IP地址,或者显示某个IP地址下的编辑/用户。\n可在IP地址后方附加“/xff”以使用XFF头信息来获取同一客户端IP地址下的用户和编辑。支持IPv4(CIDR $1-32)和IPv6(CIDR $2-128)。\n由于性能问题,本工具最多返回$3笔最近编辑信息。\n请确保您的操作符合方针。", + "checkuser-desc": "授予有相应权限的用户核查用户的IP地址及其他信息的能力", "checkuser": "用户查核", "checkuserlog": "用户查核日志", "checkuser-contribs": "查核用户IP地址", "checkuser-contribs-log": "最近的用户查核", + "checkuser-contribs-log-initiator": "由该用户完成的用户检查", "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": "API: $1", "checkuser-showlog": "切换到用户查核日志", @@ -53,24 +64,27 @@ "checkuser-week-1": "上周", "checkuser-week-2": "前两周", "checkuser-month": "前30天", + "checkuser-month-2": "60 天内", "checkuser-all": "所有", "checkuser-cidr-label": "检查指定IP列表的共同区段", "checkuser-cidr-res": "通用CIDR:", + "checkuser-cidr-affected-ips": "受影响的 IP 地址:", + "checkuser-cidr-too-small": "范围过大", "checkuser-empty": "日志里没有项目。", "checkuser-nomatch": "找不到匹配项目。", "checkuser-nomatch-edits": "找不到匹配项目。最近一次编辑于$1$2。", "checkuser-check": "查核", "checkuser-check-this-user": "查核该用户", + "checkuser-investigate-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地址自动封禁,停用账户创建。IP地址将仅对匿名用户封禁一周,账户创建将停用。", + "checkuser-massblock-text": "选择的账号将被不限期封禁,并启用IP地址自动封禁,停用账号创建。IP地址将仅对匿名用户封禁一周,账号创建将停用。", "checkuser-blockemail": "阻止发送电子邮件", "checkuser-blocktalk": "在封禁期间阻止编辑他们自己的讨论页", "checkuser-blocktag": "替换用户页面内容为:", @@ -85,14 +99,18 @@ "checkuser-noreason": "您必须解释此次查询的原因。", "checkuser-too-many": "结果过多(根据查询估计),请缩小CIDR的范围。\n下面列出了使用过的IP地址(最多$1个,按地址排列):", "checkuser-user-nonexistent": "指定的用户不存在。", + "checkuser-target-nonexistent": "指定的目标不存在。", + "checkuser-initiator-nonexistent": "指定的操作者不存在。", "checkuser-search": "搜索用户查核日志记录", "checkuser-search-submit": "搜索", "checkuser-search-initiator": "操作者", "checkuser-search-target": "目标", "checkuser-log-search-target": "目标:", + "checkuser-log-search-initiator": "操作者:", "checkuser-log-search-type": "搜索类型:", "checkuser-ipeditcount": "~在全部用户中$1", "checkuser-showmain": "切换到用户查核主表单", + "checkuser-show-investigate": "切换到调查主表单", "checkuser-limited": "'''结果已因效率原因而被删减。'''", "checkuser-log-entry-userips": "$3,$1获取了$2的IP地址", "checkuser-log-entry-ipedits": "$3,$1获取了<bdi>$2</bdi>的编辑记录", @@ -100,6 +118,7 @@ "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-log-entry-investigate": "$3,$1查找$2的信息", "checkuser-autocreate-action": "已自动创建", "checkuser-create-action": "已创建", "checkuser-email-action": "向用户“$1”发送电邮", @@ -109,6 +128,7 @@ "checkuser-login-success": "成功作为$1登录至{{SITENAME}}", "group-checkuser.css": "/* 这里放置的CSS将只影响用户查核员 */", "group-checkuser.js": "/* 这里放置的JS将只影响用户查核员 */", + "checkuser-link-investigate-label": "试试新的CheckUser工具", "checkuser-investigateblock": "封禁用户", "checkuser-investigateblock-target": "用户名和IP地址", "checkuser-investigateblock-actions": "封禁操作", @@ -120,24 +140,80 @@ "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-text-label": "Wikitext", "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": "调查", + "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-subtitle-show-checkuser": "切换到CheckUser", + "checkuser-investigate-indicator-new-investigation": "新调查", "checkuser-investigate-indicator-logs": "日志", - "checkuser-investigate-tab-preliminary-check": "账户信息", + "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-compare-copy-button-label": "显示维基文本", - "checkuser-investigate-compare-copy-message-label": "您是否想要将这些信息复制为维基文本格式的表格?", + "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": "显示wikitext", + "checkuser-investigate-compare-copy-button-label-hide": "隐藏wikitext", + "checkuser-investigate-compare-toollinks-ipcheck": "代理检查", + "checkuser-investigate-compare-copy-message-label": "您是否想要将这些信息复制为wikitext格式的表格?", + "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-filter-label": "从结果中筛选" + "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-hant.json b/CheckUser/i18n/zh-hant.json index 231b5e80..438aa27b 100644 --- a/CheckUser/i18n/zh-hant.json +++ b/CheckUser/i18n/zh-hant.json @@ -5,6 +5,7 @@ "Alexsh", "Anakmalaysia", "Cwlin0416", + "Diskdance", "EagerLin", "Horacewai2", "Kly", @@ -15,26 +16,29 @@ "Mark85296341", "Oapbtommy", "Sanmosa", + "Tranve", "Waihorace", + "Winston Sung", "Wrightbus", "Xiplus", - "一個正常人" + "一個正常人", + "星海" ] }, - "checkuser-summary": "本工具會從最近更改中取得使用者使用過的 IP 位址,可使用 XFF 標頭資訊來取得同一客戶端 IP 位址下的使用者和編輯,即在 IP 位址後方加上 \"/xff\"。 本工具支援 IPv4 (CIDR $1-32) 與 IPv6 (CIDR $2-128)。 考量到效率問題,本工具只允許查詢最近 5000 筆編輯。 請確認你的操作符合政策規範。", + "checkuser-summary": "本工具會從最近更改中取得使用者使用過的 IP 位址,可使用 XFF 標頭資訊來取得同一客戶端 IP 位址下的使用者和編輯,即在 IP 位址後方加上 \"/xff\"。 本工具支援 IPv4 (CIDR $1-32) 與 IPv6 (CIDR $2-128)。 考量到效率問題,本工具只允許查詢最近 $3 筆編輯。 請確認你的操作符合政策規範。", "checkuser-desc": "授權使用者適當的權限能夠檢查使用者的 IP 位址與其他資訊", - "checkuser-logcase": "搜尋時請注意大小寫的區分", "checkuser": "查核使用者", "checkuserlog": "檢查使用者日誌", "checkuser-contribs": "檢查使用者 IP 位址", "checkuser-contribs-log": "最近的使用者檢查", + "checkuser-contribs-log-initiator": "由該使用者完成的使用者檢查", "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": "API:$1", "checkuser-showlog": "切換到用戶查核日誌", @@ -47,17 +51,22 @@ "checkuser-week-1": "最近 1 週", "checkuser-week-2": "最近 2 週", "checkuser-month": "最近 30 天", + "checkuser-month-2": "最近 60 天", "checkuser-all": "全部", "checkuser-cidr-label": "尋找 IP 位址清單中共同的範圍與影響的 IP 位址", "checkuser-cidr-res": "通用 CIDR:", + "checkuser-cidr-affected-ips": "受影響的 IP 位址:", + "checkuser-cidr-too-small": "範圍太大", "checkuser-empty": "沒有任何日誌項目。", "checkuser-nomatch": "沒有符合的資訊", "checkuser-nomatch-edits": "沒有符合的資訊。\n最近一次編輯於 $1 $2。", "checkuser-check": "檢查", "checkuser-check-this-user": "檢查此使用者", + "checkuser-investigate-this-user": "調查這名使用者", "checkuser-recent-checks": "此使用者的最近檢查", "checkuser-log-fail": "無法新增日誌項目。", - "checkuser-nolog": "找不到日誌檔。", + "checkuser-log-checks-by": "檢查由", + "checkuser-log-checks-on": "檢查在", "checkuser-blocked": "已封鎖", "checkuser-gblocked": "全域封鎖", "checkuser-locked": "已鎖定", @@ -79,14 +88,18 @@ "checkuser-noreason": "您必須提供進行查詢的原因。", "checkuser-too-many": "查詢結果過多 (根據查詢估計),請縮小 CIDR 的範圍。\n以下為使用到的 IP 位址 (最多 $1 個,依位址排列):", "checkuser-user-nonexistent": "指定的使用者不存在。", + "checkuser-target-nonexistent": "指定的目標不存在。", + "checkuser-initiator-nonexistent": "指定的操作者不存在。", "checkuser-search": "搜尋用戶查核日誌", "checkuser-search-submit": "搜尋", "checkuser-search-initiator": "操作者", "checkuser-search-target": "目標", "checkuser-log-search-target": "目標:", + "checkuser-log-search-initiator": "操作者:", "checkuser-log-search-type": "搜尋類型:", "checkuser-ipeditcount": "~從全部使用者中 $1", "checkuser-showmain": "切換至檢查使用者主表單", + "checkuser-show-investigate": "切換到調查主要表單", "checkuser-limited": "'''查詢結果因效能問題已刪減。'''", "checkuser-log-entry-userips": "$3,$1取得了$2的IP地址", "checkuser-log-entry-ipedits": "$3,$1獲取了<bdi>$2</bdi>的編輯記錄", @@ -94,10 +107,11 @@ "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-log-entry-investigate": "$3,$1查找對於$2的資訊", "checkuser-autocreate-action": "已自動建立", "checkuser-create-action": "已建立", "checkuser-email-action": "傳送電子郵件聯絡使用者 \"$1\"", - "checkuser-reset-action": "為使用者 \"$1\" 重設密碼", + "checkuser-reset-action": "為使用者$1重設密碼", "checkuser-token-fail": "連線階段錯誤,請再試一次。", "checkuser-login-failure": "以$1身分登入{{SITENAME}}失敗", "checkuser-login-success": "成功以$1身分登入{{SITENAME}}", @@ -113,22 +127,19 @@ "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-text-label": "wikitext", "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-subtitle-show-checkuser": "切換到 CheckUser", "checkuser-investigate-indicator-new-investigation": "新調查", "checkuser-investigate-indicator-logs": "日誌", "checkuser-investigate-legend": "搜尋使用者名稱、IP 位址、或是 IP 範圍", @@ -136,7 +147,7 @@ "checkuser-investigate-tab-preliminary-check": "帳號資訊", "checkuser-investigate-tab-compare": "IP 與使用者代理", "checkuser-investigate-tab-timeline": "時間軸", - "checkuser-investigate-targets-label": "使用者名稱與 IP 位址", + "checkuser-investigate-targets-label": "使用者名稱與 IP 位址:", "checkuser-investigate-targets-placeholder": "使用者名稱或 1.1.1.1", "checkuser-investigate-duration-label": "期間", "checkuser-investigate-duration-option-all": "全部", @@ -159,9 +170,10 @@ "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-copy-button-label": "顯示 wikitext", + "checkuser-investigate-compare-copy-button-label-hide": "隱藏 wikitext", "checkuser-investigate-compare-toollinks-ipcheck": "代理檢查", - "checkuser-investigate-compare-copy-message-label": "您想要將此資訊複製成 wiki 語法表格嗎?", + "checkuser-investigate-compare-copy-message-label": "您想要將此資訊複製成 wikitext 表格嗎?", "checkuser-investigate-compare-notice-exceeded-limit": "由於技術上的限制,我們已達到可呈現紀錄的數量。以下目標所回傳的資料內容不完整:$1。請嘗試使用較少的目標、較小的時窗、或是較窄的 IP 範圍。", "checkuser-investigate-compare-notice-no-results": "沒有結果:沒有在過去 90 天來自這些使用者或 IP 的結果", "checkuser-investigate-compare-notice-no-results-filters": "沒有符合這些篩選條件的結果。嘗試移除一些篩選來擴大搜尋。", @@ -172,7 +184,7 @@ "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-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": "日期範圍", diff --git a/CheckUser/i18n/zh-hk.json b/CheckUser/i18n/zh-hk.json index bf377b38..4730f8df 100644 --- a/CheckUser/i18n/zh-hk.json +++ b/CheckUser/i18n/zh-hk.json @@ -3,15 +3,17 @@ "authors": [ "A2093064", "Liuxinyu970226", - "Xiplus" + "LuciferianThomas", + "Xiplus", + "星海" ] }, "checkuser": "查核用戶", "checkuserlog": "用戶查核日誌", "group-checkuser": "用戶查核員", "group-checkuser-member": "{{GENDER:$1|用戶查核員}}", - "grouppage-checkuser": "{{ns:project}}:用戶查核", - "checkuser-target": "IP 位址或用戶名稱:", + "grouppage-checkuser": "{{ns:project}}:用戶查核員", + "checkuser-target": "IP位址或用戶名:", "checkuser-users": "查詢用戶", "checkuser-block-success": "'''{{PLURAL:$2|用戶}} $1 {{PLURAL:$2|已被}}查封。'''", "checkuser-block-failure": "'''沒有用戶被禁封。'''", diff --git a/CheckUser/includes/CheckUserHooks.php b/CheckUser/includes/CheckUserHooks.php deleted file mode 100644 index 4facc308..00000000 --- a/CheckUser/includes/CheckUserHooks.php +++ /dev/null @@ -1,718 +0,0 @@ -<?php - -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 - * Note that other extensions (like AbuseFilter) may call this function directly - * if they want to send data to CU without creating a recentchanges entry - * @param RecentChange $rc - * @return bool - */ - public static function updateCheckUserData( RecentChange $rc ) { - 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 ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) { - return true; - } - /** - * RC_EXTERNAL recent changes are not triggered by actions on the local wiki. - * Thus there is no reason to store checkuser data about them. - * @see https://phabricator.wikimedia.org/T125664 - */ - if ( $rc->getAttribute( 'rc_type' ) == RC_EXTERNAL ) { - return true; - } - - $attribs = $rc->getAttributes(); - // Get IP - $ip = $wgRequest->getIP(); - // Get XFF header - $xff = $wgRequest->getHeader( 'X-Forwarded-For' ); - list( $xff_ip, $isSquidOnly ) = self::getClientIPfromXFF( $xff ); - // Get agent - $agent = $wgRequest->getHeader( 'User-Agent' ); - // Store the log action text for log events - // $rc_comment should just be the log_comment - // 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 = ''; - } - - $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'], - 'cuc_minor' => $attribs['rc_minor'], - 'cuc_user' => $attribs['rc_user'], - 'cuc_user_text' => $attribs['rc_user_text'], - 'cuc_actiontext' => $actionText, - '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' => IPUtils::sanitizeIP( $ip ), - 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null, - 'cuc_xff' => !$isSquidOnly ? $xff : '', - '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! - if ( isset( $attribs['rc_cur_id'] ) ) { - $rcRow['cuc_page_id'] = $attribs['rc_cur_id']; - } - - Hooks::run( 'CheckUserInsertForRecentChange', [ $rc, &$rcRow ] ); - - $dbw = $services->getDBLoadBalancer()->getConnectionRef( DB_MASTER ); - $dbw->insert( 'cu_changes', $rcRow, __METHOD__ ); - - return true; - } - - /** - * Hook function to store password reset - * Saves user data into the cu_changes table - * - * @param User $user Sender - * @param string $ip - * @param User $account Receiver - * @return bool - */ - public static function updateCUPasswordResetData( User $user, $ip, $account ) { - global $wgRequest; - - // Get XFF header - $xff = $wgRequest->getHeader( 'X-Forwarded-For' ); - list( $xff_ip, $isSquidOnly ) = self::getClientIPfromXFF( $xff ); - // Get agent - $agent = $wgRequest->getHeader( 'User-Agent' ); - - $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' => $actionText, - 'cuc_comment' => '', - 'cuc_this_oldid' => 0, - 'cuc_last_oldid' => 0, - 'cuc_type' => RC_LOG, - 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ), - 'cuc_ip' => IPUtils::sanitizeIP( $ip ), - 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null, - 'cuc_xff' => !$isSquidOnly ? $xff : '', - 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null, - 'cuc_agent' => $agent - ]; - $dbw->insert( 'cu_changes', $rcRow, __METHOD__ ); - - return true; - } - - /** - * Hook function to store email data. - * - * Saves user data into the cu_changes table. - * Uses a deferred update to save the data, because emails can be sent from code paths - * that don't open master connections. - * - * @param MailAddress $to - * @param MailAddress $from - * @param string $subject - * @param string $text - * @return bool - */ - public static function updateCUEmailData( $to, $from, $subject, $text ) { - global $wgSecretKey, $wgRequest, $wgCUPublicKey; - - if ( !$wgSecretKey || $from->name == $to->name ) { - return true; - } elseif ( wfReadOnly() ) { - return true; - } - - $userFrom = User::newFromName( $from->name ); - $userTo = User::newFromName( $to->name ); - $hash = md5( $userTo->getEmail() . $userTo->getId() . $wgSecretKey ); - // Get IP - $ip = $wgRequest->getIP(); - // Get XFF header - $xff = $wgRequest->getHeader( 'X-Forwarded-For' ); - list( $xff_ip, $isSquidOnly ) = self::getClientIPfromXFF( $xff ); - // Get agent - $agent = $wgRequest->getHeader( 'User-Agent' ); - - $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' => $actionText, - 'cuc_comment' => '', - 'cuc_this_oldid' => 0, - 'cuc_last_oldid' => 0, - 'cuc_type' => RC_LOG, - 'cuc_timestamp' => $dbr->timestamp( wfTimestampNow() ), - 'cuc_ip' => IPUtils::sanitizeIP( $ip ), - 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null, - 'cuc_xff' => !$isSquidOnly ? $xff : '', - 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null, - 'cuc_agent' => $agent - ]; - if ( trim( $wgCUPublicKey ) != '' ) { - $privateData = $userTo->getEmail() . ":" . $userTo->getId(); - $encryptedData = new CheckUserEncryptedData( $privateData, $wgCUPublicKey ); - $rcRow = array_merge( $rcRow, [ 'cuc_private' => serialize( $encryptedData ) ] ); - } - - $fname = __METHOD__; - DeferredUpdates::addCallableUpdate( function () use ( $lb, $rcRow, $fname ) { - $dbw = $lb->getConnectionRef( DB_MASTER ); - $dbw->insert( 'cu_changes', $rcRow, $fname ); - } ); - - return true; - } - - /** - * Hook function to store registration and autocreation data - * Saves user data into the cu_changes table - * - * @param User $user - * @param bool $autocreated - * @return true - */ - public static function onLocalUserCreated( User $user, $autocreated ) { - return self::logUserAccountCreation( - $user, - $autocreated ? 'checkuser-autocreate-action' : 'checkuser-create-action' - ); - } - - /** - * @param User $user - * @param string $actiontext - * @return bool - */ - protected static function logUserAccountCreation( User $user, $actiontext ) { - global $wgRequest; - - // Get IP - $ip = $wgRequest->getIP(); - // Get XFF header - $xff = $wgRequest->getHeader( 'X-Forwarded-For' ); - list( $xff_ip, $isSquidOnly ) = self::getClientIPfromXFF( $xff ); - // Get agent - $agent = $wgRequest->getHeader( 'User-Agent' ); - $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, - 'cuc_title' => '', - 'cuc_minor' => 0, - 'cuc_user' => $user->getId(), - 'cuc_user_text' => $user->getName(), - 'cuc_actiontext' => $actionText, - 'cuc_comment' => '', - 'cuc_this_oldid' => 0, - 'cuc_last_oldid' => 0, - 'cuc_type' => RC_LOG, - 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ), - 'cuc_ip' => IPUtils::sanitizeIP( $ip ), - 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null, - 'cuc_xff' => !$isSquidOnly ? $xff : '', - 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null, - 'cuc_agent' => $agent - ]; - $dbw->insert( 'cu_changes', $rcRow, __METHOD__ ); - - return true; - } - - /** - * @param AuthenticationResponse $ret - * @param User $user - * @param string $username - */ - public static function onAuthManagerLoginAuthenticateAudit( - AuthenticationResponse $ret, $user, $username - ) { - global $wgRequest, $wgCheckUserLogLogins, $wgCheckUserLogSuccessfulBotLogins; - - if ( !$wgCheckUserLogLogins ) { - return; - } - - if ( !$user ) { - $user = User::newFromName( $username, 'usable' ); - } - - if ( !$user ) { - 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; - } - - $target = "[[User:$userName|$userName]]"; - $actionText = wfMessage( $msg )->params( $target )->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 ); - - $dbw = $services->getDBLoadBalancer()->getConnectionRef( DB_MASTER ); - $rcRow = [ - 'cuc_page_id' => 0, - 'cuc_namespace' => NS_USER, - 'cuc_title' => '', - 'cuc_minor' => 0, - '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' => IPUtils::sanitizeIP( $ip ), - 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null, - 'cuc_xff' => !$isSquidOnly ? $xff : '', - 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null, - 'cuc_agent' => $agent - ]; - $dbw->insert( 'cu_changes', $rcRow, __METHOD__ ); - } - - /** - * Hook function to prune data from the cu_changes table - */ - public static function maybePruneIPData() { - if ( mt_rand( 0, 9 ) != 0 ) { - return; - } - - DeferredUpdates::addUpdate( new AutoCommitUpdate( - wfGetDB( DB_MASTER ), - __METHOD__, - function ( IDatabase $dbw, $fname ) { - global $wgCUDMaxAge; - - $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', - [ "cuc_timestamp < $encCutoff" ], - $fname, - [ 'LIMIT' => 500 ] - ); - - if ( $ids ) { - $dbw->delete( 'cu_changes', [ 'cuc_id' => $ids ], $fname ); - } - } - ) ); - } - - /** - * Locates the client IP within a given XFF string. - * Unlike the XFF checking to determine a user IP in WebRequest, - * this simply follows the chain and does not account for server trust. - * - * This returns an array containing: - * - The best guess of the client IP - * - Whether all the proxies are just squid/varnish - * - * @param string $xff XFF header value - * @return array (string|null, bool) - * @todo move this to a utility class - */ - public static function getClientIPfromXFF( $xff ) { - global $wgUsePrivateIPs; - - if ( !strlen( $xff ) ) { - return [ null, false ]; - } - - # Get the list in the form of <PROXY N, ... PROXY 1, CLIENT> - $ipchain = array_map( 'trim', explode( ',', $xff ) ); - $ipchain = array_reverse( $ipchain ); - - $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup(); - - $client = null; // best guess of the client IP - $isSquidOnly = false; // all proxy servers where site Squid/Varnish servers? - # Step through XFF list and find the last address in the list which is a - # sensible proxy server. Set $ip to the IP address given by that proxy server, - # 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 = IPUtils::canonicalize( $curIP ); - if ( $curIP === null ) { - break; // not a valid IP address - } - $curIsSquid = $proxyLookup->isConfiguredProxy( $curIP ); - if ( $client === null ) { - $client = $curIP; - $isSquidOnly = $curIsSquid; - } - if ( - isset( $ipchain[$i + 1] ) && - IPUtils::isIPAddress( $ipchain[$i + 1] ) && - ( - IPUtils::isPublic( $ipchain[$i + 1] ) || - $wgUsePrivateIPs || - $curIsSquid // bug 48919 - ) - ) { - $client = IPUtils::canonicalize( $ipchain[$i + 1] ); - $isSquidOnly = ( $isSquidOnly && $curIsSquid ); - continue; - } - break; - } - - return [ $client, $isSquidOnly ]; - } - - public static function onLoadExtensionSchemaUpdates( DatabaseUpdater $updater ) { - $base = __DIR__ . '/..'; - $dbType = $updater->getDB()->getType(); - $isCUInstalled = $updater->tableExists( 'cu_changes' ); - - $updater->addExtensionTable( - 'cu_changes', self::getTableFileName( $dbType, 'cu_changes' ) - ); - $updater->addExtensionTable( - 'cu_log', self::getTableFileName( $dbType, 'cu_log' ) - ); - - if ( $dbType === 'mysql' ) { - $updater->addExtensionIndex( - 'cu_changes', - 'cuc_ip_hex_time', - "$base/archives/patch-cu_changes_indexes.sql" - ); - $updater->addExtensionIndex( - 'cu_changes', - 'cuc_user_ip_time', - "$base/archives/patch-cu_changes_indexes2.sql" - ); - $updater->addExtensionField( - 'cu_changes', - 'cuc_private', - "$base/archives/patch-cu_changes_privatedata.sql" - ); - } elseif ( $dbType === 'postgres' ) { - $updater->addExtensionUpdate( - [ 'addPgField', 'cu_changes', 'cuc_private', 'BYTEA' ] - ); - } - - if ( !$isCUInstalled ) { - // 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::class ); - } - } - - /** - * @param string $type DB type - * @param string $name Table name - * @return string - */ - private static function getTableFileName( $type, $name ) { - $file = __DIR__ . '/../' . $name; - return $type === 'postgres' - ? $file . '.pg.sql' - : $file . '.sql'; - } - - /** - * Tell the parser test engine to create a stub cu_changes table, - * or temporary pages won't save correctly during the test run. - * @param array &$tables - * @return bool - */ - public static function checkUserParserTestTables( &$tables ) { - $tables[] = 'cu_changes'; - return true; - } - - /** - * Add a link to Special:CheckUser and Special:CheckUserLog - * on Special:Contributions/<username> for - * privileged users. - * @param int $id User ID - * @param Title $nt User page title - * @param array &$links Tool links - * @param SpecialPage $sp Special page - */ - public static function checkUserContributionsLinks( - $id, Title $nt, array &$links, SpecialPage $sp - ) { - $user = $sp->getUser(); - $linkRenderer = $sp->getLinkRenderer(); - $permissionManager = MediaWikiServices::getInstance()->getPermissionManager(); - - if ( $permissionManager->userHasRight( $user, 'checkuser' ) ) { - $links['checkuser'] = $linkRenderer->makeKnownLink( - SpecialPage::getTitleFor( 'CheckUser' ), - $sp->msg( 'checkuser-contribs' )->text(), - [], - [ 'user' => $nt->getText() ] - ); - } - if ( $permissionManager->userHasRight( $user, 'checkuser-log' ) ) { - $links['checkuser-log'] = $linkRenderer->makeKnownLink( - SpecialPage::getTitleFor( 'CheckUserLog' ), - $sp->msg( 'checkuser-contribs-log' )->text(), - [], - [ - 'cuSearchType' => 'target', - 'cuSearch' => $nt->getText() - ] - ); - } - } - - /** - * Retroactively autoblocks the last IP used by the user (if it is a user) - * blocked by this block. - * - * @param DatabaseBlock $block - * @param array &$blockIds - * @return bool - */ - public static function doRetroactiveAutoblock( DatabaseBlock $block, array &$blockIds ) { - $dbr = wfGetDB( DB_REPLICA ); - - $user = User::newFromName( (string)$block->getTarget(), false ); - if ( !$user->getId() ) { - return true; // user in an IP? - } - - $options = [ 'ORDER BY' => 'cuc_timestamp DESC' ]; - $options['LIMIT'] = 1; // just the last IP used - - $res = $dbr->select( 'cu_changes', - [ 'cuc_ip' ], - [ 'cuc_user' => $user->getId() ], - __METHOD__, - $options - ); - - # Iterate through IPs used (this is just one or zero for now) - foreach ( $res as $row ) { - if ( $row->cuc_ip ) { - $id = $block->doAutoblock( $row->cuc_ip ); - if ( $id ) { - $blockIds[] = $id; - } - } - } - - return false; // autoblock handled - } - - public static function onUserMergeAccountFields( array &$updateFields ) { - $updateFields[] = [ 'cu_changes', 'cuc_user', 'cuc_user_text' ]; - $updateFields[] = [ 'cu_log', 'cul_user', 'cul_user_text' ]; - $updateFields[] = [ 'cu_log', 'cul_target_id' ]; - - return true; - } - - /** - * For integration with the Renameuser extension. - * - * @param RenameuserSQL $renameUserSQL - * @return bool - */ - public static function onRenameUserSQL( RenameuserSQL $renameUserSQL ) { - $renameUserSQL->tablesJob['cu_changes'] = [ - RenameuserSQL::NAME_COL => 'cuc_user_text', - RenameuserSQL::UID_COL => 'cuc_user', - RenameuserSQL::TIME_COL => 'cuc_timestamp', - 'uniqueKey' => 'cuc_id' - ]; - - $renameUserSQL->tables['cu_log'] = [ 'cul_user_text', 'cul_user' ]; - - return true; - } -} diff --git a/CheckUser/includes/CheckUserLogPager.php b/CheckUser/includes/CheckUserLogPager.php deleted file mode 100644 index 08644b3e..00000000 --- a/CheckUser/includes/CheckUserLogPager.php +++ /dev/null @@ -1,129 +0,0 @@ -<?php - -use MediaWiki\Cache\LinkBatchFactory; -use Wikimedia\Rdbms\IResultWrapper; - -class CheckUserLogPager extends ReverseChronologicalPager { - /** - * @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, LinkBatchFactory $linkBatchFactory ) { - parent::__construct( $context ); - $this->searchConds = $conds['queryConds']; - // getDateCond() actually *sets* the timestamp offset.. - $this->getDateCond( $conds['year'], $conds['month'] ); - $this->linkBatchFactory = $linkBatchFactory; - } - - public function formatRow( $row ) { - $user = Linker::userLink( $row->cul_user, $row->user_name ); - - $target = Linker::userLink( $row->cul_target_id, $row->cul_target_text ) . - Linker::userToolLinks( $row->cul_target_id, trim( $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 - // checkuser-log-entry-ipusers-xff, checkuser-log-entry-useredits - return '<li>' . - $this->msg( - 'checkuser-log-entry-' . $row->cul_type, - $user, - $target, - $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>'; - } - - /** - * @return string - */ - public function getStartBody() { - if ( $this->getNumRows() ) { - return '<ul>'; - } else { - return ''; - } - } - - /** - * @return string - */ - public function getEndBody() { - if ( $this->getNumRows() ) { - return '</ul>'; - } else { - return ''; - } - } - - /** - * @return string - */ - public function getEmptyBody() { - return '<p>' . $this->msg( 'checkuser-empty' )->escaped() . '</p>'; - } - - 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' ], - [ 'cul_type != ' . $excludeType ] - ) - ]; - } - - public function getIndexField() { - return 'cul_timestamp'; - } - - public function selectFields() { - return [ - 'cul_id', 'cul_timestamp', 'cul_user', 'cul_reason', 'cul_type', - 'cul_target_id', 'cul_target_text', 'user_name' - ]; - } - - /** - * Do a batch query for links' existence and add it to LinkCache - * - * @param IResultWrapper $result - */ - protected function preprocessResults( $result ) { - if ( $this->getNumRows() === 0 ) { - return; - } - - $lb = $this->linkBatchFactory->newLinkBatch(); - $lb->setCaller( __METHOD__ ); - foreach ( $result as $row ) { - $lb->add( NS_USER, $row->user_name ); // Performer - if ( $row->cul_type == 'userips' || $row->cul_type == 'useredits' ) { - $lb->add( NS_USER, $row->cul_target_text ); - $lb->add( NS_USER_TALK, $row->cul_target_text ); - } - } - $lb->execute(); - $result->seek( 0 ); - } -} diff --git a/CheckUser/includes/ServiceWiring.php b/CheckUser/includes/ServiceWiring.php deleted file mode 100644 index 8052c4bb..00000000 --- a/CheckUser/includes/ServiceWiring.php +++ /dev/null @@ -1,132 +0,0 @@ -<?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/specials/SpecialCheckUser.php b/CheckUser/includes/specials/SpecialCheckUser.php deleted file mode 100644 index 743065ba..00000000 --- a/CheckUser/includes/specials/SpecialCheckUser.php +++ /dev/null @@ -1,2138 +0,0 @@ -<?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 string[] $message Used to cache frequently used messages - */ - protected $message = []; - - /** - * @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() { - return true; // logging - } - - 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) - $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 ( $permissionManager->userHasRight( $this->getUser(), 'checkuser-log' ) ) { - $subtitleLink = $this->getLinkRenderer()->makeKnownLink( - SpecialPage::getTitleFor( 'CheckUserLog' ), - $this->msg( 'checkuser-showlog' )->text() - ); - if ( !$user === false ) { - $subtitleLink .= ' | ' . $this->getLinkRenderer()->makeKnownLink( - SpecialPage::getTitleFor( 'CheckUserLog', $user ), - $this->msg( 'checkuser-recent-checks' )->text() - ); - } - $out->addSubtitle( $subtitleLink ); - } - - 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 ); - $checktype = $request->getVal( 'checktype' ); - $period = $request->getInt( 'period' ); - $users = $request->getArray( 'users' ); - $tag = $request->getBool( 'usetag' ) ? - trim( $request->getVal( 'tag' ) ) : ''; - $talkTag = $request->getBool( 'usettag' ) ? - trim( $request->getVal( 'talktag' ) ) : ''; - - $blockParams = [ - 'reason' => $blockreason, - 'talk' => $disableUserTalk, - 'email' => $disableEmail, - 'reblock' => $request->getBool( 'reblock' ) - ]; - - $ip = $name = $xff = ''; - $m = []; - if ( IPUtils::isIPAddress( $user ) ) { - // A single IP address or an IP range - $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 = IPUtils::sanitizeIP( $m[1] ); - } else { - // A user? - $name = $user; - } - - $this->showIntroductoryText(); - $this->showForm( $user, $checktype, $ip, $xff, $name, $period ); - - // Perform one of the various submit operations... - if ( $request->wasPosted() ) { - if ( !$this->getUser()->matchEditToken( $request->getVal( 'wpEditToken' ) ) ) { - $out->wrapWikiMsg( '<div class="error">$1</div>', 'checkuser-token-fail' ); - } elseif ( $request->getVal( 'action' ) === 'block' ) { - $this->doMassUserBlock( $users, $blockParams, $tag, $talkTag ); - } elseif ( !$this->checkReason() ) { - $out->addWikiMsg( 'checkuser-noreason' ); - } elseif ( $checktype == 'subuserips' ) { - $this->doUserIPsRequest( $name, $period ); - } elseif ( $xff && $checktype == 'subedits' ) { - $this->doIPEditsRequest( $xff, true, $period ); - } elseif ( $ip && $checktype == 'subedits' ) { - $this->doIPEditsRequest( $ip, false, $period ); - } elseif ( $name && $checktype == 'subedits' ) { - $this->doUserEditsRequest( $user, $period ); - } elseif ( $xff && $checktype == 'subipusers' ) { - $this->doIPUsersRequest( $xff, true, $period, $tag, $talkTag ); - } elseif ( $checktype == 'subipusers' ) { - $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()->addWikiMsg( - 'checkuser-summary', - $cidrLimit['IPv4'], - $cidrLimit['IPv6'] - ); - } - - /** - * Show the CheckUser query form - * - * @param string $user - * @param string $checktype - * @param string $ip - * @param string $xff - * @param string $name - * @param int $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 = false; - if ( $checktype == 'subipusers' && ( $ip || $xff ) ) { - $encipusers = true; - } elseif ( $checktype == 'subuserips' && $name ) { - $encuserips = true; - } elseif ( $checktype == 'subedits' ) { - $encedits = true; - // Defaults otherwise - } elseif ( $ip || $xff ) { - $encedits = true; - } else { - $encuserips = true; - } - - $form = Xml::openElement( 'form', [ 'action' => $action, - 'name' => 'checkuserform', 'id' => 'checkuserform', 'method' => 'post' ] ); - $form .= '<fieldset><legend>' . $this->msg( 'checkuser-query' )->escaped() . '</legend>'; - $form .= Xml::openElement( 'table', [ 'style' => 'border:0' ] ); - $form .= '<tr>'; - $form .= '<td>' . $this->msg( 'checkuser-target' )->escaped() . '</td>'; - // User field should fit things like "2001:0db8:85a3:08d3:1319:8a2e:0370:7344/100/xff" - $form .= '<td>' . Xml::input( 'user', 46, $user, [ 'id' => 'checktarget' ] ); - $form .= ' ' . $this->getPeriodMenu( $period ) . '</td>'; - $form .= '</tr><tr>'; - $form .= '<td></td>'; - $form .= Xml::openElement( 'td', [ 'class' => 'checkuserradios' ] ); - $form .= Xml::openElement( 'table', [ 'style' => 'border:0' ] ); - $form .= '<tr>'; - $form .= '<td>' . - Xml::radio( 'checktype', 'subuserips', $encuserips, [ 'id' => 'subuserips' ] ); - $form .= ' ' . Xml::label( $this->msg( 'checkuser-ips' )->text(), 'subuserips' ) . '</td>'; - $form .= '<td>' . - Xml::radio( 'checktype', 'subedits', $encedits, [ 'id' => 'subedits' ] ); - $form .= ' ' . Xml::label( $this->msg( 'checkuser-edits' )->text(), 'subedits' ) . '</td>'; - $form .= '<td>' . - Xml::radio( 'checktype', 'subipusers', $encipusers, [ 'id' => 'subipusers' ] ); - $form .= ' ' . - Xml::label( $this->msg( 'checkuser-users' )->text(), 'subipusers' ) . '</td>'; - $form .= '</tr>'; - $form .= Xml::closeElement( 'table' ); - $form .= Xml::closeElement( 'td' ); - $form .= '</tr><tr>'; - $form .= '<td>' . $this->msg( 'checkuser-reason' )->escaped() . '</td>'; - $form .= '<td>' . Xml::input( 'reason', 46, $this->reason, - [ 'maxlength' => '150', 'id' => 'checkreason' ] ); - $form .= '   ' . Xml::submitButton( $this->msg( 'checkuser-check' )->text(), - [ 'id' => 'checkusersubmit', 'name' => 'checkusersubmit' ] ) . '</td>'; - $form .= '</tr>'; - $form .= Xml::closeElement( 'table' ); - $form .= '</fieldset>'; - $form .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() ); - $form .= Xml::closeElement( 'form' ); - - $this->getOutput()->addHTML( $form ); - } - - /** - * Get a selector of time period options - * @param int $selected Currently selected option - * @return string - */ - protected function getPeriodMenu( $selected ) { - $s = '<label for="period">' . - $this->msg( 'checkuser-period' )->escaped() . '</label> '; - $s .= Xml::openElement( - '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::closeElement( 'select' ) . "\n"; - return $s; - } - - /** - * Make a quick JS form for admins to calculate block ranges - */ - protected function addJsCIDRForm() { - $s = '<fieldset id="mw-checkuser-cidrform" style="display:none; clear:both;">' . - '<legend>' . $this->msg( 'checkuser-cidr-label' )->escaped() . '</legend>'; - $s .= '<textarea id="mw-checkuser-iplist" dir="ltr" rows="5" cols="50"></textarea><br />'; - $s .= $this->msg( 'checkuser-cidr-res' )->escaped() . ' ' . - Xml::input( 'mw-checkuser-cidr-res', 35, '', [ 'id' => 'mw-checkuser-cidr-res' ] ) . - ' <strong id="mw-checkuser-ipnote"></strong>'; - $s .= '</fieldset>'; - $this->getOutput()->addHTML( $s ); - } - - /** - * @return bool - */ - protected function checkReason() { - return ( !$this->getConfig()->get( 'CheckUserForceSummary' ) || strlen( $this->reason ) ); - } - - /** - * 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 - */ - protected function preCacheMessages() { - if ( $this->message === [] ) { - $msgKeys = [ 'diff', 'hist', 'minoreditletter', 'newpageletter', 'blocklink', 'log' ]; - foreach ( $msgKeys as $msg ) { - $this->message[$msg] = $this->msg( $msg )->escaped(); - } - } - } - - /** - * Block a list of selected users - * @param array $users - * @param array $blockParams - * @param string $tag - * @param string $talkTag - */ - protected function doMassUserBlock( $users, $blockParams, $tag = '', $talkTag = '' ) { - $usersCount = count( $users ); - $permissionManager = MediaWikiServices::getInstance()->getPermissionManager(); - - if ( !$permissionManager->userHasRight( $this->getUser(), 'block' ) - || $this->getUser()->getBlock() - || !$usersCount - ) { - $this->getOutput()->addWikiMsg( 'checkuser-block-failure' ); - return; - } elseif ( $usersCount > $this->getConfig()->get( 'CheckUserMaxBlocks' ) ) { - $this->getOutput()->addWikiMsg( 'checkuser-block-limit' ); - return; - } elseif ( !$blockParams['reason'] ) { - $this->getOutput()->addWikiMsg( 'checkuser-block-noreason' ); - return; - } - - $blockedUsers = $this->doMassUserBlockInternal( - $users, - $blockParams, - $tag, - $talkTag - ); - $blockedCount = count( $blockedUsers ); - if ( $blockedCount > 0 ) { - $lang = $this->getLanguage(); - $this->getOutput()->addWikiMsg( 'checkuser-block-success', - $lang->listToText( $blockedUsers ), - $lang->formatNum( $blockedCount ) - ); - } else { - $this->getOutput()->addWikiMsg( 'checkuser-block-failure' ); - } - } - - /** - * Block a list of selected users - * - * @param string[] $users - * @param array $blockParams - * @param string $tag replaces user pages - * @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 = '' - ) { - $currentUser = $this->getUser(); - $blockAllowsUTEdit = $this->getConfig()->get( 'BlockAllowsUTEdit' ); - $safeUsers = []; - foreach ( $users as $name ) { - $u = User::newFromName( $name, false ); - // Do some checks to make sure we can block this user first - if ( $u === null ) { - // Invalid user - continue; - } - $isIP = IPUtils::isIPAddress( $u->getName() ); - if ( !$u->getId() && !$isIP ) { - // Not a registered user or an IP - continue; - } - - if ( $u->getBlock() && !$blockParams['reblock'] ) { - continue; - } - - 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'] ); - } - - } - } - - return $safeUsers; - } - - /** - * Make an edit to the given page with the tag provided - * - * @param Title $title - * @param string $tag - * @param string $summary - */ - protected function tagPage( Title $title, $tag, $summary ) { - // Check length to avoid mistakes - if ( strlen( $tag ) > 2 ) { - $page = WikiPage::factory( $title ); - $flags = 0; - if ( $page->exists() ) { - $flags |= EDIT_MINOR; - } - $page->doEditContent( new WikitextContent( $tag ), $summary, - $flags, false, $this->getUser() ); - } - } - - /** - * Give a "no matches found for X" message. - * If $checkLast, then mention the last edit by this user or IP. - * - * @param string $userName - * @param bool $checkLast - * @return string - */ - protected function noMatchesMessage( $userName, $checkLast = true ) { - if ( $checkLast ) { - $dbr = wfGetDB( DB_REPLICA ); - $actorMigration = ActorMigration::newMigration(); - $user = User::newFromName( $userName, false ); - - $lastEdit = false; - - $revWhere = $actorMigration->getWhere( $dbr, 'rev_user', $user ); - foreach ( $revWhere['orconds'] as $cond ) { - $lastEdit = max( $lastEdit, $dbr->selectField( - [ 'revision' ] + $revWhere['tables'], - 'rev_timestamp', - $cond, - __METHOD__, - [ 'ORDER BY' => 'rev_timestamp DESC' ], - $revWhere['joins'] - ) ); - } - $logWhere = $actorMigration->getWhere( $dbr, 'log_user', $user ); - foreach ( $logWhere['orconds'] as $cond ) { - $lastEdit = max( $lastEdit, $dbr->selectField( - [ 'logging' ] + $logWhere['tables'], - 'log_timestamp', - $cond, - __METHOD__, - [ 'ORDER BY' => 'log_timestamp DESC' ], - $logWhere['joins'] - ) ); - } - - 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->userDate( $lastEditTime, $contextUser ), - $lang->userTime( $lastEditTime, $contextUser ) - )->parseAsBlock(); - } - } - return $this->msg( 'checkuser-nomatch' )->parseAsBlock(); - } - - /** - * Show all the IPs used by a user - * - * @param string $user - * @param int $period - * @return void - */ - protected function doUserIPsRequest( $user, $period = 0 ) { - $out = $this->getOutput(); - - $userTitle = Title::newFromText( $user, NS_USER ); - if ( $userTitle !== null ) { - // normalize the username - $user = $userTitle->getText(); - } - // IPs are passed in as a blank string - if ( !$user ) { - $out->addWikiMsg( 'nouserspecified' ); - return; - } - // Get ID, works better than text as user may have been renamed - $user_id = User::idFromName( $user ); - - // If user is not IP or nonexistent - if ( !$user_id ) { - $out->addWikiMsg( 'nosuchusershort', $user ); - return; - } - - // Record check... - 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 ); - if ( $time_conds !== false ) { - $conds[] = $time_conds; - } - - // Ordering by the latest timestamp makes a small filesort on the IP list - return $dbr->select( - 'cu_changes', - [ - 'cuc_ip', - 'cuc_ip_hex', - 'count' => 'COUNT(*)', - 'first' => 'MIN(cuc_timestamp)', - 'last' => 'MAX(cuc_timestamp)', - ], - $conds, - __METHOD__, - [ - 'ORDER BY' => 'last DESC', - 'GROUP BY' => [ 'cuc_ip', 'cuc_ip_hex' ], - 'LIMIT' => $limit, - 'USE INDEX' => 'cuc_user_ip_time', - ] - ); - } - - /** - * 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; - } - $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(); - - return $ipSets; - } - - /** - * 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>'; - } - - // 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 = DatabaseBlock::newFromTarget( null, $ip, false ); - if ( $block instanceof DatabaseBlock ) { - return $this->getBlockFlag( $block ); - } - return ''; - } - - /** - * Get a link to block information about the passed block for displaying to the user. - * - * @param DatabaseBlock $block - * @return string - */ - protected function getBlockFlag( DatabaseBlock $block ) { - if ( $block->getType() == DatabaseBlock::TYPE_AUTO ) { - $ret = $this->getLinkRenderer()->makeKnownLink( - SpecialPage::getTitleFor( 'BlockList' ), - $this->msg( 'checkuser-blocked' )->text(), - [], - [ 'wpTarget' => "#{$block->getId()}" ] - ); - } else { - $userPage = Title::makeTitle( NS_USER, $block->getTarget() ); - $ret = $this->getLinkRenderer()->makeKnownLink( - SpecialPage::getTitleFor( 'Log' ), - $this->msg( 'checkuser-blocked' )->text(), - [], - [ - 'type' => 'block', - 'page' => $userPage->getPrefixedText() - ] - ); - } - - // Add the blocked range if the block is on a range - if ( $block->getType() == DatabaseBlock::TYPE_RANGE ) { - $ret .= ' - ' . htmlspecialchars( $block->getTarget() ); - } - - return '<strong>' . - $this->msg( 'parentheses' )->rawParams( $ret )->escaped() - . '</strong>'; - } - - /** - * Shows all changes made by an IP address or range - * - * @param string $ip - * @param bool $xfor if query is for XFF - * @param int $period - * @return void - */ - protected function doIPEditsRequest( $ip, $xfor = false, $period = 0 ) { - $out = $this->getOutput(); - $index = $xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time'; - - // Invalid IPs are passed in as a blank string - if ( !$ip || !self::isValidRange( $ip ) ) { - $out->addWikiMsg( 'badipaddress' ); - return; - } - - $logType = $xfor ? 'ipedits-xff' : 'ipedits'; - - // Record check in the logs - self::addLogEntry( $logType, 'ip', $ip, $this->reason ); - - // 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. - $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; - } - - // 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', - '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, - [ - 'user' => $ip, - 'reason' => $this->reason, - 'checktype' => 'subipusers' - ] - ); - $s .= ' ' . $this->getTimeRangeString( $row->first, $row->last ) . ' '; - $s .= ' [<strong>' . htmlspecialchars( $lang->formatNum( $row->count ) ) . - "</strong>]</li>\n"; - ++$counter; - } - $s .= '</ol>'; - - $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; - } - - $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_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' => $limit, - 'USE INDEX' => $index, - ] - ); - } - - /** - * 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->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 .= $this->CUChangesLine( $row ); - ++$counter; - } - $s .= '</ul></div>'; - - $out->addHTML( $s ); - } - - /** - * @param IResultWrapper $rows Results with cuc_namespace and cuc_title field - */ - protected function doLinkCache( IResultWrapper $rows ) { - $lb = $this->linkBatchFactory->newLinkBatch(); - $lb->setCaller( __METHOD__ ); - foreach ( $rows as $row ) { - if ( $row->cuc_title !== '' ) { - $lb->add( $row->cuc_namespace, $row->cuc_title ); - } - } - $lb->execute(); - $rows->seek( 0 ); - } - - /** - * Shows all changes made by a particular user - * - * @param string $user - * @param int $period - * @return void - */ - protected function doUserEditsRequest( $user, $period = 0 ) { - $out = $this->getOutput(); - - $userTitle = Title::newFromText( $user, NS_USER ); - if ( $userTitle !== null ) { - // normalize the username - $user = $userTitle->getText(); - } - // IPs are passed in as a blank string - if ( !$user ) { - $out->addWikiMsg( 'nouserspecified' ); - return; - } - // Get ID, works better than text as user may have been renamed - $user_id = User::idFromName( $user ); - - // If user is not IP or nonexistent - if ( !$user_id ) { - $out->addHTML( $this->msg( 'nosuchusershort', $user )->parseAsBlock() ); - return; - } - - // Record check... - 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 ); - $conds = [ 'cuc_user' => $user_id ]; - $time_conds = $this->getTimeConds( $period ); - if ( $time_conds !== false ) { - $conds[] = $time_conds; - } - - if ( $period ) { - return $dbr->selectField( - 'cu_changes', - 'COUNT(*)', - $conds, - __METHOD__, - [ 'USE INDEX' => 'cuc_user_ip_time' ] - ); - } else { - return $dbr->estimateRowCount( - 'cu_changes', - '*', - $conds, - __METHOD__, - [ 'USE INDEX' => 'cuc_user_ip_time' ] - ); - } - } - - /** - * 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' ); - } - - $dbr = wfGetDB( DB_REPLICA ); - $conds = [ 'cuc_user' => $user_id ]; - $time_conds = $this->getTimeConds( $period ); - if ( $time_conds !== false ) { - $conds[] = $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' => $limit, - 'USE INDEX' => 'cuc_user_ip_time' - ] - ); - } - - /** - * 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 ); - } - - /** - * Lists all users in recent changes who used an IP, newest to oldest down - * Outputs usernames, latest and earliest found edit date, and count - * List unique IPs used for each user in time order, list corresponding user agent - * - * @param string $ip - * @param bool $xfor - * @param int $period - * @param string $tag - * @param string $talkTag - * @return void - */ - protected function doIPUsersRequest( - $ip, $xfor = false, $period = 0, $tag = '', $talkTag = '' - ) { - $out = $this->getOutput(); - $index = $xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time'; - - // Invalid IPs are passed in as a blank string - if ( !$ip || !self::isValidRange( $ip ) ) { - $out->addWikiMsg( 'badipaddress' ); - return; - } - - $logType = $xfor ? 'ipusers-xff' : 'ipusers'; - - // Log the check... - self::addLogEntry( $logType, 'ip', $ip, $this->reason ); - - // Are there too many edits? - $rangecount = $this->getIPUsersCount( $ip, $xfor, $index, $period ); - if ( $rangecount > 10000 ) { - $result = $this->IPUsersTooManyDB( $ip, $xfor, $index, $period ); - $this->IPUsersTooMany( $result, $ip, $xfor ); - return; - } elseif ( $rangecount === 0 ) { - $out->addHTML( $this->noMatchesMessage( $ip, !$xfor ) . "\n" ); - return; - } - - // OK, do the real query... - $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', - ], - $conds, - __METHOD__, - [ - 'ORDER BY' => 'cuc_timestamp DESC', - 'LIMIT' => $limit, - 'USE INDEX' => $index, - ] - ); - } - - /** - * @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; - } - } - } - - 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 ] ) . ' '; - // 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] ); - } 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' => $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}' - ); - } - $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 {$globalBlockingToollink}' - ); - } - $linkGB = Html::element( 'a', - [ - 'href' => $centralGBUrl . "/" . $name, - 'title' => $this->msg( 'globalblocking-block-submit' )->text(), - ], - $gblinkAlias - ); - } 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 - ); - } 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; - } - } - // 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(); - } - } - // 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 .= '   <span style="background-color: ' . $c . - '"><strong>XFF</strong>: '; - $s .= $this->getSelfLink( $xffString, [ 'user' => $client . '/xff' ] ) . - '</span>'; - } - $s .= "</li>\n"; - } - $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 .= '</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 ); - } - - /** - * @param string $tag - * @param string $talkTag - * @return string - */ - protected function getBlockForm( $tag, $talkTag ) { - $config = $this->getConfig(); - $checkUserCAMultiLock = $config->get( 'CheckUserCAMultiLock' ); - if ( $checkUserCAMultiLock !== false ) { - if ( !ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) ) { - // $wgCheckUserCAMultiLock shouldn't be enabled if CA is not loaded - throw new Exception( '$wgCheckUserCAMultiLock requires CentralAuth extension.' ); - } - - $caUserGroups = CentralAuthUser::getInstance( $this->getUser() )->getGlobalGroups(); - // Only load the script for users in the configured global group(s) - if ( count( array_intersect( $checkUserCAMultiLock['groups'], $caUserGroups ) ) ) { - $out = $this->getOutput(); - $centralMLUrl = WikiMap::getForeignURL( - $checkUserCAMultiLock['centralDB'], - // Use canonical name instead of local name so that it works - // even if the local language is different from central wiki - 'Special:MultiLock' - ); - if ( $centralMLUrl === false ) { - throw new Exception( - "Could not retrieve URL for {$checkUserCAMultiLock['centralDB']}" - ); - } - $out->addJsConfigVars( 'wgCUCAMultiLockCentral', $centralMLUrl ); - $out->addModules( 'ext.checkUser' ); - } - } - - $s = "<fieldset>\n"; - $s .= '<legend>' . $this->msg( 'checkuser-massblock' )->escaped() . "</legend>\n"; - $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' )->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' )->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' )->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' )->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() . ' '; - $s .= Xml::input( 'blockreason', 46, '', [ 'maxlength' => '150', 'id' => 'blockreason' ] ); - $s .= ' ' . Xml::submitButton( $this->msg( 'checkuser-massblock-commit' )->text(), - [ 'id' => 'checkuserblocksubmit', 'name' => 'checkuserblock' ] ) . "</p>\n"; - $s .= "</fieldset>\n"; - - return $s; - } - - /** - * Get an HTML link (<a> element) to Special:CheckUser - * - * @param string $text content to use within <a> tag - * @param array $params query parameters to use in the URL - * @return string - */ - private function getSelfLink( $text, array $params ) { - static $title; - if ( $title === null ) { - $title = $this->getPageTitle(); - } - return $this->getLinkRenderer()->makeKnownLink( - $title, - new HtmlArmor( '<bdi>' . htmlspecialchars( $text ) . '</bdi>' ), - [], - $params - ); - } - - /** - * @param string $ip - * @param int $userId - * @param User $user - * @return array - */ - protected function userBlockFlags( $ip, $userId, $user ) { - $flags = []; - - $block = DatabaseBlock::newFromTarget( $user, $ip, false ); - if ( $block instanceof DatabaseBlock ) { - // Locally blocked - $flags[] = $this->getBlockFlag( $block ); - } elseif ( $ip == $user->getName() && $user->isBlockedGlobally( $ip ) ) { - // Globally blocked IP - $flags[] = '<strong>(' . $this->msg( 'checkuser-gblocked' )->escaped() . ')</strong>'; - } elseif ( self::userWasBlocked( $user->getName() ) ) { - // Previously blocked - $userpage = $user->getUserPage(); - $blocklog = $this->getLinkRenderer()->makeKnownLink( - SpecialPage::getTitleFor( 'Log' ), - $this->msg( 'checkuser-wasblocked' )->text(), - [], - [ - 'type' => 'block', - 'page' => $userpage->getPrefixedText() - ] - ); - // @todo FIXME: Hard coded parentheses. - $flags[] = '<strong>(' . $blocklog . ')</strong>'; - } - - // Show if account is local only - if ( $user->getId() && - CentralIdLookup::factory() - ->centralIdFromLocalUser( $user, CentralIdLookup::AUDIENCE_RAW ) === 0 - ) { - // @todo FIXME: i18n issue: Hard coded parentheses. - $flags[] = '<strong>(' . $this->msg( 'checkuser-localonly' )->escaped() . ')</strong>'; - } - // Check for extra user rights... - if ( $userId ) { - if ( $user->isLocked() ) { - // @todo FIXME: i18n issue: Hard coded parentheses. - $flags[] = '<b>(' . $this->msg( 'checkuser-locked' )->escaped() . ')</b>'; - } - $list = []; - foreach ( $user->getGroups() as $group ) { - $list[] = self::buildGroupLink( $group, $user->getName() ); - } - $groups = $this->getLanguage()->commaList( $list ); - if ( $groups ) { - // @todo FIXME: i18n issue: Hard coded parentheses. - $flags[] = '<i>(' . $groups . ')</i>'; - } - } - - return $flags; - } - - /** - * Get a streamlined recent changes line with IP data - * - * @param stdClass $row - * @return string - */ - protected function CUChangesLine( $row ) { - static $flagCache = []; - $line = ''; - // Add date headers as needed - $date = htmlspecialchars( - $this->getLanguage()->userDate( wfTimestamp( TS_MW, $row->cuc_timestamp ), $this->getUser() ) - ); - if ( $this->lastdate === null ) { - $this->lastdate = $date; - $line .= "\n<h4>$date</h4>\n<ul class=\"special\">"; - } elseif ( $date !== $this->lastdate ) { - $line .= "</ul>\n<h4>$date</h4>\n<ul class=\"special\">"; - $this->lastdate = $date; - } - $line .= '<li>'; - // Create diff/hist/page links - $line .= $this->getLinksFromRow( $row ); - // Show date - $line .= ' . . ' . htmlspecialchars( - $this->getLanguage()->userTime( wfTimestamp( TS_MW, $row->cuc_timestamp ), $this->getUser() ) - ) . ' . . '; - // Userlinks - $user = User::newFromId( $row->cuc_user ); - if ( !IPUtils::isIPAddress( $row->cuc_user_text ) ) { - $idforlinknfn = -1; - } else { - $idforlinknfn = $row->cuc_user; - } - $classnouser = false; - if ( IPUtils::isIPAddress( $row->cuc_user_text ) !== IPUtils::isIPAddress( $user ) ) { - // User does not exist - $idforlink = -1; - $classnouser = true; - } else { - $idforlink = $row->cuc_user; - } - if ( $classnouser === true ) { - $line .= '<span class=\'mw-checkuser-nonexistent-user\'>'; - } else { - $line .= '<span>'; - } - $line .= Linker::userLink( - $idforlinknfn, $row->cuc_user_text, $row->cuc_user_text ) . '</span>'; - $line .= Linker::userToolLinksRedContribs( - $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 = IPUtils::isIPAddress( $row->cuc_user_text ) ? $row->cuc_user_text : ''; - $flags = $this->userBlockFlags( $ip, $row->cuc_user, $user ); - $flagCache[$row->cuc_user_text] = $flags; - } - // Add any block information - if ( count( $flags ) ) { - $line .= ' ' . implode( ' ', $flags ); - } - // Action text, hackish ... - if ( $row->cuc_actiontext ) { - $line .= ' ' . Linker::formatComment( $row->cuc_actiontext ) . ' '; - } - // 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 />        <small>'; - // IP - $line .= ' <strong>IP</strong>: '; - $line .= $this->getSelfLink( $row->cuc_ip, - [ - 'user' => $row->cuc_ip, - 'reason' => $this->reason - ] - ); - // XFF - if ( $row->cuc_xff != null ) { - // Flag our trusted proxies - list( $client ) = CheckUserHooks::getClientIPfromXFF( $row->cuc_xff ); - $trusted = ( $client === $row->cuc_ip ); // XFF was trusted if client came from it - $c = $trusted ? '#F0FFF0' : '#FFFFCC'; - $line .= '   '; - $line .= '<span class="mw-checkuser-xff" style="background-color: ' . $c . '">' . - '<strong>XFF</strong>: '; - $line .= $this->getSelfLink( $row->cuc_xff, - [ - 'user' => $client . '/xff', - 'reason' => $this->reason - ] - ); - $line .= '</span>'; - } - // User agent - $line .= '   <span class="mw-checkuser-agent" style="color:#888;">' . - htmlspecialchars( $row->cuc_agent ) . '</span>'; - - $line .= "</small></li>\n"; - - return $line; - } - - /** - * Get formatted timestamp(s) to show the time of first and last change. - * If both timestamps are the same, it will be shown only once. - * - * @param string $first Timestamp of the first change - * @param string $last Timestamp of the last change - * @return string - */ - protected function getTimeRangeString( $first, $last ) { - $s = $this->getFormattedTimestamp( $first ); - if ( $first !== $last ) { - // @todo i18n issue - hardcoded string - $s .= ' -- '; - $s .= $this->getFormattedTimestamp( $last ); - } - return $this->msg( 'parentheses' )->params( $s )->escaped(); - } - - /** - * Get a formatted timestamp string in the current language - * for displaying to the user. - * - * @param string $timestamp - * @return string - */ - protected function getFormattedTimestamp( $timestamp ) { - return $this->getLanguage()->userTimeAndDate( - wfTimestamp( TS_MW, $timestamp ), $this->getUser() - ); - } - - /** - * @param stdClass $row - * @return string diff, hist and page other links related to the change - */ - protected function getLinksFromRow( $row ) { - $links = []; - // Log items - if ( $row->cuc_type == RC_LOG ) { - $title = Title::makeTitle( $row->cuc_namespace, $row->cuc_title ); - // @todo FIXME: Hard coded parentheses. - $links['log'] = '(' . $this->getLinkRenderer()->makeKnownLink( - SpecialPage::getTitleFor( 'Log' ), - new HtmlArmor( $this->message['log'] ), - [], - [ 'page' => $title->getPrefixedText() ] - ) . ')'; - } else { - $title = Title::makeTitle( $row->cuc_namespace, $row->cuc_title ); - // New pages - if ( $row->cuc_type == RC_NEW ) { - $links['diff'] = '(' . $this->message['diff'] . ') '; - } else { - // Diff link - // @todo FIXME: Hard coded parentheses. - $links['diff'] = ' (' . $this->getLinkRenderer()->makeKnownLink( - $title, - new HtmlArmor( $this->message['diff'] ), - [], - [ - 'curid' => $row->cuc_page_id, - 'diff' => $row->cuc_this_oldid, - 'oldid' => $row->cuc_last_oldid - ] - ) . ') '; - } - // History link - // @todo FIXME: Hard coded parentheses. - $links['history'] = ' (' . $this->getLinkRenderer()->makeKnownLink( - $title, - new HtmlArmor( $this->message['hist'] ), - [], - [ - 'curid' => $title->exists() ? $row->cuc_page_id : null, - 'action' => 'history' - ] - ) . ') . . '; - // Some basic flags - if ( $row->cuc_type == RC_NEW ) { - $links['newpage'] = '<span class="newpage">' . $this->message['newpageletter'] . - '</span>'; - } - if ( $row->cuc_minor ) { - $links['minor'] = '<span class="minor">' . $this->message['minoreditletter'] . - '</span>'; - } - // Page link - $links['title'] = $this->getLinkRenderer()->makeLink( $title ); - } - - Hooks::run( 'SpecialCheckUserGetLinksFromRow', [ $this, $row, &$links ] ); - // @phan-suppress-next-line PhanRedundantCondition May set by hook - if ( is_array( $links ) ) { - return implode( ' ', $links ); - } else { - wfDebugLog( __CLASS__, - __METHOD__ . ': Expected array from SpecialCheckUserGetLinksFromRow $links param,' - . ' but received ' . gettype( $links ) - ); - return ''; - } - } - - protected static function userWasBlocked( $name ) { - $userpage = Title::makeTitle( NS_USER, $name ); - return (bool)wfGetDB( DB_REPLICA )->selectField( 'logging', '1', - [ - 'log_type' => [ 'block', 'suppress' ], - 'log_action' => 'block', - 'log_namespace' => $userpage->getNamespace(), - 'log_title' => $userpage->getDBkey() - ], - __METHOD__, - [ 'USE INDEX' => 'page_time' ] - ); - } - - /** - * Format a link to a group description page - * - * @param string $group - * @param string $username - * @return string - */ - protected static function buildGroupLink( $group, $username ) { - static $cache = []; - if ( !isset( $cache[$group] ) ) { - $cache[$group] = UserGroupMembership::getLink( - $group, RequestContext::getMain(), 'html' - ); - } - return $cache[$group]; - } - - /** - * @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 ) { - $type = $xfor ? 'xff' : 'ip'; - - 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 ( IPUtils::isValid( $target ) ) { - return [ "cuc_{$type}_hex" => IPUtils::toHex( $target ) ]; - } - return false; // invalid IP - } - - protected function getTimeConds( $period ) { - if ( !$period ) { - return false; - } - $dbr = wfGetDB( DB_REPLICA ); - $cutoff_unixtime = time() - ( $period * 24 * 3600 ); - $cutoff_unixtime = $cutoff_unixtime - ( $cutoff_unixtime % 86400 ); - $cutoff = $dbr->addQuotes( $dbr->timestamp( $cutoff_unixtime ) ); - return "cuc_timestamp > $cutoff"; - } - - public static function addLogEntry( $logType, $targetType, $target, $reason, $targetID = 0 ) { - $user = RequestContext::getMain()->getUser(); - - if ( $targetType == 'ip' ) { - list( $rangeStart, $rangeEnd ) = IPUtils::parseRange( $target ); - $targetHex = $rangeStart; - if ( $rangeStart == $rangeEnd ) { - $rangeStart = $rangeEnd = ''; - } - } else { - $targetHex = $rangeStart = $rangeEnd = ''; - } - - $timestamp = time(); - $data = [ - 'cul_user' => $user->getId(), - 'cul_user_text' => $user->getName(), - 'cul_reason' => $reason, - 'cul_type' => $logType, - 'cul_target_id' => $targetID, - 'cul_target_text' => trim( $target ), - 'cul_target_hex' => $targetHex, - 'cul_range_start' => $rangeStart, - 'cul_range_end' => $rangeEnd - ]; - $fname = __METHOD__; - - DeferredUpdates::addCallableUpdate( - function () use ( $data, $timestamp, $fname ) { - $dbw = wfGetDB( DB_MASTER ); - $dbw->insert( - 'cu_log', - [ - 'cul_timestamp' => $dbw->timestamp( $timestamp ) - ] + $data, - $fname - ); - }, - DeferredUpdates::PRESEND // fail on error and show no output - ); - } - - /** - * Return an array of subpages beginning with $search that this special page will accept. - * - * @param string $search Prefix to search for - * @param int $limit Maximum number of results to return (usually 10) - * @param int $offset Number of results to skip (usually 0) - * @return string[] Matching subpages - */ - public function prefixSearchSubpages( $search, $limit, $offset ) { - $user = User::newFromName( $search ); - if ( !$user ) { - // No prefix suggestion for invalid user - return []; - } - // Autocomplete subpage as user list - public to allow caching - return UserNamePrefixSearch::search( 'public', $search, $limit, $offset ); - } - - protected function getGroupName() { - return 'users'; - } -} diff --git a/CheckUser/includes/specials/SpecialCheckUserLog.php b/CheckUser/includes/specials/SpecialCheckUserLog.php deleted file mode 100644 index e8ccf646..00000000 --- a/CheckUser/includes/specials/SpecialCheckUserLog.php +++ /dev/null @@ -1,187 +0,0 @@ -<?php - -use MediaWiki\Cache\LinkBatchFactory; -use MediaWiki\MediaWikiServices; -use Wikimedia\IPUtils; - -class SpecialCheckUserLog extends SpecialPage { - /** - * @var string - */ - protected $target; - - /** @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 ( $permissionManager->userHasRight( $this->getUser(), 'checkuser' ) ) { - $subtitleLink = $this->getLinkRenderer()->makeKnownLink( - SpecialPage::getTitleFor( 'CheckUser' ), - $this->msg( 'checkuser-showmain' )->text() - ); - if ( !$this->target === false ) { - $subtitleLink .= ' | ' . $this->getLinkRenderer()->makeKnownLink( - SpecialPage::getTitleFor( 'CheckUser', $this->target ), - $this->msg( 'checkuser-check-this-user' )->text() - ); - } - $out->addSubtitle( $subtitleLink ); - } - - $type = $request->getVal( 'cuSearchType', 'target' ); - - $this->displaySearchForm(); - - // Default to all log entries - we'll add conditions below if a target was provided - $searchConds = []; - - if ( $this->target !== '' ) { - $searchConds = ( $type === 'initiator' ) - ? $this->getPerformerSearchConds() - : $this->getTargetSearchConds(); - } - - if ( $searchConds === null ) { - // Invalid target was input so show an error message and stop from here - $out->wrapWikiMsg( "<div class='errorbox'>\n$1\n</div>", 'checkuser-user-nonexistent' ); - return; - } - - $pager = new CheckUserLogPager( - $this->getContext(), - [ - 'queryConds' => $searchConds, - 'year' => $request->getInt( 'year' ), - 'month' => $request->getInt( 'month' ), - ], - $this->linkBatchFactory - ); - - $out->addHTML( - $pager->getNavigationBar() . - $pager->getBody() . - $pager->getNavigationBar() - ); - } - - /** - * Use an HTMLForm to create and output the search form used on this page. - */ - protected function displaySearchForm() { - $request = $this->getRequest(); - $fields = [ - 'target' => [ - 'type' => 'user', - // validation in execute() currently - 'exists' => false, - 'ipallowed' => true, - 'name' => 'cuSearch', - 'size' => 40, - 'label-message' => 'checkuser-log-search-target', - 'default' => $this->target, - ], - 'type' => [ - 'type' => 'radio', - 'name' => 'cuSearchType', - 'label-message' => 'checkuser-log-search-type', - 'options-messages' => [ - 'checkuser-search-target' => 'target', - 'checkuser-search-initiator' => 'initiator', - ], - 'flatlist' => true, - 'default' => 'target', - ], - // @todo hack until HTMLFormField has a proper date selector - 'monthyear' => [ - 'type' => 'info', - 'default' => Xml::dateMenu( $request->getInt( 'year' ), $request->getInt( 'month' ) ), - 'raw' => true, - ], - ]; - - $form = HTMLForm::factory( 'table', $fields, $this->getContext() ); - $form->setMethod( 'get' ) - ->setWrapperLegendMsg( 'checkuser-search' ) - ->setSubmitTextMsg( 'checkuser-search-submit' ) - ->prepareForm() - ->displayForm( false ); - } - - /** - * Get DB search conditions depending on the CU performer/initiator - * Use this only for searches by 'initiator' type - * - * @return array|null array if valid target, null if invalid - */ - protected function getPerformerSearchConds() { - $initiator = User::newFromName( $this->target ); - if ( $initiator && $initiator->getId() ) { - return [ 'cul_user' => $initiator->getId() ]; - } - return null; - } - - /** - * Get DB search conditions according to the CU target given. - * - * @return array|null array if valid target, null if invalid target given - */ - protected function getTargetSearchConds() { - list( $start, $end ) = IPUtils::parseRange( $this->target ); - $conds = null; - - if ( $start !== false ) { - $dbr = wfGetDB( DB_REPLICA ); - if ( $start === $end ) { - // Single IP address - $conds = [ - 'cul_target_hex = ' . $dbr->addQuotes( $start ) . ' OR ' . - '(cul_range_end >= ' . $dbr->addQuotes( $start ) . ' AND ' . - 'cul_range_start <= ' . $dbr->addQuotes( $start ) . ')' - ]; - } else { - // IP range - $conds = [ - '(cul_target_hex >= ' . $dbr->addQuotes( $start ) . ' AND ' . - 'cul_target_hex <= ' . $dbr->addQuotes( $end ) . ') OR ' . - '(cul_range_end >= ' . $dbr->addQuotes( $start ) . ' AND ' . - 'cul_range_start <= ' . $dbr->addQuotes( $end ) . ')' - ]; - } - } else { - $user = User::newFromName( $this->target ); - if ( $user && $user->getId() ) { - // Registered user - $conds = [ - 'cul_type' => [ 'userips', 'useredits' ], - 'cul_target_id' => $user->getId(), - ]; - } - } - return $conds; - } - - protected function getGroupName() { - return 'changes'; - } -} diff --git a/CheckUser/maintenance/fixTrailingSpacesInLogs.php b/CheckUser/maintenance/fixTrailingSpacesInLogs.php new file mode 100644 index 00000000..594d8d07 --- /dev/null +++ b/CheckUser/maintenance/fixTrailingSpacesInLogs.php @@ -0,0 +1,75 @@ +<?php + +namespace MediaWiki\CheckUser\Maintenance; + +use LoggedUpdateMaintenance; +use MediaWiki\MediaWikiServices; + +$IP = getenv( 'MW_INSTALL_PATH' ); +if ( $IP === false ) { + $IP = __DIR__ . '/../../..'; +} +require_once "$IP/maintenance/Maintenance.php"; + +/** + * Maintenance script for fixing trailing spaces issue in cu_log (see T275704) + * + * @codeCoverageIgnore No need to cover, single-use script. + */ +class FixTrailingSpacesInLogs extends LoggedUpdateMaintenance { + + public function __construct() { + parent::__construct(); + $this->requireExtension( 'CheckUser' ); + $this->addDescription( 'Remove trailing spaces from all cu_log entries, if there are any' ); + } + + /** + * @inheritDoc + */ + protected function getUpdateKey() { + return 'CheckUserFixTrailingSpacesInLogs'; + } + + /** + * @inheritDoc + */ + protected function doDBUpdates() { + $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); + $mainLb = $lbFactory->getMainLB(); + $dbr = $mainLb->getConnectionRef( DB_REPLICA, 'vslow' ); + $dbw = $mainLb->getConnectionRef( DB_PRIMARY ); + $batchSize = $this->getBatchSize(); + + $maxId = $dbr->newSelectQueryBuilder() + ->field( 'MAX(cul_id)' ) + ->table( 'cu_log' ) + ->caller( __METHOD__ ) + ->fetchField(); + $prevId = 0; + $curId = $batchSize; + do { + $dbw->update( + 'cu_log', + [ + "cul_target_text = TRIM(cul_target_text)" + ], + [ + "cul_id > $prevId", + "cul_id <= $curId" + ], + __METHOD__ + ); + $lbFactory->waitForReplication(); + + $this->output( "Processed $batchSize rows out of $maxId.\n" ); + $prevId = $curId; + $curId += $batchSize; + } while ( $prevId <= $maxId ); + + return true; + } +} + +$maintClass = FixTrailingSpacesInLogs::class; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/CheckUser/maintenance/importCheckUserLogs.php b/CheckUser/maintenance/importCheckUserLogs.php index e15429bb..30933680 100644 --- a/CheckUser/maintenance/importCheckUserLogs.php +++ b/CheckUser/maintenance/importCheckUserLogs.php @@ -1,5 +1,6 @@ <?php +use MediaWiki\MediaWikiServices; use Wikimedia\IPUtils; $IP = getenv( 'MW_INSTALL_PATH' ); @@ -43,6 +44,11 @@ class ImportCheckUserLogs extends Maintenance { fclose( $file ); } + /** + * @param string $line + * + * @return array|null + */ protected function parseLogLine( $line ) { $rxTimestamp = '(?P<timestamp>\d+:\d+, \d+ \w+ \d+)'; $rxUser = '(?P<user>.*?)'; @@ -84,26 +90,34 @@ class ImportCheckUserLogs extends Maintenance { return null; } + /** + * @param resource $file + */ protected function importLog( $file ) { global $wgDBname; $matched = 0; $unmatched = 0; - while ( false !== ( $line = fgets( $file ) ) ) { + $services = MediaWikiServices::getInstance(); + $userFactory = $services->getUserFactory(); + $culActorMigrationStage = $services->getMainConfig()->get( 'CheckUserLogActorMigrationStage' ); + + while ( !feof( $file ) ) { + $line = fgets( $file ); $data = $this->parseLogLine( $line ); if ( $data ) { - if ( $data['wiki'] != wfWikiID() && $data['wiki'] != $wgDBname ) { + if ( $data['wiki'] != WikiMap::getCurrentWikiId() && $data['wiki'] != $wgDBname ) { $unmatched++; continue; } // Local wiki lookups... - $user = User::newFromName( $data['user'] ); + $user = $userFactory->newFromName( $data['user'] ); list( $start, $end ) = IPUtils::parseRange( $data['target'] ); if ( $start === false ) { - $targetUser = User::newFromName( $data['target'] ); + $targetUser = $userFactory->newFromName( $data['target'] ); $targetID = $targetUser ? $targetUser->getId() : 0; $start = $end = $hex = ''; } else { @@ -115,7 +129,7 @@ class ImportCheckUserLogs extends Maintenance { } if ( !$this->hasOption( 'dry-run' ) ) { - $dbw = $this->getDB( DB_MASTER ); + $dbw = $this->getDB( DB_PRIMARY ); $fields = [ 'cul_timestamp' => $dbw->timestamp( $data['timestamp'] ), 'cul_user' => $user->getId(), @@ -126,7 +140,12 @@ class ImportCheckUserLogs extends Maintenance { 'cul_target_text' => $data['target'], 'cul_target_hex' => $hex, 'cul_range_start' => $start, - 'cul_range_end' => $end ]; + 'cul_range_end' => $end + ]; + + if ( $culActorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { + $fields['cul_actor'] = $user->getActorId(); + } $dbw->insert( 'cu_log', $fields, __METHOD__ ); } @@ -141,12 +160,16 @@ class ImportCheckUserLogs extends Maintenance { ); } + /** + * @param resource $file + */ protected function testLog( $file ) { $matched = 0; $unmatched = 0; $badtime = 0; - while ( false !== ( $line = fgets( $file ) ) ) { + while ( !feof( $file ) ) { + $line = fgets( $file ); $data = $this->parseLogLine( $line ); if ( $data ) { $matched++; diff --git a/CheckUser/maintenance/populateCheckUserTable.php b/CheckUser/maintenance/populateCheckUserTable.php index d0f81713..654462e6 100644 --- a/CheckUser/maintenance/populateCheckUserTable.php +++ b/CheckUser/maintenance/populateCheckUserTable.php @@ -1,5 +1,6 @@ <?php +use MediaWiki\CheckUser\Hooks; use MediaWiki\MediaWikiServices; use Wikimedia\IPUtils; @@ -25,15 +26,24 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance { $this->requireExtension( 'CheckUser' ); } + /** + * @inheritDoc + */ protected function getUpdateKey() { return __CLASS__; } + /** + * @inheritDoc + */ protected function doDBUpdates() { - $db = $this->getDB( DB_MASTER ); + $db = $this->getDB( DB_PRIMARY ); // Check if the table is empty - $rcRows = $db->selectField( 'recentchanges', 'COUNT(*)', [], __METHOD__ ); + $rcRows = $db->newSelectQueryBuilder() + ->table( 'recentchanges' ) + ->caller( __METHOD__ ) + ->fetchRowCount(); if ( !$rcRows ) { $this->output( "recentchanges is empty; nothing to add.\n" ); return true; @@ -54,42 +64,55 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance { $cutoffCond = ""; } - $start = (int)$db->selectField( 'recentchanges', 'MIN(rc_id)', [], __METHOD__ ); - $end = (int)$db->selectField( 'recentchanges', 'MAX(rc_id)', [], __METHOD__ ); + $start = (int)$db->newSelectQueryBuilder() + ->field( 'MIN(rc_id)' ) + ->table( 'recentchanges' ) + ->caller( __METHOD__ ) + ->fetchField(); + $end = (int)$db->newSelectQueryBuilder() + ->field( 'MAX(rc_id)' ) + ->table( 'recentchanges' ) + ->caller( __METHOD__ ) + ->fetchField(); // Do remaining chunk $end += $this->mBatchSize - 1; $blockStart = $start; $blockEnd = $start + $this->mBatchSize - 1; $this->output( - "Starting poulation of cu_changes with recentchanges rc_id from $start to $end\n" + "Starting population of cu_changes with recentchanges rc_id from $start to $end\n" ); - $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); + $services = MediaWikiServices::getInstance(); + $lbFactory = $services->getDBLoadBalancerFactory(); - $commentStore = CommentStore::getStore(); + $actorMigrationStage = $services->getMainConfig()->get( 'CheckUserActorMigrationStage' ); + + $commentStore = $services->getCommentStore(); $rcQuery = RecentChange::getQueryInfo(); + $contLang = $services->getContentLanguage(); while ( $blockStart <= $end ) { $this->output( "...migrating rc_id from $blockStart to $blockEnd\n" ); $cond = "rc_id BETWEEN $blockStart AND $blockEnd $cutoffCond"; - $res = $db->select( - $rcQuery['tables'], - $rcQuery['fields'], - $cond, - __METHOD__, - [], - $rcQuery['joins'] - ); + $res = $db->newSelectQueryBuilder() + ->fields( $rcQuery['fields'] ) + ->tables( $rcQuery['tables'] ) + ->joinConds( $rcQuery['joins'] ) + ->conds( $cond ) + ->caller( __METHOD__ ) + ->fetchResultSet(); $batch = []; foreach ( $res as $row ) { - $batch[] = [ + $entry = [ 'cuc_timestamp' => $row->rc_timestamp, 'cuc_user' => $row->rc_user ?? 0, 'cuc_user_text' => $row->rc_user_text, 'cuc_namespace' => $row->rc_namespace, 'cuc_title' => $row->rc_title, - 'cuc_comment' => $commentStore->getComment( 'rc_comment', $row )->text, + 'cuc_comment' => $contLang->truncateForDatabase( + $commentStore->getComment( 'rc_comment', $row )->text, Hooks::TEXT_FIELD_LENGTH + ), 'cuc_minor' => $row->rc_minor, 'cuc_page_id' => $row->rc_cur_id, 'cuc_this_oldid' => $row->rc_this_oldid, @@ -98,6 +121,12 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance { 'cuc_ip' => $row->rc_ip, 'cuc_ip_hex' => IPUtils::toHex( $row->rc_ip ), ]; + + if ( $actorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { + $entry['cuc_actor'] = $row->rc_actor; + } + + $batch[] = $entry; } if ( count( $batch ) ) { $db->insert( 'cu_changes', $batch, __METHOD__ ); diff --git a/CheckUser/maintenance/populateCucActor.php b/CheckUser/maintenance/populateCucActor.php new file mode 100644 index 00000000..0b81c713 --- /dev/null +++ b/CheckUser/maintenance/populateCucActor.php @@ -0,0 +1,140 @@ +<?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 + */ + +namespace MediaWiki\CheckUser\Maintenance; + +use LoggedUpdateMaintenance; +use MediaWiki\MediaWikiServices; + +$IP = getenv( 'MW_INSTALL_PATH' ); +if ( $IP === false ) { + $IP = __DIR__ . '/../../..'; +} +require_once "$IP/maintenance/Maintenance.php"; + +/** + * Maintenance script for filling up cuc_actor. + * + * @author Zabe + */ +class PopulateCucActor extends LoggedUpdateMaintenance { + + public function __construct() { + parent::__construct(); + $this->requireExtension( 'CheckUser' ); + $this->addDescription( 'Populate the cuc_actor column.' ); + $this->addOption( + 'sleep', + 'Sleep time (in seconds) between every batch. Default: 0', + false, + true + ); + } + + /** + * @inheritDoc + */ + protected function getUpdateKey() { + return 'PopulateCucActor'; + } + + /** + * @inheritDoc + */ + protected function doDBUpdates() { + $services = MediaWikiServices::getInstance(); + $actorStore = $services->getActorStore(); + $lbFactory = $services->getDBLoadBalancerFactory(); + $mainLb = $lbFactory->getMainLB(); + $dbr = $mainLb->getConnectionRef( DB_REPLICA, 'vslow' ); + $dbw = $mainLb->getConnectionRef( DB_PRIMARY ); + $batchSize = $this->getBatchSize(); + + $prevId = (int)$dbr->newSelectQueryBuilder() + ->field( 'MIN(cuc_id)' ) + ->table( 'cu_changes' ) + ->caller( __METHOD__ ) + ->fetchField(); + $curId = $prevId + $batchSize; + $maxId = (int)$dbr->newSelectQueryBuilder() + ->field( 'MAX(cuc_id)' ) + ->table( 'cu_changes' ) + ->caller( __METHOD__ ) + ->fetchField(); + + if ( !$maxId ) { + $this->output( "The cu_changes table seems to be empty.\n" ); + return true; + } + + $diff = $maxId - $prevId; + $failed = 0; + $sleep = (int)$this->getOption( 'sleep', 0 ); + + do { + $res = $dbr->newSelectQueryBuilder() + ->fields( [ 'cuc_id', 'cuc_user_text' ] ) + ->table( 'cu_changes' ) + ->conds( [ + 'cuc_actor' => 0, + "cuc_id BETWEEN $prevId AND $curId" + ] ) + ->caller( __METHOD__ ) + ->fetchResultSet(); + + foreach ( $res as $row ) { + $actor = $actorStore->findActorIdByName( $row->cuc_user_text, $dbr ); + + if ( !$actor ) { + $failed++; + continue; + } + + $dbw->update( + 'cu_changes', + [ + 'cuc_actor' => $actor + ], + [ + 'cuc_id' => $row->cuc_id + ], + __METHOD__ + ); + } + + $lbFactory->waitForReplication(); + + if ( $sleep > 0 ) { + sleep( $sleep ); + } + + $this->output( "Processed $batchSize rows out of $diff.\n" ); + + $prevId = $curId; + $curId += $batchSize; + } while ( $prevId <= $maxId ); + + $this->output( "Done. Migration failed for $failed row(s).\n" ); + return true; + } +} + +$maintClass = PopulateCucActor::class; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/CheckUser/maintenance/populateCulActor.php b/CheckUser/maintenance/populateCulActor.php new file mode 100644 index 00000000..12713868 --- /dev/null +++ b/CheckUser/maintenance/populateCulActor.php @@ -0,0 +1,136 @@ +<?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 + */ + +namespace MediaWiki\CheckUser\Maintenance; + +use LoggedUpdateMaintenance; +use MediaWiki\MediaWikiServices; + +$IP = getenv( 'MW_INSTALL_PATH' ); +if ( $IP === false ) { + $IP = __DIR__ . '/../../..'; +} +require_once "$IP/maintenance/Maintenance.php"; + +/** + * Maintenance script for filling up cul_actor. + * + * @author Zabe + */ +class PopulateCulActor extends LoggedUpdateMaintenance { + + public function __construct() { + parent::__construct(); + $this->requireExtension( 'CheckUser' ); + $this->addDescription( 'Populate the cul_actor column.' ); + $this->addOption( + 'sleep', + 'Sleep time (in seconds) between every batch. Default: 0', + false, + true + ); + } + + /** + * @inheritDoc + */ + protected function getUpdateKey() { + return 'PopulateCulActor'; + } + + /** + * @inheritDoc + */ + protected function doDBUpdates() { + $services = MediaWikiServices::getInstance(); + $actorStore = $services->getActorStore(); + $lbFactory = $services->getDBLoadBalancerFactory(); + $mainLb = $lbFactory->getMainLB(); + $dbr = $mainLb->getConnectionRef( DB_REPLICA, 'vslow' ); + $dbw = $mainLb->getConnectionRef( DB_PRIMARY ); + $batchSize = $this->getBatchSize(); + + $prevId = 0; + $curId = $prevId + $batchSize; + $maxId = (int)$dbr->newSelectQueryBuilder() + ->field( 'MAX(cul_id)' ) + ->table( 'cu_log' ) + ->caller( __METHOD__ ) + ->fetchField(); + + if ( !$maxId ) { + $this->output( "The cu_log table seems to be empty.\n" ); + return true; + } + + $diff = $maxId - $prevId; + $failed = 0; + $sleep = (int)$this->getOption( 'sleep', 0 ); + + do { + $res = $dbr->newSelectQueryBuilder() + ->fields( [ 'cul_id', 'cul_user_text' ] ) + ->table( 'cu_log' ) + ->conds( [ + 'cul_actor' => 0, + "cul_id BETWEEN $prevId AND $curId" + ] ) + ->caller( __METHOD__ ) + ->fetchResultSet(); + + foreach ( $res as $row ) { + $actor = $actorStore->findActorIdByName( $row->cul_user_text, $dbr ); + + if ( !$actor ) { + $failed++; + continue; + } + + $dbw->update( + 'cu_log', + [ + 'cul_actor' => $actor + ], + [ + 'cul_id' => $row->cul_id + ], + __METHOD__ + ); + } + + $lbFactory->waitForReplication(); + + if ( $sleep > 0 ) { + sleep( $sleep ); + } + + $this->output( "Processed $batchSize rows out of $diff.\n" ); + + $prevId = $curId; + $curId += $batchSize; + } while ( $prevId <= $maxId ); + + $this->output( "Done. Migration failed for $failed row(s).\n" ); + return true; + } +} + +$maintClass = PopulateCulActor::class; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/CheckUser/maintenance/purgeOldData.php b/CheckUser/maintenance/purgeOldData.php index 7046ac9e..cb6ecf7d 100644 --- a/CheckUser/maintenance/purgeOldData.php +++ b/CheckUser/maintenance/purgeOldData.php @@ -1,11 +1,11 @@ <?php -use MediaWiki\MediaWikiServices; +use Wikimedia\Rdbms\SelectQueryBuilder; if ( getenv( 'MW_INSTALL_PATH' ) ) { $IP = getenv( 'MW_INSTALL_PATH' ); } else { - $IP = __DIR__ . '/../../..'; + $IP = dirname( __DIR__, 3 ); } require_once "$IP/maintenance/Maintenance.php"; @@ -19,38 +19,49 @@ class PurgeOldData extends Maintenance { } public function execute() { - global $wgCUDMaxAge, $wgRCMaxAge, $wgPutIPinRC; + $config = $this->getConfig(); + $CUDMaxAge = $config->get( 'CUDMaxAge' ); + $RCMaxAge = $config->get( 'RCMaxAge' ); + $PutIPinRC = $config->get( 'PutIPinRC' ); $this->output( "Purging data from cu_changes..." ); - $count = $this->prune( 'cu_changes', 'cuc_timestamp', $wgCUDMaxAge ); + $count = $this->prune( 'cu_changes', 'cuc_timestamp', $CUDMaxAge ); $this->output( $count . " rows.\n" ); - if ( $wgPutIPinRC ) { + if ( $PutIPinRC ) { $this->output( "Purging data from recentchanges..." ); - $count = $this->prune( 'recentchanges', 'rc_timestamp', $wgRCMaxAge ); + $count = $this->prune( 'recentchanges', 'rc_timestamp', $RCMaxAge ); $this->output( $count . " rows.\n" ); } $this->output( "Done.\n" ); } + /** + * @param string $table + * @param string $ts_column + * @param int $maxAge + * + * @return int + */ protected function prune( $table, $ts_column, $maxAge ) { - $dbw = wfGetDB( DB_MASTER ); - - $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); - + $dbw = $this->getDB( DB_PRIMARY ); $expiredCond = "$ts_column < " . $dbw->addQuotes( $dbw->timestamp( time() - $maxAge ) ); $count = 0; while ( true ) { // Get the first $this->mBatchSize (or less) items - $res = $dbw->select( $table, $ts_column, - $expiredCond, - __METHOD__, - [ 'ORDER BY' => "$ts_column ASC", 'LIMIT' => $this->mBatchSize ] - ); + $res = $dbw->newSelectQueryBuilder() + ->field( $ts_column ) + ->table( $table ) + ->conds( $expiredCond ) + ->orderBy( $ts_column, SelectQueryBuilder::SORT_ASC ) + ->limit( $this->mBatchSize ) + ->caller( __METHOD__ ) + ->fetchResultSet(); if ( !$res->numRows() ) { - break; // all cleared + // all cleared + break; } // Record the start and end timestamp for the set $blockStart = $dbw->addQuotes( $res->fetchRow()[$ts_column] ); @@ -65,7 +76,6 @@ class PurgeOldData extends Maintenance { $count += $dbw->affectedRows(); $this->commitTransaction( $dbw, __METHOD__ ); - $lbFactory->waitForReplication(); } return $count; diff --git a/CheckUser/modules/.eslintrc.json b/CheckUser/modules/.eslintrc.json new file mode 100644 index 00000000..dfc75b8b --- /dev/null +++ b/CheckUser/modules/.eslintrc.json @@ -0,0 +1,12 @@ +{ + "root": true, + "extends": [ + "wikimedia/client-es5", + "wikimedia/jquery", + "wikimedia/mediawiki" + ], + "rules": { + "no-jquery/no-global-selector": "off", + "no-implicit-globals": "off" + } +} diff --git a/CheckUser/modules/ext.checkUser.styles/checkuser.less b/CheckUser/modules/ext.checkUser.styles/checkuser.less new file mode 100644 index 00000000..189e02a9 --- /dev/null +++ b/CheckUser/modules/ext.checkUser.styles/checkuser.less @@ -0,0 +1,81 @@ +@import 'mediawiki.skin.variables.less'; + +.mw-checkuser-edits-count { + display: inline-block; + + &:before { + content: '@{msg-brackets-start}'; + } + + &:after { + content: '@{msg-brackets-end}'; + } +} + +.mw-checkuser-links-no-parentheses > span:not( :first-child ):before { + content: ' @{msg-pipe-separator} '; +} + +.mw-special-CheckUserLog { + .mw-checkuser-log-highlight-entry { + background-color: #fcc; + } +} + +.mw-special-CheckUser { + .mw-checkuser-paging-links-form { + display: inline-block; + font-size: inherit; + } + + .mw-checkuser-paging-links { + text-decoration: none; + color: @color-link; + background: none; + border: 0; + padding: 0; + font-size: unset; + font-family: inherit; + } + + .mw-checkuser-paging-links:not( [ href ] ) { + cursor: pointer; + } + + .mw-checkuser-paging-links:visited { + color: @color-link--visited; + } + + .mw-checkuser-paging-links:active { + color: @color-link--active; + } + + .mw-checkuser-paging-links:hover, + .mw-checkuser-paging-links:focus { + text-decoration: underline; + } + + .mw-checkuser-indented { + margin-left: 2.5%; + } + + .mw-checkuser-get-edits-results { + .mw-checkuser-agent { + color: #888; + } + } + + .mw-checkuser-xff { + background-color: #ffc; + } + + .mw-checkuser-xff-trusted { + background-color: #f0fff0; + } + + .mw-checkuser-multilock-link, + .mw-checkuser-multilock-link-header { + margin-top: 12px; + display: table; + } +} diff --git a/CheckUser/modules/ext.checkUser.investigate.styles/investigate.less b/CheckUser/modules/ext.checkUser.styles/investigate.less index af8429e6..364ccc9d 100644 --- a/CheckUser/modules/ext.checkUser.investigate.styles/investigate.less +++ b/CheckUser/modules/ext.checkUser.styles/investigate.less @@ -28,11 +28,7 @@ .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; } @@ -143,16 +139,13 @@ } 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 { + td:hover.ext-checkuser-investigate-table-cell-pinnable { background-color: #fc3; } } .ext-checkuser-investigate-table-row-hover-data-match, - tr:hover, - tr:focus-within { + tr:hover { td { background-color: #fef6e7; } @@ -232,3 +225,7 @@ opacity: 0.2; } } + +.ext-checkuser-investigate-timeline-row-title { + unicode-bidi: embed; +} diff --git a/CheckUser/modules/ext.checkUser.investigateblock.styles/investigateblock.less b/CheckUser/modules/ext.checkUser.styles/investigateblock.less index bbb6fd57..bbb6fd57 100644 --- a/CheckUser/modules/ext.checkUser.investigateblock.styles/investigateblock.less +++ b/CheckUser/modules/ext.checkUser.styles/investigateblock.less diff --git a/CheckUser/modules/ext.checkUser/caMultiLock.js b/CheckUser/modules/ext.checkUser/caMultiLock.js deleted file mode 100644 index 8050d815..00000000 --- a/CheckUser/modules/ext.checkUser/caMultiLock.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * 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/checkuser/caMultiLock.js b/CheckUser/modules/ext.checkUser/checkuser/caMultiLock.js new file mode 100644 index 00000000..a00357be --- /dev/null +++ b/CheckUser/modules/ext.checkUser/checkuser/caMultiLock.js @@ -0,0 +1,91 @@ +/** + * 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 + var $checkUserBlockFieldset = $( '#checkuserblock fieldset' ); + $checkUserBlockFieldset.append( + $( '<a>' ).attr( { + class: 'mw-checkuser-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 () { + $( '.mw-checkuser-multilock-link, .mw-checkuser-multilock-link-header, .mw-checkuser-multilock-link-list' ).remove(); + var names = []; + var urls = []; + $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 ); + } + } + } ); + + // Split the names up into batches of username length of a + // maximum of 2,000 including the centralURL + other parts + // of the GET parameters + var i = 0; + while ( i < names.length ) { + var url = centralURL + '?wpTarget='; + var firstUsername = true; + while ( i < names.length ) { + var urlComponent = names[ i ]; + if ( !firstUsername ) { + urlComponent = '\n' + urlComponent; + } else { + firstUsername = false; + } + urlComponent = encodeURIComponent( urlComponent ); + if ( urlComponent.length + url.length >= 2000 ) { + break; + } + url += urlComponent; + i = i + 1; + } + urls.push( url ); + } + + // Update the href of the link with the latest change + if ( urls.length > 1 ) { + $checkUserBlockFieldset.append( + $( '<span>' ).attr( { + class: 'mw-checkuser-multilock-link-header' + } ).text( mw.msg( 'checkuser-centralauth-multilock-list' ) ) + ); + var links = ''; + urls.forEach( function ( urlToAdd, index ) { + var $li = $( '<li>' ); + var $a = $( '<a>' ); + $a.attr( 'href', urlToAdd ) + .text( mw.msg( 'checkuser-centralauth-multilock-list-item', index + 1 ) ); + $li.append( $a ); + links += $li[ 0 ].outerHTML; + } ); + $checkUserBlockFieldset.append( + $( '<ul>' ).attr( { class: 'mw-checkuser-multilock-link-list' } ).append( links ) + ); + } else { + $checkUserBlockFieldset.append( + $( '<a>' ).attr( { + class: 'mw-checkuser-multilock-link', + href: urls[ 0 ] + } ).text( mw.msg( 'checkuser-centralauth-multilock' ) ) + ); + } + } ); + +}() ); diff --git a/CheckUser/modules/ext.checkUser/cidr.js b/CheckUser/modules/ext.checkUser/checkuser/cidr.js index 8de64478..43965450 100644 --- a/CheckUser/modules/ext.checkUser/cidr.js +++ b/CheckUser/modules/ext.checkUser/checkuser/cidr.js @@ -1,9 +1,14 @@ -/* eslint-disable one-var, vars-on-top */ /* -- (c) Aaron Schulz 2009 */ ( function () { + $( '#mw-checkuser-ipnote' ).css( 'font-weight', '600' ); var showResults = function ( size, cidr ) { - $( '#mw-checkuser-cidr-res' ).val( cidr ); - $( '#mw-checkuser-ipnote' ).text( size ); + if ( cidr.toString() === '!' ) { + cidr = mw.message( 'checkuser-cidr-too-small' ).text(); + } + $( '#mw-checkuser-cidr-res input' ).val( cidr ); + $( '#mw-checkuser-ipnote' ).text( + mw.message( 'checkuser-cidr-affected-ips' ).text() + ' ' + size.toLocaleString() + ); }; /** @@ -16,11 +21,11 @@ return; // no JS form } form.style.display = 'inline'; // unhide form (JS active) - var iplist = document.getElementById( 'mw-checkuser-iplist' ); - if ( !iplist ) { + var $iplist = $( '#mw-checkuser-iplist textarea' ).first(); + if ( !$iplist ) { return; // no JS form } - var text = iplist.value, ips; + var text = $iplist.val(), ips; // Each line should have one IP or range if ( text.indexOf( '\n' ) !== -1 ) { ips = text.split( '\n' ); @@ -79,7 +84,7 @@ prefix = ''; // Rebuild formatted binPrefix for each IP // Apply any valid CIDRs if ( cidr ) { - bin = bin.substring( 0, cidr ); // truncate bin + bin = bin.slice( 0, Math.max( 0, cidr ) ); // truncate bin } // Init binPrefix if ( binPrefix === 0 ) { @@ -89,7 +94,7 @@ 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 + binPrefix = binPrefix.slice( 0, Math.max( 0, x ) ); // shorten binPrefix break; } } @@ -98,7 +103,7 @@ prefixCidr = binPrefix.length; // CIDR too small? if ( prefixCidr < 16 ) { - showResults( '!', '>' + Math.pow( 2, 32 - prefixCidr ) ); + showResults( '>' + Math.pow( 2, 32 - prefixCidr ).toLocaleString(), '!' ); return; // too big } // Build the IP in dotted-quad form @@ -160,7 +165,7 @@ prefix = ''; // Rebuild formatted binPrefix for each IP // Apply any valid CIDRs if ( cidr ) { - bin = bin.substring( 0, cidr ); // truncate bin + bin = bin.slice( 0, Math.max( 0, cidr ) ); // truncate bin } // Init binPrefix if ( binPrefix === 0 ) { @@ -170,7 +175,7 @@ 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 + binPrefix = binPrefix.slice( 0, Math.max( 0, x ) ); // shorten binPrefix break; } } @@ -179,7 +184,7 @@ prefixCidr = binPrefix.length; // CIDR too small? if ( prefixCidr < 32 ) { - showResults( '!', '>' + Math.pow( 2, 128 - prefixCidr ) ); + showResults( '>' + Math.pow( 2, 128 - prefixCidr ).toLocaleString(), '!' ); return; // too big } // Build the IP in dotted-quad form @@ -210,7 +215,7 @@ if ( prefixCidr !== false ) { full += '/' + prefixCidr; } - showResults( '~' + ipCount, full ); + showResults( '~' + ipCount.toLocaleString(), full ); } else { showResults( '?', '' ); } @@ -219,7 +224,7 @@ $( function () { updateCIDRresult(); - $( '#mw-checkuser-iplist' ).on( 'keyup click', function () { + $( '#mw-checkuser-iplist textarea' ).on( 'keyup click', function () { updateCIDRresult(); } ); } ); diff --git a/CheckUser/modules/ext.checkUser/checkuserlog/highlightScroll.js b/CheckUser/modules/ext.checkUser/checkuserlog/highlightScroll.js new file mode 100644 index 00000000..d410b456 --- /dev/null +++ b/CheckUser/modules/ext.checkUser/checkuserlog/highlightScroll.js @@ -0,0 +1,16 @@ +/** + * Scroll to the highlighted log entry in Special:CheckUserLog. + * + * If the page includes at least one entry that is highlighted, scroll to the first one. + */ +( function () { + var $highlightEntry = $( '.mw-checkuser-log-highlight-entry' ).first(); + if ( + $highlightEntry.length > 0 && + $highlightEntry.offset().top > $( window ).height() + ) { + $( window ).scrollTop( + $highlightEntry.offset().top - 100 + ); + } +}() ); diff --git a/CheckUser/modules/ext.checkUser/dispatcher.js b/CheckUser/modules/ext.checkUser/dispatcher.js new file mode 100644 index 00000000..e549496e --- /dev/null +++ b/CheckUser/modules/ext.checkUser/dispatcher.js @@ -0,0 +1,12 @@ +( function () { + if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Investigate' ) { + require( './investigate/init.js' ); + } else if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'InvestigateBlock' ) { + require( './investigateblock/investigateblock.js' ); + } else if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'CheckUser' ) { + require( './checkuser/cidr.js' ); + require( './checkuser/caMultiLock.js' ); + } else if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'CheckUserLog' ) { + require( './checkuserlog/highlightScroll.js' ); + } +}() ); diff --git a/CheckUser/modules/ext.checkUser/investigate/InvestigateMenuSelectWidget.js b/CheckUser/modules/ext.checkUser/investigate/InvestigateMenuSelectWidget.js new file mode 100644 index 00000000..235f6b72 --- /dev/null +++ b/CheckUser/modules/ext.checkUser/investigate/InvestigateMenuSelectWidget.js @@ -0,0 +1,51 @@ +/** + * Investigate Menu Select Widget + * + * @class + * + * @constructor + * @param {Object} [config] Configuration options + */ + +var InvestigateMenuSelectWidget = function ( config ) { + // Parent constructor + InvestigateMenuSelectWidget.super.call( this, config ); +}; + +/* Setup */ + +OO.inheritClass( InvestigateMenuSelectWidget, OO.ui.MenuSelectWidget ); + +/** + * @inheritdoc + */ +InvestigateMenuSelectWidget.prototype.onDocumentMouseUp = function ( e ) { + if ( !this.selecting ) { + var item = this.findTargetItem( e ); + if ( item && item.isSelectable() ) { + this.selecting = item; + } + } + if ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT && this.selecting ) { + this.emit( 'investigate', this.selecting ); + } + return InvestigateMenuSelectWidget.super.prototype.onDocumentMouseUp.call( this, e ); +}; + +/** + * @inheritdoc + */ +InvestigateMenuSelectWidget.prototype.onDocumentKeyDown = function ( e ) { + var selected = this.findSelectedItems(), + currentItem = this.findHighlightedItem() || ( + Array.isArray( selected ) ? selected[ 0 ] : selected + ); + + if ( e.keyCode === OO.ui.Keys.ENTER ) { + this.emit( 'investigate', currentItem ); + } + + return InvestigateMenuSelectWidget.super.prototype.onDocumentKeyDown.call( this, e ); +}; + +module.exports = InvestigateMenuSelectWidget; diff --git a/CheckUser/modules/ext.checkUser.investigate/blockform.js b/CheckUser/modules/ext.checkUser/investigate/blockform.js index 76783576..76783576 100644 --- a/CheckUser/modules/ext.checkUser.investigate/blockform.js +++ b/CheckUser/modules/ext.checkUser/investigate/blockform.js diff --git a/CheckUser/modules/ext.checkUser.investigate/copy.js b/CheckUser/modules/ext.checkUser/investigate/copy.js index 647bd0a7..22634509 100644 --- a/CheckUser/modules/ext.checkUser.investigate/copy.js +++ b/CheckUser/modules/ext.checkUser/investigate/copy.js @@ -3,7 +3,9 @@ * This feature is available for wikis that have Parsoid/RESTBase. */ module.exports = function addCopyFeature() { - var copyTextLayout, messageWidget, wikitextButton; + var copyTextLayout, messageWidget, wikitextButton, + hidden = true, + requested = false; function onWikitextButtonClick() { var url, html; @@ -13,7 +15,7 @@ module.exports = function addCopyFeature() { $table.find( '.oo-ui-widget, .ext-checkuser-investigate-table-options-container' ).remove(); $table.find( '.mw-userlink' ) - .attr( 'rel', 'mw:WikiLink' ) + .attr( 'rel', 'mw:ExtLink' ) .attr( 'href', function () { return new mw.Uri( $( this ).attr( 'href' ) ).toString(); } ); @@ -30,17 +32,27 @@ module.exports = function addCopyFeature() { return $table[ 0 ].outerHTML; } - wikitextButton.setDisabled( true ); - copyTextLayout.textInput.pushPending(); - copyTextLayout.toggle( true ); + hidden = !hidden; + if ( hidden ) { + wikitextButton.setLabel( mw.msg( 'checkuser-investigate-compare-copy-button-label' ) ); + copyTextLayout.toggle( false ); + } else { + wikitextButton.setLabel( mw.msg( 'checkuser-investigate-compare-copy-button-label-hide' ) ); + 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 ); - } ); + if ( !requested ) { + copyTextLayout.textInput.pushPending(); + $.ajax( url, { data: { html: html }, type: 'POST' } ).then( function ( data ) { + copyTextLayout.textInput.popPending(); + copyTextLayout.textInput.setValue( data ); + } ); + } + + requested = true; } messageWidget = new OO.ui.MessageWidget( { diff --git a/CheckUser/modules/ext.checkUser.investigate/init.js b/CheckUser/modules/ext.checkUser/investigate/init.js index d92c3440..d92c3440 100644 --- a/CheckUser/modules/ext.checkUser.investigate/init.js +++ b/CheckUser/modules/ext.checkUser/investigate/init.js diff --git a/CheckUser/modules/ext.checkUser.investigate/tables.js b/CheckUser/modules/ext.checkUser/investigate/tables.js index 6f7fa464..79ba4839 100644 --- a/CheckUser/modules/ext.checkUser.investigate/tables.js +++ b/CheckUser/modules/ext.checkUser/investigate/tables.js @@ -1,3 +1,5 @@ +var InvestigateMenuSelectWidget = require( './InvestigateMenuSelectWidget.js' ); + /** * Add highlight pinning capability and tool links to tables. */ @@ -49,7 +51,7 @@ module.exports = function setupTables() { function onPinnableCellHover( event ) { // Toggle on for mouseover, off for mouseout - updateMatchingElements( $( this ), event.type === 'mouseover' || event.type === 'focusin', 'hover-data-match' ); + updateMatchingElements( $( this ), event.type === 'mouseover', 'hover-data-match' ); } function onToggleButtonChange( $tableCell, value ) { @@ -88,10 +90,25 @@ module.exports = function setupTables() { key = getDataKey( $tableCell ), options = [], selectWidget, + contribsOptionWidget, + checksOptionWidget, toggleButton, message, $links; + /** + * Hack for setting an icon as the indicator. Call setIndicator with + * a dummy indicator type, to do everything that is needed to set an + * indicator, then swap in the class for the newWindow icon. + * + * @param {OO.ui.MenuOptionWidget} optionWidget + */ + function setNewWindowIndicator( optionWidget ) { + optionWidget.setIndicator( 'placeholder' ); + optionWidget.$indicator.removeClass( 'oo-ui-indicator-placeholder' ); + optionWidget.$indicator.addClass( 'oo-ui-icon-newWindow' ); + } + $tableCell.prepend( $optionsContainer ); if ( buttonTypes.filter ) { @@ -129,7 +146,7 @@ module.exports = function setupTables() { } if ( buttonTypes.contribs ) { - options.push( new OO.ui.MenuOptionWidget( { + contribsOptionWidget = new OO.ui.MenuOptionWidget( { icon: 'userContributions', label: mw.msg( 'checkuser-investigate-compare-table-button-contribs-label' ), data: { @@ -139,37 +156,45 @@ module.exports = function setupTables() { } ), tool: 'Special:Contributions' } - } ) ); + } ); + setNewWindowIndicator( contribsOptionWidget ); + options.push( contribsOptionWidget ); } if ( buttonTypes.checks ) { - options.push( new OO.ui.MenuOptionWidget( { + checksOptionWidget = 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(), + href: new mw.Title( 'Special:CheckUserLog' ).getUrl( { + cuSearch: $tableCell.data( 'value' ) + } ), tool: 'Special:InvestigateLog' } - } ) ); + } ); + setNewWindowIndicator( checksOptionWidget ); + options.push( checksOptionWidget ); } 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, + var optionWidget, + label = $link.text, href = $link.getAttribute( 'href' ); - options.push( new OO.ui.MenuOptionWidget( { - icon: 'linkExternal', + optionWidget = new OO.ui.MenuOptionWidget( { + icon: 'globe', label: label, data: { type: 'toolLinks', href: href, tool: new mw.Uri( href ).host } - } ) ); + } ); + setNewWindowIndicator( optionWidget ); + options.push( optionWidget ); } ); } @@ -181,10 +206,11 @@ module.exports = function setupTables() { menu: { horizontalPosition: 'end', items: options - } + }, + menuClass: InvestigateMenuSelectWidget } ); - selectWidget.getMenu().on( 'choose', function ( item ) { + selectWidget.getMenu().on( 'investigate', function ( item ) { var data = item.getData(); switch ( data.type ) { case 'filter': @@ -231,11 +257,6 @@ module.exports = function setupTables() { $( '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 ), { diff --git a/CheckUser/modules/ext.checkUser.investigateblock/investigateblock.js b/CheckUser/modules/ext.checkUser/investigateblock/investigateblock.js index ddb8c505..211517a6 100644 --- a/CheckUser/modules/ext.checkUser.investigateblock/investigateblock.js +++ b/CheckUser/modules/ext.checkUser/investigateblock/investigateblock.js @@ -18,12 +18,12 @@ } 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 = 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 ); diff --git a/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate/checkuserinvestigate.js b/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate/checkuserinvestigate.js index e15a42bb..4a0eaedc 100644 --- a/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate/checkuserinvestigate.js +++ b/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate/checkuserinvestigate.js @@ -2,8 +2,6 @@ * Special:Invesitgate guided tour */ ( function ( gt ) { - var tour; - if ( mw.config.get( 'wgCanonicalSpecialPageName' ) !== 'Investigate' ) { return; } @@ -12,7 +10,11 @@ return; } - tour = new gt.TourBuilder( { + var canBlock = mw.config.get( 'wgCheckUserInvestigateCanBlock' ); + var canCopy = mw.config.get( 'wgVisualEditorConfig' ) && + mw.config.get( 'wgVisualEditorConfig' ).fullRestbaseUrl; + + var tour = new gt.TourBuilder( { name: 'checkuserinvestigate', shouldLog: true, isSinglePage: false @@ -79,10 +81,18 @@ autoFocus: false, overlay: true, onShow: handleIpTargetOnShow, - onHide: handleIpTargetOnHide + onHide: handleIpTargetOnHide, + buttons: [ + { + action: 'back' + }, + { + action: ( canCopy || canBlock ) ? 'next' : 'end' + } + ] } ) .back( 'addusertargets' ) - .next( 'block' ); + .next( canBlock ? 'block' : 'copywikitext' ); tour.step( { name: 'block', @@ -97,8 +107,7 @@ action: 'back' }, { - // If the copy button is not present, end the tour. - action: $( '.ext-checkuser-investigate-copy-button' ).length ? 'next' : 'end' + action: canCopy ? 'next' : 'end' } ] } ) @@ -122,6 +131,6 @@ } ] } ) - .back( 'block' ); + .back( canBlock ? 'block' : 'filterip' ); }( mw.guidedTour ) ); diff --git a/CheckUser/package-lock.json b/CheckUser/package-lock.json index 3a52fe0d..f2733acf 100644 --- a/CheckUser/package-lock.json +++ b/CheckUser/package-lock.json @@ -1,443 +1,10485 @@ { - "name": "checkuser", - "version": "0.0.0", - "lockfileVersion": 1, + "name": "CheckUser", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "CheckUser", + "devDependencies": { + "@wdio/cli": "7.16.13", + "@wdio/dot-reporter": "7.4.2", + "@wdio/junit-reporter": "7.16.13", + "@wdio/local-runner": "7.16.13", + "@wdio/mocha-framework": "7.16.13", + "@wdio/spec-reporter": "7.16.13", + "@wdio/sync": "7.4.6", + "eslint-config-wikimedia": "0.22.1", + "grunt": "1.5.3", + "grunt-banana-checker": "0.10.0", + "grunt-eslint": "24.0.0", + "grunt-stylelint": "0.17.0", + "stylelint-config-wikimedia": "0.13.0", + "wdio-mediawiki": "1.2.0", + "webdriverio": "7.16.13" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/runtime": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", + "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", + "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.18.0.tgz", + "integrity": "sha512-TjT8KJULV4I6ZiwIoKr6eMs+XpRejqwJ/VA+QPDeFGe9j6bZFKmMJ81EeFsGm6JNZhnzm37aoxVROmTh2PZoyA==", + "dev": true, + "dependencies": { + "comment-parser": "1.3.0", + "esquery": "^1.4.0", + "jsdoc-type-pratt-parser": "~2.2.2" + }, + "engines": { + "node": "^12 || ^14 || ^16 || ^17" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@mdn/browser-compat-data": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.1.11.tgz", + "integrity": "sha512-sYJ5CWXVAJX3608rV3WowUGxPm3p7HCgoGh/eBseCQ2c5ALBz6oRTK2OWPFz679aBUik6IY1IlA89uxbb5/FjA==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.44", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.44.tgz", + "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==", + "dev": true + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", + "dev": true + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", + "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "node_modules/@types/cucumber": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cucumber/-/cucumber-6.0.1.tgz", + "integrity": "sha512-+GZV6xfN0MeN9shDCdny8GbC8N0+U6uca8cjyaJndcwmrUhwS6qOU2vmYn0d71EOwJF568/v3SxJ8VKxuZNYRw==", + "dev": true + }, + "node_modules/@types/diff": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.2.tgz", + "integrity": "sha512-uw8eYMIReOwstQ0QKF0sICefSy8cNO/v7gOTiIy9SbwuHyEecJUm7qlgueOO5S1udZ5I/irVydHVwMchgzbKTg==", + "dev": true + }, + "node_modules/@types/easy-table": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/easy-table/-/easy-table-0.0.33.tgz", + "integrity": "sha512-/vvqcJPmZUfQwCgemL0/34G7bIQnCuvgls379ygRlcC1FqNqk3n+VZ15dAO51yl6JNDoWd8vsk+kT8zfZ1VZSw==", + "dev": true + }, + "node_modules/@types/ejs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", + "dev": true + }, + "node_modules/@types/fibers": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/fibers/-/fibers-3.1.1.tgz", + "integrity": "sha512-yHoUi46uika0snoTpNcVqUSvgbRndaIps4TUCotrXjtc0DHDoPQckmyXEZ2bX3e4mpJmyEW3hRhCwQa/ISCPaA==", + "dev": true + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "node_modules/@types/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-Pxxx3i3AyK7vKAj3LRM/vF7ETcHKiLJ/u5CnNgbz/eYj/vB3xGAYtRxI5IKtq0hpe5iFHD22BKV3n6WHUu0k4Q==", + "dev": true, + "dependencies": { + "@types/through": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-stringify-safe": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/json-stringify-safe/-/json-stringify-safe-5.0.0.tgz", + "integrity": "sha512-UUA1sH0RSRROdInuDOA1yoRzbi5xVFD1RHCoOvNRPTNwR8zBkJ/84PZ6NhKVDtKp0FTeIccJCdQz1X2aJPr4uw==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.14.186", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz", + "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==", + "dev": true + }, + "node_modules/@types/lodash.flattendeep": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.7.tgz", + "integrity": "sha512-1h6GW/AeZw/Wej6uxrqgmdTDZX1yFS39lRsXYkg+3kWvOWWrlGCI6H7lXxlUHOzxDT4QeYGmgPpQ3BX9XevzOg==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/lodash.pickby": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.7.tgz", + "integrity": "sha512-4ebXRusuLflfscbD0PUX4eVknDHD9Yf+uMtBIvA/hrnTqeAzbuHuDjvnYriLjUrI9YrhCPVKUf4wkRSXJQ6gig==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/lodash.union": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.7.tgz", + "integrity": "sha512-6HXM6tsnHJzKgJE0gA/LhTGf/7AbjUk759WZ1MziVm+OBNAATHhdgj+a3KVE8g76GCLAnN4ZEQQG1EGgtBIABA==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "dev": true + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/object-inspect": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/object-inspect/-/object-inspect-1.8.1.tgz", + "integrity": "sha512-0JTdf3CGV0oWzE6Wa40Ayv2e2GhpP3pEJMcrlM74vBSJPuuNkVwfDnl0SZxyFCXETcB4oKA/MpTVfuYSMOelBg==", + "dev": true + }, + "node_modules/@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 + }, + "node_modules/@types/puppeteer": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.6.tgz", + "integrity": "sha512-98Kghehs7+/GD9b56qryhqdqVCXUTbetTv3PlvDnmFRTHQH0j9DIp1f7rkAW3BAj4U3yoeSEQnKgdW8bDq0Y0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/recursive-readdir": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/stream-buffers": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.4.tgz", + "integrity": "sha512-qU/K1tb2yUdhXkLIATzsIPwbtX6BpZk0l3dPW6xqWyhfzzM1ECaQ/8faEnu3CNraLiQ9LHyQQPBGp7N9Fbs25w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw==", + "dev": true + }, + "node_modules/@types/through": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz", + "integrity": "sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==", + "dev": true + }, + "node_modules/@types/ua-parser-js": { + "version": "0.7.36", + "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz", + "integrity": "sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==", + "dev": true + }, + "node_modules/@types/validator": { + "version": "13.7.7", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.7.tgz", + "integrity": "sha512-jiEw2kTUJ8Jsh4A1K4b5Pkjj9Xz6FktLLOQ36ZVLRkmxFbpTvAV2VRoKMojz8UlZxNg/2dZqzpigH4JYn1bkQg==", + "dev": true + }, + "node_modules/@types/which": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-1.3.2.tgz", + "integrity": "sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/@wdio/cli": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.16.13.tgz", + "integrity": "sha512-y0C/eLLyLCVWrsJVimozUQBQWD/goIUxmtB91rjMAqTjeLn5b0VoPhr+EKXGCHXz3ylvXGGJ3RaI0l1vz9Cf8w==", + "dev": true, + "dependencies": { + "@types/ejs": "^3.0.5", + "@types/fs-extra": "^9.0.4", + "@types/inquirer": "^8.1.2", + "@types/lodash.flattendeep": "^4.4.6", + "@types/lodash.pickby": "^4.6.6", + "@types/lodash.union": "^4.6.6", + "@types/node": "^17.0.4", + "@types/recursive-readdir": "^2.2.0", + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "async-exit-hook": "^2.0.1", + "chalk": "^4.0.0", + "chokidar": "^3.0.0", + "cli-spinners": "^2.1.0", + "ejs": "^3.0.1", + "fs-extra": "^10.0.0", + "inquirer": "8.1.5", + "lodash.flattendeep": "^4.4.0", + "lodash.pickby": "^4.6.0", + "lodash.union": "^4.6.0", + "mkdirp": "^1.0.4", + "recursive-readdir": "^2.2.2", + "webdriverio": "7.16.13", + "yargs": "^17.0.0", + "yarn-install": "^1.0.0" + }, + "bin": { + "wdio": "bin/wdio.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wdio/cli/node_modules/yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wdio/cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wdio/config": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.13.tgz", + "integrity": "sha512-LSGoa83tWQIBppB+LeHjY40B9tuuvmDV1qdBLVXR1ROcOUWWz/oQP3NFLtLm3266LXoJUbwebzGcRIK1EcNk3Q==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/dot-reporter": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/dot-reporter/-/dot-reporter-7.4.2.tgz", + "integrity": "sha512-jHy57G+155p1c96egjLKPHTh4B6t6/5rPKThiw88ldtsmvnZUk6Y74Cpyl2a3lfUrJ09QZ6G7iBjqwkrQ3x1cg==", + "dev": true, + "dependencies": { + "@wdio/reporter": "7.4.2", + "@wdio/types": "7.4.2", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@wdio/cli": "^7.0.0" + } + }, + "node_modules/@wdio/dot-reporter/node_modules/@wdio/types": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.4.2.tgz", + "integrity": "sha512-LLSaeC8yCMlQdB75J2TFEE/NAKb7vRCbLAXQmqBm6THNJll1U/Mk9tHIaUK624Eqf5qGBwQ0UKRKnx8qevzPUA==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/junit-reporter": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/junit-reporter/-/junit-reporter-7.16.13.tgz", + "integrity": "sha512-VKhly72NZY2/SNnfbYXO/HHov9oj+pk0aaq5TNzIJJoqtH4uqDz+L2p7wu9nKnRnywmwvaTm7pbYZGlOuty26A==", + "dev": true, + "dependencies": { + "@types/json-stringify-safe": "^5.0.0", + "@types/validator": "^13.1.3", + "@wdio/reporter": "7.16.13", + "@wdio/types": "7.16.13", + "json-stringify-safe": "^5.0.1", + "junit-report-builder": "^3.0.0", + "validator": "^13.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@wdio/cli": "^7.0.0" + } + }, + "node_modules/@wdio/junit-reporter/node_modules/@wdio/reporter": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.16.13.tgz", + "integrity": "sha512-S7OH96yfSCJwmirsvT8khfWUfoMTiw0O1+UyiOYS/g0l+IideVK83kpyXYWfsALPahL2te0g57lPazriSfNAyA==", + "dev": true, + "dependencies": { + "@types/diff": "^5.0.0", + "@types/node": "^17.0.4", + "@types/object-inspect": "^1.8.0", + "@types/supports-color": "^8.1.0", + "@types/tmp": "^0.2.0", + "@wdio/types": "7.16.13", + "diff": "^5.0.0", + "fs-extra": "^10.0.0", + "object-inspect": "^1.10.3", + "supports-color": "8.1.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/junit-reporter/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/junit-reporter/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@wdio/local-runner": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.16.13.tgz", + "integrity": "sha512-Ri8R6RHD5VjI4m2CramKO9w+4jD7VwEoQFWqFzUI1g31UAuN1zy67R3UiYv0ohiBTW4MZt90CMLgumQNk7C5kA==", + "dev": true, + "dependencies": { + "@types/stream-buffers": "^3.0.3", + "@wdio/logger": "7.16.0", + "@wdio/repl": "7.16.13", + "@wdio/runner": "7.16.13", + "@wdio/types": "7.16.13", + "async-exit-hook": "^2.0.1", + "split2": "^4.0.0", + "stream-buffers": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@wdio/cli": "^7.0.0" + } + }, + "node_modules/@wdio/local-runner/node_modules/split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/@wdio/logger": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.16.0.tgz", + "integrity": "sha512-/6lOGb2Iow5eSsy7RJOl1kCwsP4eMlG+/QKro5zUJsuyNJSQXf2ejhpkzyKWLgQbHu83WX6cM1014AZuLkzoQg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/mocha-framework": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.16.13.tgz", + "integrity": "sha512-yaLxEF5evXACGqxkch/IoJz8JGoQmcV+X635JBiMF6tl0+HSTYrL1ZPk1cED+9OI4jIPtmlhbgzne9IhoKCbpg==", + "dev": true, + "dependencies": { + "@types/mocha": "^9.0.0", + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "expect-webdriverio": "^3.0.0", + "mocha": "^9.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/protocols": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", + "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/repl": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.13.tgz", + "integrity": "sha512-XWh3dzp6U8LLL4cNGWFra+quVyXZ25Ym38zpsBVtV0/z5NCHJmjRS4ytyvvkzbQ8SyqQ7Y3G8MjfGNi2sBNkIQ==", + "dev": true, + "dependencies": { + "@wdio/utils": "7.16.13" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/reporter": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.4.2.tgz", + "integrity": "sha512-TRT1suI/H6Fi3JWoNXYDuvQ+LhszKU7Z41IRdoXUOn5ZnDFAvF3fMDvHyGjVXEv7oyDFgqunKnBhHM8xpq5Dbg==", + "dev": true, + "dependencies": { + "@types/cucumber": "^6.0.1", + "@wdio/types": "7.4.2", + "fs-extra": "^9.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/reporter/node_modules/@wdio/types": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.4.2.tgz", + "integrity": "sha512-LLSaeC8yCMlQdB75J2TFEE/NAKb7vRCbLAXQmqBm6THNJll1U/Mk9tHIaUK624Eqf5qGBwQ0UKRKnx8qevzPUA==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/reporter/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@wdio/runner": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.16.13.tgz", + "integrity": "sha512-/PJUK+8orHsUd5v8edWv5XS3pKx/si7DoYkU8PsgQX9FnU2y3oRfHrQwzI8s3TOnGag79f+yrGzzGCZFmmW0cw==", + "dev": true, + "dependencies": { + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "deepmerge": "^4.0.0", + "gaze": "^1.1.2", + "webdriver": "7.16.13", + "webdriverio": "7.16.13" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/spec-reporter": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.16.13.tgz", + "integrity": "sha512-4gnflBJU+QDcmWgRy3tSRD47cqZmdjPLEJhsfhv/aBNtWPWMJtQru7nDFcLkxKLFPiN0D1F7gUMWbUMaDVlojg==", + "dev": true, + "dependencies": { + "@types/easy-table": "^0.0.33", + "@wdio/reporter": "7.16.13", + "@wdio/types": "7.16.13", + "chalk": "^4.0.0", + "easy-table": "^1.1.1", + "pretty-ms": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@wdio/cli": "^7.0.0" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/@wdio/reporter": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.16.13.tgz", + "integrity": "sha512-S7OH96yfSCJwmirsvT8khfWUfoMTiw0O1+UyiOYS/g0l+IideVK83kpyXYWfsALPahL2te0g57lPazriSfNAyA==", + "dev": true, + "dependencies": { + "@types/diff": "^5.0.0", + "@types/node": "^17.0.4", + "@types/object-inspect": "^1.8.0", + "@types/supports-color": "^8.1.0", + "@types/tmp": "^0.2.0", + "@wdio/types": "7.16.13", + "diff": "^5.0.0", + "fs-extra": "^10.0.0", + "object-inspect": "^1.10.3", + "supports-color": "8.1.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@wdio/sync": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.4.6.tgz", + "integrity": "sha512-kbgDXalRmZmPgTcJYdbvURw/EOpDEb3w3ca+W0qc+cUlvrPGKu2l76vMiZQqPKLfHnPhDbpLSYvZfM19vrFK6w==", + "dev": true, + "dependencies": { + "@types/fibers": "^3.1.0", + "@types/puppeteer": "^5.4.0", + "@wdio/logger": "7.4.2", + "@wdio/types": "7.4.2", + "fibers": "^5.0.0", + "webdriverio": "7.4.6" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/@wdio/config": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.4.2.tgz", + "integrity": "sha512-TCHBHtKeV4659rNuC0SIjtv0ttM8WSQBwogY3Zuf55LTtVuWyNHQJ2vcquqL2mszOg2jPRfhdEn+E5U0Sp/auA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.4.2", + "@wdio/types": "7.4.2", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@wdio/logger": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.4.2.tgz", + "integrity": "sha512-vYH0glKyw/rIJ/FJ4g+WQfx6MRKnWEPUspejv5Vit32STKa1IPotw/Y/Axv2qy6os1VHAs9CfH43930q9QZLkA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@wdio/protocols": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.4.2.tgz", + "integrity": "sha512-WEcCwTQxknj6TS+oa+ipEH1i2E/gSYRMpISSl8qC71ZTav9h3tA4eTNEnKzS2Foi+DjWBkwZ23YV8fjoQB+zPg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@wdio/repl": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.4.6.tgz", + "integrity": "sha512-ebLZIvJUfSCsgJS5GQavU5BfHHlLguhA+NaD2ezjHCvU2Fsbvj429oLtdlyZTkA2ElOqowX6Gw0c5hZ3FPZatA==", + "dev": true, + "dependencies": { + "@wdio/utils": "7.4.6" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@wdio/types": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.4.2.tgz", + "integrity": "sha512-LLSaeC8yCMlQdB75J2TFEE/NAKb7vRCbLAXQmqBm6THNJll1U/Mk9tHIaUK624Eqf5qGBwQ0UKRKnx8qevzPUA==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@wdio/utils": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.4.6.tgz", + "integrity": "sha512-Rdw5/eEEZR+rytK4DmwuzJ74SoR0vBG860w+BCvxgNBWRbr94TySMX4hlxLqLInU0N5Ur38LR0AJej8XTuaQdg==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.4.2", + "@wdio/types": "7.4.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@wdio/sync/node_modules/chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" + } + }, + "node_modules/@wdio/sync/node_modules/devtools": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.4.6.tgz", + "integrity": "sha512-eLsbQUDLxiZIqW+NWef6MDzq6ogMBLRvIHZ/flNwVQUrATF+Zo2W7+Ork/5n2wbK5L/5lrFoNXeIgTlzgTvWFg==", + "dev": true, + "dependencies": { + "@wdio/config": "7.4.2", + "@wdio/logger": "7.4.2", + "@wdio/protocols": "7.4.2", + "@wdio/types": "7.4.2", + "@wdio/utils": "7.4.6", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^7.1.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/devtools-protocol": { + "version": "0.0.863986", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.863986.tgz", + "integrity": "sha512-WMf5KuRLsLwJMp9JdawSvoEpxZPqyyNeOZ3YR8QF8lE9IVHbbpdWeuXV22SJxPUemFeznvVlwSBeQz91nL+41A==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@wdio/sync/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/@wdio/sync/node_modules/puppeteer-core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-7.1.0.tgz", + "integrity": "sha512-2wjKs3L1rYuoVNNtRR/GbAGjbt6LF8DRUxcg/UoCQZrzjfppWlrIqiHRF5uBzJk+Nc0w7ZkvVzKQCvB5PFqFdA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.847576", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/@wdio/sync/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.847576", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.847576.tgz", + "integrity": "sha512-0M8kobnSQE0Jmly7Mhbeq0W/PpZfnuK+WjN2ZRVPbGqYwCHCioAVp84H0TcLimgECcN5H976y5QiXMGBC9JKmg==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/rgb2hex": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.3.tgz", + "integrity": "sha512-clEe0m1xv+Tva1B/TOepuIcvLAxP0U+sCDfgt1SX1HmI2Ahr5/Cd/nzJM1e78NKVtWdoo0s33YehpFA8UfIShQ==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/ua-parser-js": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", + "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/@wdio/sync/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/sync/node_modules/webdriver": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.4.6.tgz", + "integrity": "sha512-L8ctz72XZXYy6AwM9oQCN81mJ9MFF4TS9bxgMoI4zVV5Jc2PxMlrmq9FpqWCUF2JDDTM9Qt2c8uqlWAId4uNOg==", + "dev": true, + "dependencies": { + "@wdio/config": "7.4.2", + "@wdio/logger": "7.4.2", + "@wdio/protocols": "7.4.2", + "@wdio/types": "7.4.2", + "@wdio/utils": "7.4.6", + "got": "^11.0.2", + "lodash.merge": "^4.6.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/webdriverio": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.4.6.tgz", + "integrity": "sha512-heSx8QdBSftnR0+XuHbFtmmJmJujKr50Tq57tAdOstkMn1YNldM5ALAnlhSfKGHFZqAVphtJs1Xm/R1MT7NtCw==", + "dev": true, + "dependencies": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.4.2", + "@wdio/logger": "7.4.2", + "@wdio/protocols": "7.4.2", + "@wdio/repl": "7.4.6", + "@wdio/types": "7.4.2", + "@wdio/utils": "7.4.6", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.4.6", + "devtools-protocol": "^0.0.863986", + "fs-extra": "^9.0.1", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^7.1.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.3", + "serialize-error": "^8.0.0", + "webdriver": "7.4.6" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@wdio/types": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.16.13.tgz", + "integrity": "sha512-HIeXKCL+mUjyJxvnHSoaIo3NRgZLbeekyRIwo6USfd9qGlQ8dQ6fyCR3ZU9VqNz9j4+JIn+LRQ7imbz5SdnGbw==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/utils": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.13.tgz", + "integrity": "sha512-O6D89Ghtm5XtTv4DPKvCBKZOZYNONIcBM5/hmdr3V9mzVrTFq8Q3uE8pmmq303Oh91KcoN8Em5zoAG7Zpc5tRg==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "p-iteration": "^1.1.8" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/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 + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/archiver": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "dev": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.3", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/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 + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/archiver/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver/node_modules/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, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aria-query": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.2.tgz", + "integrity": "sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-metadata-inferer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.7.0.tgz", + "integrity": "sha512-OkMLzd8xelb3gmnp6ToFvvsHLtS6CbagTkFQvQ+ZYFe3/AIl9iKikNR9G7pY3GfOR/2Xc222hwBjzI7HLkE76Q==", + "dev": true, + "dependencies": { + "@mdn/browser-compat-data": "^3.3.14" + } + }, + "node_modules/ast-metadata-inferer/node_modules/@mdn/browser-compat-data": { + "version": "3.3.14", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-3.3.14.tgz", + "integrity": "sha512-n2RC9d6XatVbWFdHLimzzUJxJ1KY8LdjqrW6YvGPiRmsHkhOUx74/Ct10x5Yo7bC/Jvqx7cDEW8IMPv/+vwEzA==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "dev": true + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/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, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bl/node_modules/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, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.0.tgz", + "integrity": "sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001313", + "electron-to-chromium": "^1.4.76", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/browserslist-config-wikimedia": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/browserslist-config-wikimedia/-/browserslist-config-wikimedia-0.4.0.tgz", + "integrity": "sha512-U/fmsaGlCKOqRIjKqXwQ44qFqiStngRTphj1Cf6IHV6J8OK8T0gu9dKc7Ljq4v7bwhnhN+YCCa4fA3nZlPNivQ==", + "dev": true + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cac": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", + "integrity": "sha512-hq4rxE3NT5PlaEiVV39Z45d6MoFcQZG5dsgJqtAUeOz3408LEQAElToDkf9i5IYSCOmK0If/81dLg7nKxqPR0w==", + "dev": true, + "dependencies": { + "camelcase-keys": "^3.0.0", + "chalk": "^1.1.3", + "indent-string": "^3.0.0", + "minimist": "^1.2.0", + "read-pkg-up": "^1.0.1", + "suffix": "^0.1.0", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cac/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/camelcase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", + "integrity": "sha512-U4E6A6aFyYnNW+tDt5/yIUKQURKXe3WMFPfX4FxrQFcwZ/R08AUk1xWcUtlr7oq6CV07Ji+aa69V2g7BSpblnQ==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/cac/node_modules/indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cac/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/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, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/cac/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/cac/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cac/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001315", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001315.tgz", + "integrity": "sha512-5v7LFQU4Sb/qvkz7JcZkvtSH1Ko+1x2kgo3ocdBeMGZSOFpuE1kkm0kpTwLtWeFrw5qw08ulLxJjVIXIS8MkiQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/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 + }, + "node_modules/chalk/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/chrome-launcher": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.1.tgz", + "integrity": "sha512-UugC8u59/w2AyX5sHLZUHoxBAiSiunUhZa3zZwMH6zPVis0C3dDKiRWyUGIo14tTbZHGVviWxv3PQWZ7taZ4fg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chrome-launcher/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha1-jffHquUf02h06PjQW5GAvBGj/tc=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/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, + "dependencies": { + "is-regexp": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/colord": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", + "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==", + "dev": true + }, + "node_modules/colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comment-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.0.tgz", + "integrity": "sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "dev": true, + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/compress-commons/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/compress-commons/node_modules/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, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/core-js": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", + "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.25.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.5.tgz", + "integrity": "sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/crc32-stream/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/crc32-stream/node_modules/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, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-functions-list": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.0.1.tgz", + "integrity": "sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw==", + "dev": true, + "engines": { + "node": ">=12.22" + } + }, + "node_modules/css-rule-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/css-rule-stream/-/css-rule-stream-1.1.0.tgz", + "integrity": "sha1-N4bnGYmD2WWibjGVfgkHjLt3BaI=", + "dev": true, + "dependencies": { + "css-tokenize": "^1.0.1", + "duplexer2": "0.0.2", + "ldjson-stream": "^1.2.1", + "through2": "^0.6.3" + }, + "bin": { + "css-rule-stream": "index.js" + } + }, + "node_modules/css-rule-stream/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/css-rule-stream/node_modules/through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "dependencies": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/css-shorthand-properties": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz", + "integrity": "sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==", + "dev": true + }, + "node_modules/css-tokenize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-tokenize/-/css-tokenize-1.0.1.tgz", + "integrity": "sha1-RiXLHtohwUOFi3+B1oA8HSb8FL4=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^1.0.33" + } + }, + "node_modules/css-value": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", + "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", + "dev": true + }, + "node_modules/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, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/date-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", + "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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=", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/devtools": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.13.tgz", + "integrity": "sha512-jm/DL5tlOUUMe0pUgahDqixw3z+NANLN6DYDeZPFv7z0CBtmnaTyOe2zbT0apLxCBpi800VeXaISVZwmKE2NiQ==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "@types/ua-parser-js": "^0.7.33", + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "chrome-launcher": "^0.15.0", + "edge-paths": "^2.1.0", + "puppeteer-core": "^13.0.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.1", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.953906", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.953906.tgz", + "integrity": "sha512-Z2vAafCNnl0Iw/u7TUjqOXW1sOhAMDOviflmUoUIxfq2rgfsoCO3qruB/LUJCdqF9aTJ32DUjXyMsX3+if6kDQ==", + "dev": true + }, + "node_modules/devtools/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/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, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/doiuse": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/doiuse/-/doiuse-4.4.1.tgz", + "integrity": "sha512-TUpr1/YNg20IB09tZmwGCTsTQoxj8jUld/hUZprZMj8vj0VpAJySXEWCr8WMvqvgzk0/kG/FxeSMGKode4UjPg==", + "dev": true, + "dependencies": { + "browserslist": "^4.16.1", + "caniuse-lite": "^1.0.30001179", + "css-rule-stream": "^1.1.0", + "duplexer2": "0.0.2", + "ldjson-stream": "^1.2.1", + "multimatch": "^5.0.0", + "postcss": "^8.2.4", + "source-map": "^0.7.3", + "through2": "^4.0.2", + "yargs": "^16.2.0" + }, + "bin": { + "doiuse": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "dependencies": { + "readable-stream": "~1.1.9" + } + }, + "node_modules/easy-table": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz", + "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "optionalDependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/edge-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-2.2.1.tgz", + "integrity": "sha512-AI5fC7dfDmCdKo3m5y7PkYE8m6bMqR6pvVpgtrZkkhcJXFLelUgkjrhk3kXXx8Kbw2cRaTT4LkOR7hqf39KJdw==", + "dev": true, + "dependencies": { + "@types/which": "^1.3.2", + "which": "^2.0.2" + } + }, + "node_modules/edge-paths/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.82", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.82.tgz", + "integrity": "sha512-Ks+ANzLoIrFDUOJdjxYMH6CMKB8UQo5modAwvSZTxgF+vEs/U7G5IbWFUp6dS4klPkTDVdxbORuk8xAXXhMsWw==", + "dev": true + }, + "node_modules/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 + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/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, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", + "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-wikimedia": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.22.1.tgz", + "integrity": "sha512-TtN+gWJrcW0i1sEu7vPE1tHpEilrMUuTxP6UK97Amvva/KDV9/tvRUifGhw0q5uBswp+HWgF12p8rq68hZqMbA==", + "dev": true, + "dependencies": { + "eslint": "^8.6.0", + "eslint-plugin-compat": "^4.0.2", + "eslint-plugin-es": "^4.1.0", + "eslint-plugin-jsdoc": "^37.7.1", + "eslint-plugin-json-es": "^1.5.4", + "eslint-plugin-mediawiki": "^0.3.0", + "eslint-plugin-mocha": "^9.0.0", + "eslint-plugin-no-jquery": "^2.7.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-qunit": "^7.2.0", + "eslint-plugin-unicorn": "^40.1.0", + "eslint-plugin-vue": "^8.4.1", + "eslint-plugin-wdio": "^7.4.2", + "eslint-plugin-yml": "^0.13.0" + } + }, + "node_modules/eslint-plugin-compat": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.0.2.tgz", + "integrity": "sha512-xqvoO54CLTVaEYGMzhu35Wzwk/As7rCvz/2dqwnFiWi0OJccEtGIn+5qq3zqIu9nboXlpdBN579fZcItC73Ycg==", + "dev": true, + "dependencies": { + "@mdn/browser-compat-data": "^4.1.5", + "ast-metadata-inferer": "^0.7.0", + "browserslist": "^4.16.8", + "caniuse-lite": "^1.0.30001304", + "core-js": "^3.16.2", + "find-up": "^5.0.0", + "lodash.memoize": "4.1.2", + "semver": "7.3.5" + }, + "engines": { + "node": ">=9.x" + }, + "peerDependencies": { + "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-compat/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-compat/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-compat/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-compat/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-compat/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-es": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", + "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "37.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-37.7.1.tgz", + "integrity": "sha512-ySxDTedl6qKXT/VeTwcZlhsRtvNQZGPklyVnaL5+ge20vowzFA9CKvrY0NXRqvdIz6JBVMFpxX9DSmS3OyAUOQ==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.18.0", + "comment-parser": "1.3.0", + "debug": "^4.3.3", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.4.0", + "regextras": "^0.8.0", + "semver": "^7.3.5", + "spdx-expression-parse": "^3.0.1" + }, + "engines": { + "node": "^12 || ^14 || ^16 || ^17" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-json-es": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-json-es/-/eslint-plugin-json-es-1.5.4.tgz", + "integrity": "sha512-DdjnNMUZ1iMrUXfxUQrTU7IyoEOsa4Kg0Zd6nOyOq1mUb75deK7NrcbI1FlWGdGVgqX99bUOD27i81EYiG794Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0" + }, + "peerDependencies": { + "eslint": ">= 7" + } + }, + "node_modules/eslint-plugin-json-es/node_modules/eslint-visitor-keys": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", + "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-plugin-mediawiki": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.3.0.tgz", + "integrity": "sha512-Lhyj2PSkhDzYSc1PNbURysY/WoqvY0brw558ZInT3erzf5KUlro18MTKFdV+nlht475ZgnsfHsgfg6Ut2w1SVg==", + "dev": true, + "dependencies": { + "eslint-plugin-vue": "^7.20.0", + "upath": "^2.0.1" + }, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-plugin-mediawiki/node_modules/eslint-plugin-vue": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.20.0.tgz", + "integrity": "sha512-oVNDqzBC9h3GO+NTgWeLMhhGigy6/bQaQbHS+0z7C4YEu/qK/yxHvca/2PTZtGNPsCrHwOTgKMrwu02A9iPBmw==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.1.0", + "natural-compare": "^1.4.0", + "semver": "^6.3.0", + "vue-eslint-parser": "^7.10.0" + }, + "engines": { + "node": ">=8.10" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-mediawiki/node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-mediawiki/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-mediawiki/node_modules/vue-eslint-parser": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz", + "integrity": "sha512-qh3VhDLeh773wjgNTl7ss0VejY9bMMa0GoDG2fQVyDzRFdiU3L7fw74tWZDHNQXdZqxO3EveQroa9ct39D2nqg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "eslint-scope": "^5.1.1", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.2.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8.10" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-plugin-mocha": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-9.0.0.tgz", + "integrity": "sha512-d7knAcQj1jPCzZf3caeBIn3BnW6ikcvfz0kSqQpwPYcVGLoJV5sz0l0OJB2LR8I7dvTDbqq1oV6ylhSgzA10zg==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "ramda": "^0.27.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-mocha/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-plugin-no-jquery": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.7.0.tgz", + "integrity": "sha512-Aeg7dA6GTH1AcWLlBtWNzOU9efK5KpNi7b0EhBO0o0M+awyzguUUo8gF6hXGjQ9n5h8/uRtYv9zOqQkeC5CG0w==", + "dev": true, + "peerDependencies": { + "eslint": ">=2.3.0" + } + }, + "node_modules/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, + "dependencies": { + "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" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/eslint-plugin-node/node_modules/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, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/eslint-plugin-qunit": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-7.2.0.tgz", + "integrity": "sha512-ebT6aOpmMj4vchG0hVw9Ukbutk/lgywrc8gc9w9hH2/4WjKqwMlyM7iVwqB7OAXv6gtQMJZuziT0wNjjymAuWA==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "requireindex": "^1.2.0" + }, + "engines": { + "node": "12.x || 14.x || >=16.0.0" + } + }, + "node_modules/eslint-plugin-qunit/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "40.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-40.1.0.tgz", + "integrity": "sha512-y5doK2DF9Sr5AqKEHbHxjFllJ167nKDRU01HDcWyv4Tnmaoe9iNxMrBnaybZvWZUaE3OC5Unu0lNIevYamloig==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.15.7", + "ci-info": "^3.3.0", + "clean-regexp": "^1.0.0", + "eslint-utils": "^3.0.0", + "esquery": "^1.4.0", + "indent-string": "^4.0.0", + "is-builtin-module": "^3.1.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "read-pkg-up": "^7.0.1", + "regexp-tree": "^0.1.24", + "safe-regex": "^2.1.1", + "semver": "^7.3.5", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=7.32.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.4.1.tgz", + "integrity": "sha512-nmWOhNmDx9TZ+yP9ZhezTkZUupSHsYA2TocRm+efPSXMOyFrVczVlaIuQcLBjCtI8CbkBiUQ3VcyQsjlIhDrhA==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-wdio": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-7.4.2.tgz", + "integrity": "sha512-tkISFycJmRFMKsEjetRcAmWSHKJKnw5rKHDxfE7Ob3tF5lbmYlCLfNKH0UwanOpSdulpe52s3K+CBHSd6qUUNQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/eslint-plugin-yml": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-0.13.0.tgz", + "integrity": "sha512-rZvdnhe28jIbgSIZo3qYqkl9hKslyTDfMwqIGDzz873gxghzBw0yeFG+P7sMfOkFfpqwJzZy3IKe2cIiCp4FrA==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^0.5.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/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, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-utils/node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "node_modules/execall": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", + "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", + "dev": true, + "dependencies": { + "clone-regexp": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect-webdriverio": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-3.4.0.tgz", + "integrity": "sha512-7Ivy1IB35pmkbCcI36un2OMytGEYCy1PcdqrlDnWZBzTpewAO14r+gO2FSuO5kNpDWm3gZSD4NYLG1KXJOlI3w==", + "dev": true, + "dependencies": { + "expect": "^28.1.0", + "jest-matcher-utils": "^28.1.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/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==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fibers": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.3.tgz", + "integrity": "sha512-/qYTSoZydQkM21qZpGLDLuCq8c+B8KhuCQ1kLPvnRNhxhVbvrpmH9l2+Lblf5neDuEsY4bfT7LeO553TXQDvJw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/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, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dev": true, + "dependencies": { + "glob": "~5.0.0" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/findup-sync/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/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, + "dependencies": { + "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" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/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, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/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=", + "dev": true + }, + "node_modules/gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "dependencies": { + "globule": "^1.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getobject": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.0.tgz", + "integrity": "sha512-tbUz6AKKKr2YiMB+fLWIgq5ZeBOobop9YMMAU9dC54/ot2ksMXt3DOFyBuhZw6ptcVszEykgByK20j7W9jHFag==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/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, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/globals": { + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=", + "dev": true + }, + "node_modules/globule": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", + "dev": true, + "dependencies": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/got": { + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/grunt": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", + "integrity": "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==", + "dev": true, + "dependencies": { + "dateformat": "~3.0.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.2", + "findup-sync": "~0.3.0", + "glob": "~7.1.6", + "grunt-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", + "grunt-legacy-log": "~3.0.0", + "grunt-legacy-util": "~2.0.1", + "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" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/grunt-banana-checker": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/grunt-banana-checker/-/grunt-banana-checker-0.10.0.tgz", + "integrity": "sha512-Sx+P3zWjn4YmBCqzidnCEkYrACe1SLTIT8kKC6C3f21Hu6sm17U/V+re343cuK3U+iGZv15ux6bY+69buIbYrA==", + "dev": true, + "bin": { + "banana-checker": "src/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/grunt-cli": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", + "dev": true, + "dependencies": { + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-cli/node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/grunt-eslint": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/grunt-eslint/-/grunt-eslint-24.0.0.tgz", + "integrity": "sha512-WpTeBBFweyhMuPjGwRSQV9JFJ+EczIdlsc7Dd/1g78QVI1aZsk4g/H3e+3S5HEwsS1RKL2YZIrGj8hMLlBfN8w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "eslint": "^8.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + }, + "peerDependencies": { + "grunt": ">=1" + } + }, + "node_modules/grunt-known-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.19" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "chalk": "~4.1.0", + "lodash": "~4.17.19" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-legacy-util": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", + "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", + "dev": true, + "dependencies": { + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.21", + "underscore.string": "~3.3.5", + "which": "~2.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-legacy-util/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/grunt-stylelint": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/grunt-stylelint/-/grunt-stylelint-0.17.0.tgz", + "integrity": "sha512-aVpqPO7h98haGRZKnj9nkMTMGjzmVQWyN/FNB/qkbcVG6pguZ48yZi8YO+ULynzNK9YFqWhWBFgAs71m7ZpK+A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "stylelint": "^14.0.0" + } + }, + "node_modules/grunt/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/http2-wrapper/node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/inquirer": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", + "integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.2.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "node_modules/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, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-builtin-module": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.1.0.tgz", + "integrity": "sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.2.2.tgz", + "integrity": "sha512-zRokSWcPLSWkoNzsWn9pq7YYSwDhKyEe+cJYT2qaPqLOOJb5sFSi46BPj81vP+e8chvCNdQL9RG86Bi9EI6MDw==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/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==", + "dev": true + }, + "node_modules/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=", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/junit-report-builder": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-3.0.1.tgz", + "integrity": "sha512-B8AZ2q24iGwPM3j/ZHc9nD0BY1rKhcnWCA1UvT8mhHfR8Vo/HTtg3ojMyo55BgctqQGZG7H8z0+g+mEUc32jgg==", + "dev": true, + "dependencies": { + "date-format": "4.0.3", + "lodash": "^4.17.21", + "make-dir": "^3.1.0", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/keyv": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", + "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/known-css-properties": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.24.0.tgz", + "integrity": "sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==", + "dev": true + }, + "node_modules/ky": { + "version": "0.28.7", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.28.7.tgz", + "integrity": "sha512-a23i6qSr/ep15vdtw/zyEQIDLoUaKDg9Jf04CYl/0ns/wXNYna26zJpI+MeIFaPeDvkrjLPrKtKOiiI3IE53RQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/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 + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/ldjson-stream": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz", + "integrity": "sha1-kb7O2lrE7SsX5kn7d356v6AYnCs=", + "dev": true, + "dependencies": { + "split2": "^0.2.1", + "through2": "^0.6.1" + } + }, + "node_modules/ldjson-stream/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/ldjson-stream/node_modules/through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "dependencies": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/liftup/node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.3.0.tgz", + "integrity": "sha512-BbqAKApLb9ywUli+0a+PcV04SyJ/N1q/8qgCNe6U97KbPCS1BTksEuHFLYdvc8DltuhfxIUBqDZsC0bBGtl3lA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/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 + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true + }, + "node_modules/lodash.isobject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true + }, + "node_modules/lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loglevel": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", + "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-plugin-prefix": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", + "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", + "dev": true + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-obj": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", + "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/marky": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", + "dev": true + }, + "node_modules/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 + }, + "node_modules/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "dev": true, + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/multimatch/node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/mwbot": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mwbot/-/mwbot-2.0.0.tgz", + "integrity": "sha512-9iTx8oFMntC60yyaPJjN4GEgiQlal7i03jATu7kq5b9BGW5aNz7YbrpjaciLNr0Z33PTdQe0hRTJ0JdUJi2WQg==", + "dev": true, + "dependencies": { + "bluebird": "^3.7.2", + "request": "^2.88.2", + "semlog": "^0.6.10", + "semver": "7.3.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mwbot/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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 + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-iteration": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/p-iteration/-/p-iteration-1.1.8.tgz", + "integrity": "sha512-IMFBSDIYcPNnW7uWYGrBqmvTiq7W0uB0fJn6shQZs7dlF3OvrHOre+JT9ikSZ7gZS3vWqclVgoQSvToJrns7uQ==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/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, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=6" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/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=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-less": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-6.0.0.tgz", + "integrity": "sha512-FPX16mQLyEjLzEuuJtxA8X3ejDLNGGEG503d2YGZR5Ask1SpDN8KmZUMpzCvyalWRywAn1n1VOA5dcqfCLo5rg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "postcss": "^8.3.5" + } + }, + "node_modules/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 + }, + "node_modules/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 + }, + "node_modules/postcss-safe-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "dev": true, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dev": true, + "dependencies": { + "parse-ms": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prettyjson": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.5.tgz", + "integrity": "sha512-rksPWtoZb2ZpT5OVgtmy0KHVM+Dca3iVwWY9ifwhcexfjebtgjg3wmrUt9PvJ59XIYBcknQeYHD8IAnVlh9lAw==", + "dev": true, + "dependencies": { + "colors": "1.4.0", + "minimist": "^1.2.0" + }, + "bin": { + "prettyjson": "bin/prettyjson" + } + }, + "node_modules/prettyjson/node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/puppeteer-core": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", + "integrity": "sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==", + "dev": true, + "dependencies": { + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.981744", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "pkg-dir": "4.2.0", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.5.0" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.981744", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", + "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", + "dev": true + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-selector-shadow-dom": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.0.tgz", + "integrity": "sha512-bK0/0cCI+R8ZmOF1QjT7HupDUYCxbf/9TJgAmSXQxZpftXmTAeil9DRoCnTDkWbvOyZzhcMBwKpptWcdkGFIMg==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/ramda": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", + "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==", + "dev": true + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/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, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz", + "integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/regexp-tree": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", + "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", + "dev": true, + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regextras": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", + "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", + "dev": true, + "engines": { + "node": ">=0.1.14" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/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, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/resq": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/resq/-/resq-1.10.2.tgz", + "integrity": "sha512-HmgVS3j+FLrEDBTDYysPdPVF9/hioDMJ/otOiQDKqk77YfZeeLOj0qi34yObumcud1gBpk+wpBTEg4kMicD++A==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^2.0.1" + } + }, + "node_modules/resq/node_modules/fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", + "dev": true + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rgb2hex": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.5.tgz", + "integrity": "sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", + "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", + "dev": true, + "dependencies": { + "regexp-tree": "~0.1.1" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/semlog": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/semlog/-/semlog-0.6.10.tgz", + "integrity": "sha512-FFUGeVy3vJnOV+3jOL4deYb1iVJpVLCJQHpXlDqMYVykl9t7G/Uuu71sEWjwJtTbaj5AmDXAQtTQN/t1sUhE2Q==", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "prettyjson": "^1.1.3" + } + }, + "node_modules/semlog/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semlog/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semlog/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semlog/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semlog/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/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 + }, + "node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/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 + }, + "node_modules/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, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/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 + }, + "node_modules/specificity": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz", + "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==", + "dev": true, + "bin": { + "specificity": "bin/specificity" + } + }, + "node_modules/split2": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz", + "integrity": "sha1-At2smtwD7Au3jBKC7Aecpuha6QA=", + "dev": true, + "dependencies": { + "through2": "~0.6.1" + } + }, + "node_modules/split2/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/split2/node_modules/through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "dependencies": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stream-buffers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", + "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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 + }, + "node_modules/stylelint": { + "version": "14.8.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.8.1.tgz", + "integrity": "sha512-0YxTop3wTeEVmQWhS7jjLFaBkvfPmffRiJ6eFIDlK++f3OklaobTYFJu32E5u/cIrFLbcW52pLqrYpihA/y0/w==", + "dev": true, + "dependencies": { + "balanced-match": "^2.0.0", + "colord": "^2.9.2", + "cosmiconfig": "^7.0.1", + "css-functions-list": "^3.0.1", + "debug": "^4.3.4", + "execall": "^2.0.0", + "fast-glob": "^3.2.11", + "fastest-levenshtein": "^1.0.12", + "file-entry-cache": "^6.0.1", + "get-stdin": "^8.0.0", + "global-modules": "^2.0.0", + "globby": "^11.1.0", + "globjoin": "^0.1.4", + "html-tags": "^3.2.0", + "ignore": "^5.2.0", + "import-lazy": "^4.0.0", + "imurmurhash": "^0.1.4", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.24.0", + "mathml-tag-names": "^2.1.3", + "meow": "^9.0.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "normalize-selector": "^0.2.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.12", + "postcss-media-query-parser": "^0.2.3", + "postcss-resolve-nested-selector": "^0.1.1", + "postcss-safe-parser": "^6.0.0", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", + "resolve-from": "^5.0.0", + "specificity": "^0.4.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "style-search": "^0.1.0", + "supports-hyperlinks": "^2.2.0", + "svg-tags": "^1.0.0", + "table": "^6.8.0", + "v8-compile-cache": "^2.3.0", + "write-file-atomic": "^4.0.1" + }, + "bin": { + "stylelint": "bin/stylelint.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + } + }, + "node_modules/stylelint-config-recommended": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", + "integrity": "sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q==", + "dev": true, + "peerDependencies": { + "stylelint": "^14.4.0" + } + }, + "node_modules/stylelint-config-wikimedia": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.13.0.tgz", + "integrity": "sha512-1R1g/uc53z2z39ejZMALwC6fTfSZhkzDjj1v8ODCWtLCiuqWuSf3HR1ZTXT5X5AtSbZq1W9+0p5HJp6rPVXkRg==", + "dev": true, + "dependencies": { + "browserslist-config-wikimedia": "0.4.0", + "postcss-less": "6.0.0", + "stylelint": "14.8.1", + "stylelint-config-recommended": "7.0.0", + "stylelint-no-unsupported-browser-features": "5.0.3" + }, + "peerDependencies": { + "postcss-less": "^6.0.0" + } + }, + "node_modules/stylelint-no-unsupported-browser-features": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-5.0.3.tgz", + "integrity": "sha512-FqfbOTk5UEkHsAKOkPH6SvajsfO9YuoWvKxd34tCRBZug9ZNeaPn141nyWkd+ncc8S1gVmO2+O6qVAMj9bvWww==", + "dev": true, + "dependencies": { + "doiuse": "^4.4.1", + "lodash": "^4.17.15", + "postcss": "^8.3.6" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "stylelint": ">=13.0.0" + } + }, + "node_modules/stylelint/node_modules/balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", + "dev": true + }, + "node_modules/stylelint/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylelint/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/suffix": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", + "integrity": "sha512-j5uf6MJtMCfC4vBe5LFktSe4bGyNTBk7I2Kdri0jeLrcv5B9pWfxVa5JQpoxgtR8vaVB7bVxsWgnfQbX5wkhAA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "dev": true + }, + "node_modules/table": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tar-stream/node_modules/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, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/through2/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/through2/node_modules/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, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/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, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", + "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/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, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/vue-eslint-parser": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.2.0.tgz", + "integrity": "sha512-hvl8OVT8imlKk/lQyhkshqwQQChzHETcBd5abiO4ePw7ib7QUZLfW+2TUrJHKUvFOCFRJrDin5KJO9OHzB5bRQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", + "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", + "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/wdio-mediawiki": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/wdio-mediawiki/-/wdio-mediawiki-1.2.0.tgz", + "integrity": "sha512-s9vekcs++5dEdNgsJzH7NFfnM1j+u2QRBxAdjOU889RFVYOp6pFJnNQ/wzjf456Wd34gnwNQ5IB3sN9zlJAMnQ==", + "dev": true, + "dependencies": { + "mwbot": "2.0.0" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/webdriver": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.13.tgz", + "integrity": "sha512-Vfr952W1uIgDeWHPGzqH43dYLeRSZshh3TzA9ICUkvnC+Q7YziQdv/8xI8tuuyvb7lSr3VsuB2cGzyCRoC/NWw==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "got": "^11.0.2", + "ky": "^0.28.5", + "lodash.merge": "^4.6.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.13.tgz", + "integrity": "sha512-jl1VRZYL1+cPeG6klskKX7mCEBWNQWDFaNtaIl5pwWgtKWPau6fCzKntSARzfNV8+hKJKwJ2mZn5Nsxfw28Oeg==", + "dev": true, + "dependencies": { + "@types/aria-query": "^5.0.0", + "@types/node": "^17.0.4", + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/repl": "7.16.13", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "archiver": "^5.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.16.13", + "devtools-protocol": "^0.0.953906", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^13.0.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.16.13" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/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 + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yaml-eslint-parser": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-0.5.0.tgz", + "integrity": "sha512-nJeyLA3YHAzhBTZbRAbu3W6xrSCucyxExmA+ZDtEdUFpGllxAZpto2Zxo2IG0r0eiuEiBM4e+wiAdxTziTq94g==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.0.0", + "lodash": "^4.17.21", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/yaml-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yarn-install": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", + "integrity": "sha512-VO1u181msinhPcGvQTVMnHVOae8zjX/NSksR17e6eXHRveDvHCF5mGjh9hkN8mzyfnCqcBe42LdTs7bScuTaeg==", + "dev": true, + "dependencies": { + "cac": "^3.0.3", + "chalk": "^1.1.3", + "cross-spawn": "^4.0.2" + }, + "bin": { + "yarn-install": "bin/yarn-install.js", + "yarn-remove": "bin/yarn-remove.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yarn-install/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yarn-install/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yarn-install/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yarn-install/node_modules/cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "node_modules/yarn-install/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/yarn-install/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yarn-install/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/yarn-install/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "dev": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/zip-stream/node_modules/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, + "dependencies": { + "safe-buffer": "~5.2.0" + } + } + }, "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==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "^7.14.5" } }, - "@babel/core": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", - "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "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==", + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "@babel/highlight": "^7.8.3" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } + } + } + }, + "@babel/runtime": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", + "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", + "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", + "dev": true, + "requires": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.4" + } + }, + "@es-joy/jsdoccomment": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.18.0.tgz", + "integrity": "sha512-TjT8KJULV4I6ZiwIoKr6eMs+XpRejqwJ/VA+QPDeFGe9j6bZFKmMJ81EeFsGm6JNZhnzm37aoxVROmTh2PZoyA==", + "dev": true, + "requires": { + "comment-parser": "1.3.0", + "esquery": "^1.4.0", + "jsdoc-type-pratt-parser": "~2.2.2" + } + }, + "@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "argparse": "^2.0.1" } } } }, - "@babel/generator": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", - "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", "dev": true, "requires": { - "@babel/types": "^7.9.5", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" + "jest-get-type": "^28.0.2" } }, - "@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==", + "@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.9.5" + "@sinclair/typebox": "^0.24.1" } }, - "@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==", + "@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" } }, - "@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==", + "@mdn/browser-compat-data": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.1.11.tgz", + "integrity": "sha512-sYJ5CWXVAJX3608rV3WowUGxPm3p7HCgoGh/eBseCQ2c5ALBz6oRTK2OWPFz679aBUik6IY1IlA89uxbb5/FjA==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" } }, - "@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==", + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" } }, - "@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==", + "@sinclair/typebox": { + "version": "0.24.44", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.44.tgz", + "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==", + "dev": true + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "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" + "defer-to-connect": "^2.0.0" } }, - "@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==", + "@types/aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", + "dev": true + }, + "@types/cacheable-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", + "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" } }, - "@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==", + "@types/cucumber": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cucumber/-/cucumber-6.0.1.tgz", + "integrity": "sha512-+GZV6xfN0MeN9shDCdny8GbC8N0+U6uca8cjyaJndcwmrUhwS6qOU2vmYn0d71EOwJF568/v3SxJ8VKxuZNYRw==", + "dev": true + }, + "@types/diff": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.2.tgz", + "integrity": "sha512-uw8eYMIReOwstQ0QKF0sICefSy8cNO/v7gOTiIy9SbwuHyEecJUm7qlgueOO5S1udZ5I/irVydHVwMchgzbKTg==", + "dev": true + }, + "@types/easy-table": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/easy-table/-/easy-table-0.0.33.tgz", + "integrity": "sha512-/vvqcJPmZUfQwCgemL0/34G7bIQnCuvgls379ygRlcC1FqNqk3n+VZ15dAO51yl6JNDoWd8vsk+kT8zfZ1VZSw==", + "dev": true + }, + "@types/ejs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", + "dev": true + }, + "@types/fibers": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/fibers/-/fibers-3.1.1.tgz", + "integrity": "sha512-yHoUi46uika0snoTpNcVqUSvgbRndaIps4TUCotrXjtc0DHDoPQckmyXEZ2bX3e4mpJmyEW3hRhCwQa/ISCPaA==", + "dev": true + }, + "@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", "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" + "@types/node": "*" } }, - "@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==", + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "@types/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-Pxxx3i3AyK7vKAj3LRM/vF7ETcHKiLJ/u5CnNgbz/eYj/vB3xGAYtRxI5IKtq0hpe5iFHD22BKV3n6WHUu0k4Q==", "dev": true, "requires": { - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" + "@types/through": "*" } }, - "@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==", + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@types/istanbul-lib-coverage": "*" } }, - "@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==", + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-stringify-safe": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/json-stringify-safe/-/json-stringify-safe-5.0.0.tgz", + "integrity": "sha512-UUA1sH0RSRROdInuDOA1yoRzbi5xVFD1RHCoOvNRPTNwR8zBkJ/84PZ6NhKVDtKp0FTeIccJCdQz1X2aJPr4uw==", "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==", + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", "dev": true, "requires": { - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0" + "@types/node": "*" } }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "@types/lodash": { + "version": "4.14.186", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz", + "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==", + "dev": true + }, + "@types/lodash.flattendeep": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.7.tgz", + "integrity": "sha512-1h6GW/AeZw/Wej6uxrqgmdTDZX1yFS39lRsXYkg+3kWvOWWrlGCI6H7lXxlUHOzxDT4QeYGmgPpQ3BX9XevzOg==", + "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" + "@types/lodash": "*" + } + }, + "@types/lodash.pickby": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.7.tgz", + "integrity": "sha512-4ebXRusuLflfscbD0PUX4eVknDHD9Yf+uMtBIvA/hrnTqeAzbuHuDjvnYriLjUrI9YrhCPVKUf4wkRSXJQ6gig==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, + "@types/lodash.union": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.7.tgz", + "integrity": "sha512-6HXM6tsnHJzKgJE0gA/LhTGf/7AbjUk759WZ1MziVm+OBNAATHhdgj+a3KVE8g76GCLAnN4ZEQQG1EGgtBIABA==", + "dev": true, + "requires": { + "@types/lodash": "*" } }, - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "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==", + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, + "@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/object-inspect": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/object-inspect/-/object-inspect-1.8.1.tgz", + "integrity": "sha512-0JTdf3CGV0oWzE6Wa40Ayv2e2GhpP3pEJMcrlM74vBSJPuuNkVwfDnl0SZxyFCXETcB4oKA/MpTVfuYSMOelBg==", + "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/puppeteer": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.6.tgz", + "integrity": "sha512-98Kghehs7+/GD9b56qryhqdqVCXUTbetTv3PlvDnmFRTHQH0j9DIp1f7rkAW3BAj4U3yoeSEQnKgdW8bDq0Y0Q==", "dev": true, "requires": { - "regenerator-runtime": "^0.13.4" + "@types/node": "*" } }, - "@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==", + "@types/recursive-readdir": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", "dev": true, "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" + "@types/node": "*" + } + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/stream-buffers": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.4.tgz", + "integrity": "sha512-qU/K1tb2yUdhXkLIATzsIPwbtX6BpZk0l3dPW6xqWyhfzzM1ECaQ/8faEnu3CNraLiQ9LHyQQPBGp7N9Fbs25w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw==", + "dev": true + }, + "@types/through": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz", + "integrity": "sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==", + "dev": true + }, + "@types/ua-parser-js": { + "version": "0.7.36", + "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz", + "integrity": "sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==", + "dev": true + }, + "@types/validator": { + "version": "13.7.7", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.7.tgz", + "integrity": "sha512-jiEw2kTUJ8Jsh4A1K4b5Pkjj9Xz6FktLLOQ36ZVLRkmxFbpTvAV2VRoKMojz8UlZxNg/2dZqzpigH4JYn1bkQg==", + "dev": true + }, + "@types/which": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-1.3.2.tgz", + "integrity": "sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "@wdio/cli": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.16.13.tgz", + "integrity": "sha512-y0C/eLLyLCVWrsJVimozUQBQWD/goIUxmtB91rjMAqTjeLn5b0VoPhr+EKXGCHXz3ylvXGGJ3RaI0l1vz9Cf8w==", + "dev": true, + "requires": { + "@types/ejs": "^3.0.5", + "@types/fs-extra": "^9.0.4", + "@types/inquirer": "^8.1.2", + "@types/lodash.flattendeep": "^4.4.6", + "@types/lodash.pickby": "^4.6.6", + "@types/lodash.union": "^4.6.6", + "@types/node": "^17.0.4", + "@types/recursive-readdir": "^2.2.0", + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "async-exit-hook": "^2.0.1", + "chalk": "^4.0.0", + "chokidar": "^3.0.0", + "cli-spinners": "^2.1.0", + "ejs": "^3.0.1", + "fs-extra": "^10.0.0", + "inquirer": "8.1.5", + "lodash.flattendeep": "^4.4.0", + "lodash.pickby": "^4.6.0", + "lodash.union": "^4.6.0", + "mkdirp": "^1.0.4", + "recursive-readdir": "^2.2.2", + "webdriverio": "7.16.13", + "yargs": "^17.0.0", + "yarn-install": "^1.0.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==", + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { - "@babel/highlight": "^7.8.3" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" } }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true } } }, - "@babel/traverse": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", - "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", + "@wdio/config": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.13.tgz", + "integrity": "sha512-LSGoa83tWQIBppB+LeHjY40B9tuuvmDV1qdBLVXR1ROcOUWWz/oQP3NFLtLm3266LXoJUbwebzGcRIK1EcNk3Q==", "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" + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + } + }, + "@wdio/dot-reporter": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/dot-reporter/-/dot-reporter-7.4.2.tgz", + "integrity": "sha512-jHy57G+155p1c96egjLKPHTh4B6t6/5rPKThiw88ldtsmvnZUk6Y74Cpyl2a3lfUrJ09QZ6G7iBjqwkrQ3x1cg==", + "dev": true, + "requires": { + "@wdio/reporter": "7.4.2", + "@wdio/types": "7.4.2", + "chalk": "^4.0.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==", + "@wdio/types": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.4.2.tgz", + "integrity": "sha512-LLSaeC8yCMlQdB75J2TFEE/NAKb7vRCbLAXQmqBm6THNJll1U/Mk9tHIaUK624Eqf5qGBwQ0UKRKnx8qevzPUA==", "dev": true, "requires": { - "@babel/highlight": "^7.8.3" + "got": "^11.8.1" + } + } + } + }, + "@wdio/junit-reporter": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/junit-reporter/-/junit-reporter-7.16.13.tgz", + "integrity": "sha512-VKhly72NZY2/SNnfbYXO/HHov9oj+pk0aaq5TNzIJJoqtH4uqDz+L2p7wu9nKnRnywmwvaTm7pbYZGlOuty26A==", + "dev": true, + "requires": { + "@types/json-stringify-safe": "^5.0.0", + "@types/validator": "^13.1.3", + "@wdio/reporter": "7.16.13", + "@wdio/types": "7.16.13", + "json-stringify-safe": "^5.0.1", + "junit-report-builder": "^3.0.0", + "validator": "^13.0.0" + }, + "dependencies": { + "@wdio/reporter": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.16.13.tgz", + "integrity": "sha512-S7OH96yfSCJwmirsvT8khfWUfoMTiw0O1+UyiOYS/g0l+IideVK83kpyXYWfsALPahL2te0g57lPazriSfNAyA==", + "dev": true, + "requires": { + "@types/diff": "^5.0.0", + "@types/node": "^17.0.4", + "@types/object-inspect": "^1.8.0", + "@types/supports-color": "^8.1.0", + "@types/tmp": "^0.2.0", + "@wdio/types": "7.16.13", + "diff": "^5.0.0", + "fs-extra": "^10.0.0", + "object-inspect": "^1.10.3", + "supports-color": "8.1.1" } }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "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": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "has-flag": "^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==", + "@wdio/local-runner": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.16.13.tgz", + "integrity": "sha512-Ri8R6RHD5VjI4m2CramKO9w+4jD7VwEoQFWqFzUI1g31UAuN1zy67R3UiYv0ohiBTW4MZt90CMLgumQNk7C5kA==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" + "@types/stream-buffers": "^3.0.3", + "@wdio/logger": "7.16.0", + "@wdio/repl": "7.16.13", + "@wdio/runner": "7.16.13", + "@wdio/types": "7.16.13", + "async-exit-hook": "^2.0.1", + "split2": "^4.0.0", + "stream-buffers": "^3.0.2" + }, + "dependencies": { + "split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "dev": true + } } }, - "@eslint/eslintrc": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", - "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "@wdio/logger": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.16.0.tgz", + "integrity": "sha512-/6lOGb2Iow5eSsy7RJOl1kCwsP4eMlG+/QKro5zUJsuyNJSQXf2ejhpkzyKWLgQbHu83WX6cM1014AZuLkzoQg==", + "dev": true, "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" + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/mocha-framework": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.16.13.tgz", + "integrity": "sha512-yaLxEF5evXACGqxkch/IoJz8JGoQmcV+X635JBiMF6tl0+HSTYrL1ZPk1cED+9OI4jIPtmlhbgzne9IhoKCbpg==", + "dev": true, + "requires": { + "@types/mocha": "^9.0.0", + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "expect-webdriverio": "^3.0.0", + "mocha": "^9.0.0" + } + }, + "@wdio/protocols": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", + "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "dev": true + }, + "@wdio/repl": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.13.tgz", + "integrity": "sha512-XWh3dzp6U8LLL4cNGWFra+quVyXZ25Ym38zpsBVtV0/z5NCHJmjRS4ytyvvkzbQ8SyqQ7Y3G8MjfGNi2sBNkIQ==", + "dev": true, + "requires": { + "@wdio/utils": "7.16.13" + } + }, + "@wdio/reporter": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.4.2.tgz", + "integrity": "sha512-TRT1suI/H6Fi3JWoNXYDuvQ+LhszKU7Z41IRdoXUOn5ZnDFAvF3fMDvHyGjVXEv7oyDFgqunKnBhHM8xpq5Dbg==", + "dev": true, + "requires": { + "@types/cucumber": "^6.0.1", + "@wdio/types": "7.4.2", + "fs-extra": "^9.0.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==" - }, - "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==", + "@wdio/types": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.4.2.tgz", + "integrity": "sha512-LLSaeC8yCMlQdB75J2TFEE/NAKb7vRCbLAXQmqBm6THNJll1U/Mk9tHIaUK624Eqf5qGBwQ0UKRKnx8qevzPUA==", + "dev": true, "requires": { - "type-fest": "^0.8.1" + "got": "^11.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==", + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.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==", + "@wdio/runner": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.16.13.tgz", + "integrity": "sha512-/PJUK+8orHsUd5v8edWv5XS3pKx/si7DoYkU8PsgQX9FnU2y3oRfHrQwzI8s3TOnGag79f+yrGzzGCZFmmW0cw==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "deepmerge": "^4.0.0", + "gaze": "^1.1.2", + "webdriver": "7.16.13", + "webdriverio": "7.16.13" } }, - "@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==", + "@wdio/spec-reporter": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.16.13.tgz", + "integrity": "sha512-4gnflBJU+QDcmWgRy3tSRD47cqZmdjPLEJhsfhv/aBNtWPWMJtQru7nDFcLkxKLFPiN0D1F7gUMWbUMaDVlojg==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" + "@types/easy-table": "^0.0.33", + "@wdio/reporter": "7.16.13", + "@wdio/types": "7.16.13", + "chalk": "^4.0.0", + "easy-table": "^1.1.1", + "pretty-ms": "^7.0.0" + }, + "dependencies": { + "@wdio/reporter": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.16.13.tgz", + "integrity": "sha512-S7OH96yfSCJwmirsvT8khfWUfoMTiw0O1+UyiOYS/g0l+IideVK83kpyXYWfsALPahL2te0g57lPazriSfNAyA==", + "dev": true, + "requires": { + "@types/diff": "^5.0.0", + "@types/node": "^17.0.4", + "@types/object-inspect": "^1.8.0", + "@types/supports-color": "^8.1.0", + "@types/tmp": "^0.2.0", + "@wdio/types": "7.16.13", + "diff": "^5.0.0", + "fs-extra": "^10.0.0", + "object-inspect": "^1.10.3", + "supports-color": "8.1.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 + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.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==", + "@wdio/sync": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.4.6.tgz", + "integrity": "sha512-kbgDXalRmZmPgTcJYdbvURw/EOpDEb3w3ca+W0qc+cUlvrPGKu2l76vMiZQqPKLfHnPhDbpLSYvZfM19vrFK6w==", "dev": true, "requires": { - "@babel/core": ">=7.9.0" + "@types/fibers": "^3.1.0", + "@types/puppeteer": "^5.4.0", + "@wdio/logger": "7.4.2", + "@wdio/types": "7.4.2", + "fibers": "^5.0.0", + "webdriverio": "7.4.6" + }, + "dependencies": { + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@wdio/config": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.4.2.tgz", + "integrity": "sha512-TCHBHtKeV4659rNuC0SIjtv0ttM8WSQBwogY3Zuf55LTtVuWyNHQJ2vcquqL2mszOg2jPRfhdEn+E5U0Sp/auA==", + "dev": true, + "requires": { + "@wdio/logger": "7.4.2", + "@wdio/types": "7.4.2", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + } + }, + "@wdio/logger": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.4.2.tgz", + "integrity": "sha512-vYH0glKyw/rIJ/FJ4g+WQfx6MRKnWEPUspejv5Vit32STKa1IPotw/Y/Axv2qy6os1VHAs9CfH43930q9QZLkA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/protocols": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.4.2.tgz", + "integrity": "sha512-WEcCwTQxknj6TS+oa+ipEH1i2E/gSYRMpISSl8qC71ZTav9h3tA4eTNEnKzS2Foi+DjWBkwZ23YV8fjoQB+zPg==", + "dev": true + }, + "@wdio/repl": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.4.6.tgz", + "integrity": "sha512-ebLZIvJUfSCsgJS5GQavU5BfHHlLguhA+NaD2ezjHCvU2Fsbvj429oLtdlyZTkA2ElOqowX6Gw0c5hZ3FPZatA==", + "dev": true, + "requires": { + "@wdio/utils": "7.4.6" + } + }, + "@wdio/types": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.4.2.tgz", + "integrity": "sha512-LLSaeC8yCMlQdB75J2TFEE/NAKb7vRCbLAXQmqBm6THNJll1U/Mk9tHIaUK624Eqf5qGBwQ0UKRKnx8qevzPUA==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "@wdio/utils": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.4.6.tgz", + "integrity": "sha512-Rdw5/eEEZR+rytK4DmwuzJ74SoR0vBG860w+BCvxgNBWRbr94TySMX4hlxLqLInU0N5Ur38LR0AJej8XTuaQdg==", + "dev": true, + "requires": { + "@wdio/logger": "7.4.2", + "@wdio/types": "7.4.2" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "requires": { + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" + } + }, + "devtools": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.4.6.tgz", + "integrity": "sha512-eLsbQUDLxiZIqW+NWef6MDzq6ogMBLRvIHZ/flNwVQUrATF+Zo2W7+Ork/5n2wbK5L/5lrFoNXeIgTlzgTvWFg==", + "dev": true, + "requires": { + "@wdio/config": "7.4.2", + "@wdio/logger": "7.4.2", + "@wdio/protocols": "7.4.2", + "@wdio/types": "7.4.2", + "@wdio/utils": "7.4.6", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^7.1.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.863986", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.863986.tgz", + "integrity": "sha512-WMf5KuRLsLwJMp9JdawSvoEpxZPqyyNeOZ3YR8QF8lE9IVHbbpdWeuXV22SJxPUemFeznvVlwSBeQz91nL+41A==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "puppeteer-core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-7.1.0.tgz", + "integrity": "sha512-2wjKs3L1rYuoVNNtRR/GbAGjbt6LF8DRUxcg/UoCQZrzjfppWlrIqiHRF5uBzJk+Nc0w7ZkvVzKQCvB5PFqFdA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.847576", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.847576", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.847576.tgz", + "integrity": "sha512-0M8kobnSQE0Jmly7Mhbeq0W/PpZfnuK+WjN2ZRVPbGqYwCHCioAVp84H0TcLimgECcN5H976y5QiXMGBC9JKmg==", + "dev": true + } + } + }, + "rgb2hex": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.3.tgz", + "integrity": "sha512-clEe0m1xv+Tva1B/TOepuIcvLAxP0U+sCDfgt1SX1HmI2Ahr5/Cd/nzJM1e78NKVtWdoo0s33YehpFA8UfIShQ==", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", + "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriver": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.4.6.tgz", + "integrity": "sha512-L8ctz72XZXYy6AwM9oQCN81mJ9MFF4TS9bxgMoI4zVV5Jc2PxMlrmq9FpqWCUF2JDDTM9Qt2c8uqlWAId4uNOg==", + "dev": true, + "requires": { + "@wdio/config": "7.4.2", + "@wdio/logger": "7.4.2", + "@wdio/protocols": "7.4.2", + "@wdio/types": "7.4.2", + "@wdio/utils": "7.4.6", + "got": "^11.0.2", + "lodash.merge": "^4.6.1" + } + }, + "webdriverio": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.4.6.tgz", + "integrity": "sha512-heSx8QdBSftnR0+XuHbFtmmJmJujKr50Tq57tAdOstkMn1YNldM5ALAnlhSfKGHFZqAVphtJs1Xm/R1MT7NtCw==", + "dev": true, + "requires": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.4.2", + "@wdio/logger": "7.4.2", + "@wdio/protocols": "7.4.2", + "@wdio/repl": "7.4.6", + "@wdio/types": "7.4.2", + "@wdio/utils": "7.4.6", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.4.6", + "devtools-protocol": "^0.0.863986", + "fs-extra": "^9.0.1", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^7.1.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.3", + "serialize-error": "^8.0.0", + "webdriver": "7.4.6" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true + } } }, - "@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==", + "@wdio/types": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.16.13.tgz", + "integrity": "sha512-HIeXKCL+mUjyJxvnHSoaIo3NRgZLbeekyRIwo6USfd9qGlQ8dQ6fyCR3ZU9VqNz9j4+JIn+LRQ7imbz5SdnGbw==", "dev": true, "requires": { - "remark": "^12.0.0", - "unist-util-find-all-after": "^3.0.1" + "@types/node": "^17.0.4", + "got": "^11.8.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 + "@wdio/utils": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.13.tgz", + "integrity": "sha512-O6D89Ghtm5XtTv4DPKvCBKZOZYNONIcBM5/hmdr3V9mzVrTFq8Q3uE8pmmq303Oh91KcoN8Em5zoAG7Zpc5tRg==", + "dev": true, + "requires": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.13", + "p-iteration": "^1.1.8" + } }, "abbrev": { "version": "1.1.1", @@ -446,22 +10488,33 @@ "dev": true }, "acorn": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", - "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "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==" + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } }, "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -470,51 +10523,169 @@ "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==" + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } }, "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true }, "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==", + "dev": true, "requires": { "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "archiver": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "async": "^3.2.3", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "dependencies": { + "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" + } + }, + "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" + } + } + } + }, + "archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "requires": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "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 + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "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=", + "aria-query": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.2.tgz", + "integrity": "sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==", "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=", + "array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", "dev": true }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", "dev": true }, "array-slice": { @@ -529,33 +10700,72 @@ "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": { + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true }, + "ast-metadata-inferer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.7.0.tgz", + "integrity": "sha512-OkMLzd8xelb3gmnp6ToFvvsHLtS6CbagTkFQvQ+ZYFe3/AIl9iKikNR9G7pY3GfOR/2Xc222hwBjzI7HLkE76Q==", + "dev": true, + "requires": { + "@mdn/browser-compat-data": "^3.3.14" + }, + "dependencies": { + "@mdn/browser-compat-data": { + "version": "3.3.14", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-3.3.14.tgz", + "integrity": "sha512-n2RC9d6XatVbWFdHLimzzUJxJ1KY8LdjqrW6YvGPiRmsHkhOUx74/Ct10x5Yo7bC/Jvqx7cDEW8IMPv/+vwEzA==", + "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==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "dev": true + }, + "async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, "atob": { @@ -564,91 +10774,89 @@ "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" - } + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true }, - "bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "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" + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" }, "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==", + "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": { - "kind-of": "^6.0.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "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": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "safe-buffer": "~5.2.0" } } } }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -663,109 +10871,432 @@ "fill-range": "^7.0.1" } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "browserslist": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz", - "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.0.tgz", + "integrity": "sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001043", - "electron-to-chromium": "^1.3.413", - "node-releases": "^1.1.53", - "pkg-up": "^2.0.0" + "caniuse-lite": "^1.0.30001313", + "electron-to-chromium": "^1.4.76", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.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==", + "browserslist-config-wikimedia": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/browserslist-config-wikimedia/-/browserslist-config-wikimedia-0.4.0.tgz", + "integrity": "sha512-U/fmsaGlCKOqRIjKqXwQ44qFqiStngRTphj1Cf6IHV6J8OK8T0gu9dKc7Ljq4v7bwhnhN+YCCa4fA3nZlPNivQ==", + "dev": true + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, + "builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "dev": true + }, + "cac": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", + "integrity": "sha512-hq4rxE3NT5PlaEiVV39Z45d6MoFcQZG5dsgJqtAUeOz3408LEQAElToDkf9i5IYSCOmK0If/81dLg7nKxqPR0w==", + "dev": true, + "requires": { + "camelcase-keys": "^3.0.0", + "chalk": "^1.1.3", + "indent-string": "^3.0.0", + "minimist": "^1.2.0", + "read-pkg-up": "^1.0.1", + "suffix": "^0.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true + }, + "camelcase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", + "integrity": "sha512-U4E6A6aFyYnNW+tDt5/yIUKQURKXe3WMFPfX4FxrQFcwZ/R08AUk1xWcUtlr7oq6CV07Ji+aa69V2g7BSpblnQ==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "map-obj": "^1.0.0" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true + }, + "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" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true + } + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true + }, + "cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", "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" + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.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==", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, - "ccount": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz", - "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==", + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "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==", + "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": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" } }, - "character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "caniuse-lite": { + "version": "1.0.30001315", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001315.tgz", + "integrity": "sha512-5v7LFQU4Sb/qvkz7JcZkvtSH1Ko+1x2kgo3ocdBeMGZSOFpuE1kkm0kpTwLtWeFrw5qw08ulLxJjVIXIS8MkiQ==", "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==", + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "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 + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "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" + } + } + } }, - "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==", + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "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==", + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.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=", + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-glob": "^4.0.1" } } } }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chrome-launcher": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.1.tgz", + "integrity": "sha512-UugC8u59/w2AyX5sHLZUHoxBAiSiunUhZa3zZwMH6zPVis0C3dDKiRWyUGIo14tTbZHGVviWxv3PQWZ7taZ4fg==", + "dev": true, + "requires": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + } + } + }, + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha1-jffHquUf02h06PjQW5GAvBGj/tc=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, "clone-regexp": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", @@ -775,26 +11306,20 @@ "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=", + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "mimic-response": "^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==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -802,7 +11327,14 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colord": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", + "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==", + "dev": true }, "colors": { "version": "1.1.2", @@ -810,75 +11342,144 @@ "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 + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } }, - "component-emitter": { + "comment-parser": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.0.tgz", + "integrity": "sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA==", "dev": true }, + "compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "dev": true, + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "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" + } + }, + "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" + } + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, - "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" - } + "core-js": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", + "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", + "dev": true }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "core-js-pure": { + "version": "3.25.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.5.tgz", + "integrity": "sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", + "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", - "yaml": "^1.7.2" + "yaml": "^1.10.0" + } + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" }, "dependencies": { - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "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": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, - "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 + "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" + } } } }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "requires": { + "node-fetch": "2.6.7" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -889,18 +11490,98 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "requires": { "isexe": "^2.0.0" } } } }, + "css-functions-list": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.0.1.tgz", + "integrity": "sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw==", + "dev": true + }, + "css-rule-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/css-rule-stream/-/css-rule-stream-1.1.0.tgz", + "integrity": "sha1-N4bnGYmD2WWibjGVfgkHjLt3BaI=", + "dev": true, + "requires": { + "css-tokenize": "^1.0.1", + "duplexer2": "0.0.2", + "ldjson-stream": "^1.2.1", + "through2": "^0.6.3" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, + "css-shorthand-properties": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz", + "integrity": "sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==", + "dev": true + }, + "css-tokenize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-tokenize/-/css-tokenize-1.0.1.tgz", + "integrity": "sha1-RiXLHtohwUOFi3+B1oA8HSb8FL4=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^1.0.33" + } + }, + "css-value": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", + "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", + "dev": true + }, "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 }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", + "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", + "dev": true + }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -908,11 +11589,12 @@ "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "decamelize": { @@ -929,66 +11611,125 @@ "requires": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } } }, - "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 + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "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=" + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", "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" - } - } + "clone": "^1.0.2" } }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, "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 }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true + }, + "devtools": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.13.tgz", + "integrity": "sha512-jm/DL5tlOUUMe0pUgahDqixw3z+NANLN6DYDeZPFv7z0CBtmnaTyOe2zbT0apLxCBpi800VeXaISVZwmKE2NiQ==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "@types/ua-parser-js": "^0.7.33", + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "chrome-launcher": "^0.15.0", + "edge-paths": "^2.1.0", + "puppeteer-core": "^13.0.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.1", + "uuid": "^8.0.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } + } + }, + "devtools-protocol": { + "version": "0.0.953906", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.953906.tgz", + "integrity": "sha512-Z2vAafCNnl0Iw/u7TUjqOXW1sOhAMDOviflmUoUIxfq2rgfsoCO3qruB/LUJCdqF9aTJ32DUjXyMsX3+if6kDQ==", + "dev": true + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -996,77 +11737,98 @@ "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==", + "dev": true, "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==", + "doiuse": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/doiuse/-/doiuse-4.4.1.tgz", + "integrity": "sha512-TUpr1/YNg20IB09tZmwGCTsTQoxj8jUld/hUZprZMj8vj0VpAJySXEWCr8WMvqvgzk0/kG/FxeSMGKode4UjPg==", "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 - } + "browserslist": "^4.16.1", + "caniuse-lite": "^1.0.30001179", + "css-rule-stream": "^1.1.0", + "duplexer2": "0.0.2", + "ldjson-stream": "^1.2.1", + "multimatch": "^5.0.0", + "postcss": "^8.2.4", + "source-map": "^0.7.3", + "through2": "^4.0.2", + "yargs": "^16.2.0" } }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "~1.1.9" + } }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "easy-table": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz", + "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==", "dev": true, "requires": { - "domelementtype": "1" + "ansi-regex": "^5.0.1", + "wcwidth": "^1.0.1" } }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "edge-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-2.2.1.tgz", + "integrity": "sha512-AI5fC7dfDmCdKo3m5y7PkYE8m6bMqR6pvVpgtrZkkhcJXFLelUgkjrhk3kXXx8Kbw2cRaTT4LkOR7hqf39KJdw==", + "dev": true, + "requires": { + "@types/which": "^1.3.2", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dev": true, + "requires": { + "jake": "^10.8.5" } }, "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==", + "version": "1.4.82", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.82.tgz", + "integrity": "sha512-Ks+ANzLoIrFDUOJdjxYMH6CMKB8UQo5modAwvSZTxgF+vEs/U7G5IbWFUp6dS4klPkTDVdxbORuk8xAXXhMsWw==", "dev": true }, "emoji-regex": { @@ -1075,20 +11837,15 @@ "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==", + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, "requires": { - "ansi-colors": "^4.1.1" + "once": "^1.4.0" } }, - "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", @@ -1098,322 +11855,213 @@ "is-arrayish": "^0.2.1" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "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=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "eslint": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", - "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", + "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", + "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.1.3", + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "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", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash.merge": "^4.6.2", "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", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "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" - } + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, - "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" - } + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true }, - "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==", + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, "requires": { - "color-name": "~1.1.4" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" } }, - "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==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } } }, "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==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "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==", - "requires": { - "ansi-regex": "^5.0.0" - } + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "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==", + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "requires": { - "has-flag": "^4.0.0" + "argparse": "^2.0.1" } } } }, "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==", + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.22.1.tgz", + "integrity": "sha512-TtN+gWJrcW0i1sEu7vPE1tHpEilrMUuTxP6UK97Amvva/KDV9/tvRUifGhw0q5uBswp+HWgF12p8rq68hZqMbA==", "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": "^8.6.0", + "eslint-plugin-compat": "^4.0.2", + "eslint-plugin-es": "^4.1.0", + "eslint-plugin-jsdoc": "^37.7.1", + "eslint-plugin-json-es": "^1.5.4", + "eslint-plugin-mediawiki": "^0.3.0", + "eslint-plugin-mocha": "^9.0.0", + "eslint-plugin-no-jquery": "^2.7.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" + "eslint-plugin-qunit": "^7.2.0", + "eslint-plugin-unicorn": "^40.1.0", + "eslint-plugin-vue": "^8.4.1", + "eslint-plugin-wdio": "^7.4.2", + "eslint-plugin-yml": "^0.13.0" + } + }, + "eslint-plugin-compat": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.0.2.tgz", + "integrity": "sha512-xqvoO54CLTVaEYGMzhu35Wzwk/As7rCvz/2dqwnFiWi0OJccEtGIn+5qq3zqIu9nboXlpdBN579fZcItC73Ycg==", + "dev": true, + "requires": { + "@mdn/browser-compat-data": "^4.1.5", + "ast-metadata-inferer": "^0.7.0", + "browserslist": "^4.16.8", + "caniuse-lite": "^1.0.30001304", + "core-js": "^3.16.2", + "find-up": "^5.0.0", + "lodash.memoize": "4.1.2", + "semver": "7.3.5" }, "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": { + "find-up": { "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==", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "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" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" } }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "p-locate": "^5.0.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==", + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" + "yocto-queue": "^0.1.0" } }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "p-limit": "^3.0.2" } }, - "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==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "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" + "lru-cache": "^6.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==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", + "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", "dev": true, "requires": { "eslint-utils": "^2.0.0", @@ -1421,89 +12069,137 @@ } }, "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==", + "version": "37.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-37.7.1.tgz", + "integrity": "sha512-ySxDTedl6qKXT/VeTwcZlhsRtvNQZGPklyVnaL5+ge20vowzFA9CKvrY0NXRqvdIz6JBVMFpxX9DSmS3OyAUOQ==", "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", + "@es-joy/jsdoccomment": "~0.18.0", + "comment-parser": "1.3.0", + "debug": "^4.3.3", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.4.0", + "regextras": "^0.8.0", + "semver": "^7.3.5", "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==", + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "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==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "lru-cache": "^6.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==", + "eslint-plugin-json-es": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-json-es/-/eslint-plugin-json-es-1.5.4.tgz", + "integrity": "sha512-DdjnNMUZ1iMrUXfxUQrTU7IyoEOsa4Kg0Zd6nOyOq1mUb75deK7NrcbI1FlWGdGVgqX99bUOD27i81EYiG794Q==", "dev": true, "requires": { - "lodash": "^4.17.19", - "vscode-json-languageservice": "^3.7.0" + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", + "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", + "dev": true + } } }, "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==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.3.0.tgz", + "integrity": "sha512-Lhyj2PSkhDzYSc1PNbURysY/WoqvY0brw558ZInT3erzf5KUlro18MTKFdV+nlht475ZgnsfHsgfg6Ut2w1SVg==", "dev": true, "requires": { - "eslint-plugin-vue": "^6.2.2", - "upath": "^1.2.0" + "eslint-plugin-vue": "^7.20.0", + "upath": "^2.0.1" + }, + "dependencies": { + "eslint-plugin-vue": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.20.0.tgz", + "integrity": "sha512-oVNDqzBC9h3GO+NTgWeLMhhGigy6/bQaQbHS+0z7C4YEu/qK/yxHvca/2PTZtGNPsCrHwOTgKMrwu02A9iPBmw==", + "dev": true, + "requires": { + "eslint-utils": "^2.1.0", + "natural-compare": "^1.4.0", + "semver": "^6.3.0", + "vue-eslint-parser": "^7.10.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": "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" + } + }, + "vue-eslint-parser": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz", + "integrity": "sha512-qh3VhDLeh773wjgNTl7ss0VejY9bMMa0GoDG2fQVyDzRFdiU3L7fw74tWZDHNQXdZqxO3EveQroa9ct39D2nqg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-scope": "^5.1.1", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.2.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^6.3.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==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-9.0.0.tgz", + "integrity": "sha512-d7knAcQj1jPCzZf3caeBIn3BnW6ikcvfz0kSqQpwPYcVGLoJV5sz0l0OJB2LR8I7dvTDbqq1oV6ylhSgzA10zg==", "dev": true, "requires": { - "eslint-utils": "^2.1.0", + "eslint-utils": "^3.0.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==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.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==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.7.0.tgz", + "integrity": "sha512-Aeg7dA6GTH1AcWLlBtWNzOU9efK5KpNi7b0EhBO0o0M+awyzguUUo8gF6hXGjQ9n5h8/uRtYv9zOqQkeC5CG0w==", "dev": true }, "eslint-plugin-node": { @@ -1520,126 +12216,240 @@ "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-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-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 + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-7.2.0.tgz", + "integrity": "sha512-ebT6aOpmMj4vchG0hVw9Ukbutk/lgywrc8gc9w9hH2/4WjKqwMlyM7iVwqB7OAXv6gtQMJZuziT0wNjjymAuWA==", + "dev": true, + "requires": { + "eslint-utils": "^3.0.0", + "requireindex": "^1.2.0" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + } + } + }, + "eslint-plugin-unicorn": { + "version": "40.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-40.1.0.tgz", + "integrity": "sha512-y5doK2DF9Sr5AqKEHbHxjFllJ167nKDRU01HDcWyv4Tnmaoe9iNxMrBnaybZvWZUaE3OC5Unu0lNIevYamloig==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.15.7", + "ci-info": "^3.3.0", + "clean-regexp": "^1.0.0", + "eslint-utils": "^3.0.0", + "esquery": "^1.4.0", + "indent-string": "^4.0.0", + "is-builtin-module": "^3.1.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "read-pkg-up": "^7.0.1", + "regexp-tree": "^0.1.24", + "safe-regex": "^2.1.1", + "semver": "^7.3.5", + "strip-indent": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } }, "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==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.4.1.tgz", + "integrity": "sha512-nmWOhNmDx9TZ+yP9ZhezTkZUupSHsYA2TocRm+efPSXMOyFrVczVlaIuQcLBjCtI8CbkBiUQ3VcyQsjlIhDrhA==", "dev": true, "requires": { + "eslint-utils": "^3.0.0", "natural-compare": "^1.4.0", - "semver": "^5.6.0", - "vue-eslint-parser": "^7.0.0" + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.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==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-7.4.2.tgz", + "integrity": "sha512-tkISFycJmRFMKsEjetRcAmWSHKJKnw5rKHDxfE7Ob3tF5lbmYlCLfNKH0UwanOpSdulpe52s3K+CBHSd6qUUNQ==", "dev": true }, + "eslint-plugin-yml": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-0.13.0.tgz", + "integrity": "sha512-rZvdnhe28jIbgSIZo3qYqkl9hKslyTDfMwqIGDzz873gxghzBw0yeFG+P7sMfOkFfpqwJzZy3IKe2cIiCp4FrA==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^0.5.0" + } + }, "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.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==", + "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" + }, + "dependencies": { + "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 + } } }, "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==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", "dev": true }, "espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.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==" + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true }, "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==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true } } }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true }, "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==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, "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==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true } } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true }, "eventemitter2": { "version": "0.4.14", @@ -1662,56 +12472,6 @@ "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", @@ -1721,142 +12481,184 @@ "homedir-polyfill": "^1.0.1" } }, + "expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "requires": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + } + }, + "expect-webdriverio": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-3.4.0.tgz", + "integrity": "sha512-7Ivy1IB35pmkbCcI36un2OMytGEYCy1PcdqrlDnWZBzTpewAO14r+gO2FSuO5kNpDWm3gZSD4NYLG1KXJOlI3w==", + "dev": true, + "requires": { + "expect": "^28.1.0", + "jest-matcher-utils": "^28.1.0" + } + }, "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=", + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "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" - } - } + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "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" - } - } + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true + }, "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=" + "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==", + "dev": true }, "fast-glob": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz", - "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.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=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true }, "fastq": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.7.0.tgz", - "integrity": "sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" } }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "fibers": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.3.tgz", + "integrity": "sha512-/qYTSoZydQkM21qZpGLDLuCq8c+B8KhuCQ1kLPvnRNhxhVbvrpmH9l2+Lblf5neDuEsY4bfT7LeO553TXQDvJw==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, "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==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, "requires": { - "flat-cache": "^2.0.1" + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "fill-range": { @@ -1868,6 +12670,16 @@ "to-regex-range": "^5.0.1" } }, + "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" + } + }, "findup-sync": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", @@ -1911,20 +12723,27 @@ "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "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==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, "flatted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true }, "for-in": { "version": "1.0.2", @@ -1941,47 +12760,121 @@ "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=", + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "requires": { - "map-cache": "^0.2.2" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" } }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "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=" + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true }, - "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==", + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true + }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", "dev": true }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "getobject": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", - "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.0.tgz", + "integrity": "sha512-tbUz6AKKKr2YiMB+fLWIgq5ZeBOobop9YMMAU9dC54/ot2ksMXt3DOFyBuhZw6ptcVszEykgByK20j7W9jHFag==", "dev": true }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1992,11 +12885,12 @@ } }, "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" } }, "global-modules": { @@ -2020,31 +12914,34 @@ } }, "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 + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + }, + "dependencies": { + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } }, "globby": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz", - "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "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", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "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": { @@ -2053,19 +12950,58 @@ "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==", + "globule": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + } + }, + "got": { + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", "dev": true, "requires": { - "minimist": "^1.2.5" + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" } }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, "grunt": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.3.0.tgz", - "integrity": "sha512-6ILlMXv11/4cxuhSMfSU+SfvbxrPuqZrAtLN64+tZpQ3DAKfSQPQHRbTjSbdtxfyQhGZPtN0bDZJ/LdCM5WXXA==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", + "integrity": "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==", "dev": true, "requires": { "dateformat": "~3.0.3", @@ -2073,10 +13009,10 @@ "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-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", "grunt-legacy-log": "~3.0.0", - "grunt-legacy-util": "~2.0.0", + "grunt-legacy-util": "~2.0.1", "iconv-lite": "~0.4.13", "js-yaml": "~3.14.0", "minimatch": "~3.0.4", @@ -2086,9 +13022,9 @@ }, "dependencies": { "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -2098,131 +13034,54 @@ "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==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/grunt-banana-checker/-/grunt-banana-checker-0.10.0.tgz", + "integrity": "sha512-Sx+P3zWjn4YmBCqzidnCEkYrACe1SLTIT8kKC6C3f21Hu6sm17U/V+re343cuK3U+iGZv15ux6bY+69buIbYrA==", "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==", + "grunt-cli": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", "dev": true, "requires": { - "chalk": "^4.0.0", - "eslint": "^7.0.0" + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.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==", + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "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" + "abbrev": "1", + "osenv": "^0.1.4" } } } }, + "grunt-eslint": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/grunt-eslint/-/grunt-eslint-24.0.0.tgz", + "integrity": "sha512-WpTeBBFweyhMuPjGwRSQV9JFJ+EczIdlsc7Dd/1g78QVI1aZsk4g/H3e+3S5HEwsS1RKL2YZIrGj8hMLlBfN8w==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "eslint": "^8.0.1" + } + }, "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==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", "dev": true }, "grunt-legacy-log": { @@ -2245,142 +13104,57 @@ "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==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", + "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", "dev": true, "requires": { - "async": "~1.5.2", - "exit": "~0.1.1", - "getobject": "~0.1.0", + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", "hooker": "~0.2.3", - "lodash": "~4.17.20", + "lodash": "~4.17.21", "underscore.string": "~3.3.5", - "which": "~1.3.0" + "which": "~2.0.2" }, "dependencies": { - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, "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==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/grunt-stylelint/-/grunt-stylelint-0.17.0.tgz", + "integrity": "sha512-aVpqPO7h98haGRZKnj9nkMTMGjzmVQWyN/FNB/qkbcVG6pguZ48yZi8YO+ULynzNK9YFqWhWBFgAs71m7ZpK+A==", "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" - } - } + "chalk": "^4.1.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" } }, "hard-rejection": { @@ -2389,69 +13163,44 @@ "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=", + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "function-bind": "^1.1.1" } }, - "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=", + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "ansi-regex": "^2.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==", + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "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" - } } } }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -2468,29 +13217,63 @@ "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 + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", "dev": true }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "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" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "dependencies": { + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + } + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" } }, "iconv-lite": { @@ -2502,15 +13285,23 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2525,34 +13316,59 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "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 }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "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=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "inquirer": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", + "integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.2.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + } + }, "interpret": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", @@ -2569,127 +13385,50 @@ "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=", + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "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" - } - } + "binary-extensions": "^2.0.0" } }, - "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-builtin-module": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.1.0.tgz", + "integrity": "sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==", + "dev": true, + "requires": { + "builtin-modules": "^3.0.0" + } }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "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 - } + "has": "^1.0.3" } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "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=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -2698,17 +13437,18 @@ "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==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "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==", + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true }, "is-number": { @@ -2750,7 +13490,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "is-unc-path": { @@ -2762,10 +13502,16 @@ "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==", + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", "dev": true }, "is-windows": { @@ -2774,22 +13520,26 @@ "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 + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } }, "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isobject": { "version": "3.0.1", @@ -2797,62 +13547,191 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dev": true, + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + } + }, + "jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, + "jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, "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==", + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "jsdoc-type-pratt-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.2.2.tgz", + "integrity": "sha512-zRokSWcPLSWkoNzsWn9pq7YYSwDhKyEe+cJYT2qaPqLOOJb5sFSi46BPj81vP+e8chvCNdQL9RG86Bi9EI6MDw==", "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==", + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "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==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "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=" + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { - "minimist": "^1.2.5" + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" } }, - "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 + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "junit-report-builder": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-3.0.1.tgz", + "integrity": "sha512-B8AZ2q24iGwPM3j/ZHc9nD0BY1rKhcnWCA1UvT8mhHfR8Vo/HTtg3ojMyo55BgctqQGZG7H8z0+g+mEUc32jgg==", + "dev": true, + "requires": { + "date-format": "4.0.3", + "lodash": "^4.17.21", + "make-dir": "^3.1.0", + "xmlbuilder": "^15.1.1" + } + }, + "keyv": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", + "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } }, "kind-of": { "version": "6.0.3", @@ -2861,171 +13740,162 @@ "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==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.24.0.tgz", + "integrity": "sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==", "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==", + "ky": { + "version": "0.28.7", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.28.7.tgz", + "integrity": "sha512-a23i6qSr/ep15vdtw/zyEQIDLoUaKDg9Jf04CYl/0ns/wXNYna26zJpI+MeIFaPeDvkrjLPrKtKOiiI3IE53RQ==", "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=", + "lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "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" + "readable-stream": "^2.0.5" }, "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" - } - } - } + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "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" - } - } + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "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 + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" + "safe-buffer": "~5.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 - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + } + } + }, + "ldjson-stream": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz", + "integrity": "sha1-kb7O2lrE7SsX5kn7d356v6AYnCs=", + "dev": true, + "requires": { + "split2": "^0.2.1", + "through2": "^0.6.1" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "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" - } - } + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + } + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "requires": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", "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" + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" } - }, - "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=", + } + } + }, + "lighthouse-logger": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.3.0.tgz", + "integrity": "sha512-BbqAKApLb9ywUli+0a+PcV04SyJ/N1q/8qgCNe6U97KbPCS1BTksEuHFLYdvc8DltuhfxIUBqDZsC0bBGtl3lA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "marky": "^1.2.2" + }, + "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": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true } } }, @@ -3035,44 +13905,169 @@ "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=", + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.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 + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } } } }, + "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" + } + }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true + }, + "lodash.isobject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true + }, + "lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true }, "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==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "requires": { - "chalk": "^2.4.2" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" } }, - "longest-streak": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", - "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "loglevel": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", + "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==", + "dev": true + }, + "loglevel-plugin-prefix": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", + "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "dev": true }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -3089,93 +14084,124 @@ "dev": true }, "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", + "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", "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==", + "marky": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", "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==", + "meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", "dev": true, "requires": { - "unist-util-visit": "^2.0.0" + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "dependencies": { + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true + } } }, "merge2": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", - "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "mime-db": "1.52.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, "min-indent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz", - "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, "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==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true }, "minimist-options": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.0.2.tgz", - "integrity": "sha512-seq4hpWkYSUh1y7NXxzucwAN9yVlBc3Upgdjz8vLCP97jG8kaOmzYrVH/m7tQ1NYD1wdtZbSLfdy4zFmRWuc/w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "requires": { "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0" + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" }, "dependencies": { "is-plain-obj": { @@ -3186,68 +14212,284 @@ } } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" }, "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==", + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "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" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "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 + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "p-limit": "^3.0.2" } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true } } }, - "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==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", "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" + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + } } }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "mwbot": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mwbot/-/mwbot-2.0.0.tgz", + "integrity": "sha512-9iTx8oFMntC60yyaPJjN4GEgiQlal7i03jATu7kq5b9BGW5aNz7YbrpjaciLNr0Z33PTdQe0hRTJ0JdUJi2WQg==", + "dev": true, + "requires": { + "bluebird": "^3.7.2", + "request": "^2.88.2", + "semlog": "^0.6.10", + "semver": "7.3.4" + }, + "dependencies": { + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } }, "node-releases": { - "version": "1.1.53", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz", - "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", "dev": true }, "nopt": { @@ -3260,21 +14502,32 @@ } }, "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==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, "normalize-selector": { @@ -3283,57 +14536,23 @@ "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=", + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "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" - } - } - } + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true }, - "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-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true }, "object.defaults": { "version": "1.1.0", @@ -3370,14 +14589,25 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, "requires": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -3387,6 +14617,23 @@ "word-wrap": "^1.2.3" } }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -3409,50 +14656,49 @@ "os-tmpdir": "^1.0.0" } }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true + }, + "p-iteration": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/p-iteration/-/p-iteration-1.1.8.tgz", + "integrity": "sha512-IMFBSDIYcPNnW7uWYGrBqmvTiq7W0uB0fJn6shQZs7dlF3OvrHOre+JT9ikSZ7gZS3vWqclVgoQSvToJrns7uQ==", + "dev": true + }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "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": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "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": "^1.1.0" + "p-limit": "^2.2.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=", + "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 }, "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" + "callsites": "^3.0.0" } }, "parse-filepath": { @@ -3466,32 +14712,52 @@ "path-root": "^0.1.1" } }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true + }, "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=", + "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 }, "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=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true }, "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==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-root": { @@ -3509,113 +14775,95 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", "dev": true }, + "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 + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "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" - } - } - } + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true }, - "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=", + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true }, - "postcss": { - "version": "7.0.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", - "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "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" - } - } + "pinkie": "^2.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==", + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { - "htmlparser2": "^3.10.0" + "find-up": "^4.0.0" } }, - "postcss-less": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz", - "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==", + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true + }, + "postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", "dev": true, "requires": { - "postcss": "^7.0.14" + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" } }, + "postcss-less": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-6.0.0.tgz", + "integrity": "sha512-FPX16mQLyEjLzEuuJtxA8X3ejDLNGGEG503d2YGZR5Ask1SpDN8KmZUMpzCvyalWRywAn1n1VOA5dcqfCLo5rg==", + "dev": true + }, "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", @@ -3623,70 +14871,171 @@ "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==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "dev": true + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "dev": true, "requires": { - "postcss": "^7.0.26" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" } }, - "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==", + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "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==", + "dev": true + }, + "pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "gonzales-pe": "^4.3.0", - "postcss": "^7.0.21" + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } }, - "postcss-scss": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.0.0.tgz", - "integrity": "sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug==", + "pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", "dev": true, "requires": { - "postcss": "^7.0.0" + "parse-ms": "^2.1.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==", + "prettyjson": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.5.tgz", + "integrity": "sha512-rksPWtoZb2ZpT5OVgtmy0KHVM+Dca3iVwWY9ifwhcexfjebtgjg3wmrUt9PvJ59XIYBcknQeYHD8IAnVlh9lAw==", "dev": true, "requires": { - "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "colors": "1.4.0", + "minimist": "^1.2.0" + }, + "dependencies": { + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + } } }, - "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==", + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "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==" + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "puppeteer-core": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", + "integrity": "sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==", + "dev": true, + "requires": { + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.981744", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "pkg-dir": "4.2.0", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.5.0" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.981744", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", + "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", + "dev": true + } + } + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true + }, + "query-selector-shadow-dom": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.0.tgz", + "integrity": "sha512-bK0/0cCI+R8ZmOF1QjT7HupDUYCxbf/9TJgAmSXQxZpftXmTAeil9DRoCnTDkWbvOyZzhcMBwKpptWcdkGFIMg==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true }, "quick-lru": { "version": "4.0.1", @@ -3695,142 +15044,246 @@ "dev": true }, "ramda": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", - "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", + "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "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": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "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" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "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" + } + }, "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "readdir-glob": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz", + "integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==", + "dev": true, + "requires": { + "minimatch": "^5.1.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "picomatch": "^2.2.1" } }, "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "requires": { - "resolve": "^1.1.6" + "resolve": "^1.9.0" } }, - "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 + "recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "requires": { + "minimatch": "^3.0.5" + } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" } }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "regexp-tree": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", + "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", + "dev": true + }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true }, "regextras": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.7.1.tgz", - "integrity": "sha512-9YXf6xtW+qzQ+hcMQXx95MOvfqXFgsKDZodX3qZB0x2n5Z94ioetIITsBtvJbiOyxa/6s9AtyweBLCdPmPko/w==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", + "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", "dev": true }, - "remark": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/remark/-/remark-12.0.0.tgz", - "integrity": "sha512-oX4lMIS0csgk8AEbzY0h2jdR0ngiCHOpwwpxjmRa5TqAkeknY+tkhjRJGZqnCmvyuWh55/0SW5WY3R3nn3PH9A==", + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { - "remark-parse": "^8.0.0", - "remark-stringify": "^8.0.0", - "unified": "^9.0.0" + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" } }, - "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==", + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "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=", + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", "dev": true }, "resolve": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", - "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", @@ -3870,19 +15323,44 @@ "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=", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "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 + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "resq": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/resq/-/resq-1.10.2.tgz", + "integrity": "sha512-HmgVS3j+FLrEDBTDYysPdPVF9/hioDMJ/otOiQDKqk77YfZeeLOj0qi34yObumcud1gBpk+wpBTEg4kMicD++A==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1" + }, + "dependencies": { + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", + "dev": true + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } }, "reusify": { "version": "1.0.4", @@ -3890,33 +15368,58 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "rgb2hex": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.5.tgz", + "integrity": "sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==", + "dev": true + }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "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" } }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, "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==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", + "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", "dev": true, "requires": { - "ret": "~0.1.10" + "regexp-tree": "~0.1.1" } }, "safer-buffer": { @@ -3925,39 +15428,95 @@ "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==", + "semlog": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/semlog/-/semlog-0.6.10.tgz", + "integrity": "sha512-FFUGeVy3vJnOV+3jOL4deYb1iVJpVLCJQHpXlDqMYVykl9t7G/Uuu71sEWjwJtTbaj5AmDXAQtTQN/t1sUhE2Q==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "chalk": "^1.1.3", + "prettyjson": "^1.1.3" }, "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "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 + }, + "serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + }, + "dependencies": { + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.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==", + "dev": true, "requires": { "shebang-regex": "^3.0.0" } @@ -3965,12 +15524,13 @@ "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true }, "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "slash": { @@ -3980,179 +15540,58 @@ "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==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "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" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.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=", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "color-convert": "^2.0.1" } }, - "extend-shallow": { + "color-convert": { "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==", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "color-name": "~1.1.4" } }, - "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==", + "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 - }, - "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=", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "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=", + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -4166,9 +15605,9 @@ "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==", + "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", @@ -4187,117 +15626,134 @@ "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==", + "split2": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz", + "integrity": "sha1-At2smtwD7Au3jBKC7Aecpuha6QA=", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "through2": "~0.6.1" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.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==", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "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=", + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.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" - } + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true } } }, + "stream-buffers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", + "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, "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==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "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" - } - } + "strip-ansi": "^6.0.1" } }, - "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==", + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "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 - } + "ansi-regex": "^5.0.1" } }, - "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==", + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", "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" + "is-utf8": "^0.2.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==", + "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": { - "ansi-regex": "^4.1.0" + "min-indent": "^1.0.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==" + "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==", + "dev": true }, "style-search": { "version": "0.1.0", @@ -4306,337 +15762,152 @@ "dev": true }, "stylelint": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.3.2.tgz", - "integrity": "sha512-kpO3/Gz2ZY40EWUwFYYkgpzhf8ZDUyKpcui5+pS0XKJBj/EMYmZpOJoL8IFAz2yApYeg91NVy5yAjE39hDzWvQ==", + "version": "14.8.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.8.1.tgz", + "integrity": "sha512-0YxTop3wTeEVmQWhS7jjLFaBkvfPmffRiJ6eFIDlK++f3OklaobTYFJu32E5u/cIrFLbcW52pLqrYpihA/y0/w==", "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", + "balanced-match": "^2.0.0", + "colord": "^2.9.2", + "cosmiconfig": "^7.0.1", + "css-functions-list": "^3.0.1", + "debug": "^4.3.4", "execall": "^2.0.0", - "file-entry-cache": "^5.0.1", - "get-stdin": "^7.0.0", + "fast-glob": "^3.2.11", + "fastest-levenshtein": "^1.0.12", + "file-entry-cache": "^6.0.1", + "get-stdin": "^8.0.0", "global-modules": "^2.0.0", - "globby": "^11.0.0", + "globby": "^11.1.0", "globjoin": "^0.1.4", - "html-tags": "^3.1.0", - "ignore": "^5.1.4", + "html-tags": "^3.2.0", + "ignore": "^5.2.0", "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", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.24.0", "mathml-tag-names": "^2.1.3", - "meow": "^6.1.0", - "micromatch": "^4.0.2", + "meow": "^9.0.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", "normalize-selector": "^0.2.0", - "postcss": "^7.0.27", - "postcss-html": "^0.36.0", - "postcss-less": "^3.1.4", + "picocolors": "^1.0.0", + "postcss": "^8.4.12", "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", + "postcss-safe-parser": "^6.0.0", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", - "slash": "^3.0.0", "specificity": "^0.4.1", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", "style-search": "^0.1.0", - "sugarss": "^2.0.0", + "supports-hyperlinks": "^2.2.0", "svg-tags": "^1.0.0", - "table": "^5.4.6", - "v8-compile-cache": "^2.1.0", - "write-file-atomic": "^3.0.3" + "table": "^6.8.0", + "v8-compile-cache": "^2.3.0", + "write-file-atomic": "^4.0.1" }, "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==", + "balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true }, - "parse-json": { + "is-plain-object": { "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==", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "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-recommended": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", + "integrity": "sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q==", + "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==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.13.0.tgz", + "integrity": "sha512-1R1g/uc53z2z39ejZMALwC6fTfSZhkzDjj1v8ODCWtLCiuqWuSf3HR1ZTXT5X5AtSbZq1W9+0p5HJp6rPVXkRg==", "dev": true, "requires": { - "stylelint": "13.3.2" + "browserslist-config-wikimedia": "0.4.0", + "postcss-less": "6.0.0", + "stylelint": "14.8.1", + "stylelint-config-recommended": "7.0.0", + "stylelint-no-unsupported-browser-features": "5.0.3" } }, - "sugarss": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz", - "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==", + "stylelint-no-unsupported-browser-features": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-5.0.3.tgz", + "integrity": "sha512-FqfbOTk5UEkHsAKOkPH6SvajsfO9YuoWvKxd34tCRBZug9ZNeaPn141nyWkd+ncc8S1gVmO2+O6qVAMj9bvWww==", "dev": true, "requires": { - "postcss": "^7.0.2" + "doiuse": "^4.4.1", + "lodash": "^4.17.15", + "postcss": "^8.3.6" } }, + "suffix": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", + "integrity": "sha512-j5uf6MJtMCfC4vBe5LFktSe4bGyNTBk7I2Kdri0jeLrcv5B9pWfxVa5JQpoxgtR8vaVB7bVxsWgnfQbX5wkhAA==", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { "has-flag": "^3.0.0" } }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "svg-tags": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", @@ -4644,34 +15915,81 @@ "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==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "ajv": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } }, - "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=" + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "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" + } }, - "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==", + "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": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "safe-buffer": "~5.2.0" } } } @@ -4679,50 +15997,53 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, - "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=", + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "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=", + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, "requires": { - "kind-of": "^3.0.2" + "readable-stream": "3" }, "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 + "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" + } }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "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": { - "is-buffer": "^1.1.5" + "safe-buffer": "~5.2.0" } } } }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "os-tmpdir": "~1.0.2" } }, "to-regex-range": { @@ -4734,28 +16055,54 @@ "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=", + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "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==", + "trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, - "trough": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "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==", + "dev": true, "requires": { "prelude-ls": "^1.2.1" } @@ -4763,15 +16110,23 @@ "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true }, - "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==", + "ua-parser-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", + "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", + "dev": true + }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dev": true, "requires": { - "is-typedarray": "^1.0.0" + "buffer": "^5.2.1", + "through": "^2.3.8" } }, "unc-path-regex": { @@ -4790,360 +16145,525 @@ "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" - } + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true }, - "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" - } + "upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "dev": true }, - "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==", + "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==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "punycode": "^2.1.0" } }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "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" - } + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true }, - "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==", + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "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==", + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, "requires": { - "unist-util-visit": "^2.0.0" + "homedir-polyfill": "^1.0.1" } }, - "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==", + "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": { - "@types/unist": "^2.0.2" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "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" - } + "validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "dev": true }, - "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==", + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + } } }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "vue-eslint-parser": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.2.0.tgz", + "integrity": "sha512-hvl8OVT8imlKk/lQyhkshqwQQChzHETcBd5abiO4ePw7ib7QUZLfW+2TUrJHKUvFOCFRJrDin5KJO9OHzB5bRQ==", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" }, "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "eslint-scope": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", + "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", "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" - } - } + "esrecurse": "^4.3.0", + "estraverse": "^5.2.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=", + "eslint-visitor-keys": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", + "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, - "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==", + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, "requires": { - "punycode": "^2.1.0" + "defaults": "^1.0.3" } }, - "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==", + "wdio-mediawiki": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/wdio-mediawiki/-/wdio-mediawiki-1.2.0.tgz", + "integrity": "sha512-s9vekcs++5dEdNgsJzH7NFfnM1j+u2QRBxAdjOU889RFVYOp6pFJnNQ/wzjf456Wd34gnwNQ5IB3sN9zlJAMnQ==", "dev": true, "requires": { - "homedir-polyfill": "^1.0.1" + "mwbot": "2.0.0" } }, - "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==", + "webdriver": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.13.tgz", + "integrity": "sha512-Vfr952W1uIgDeWHPGzqH43dYLeRSZshh3TzA9ICUkvnC+Q7YziQdv/8xI8tuuyvb7lSr3VsuB2cGzyCRoC/NWw==", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "@types/node": "^17.0.4", + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "got": "^11.0.2", + "ky": "^0.28.5", + "lodash.merge": "^4.6.1" } }, - "vfile": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.1.0.tgz", - "integrity": "sha512-BaTPalregj++64xbGK6uIlsurN3BCRNM/P2Pg8HezlGzKd1O9PrwIac6bd9Pdx2uTb0QHoioZ+rXKolbVXEgJg==", + "webdriverio": { + "version": "7.16.13", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.13.tgz", + "integrity": "sha512-jl1VRZYL1+cPeG6klskKX7mCEBWNQWDFaNtaIl5pwWgtKWPau6fCzKntSARzfNV8+hKJKwJ2mZn5Nsxfw28Oeg==", "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" + "@types/aria-query": "^5.0.0", + "@types/node": "^17.0.4", + "@wdio/config": "7.16.13", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/repl": "7.16.13", + "@wdio/types": "7.16.13", + "@wdio/utils": "7.16.13", + "archiver": "^5.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.16.13", + "devtools-protocol": "^0.0.953906", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^13.0.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.16.13" } }, - "vfile-location": { + "webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.0.1.tgz", - "integrity": "sha512-yYBO06eeN/Ki6Kh1QAkgzYpWT1d3Qln+ZCtSbJqFExPl1S3y2qqotJQXoh6qEvl/jDlgpUJolBn3PItVnnZRqQ==", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "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==", + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "requires": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.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==", + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "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" + "isexe": "^2.0.0" } }, - "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==", + "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==", "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==", + "workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", "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==", + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "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" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "dependencies": { - "espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" + "color-convert": "^2.0.1" } + }, + "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 } } }, - "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" - } + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "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==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", "dev": true, "requires": { "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "signal-exit": "^3.0.7" } }, + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "dev": true + }, + "xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "yaml": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.9.2.tgz", - "integrity": "sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yaml-eslint-parser": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-0.5.0.tgz", + "integrity": "sha512-nJeyLA3YHAzhBTZbRAbu3W6xrSCucyxExmA+ZDtEdUFpGllxAZpto2Zxo2IG0r0eiuEiBM4e+wiAdxTziTq94g==", "dev": true, "requires": { - "@babel/runtime": "^7.9.2" + "eslint-visitor-keys": "^3.0.0", + "lodash": "^4.17.21", + "yaml": "^1.10.2" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + } + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } }, "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" }, "dependencies": { "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + } + } + }, + "yarn-install": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", + "integrity": "sha512-VO1u181msinhPcGvQTVMnHVOae8zjX/NSksR17e6eXHRveDvHCF5mGjh9hkN8mzyfnCqcBe42LdTs7bScuTaeg==", + "dev": true, + "requires": { + "cac": "^3.0.3", + "chalk": "^1.1.3", + "cross-spawn": "^4.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, + "zip-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "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" + } + }, + "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" + } } } } diff --git a/CheckUser/package.json b/CheckUser/package.json index bd882af1..9ab18cf3 100644 --- a/CheckUser/package.json +++ b/CheckUser/package.json @@ -1,17 +1,26 @@ { - "name": "checkuser", - "version": "0.0.0", + "name": "CheckUser", "private": true, - "description": "Build tools for the CheckUser extension.", "scripts": { - "test": "grunt test" + "test": "grunt test", + "selenium-daily": "npm run selenium-test", + "selenium-test": "wdio tests/selenium/wdio.conf.js" }, "devDependencies": { - "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" + "eslint-config-wikimedia": "0.22.1", + "grunt": "1.5.3", + "grunt-banana-checker": "0.10.0", + "grunt-eslint": "24.0.0", + "grunt-stylelint": "0.17.0", + "stylelint-config-wikimedia": "0.13.0", + "@wdio/cli": "7.16.13", + "@wdio/junit-reporter": "7.16.13", + "@wdio/local-runner": "7.16.13", + "@wdio/mocha-framework": "7.16.13", + "@wdio/spec-reporter": "7.16.13", + "@wdio/dot-reporter": "7.4.2", + "@wdio/sync": "7.4.6", + "wdio-mediawiki": "1.2.0", + "webdriverio": "7.16.13" } } diff --git a/CheckUser/schema/abstractSchemaChanges/patch-cu_log-actor.json b/CheckUser/schema/abstractSchemaChanges/patch-cu_log-actor.json new file mode 100644 index 00000000..187ec8e5 --- /dev/null +++ b/CheckUser/schema/abstractSchemaChanges/patch-cu_log-actor.json @@ -0,0 +1,255 @@ +{ + "before": { + "name": "cu_log", + "columns": [ + { + "name": "cul_id", + "comment": "Unique identifier", + "type": "integer", + "options": { "autoincrement": true, "notnull": true, "unsigned": true } + }, + { + "name": "cul_timestamp", + "comment": "Timestamp of CheckUser action", + "type": "mwtimestamp", + "options": { "notnull": true } + }, + { + "name": "cul_user", + "comment": "User who performed the action", + "type": "integer", + "options": { "notnull": true, "unsigned": true } + }, + { + "name": "cul_user_text", + "comment": "User who performed the action", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_reason", + "comment": "Reason given", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_reason_id", + "comment": "Reason for the check stored as a comment_id. Default of 0 is used to indicate using cul_reason.", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_reason_plaintext_id", + "comment": "Reason for the check with wikitext removed stored as a comment_id. Default of 0 is used to indicate using cul_reason.", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_type", + "comment": "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", + "type": "binary", + "options": { "notnull": true, "length": 30 } + }, + { + "name": "cul_target_id", + "comment": " Integer target, interpretation depends on cul_type For username targets, this is the user_id", + "type": "integer", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cul_target_text", + "comment": "Text target, interpretation depends on cul_type", + "type": "blob", + "options": { "notnull": true, "length": 65530 } + }, + { + "name": "cul_target_hex", + "comment": "If the target was an IP address, this contains the hexadecimal form of the IP", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_start", + "comment": "If the target was an IP range, this field contain the start, in hex form", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_end", + "comment": "If the target was an IP range, this field contain the end, in hex form", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + } + ], + "indexes": [ + { + "name": "cul_user", + "columns": [ "cul_user", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_type_target", + "columns": [ "cul_type", "cul_target_id", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_target_hex", + "columns": [ "cul_target_hex", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_range_start", + "columns": [ "cul_range_start", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_timestamp", + "columns": [ "cul_timestamp" ], + "unique": false + } + ], + "pk": [ "cul_id" ] + }, + "after": { + "name": "cu_log", + "columns": [ + { + "name": "cul_id", + "comment": "Unique identifier", + "type": "integer", + "options": { "autoincrement": true, "notnull": true, "unsigned": true } + }, + { + "name": "cul_timestamp", + "comment": "Timestamp of CheckUser action", + "type": "mwtimestamp", + "options": { "notnull": true } + }, + { + "name": "cul_user", + "comment": "User who performed the action", + "type": "integer", + "options": { "notnull": true, "unsigned": true } + }, + { + "name": "cul_user_text", + "comment": "User who performed the action", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_actor", + "comment": "User who performed the action", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_reason", + "comment": "Reason given", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_reason_id", + "comment": "Reason for the check stored as a comment_id. Default of 0 is used to indicate using cul_reason.", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_reason_plaintext_id", + "comment": "Reason for the check with wikitext removed stored as a comment_id. Default of 0 is used to indicate using cul_reason.", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_type", + "comment": "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", + "type": "binary", + "options": { "notnull": true, "length": 30 } + }, + { + "name": "cul_target_id", + "comment": " Integer target, interpretation depends on cul_type For username targets, this is the user_id", + "type": "integer", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cul_target_text", + "comment": "Text target, interpretation depends on cul_type", + "type": "blob", + "options": { "notnull": true, "length": 65530 } + }, + { + "name": "cul_target_hex", + "comment": "If the target was an IP address, this contains the hexadecimal form of the IP", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_start", + "comment": "If the target was an IP range, this field contain the start, in hex form", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_end", + "comment": "If the target was an IP range, this field contain the end, in hex form", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + } + ], + "indexes": [ + { + "name": "cul_user", + "columns": [ "cul_user", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_actor_time", + "columns": [ "cul_actor", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_type_target", + "columns": [ "cul_type", "cul_target_id", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_target_hex", + "columns": [ "cul_target_hex", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_range_start", + "columns": [ "cul_range_start", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_timestamp", + "columns": [ "cul_timestamp" ], + "unique": false + } + ], + "pk": [ "cul_id" ] + } +} diff --git a/CheckUser/schema/abstractSchemaChanges/patch-cu_log-comment_table_for_reason.json b/CheckUser/schema/abstractSchemaChanges/patch-cu_log-comment_table_for_reason.json new file mode 100644 index 00000000..f1ec5cd6 --- /dev/null +++ b/CheckUser/schema/abstractSchemaChanges/patch-cu_log-comment_table_for_reason.json @@ -0,0 +1,196 @@ +{ + "before": { + "name": "cu_log", + "columns": [ + { + "name": "cul_id", + "type": "integer", + "options": { "autoincrement": true, "notnull": true, "unsigned": true } + }, + { + "name": "cul_timestamp", + "type": "mwtimestamp", + "options": { "notnull": true } + }, + { + "name": "cul_user", + "type": "integer", + "options": { "notnull": true, "unsigned": true } + }, + { + "name": "cul_user_text", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_reason", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_type", + "type": "binary", + "options": { "notnull": true, "length": 30 } + }, + { + "name": "cul_target_id", + "type": "integer", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cul_target_text", + "type": "blob", + "options": { "notnull": true, "length": 65530 } + }, + { + "name": "cul_target_hex", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_start", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_end", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + } + ], + "indexes": [ + { + "name": "cul_user", + "columns": [ "cul_user", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_type_target", + "columns": [ "cul_type", "cul_target_id", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_target_hex", + "columns": [ "cul_target_hex", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_range_start", + "columns": [ "cul_range_start", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_timestamp", + "columns": [ "cul_timestamp" ], + "unique": false + } + ], + "pk": [ "cul_id" ] + }, + "after": { + "name": "cu_log", + "columns": [ + { + "name": "cul_id", + "type": "integer", + "options": { "autoincrement": true, "notnull": true, "unsigned": true } + }, + { + "name": "cul_timestamp", + "type": "mwtimestamp", + "options": { "notnull": true } + }, + { + "name": "cul_user", + "type": "integer", + "options": { "notnull": true, "unsigned": true } + }, + { + "name": "cul_user_text", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_reason", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_reason_id", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_reason_plaintext_id", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_type", + "type": "binary", + "options": { "notnull": true, "length": 30 } + }, + { + "name": "cul_target_id", + "type": "integer", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cul_target_text", + "type": "blob", + "options": { "notnull": true, "length": 65530 } + }, + { + "name": "cul_target_hex", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_start", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_end", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + } + ], + "indexes": [ + { + "name": "cul_user", + "columns": [ "cul_user", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_type_target", + "columns": [ "cul_type", "cul_target_id", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_target_hex", + "columns": [ "cul_target_hex", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_range_start", + "columns": [ "cul_range_start", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_timestamp", + "columns": [ "cul_timestamp" ], + "unique": false + } + ], + "pk": [ "cul_id" ] + } +} diff --git a/CheckUser/schema/mysql/patch-cu_changes-actor-comment.sql b/CheckUser/schema/mysql/patch-cu_changes-actor-comment.sql new file mode 100644 index 00000000..634025d1 --- /dev/null +++ b/CheckUser/schema/mysql/patch-cu_changes-actor-comment.sql @@ -0,0 +1,6 @@ +-- Add column for storing actor and comment +ALTER TABLE /*_*/cu_changes + ADD COLUMN cuc_actor bigint unsigned NOT NULL DEFAULT 0 AFTER cuc_user_text, + ADD COLUMN cuc_comment_id bigint unsigned NOT NULL DEFAULT 0 AFTER cuc_comment; + +CREATE INDEX /*i*/cuc_actor_ip_time ON /*_*/cu_changes (cuc_actor, cuc_ip, cuc_timestamp); diff --git a/CheckUser/schema/mysql/patch-cu_changes-cuc_id-unsigned.sql b/CheckUser/schema/mysql/patch-cu_changes-cuc_id-unsigned.sql new file mode 100644 index 00000000..dfb45dd3 --- /dev/null +++ b/CheckUser/schema/mysql/patch-cu_changes-cuc_id-unsigned.sql @@ -0,0 +1,3 @@ +-- Make cuc_id in cu_changes unsigned +ALTER TABLE /*_*/cu_changes + CHANGE cuc_id cuc_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT; diff --git a/CheckUser/schema/mysql/patch-cu_changes-cuc_timestamp.sql b/CheckUser/schema/mysql/patch-cu_changes-cuc_timestamp.sql new file mode 100644 index 00000000..501c886a --- /dev/null +++ b/CheckUser/schema/mysql/patch-cu_changes-cuc_timestamp.sql @@ -0,0 +1,3 @@ +-- Standardise type for timestamp columns +ALTER TABLE /*_*/cu_changes +CHANGE cuc_timestamp cuc_timestamp BINARY(14) NOT NULL; diff --git a/CheckUser/schema/mysql/patch-cu_log-actor.sql b/CheckUser/schema/mysql/patch-cu_log-actor.sql new file mode 100644 index 00000000..399e9ea5 --- /dev/null +++ b/CheckUser/schema/mysql/patch-cu_log-actor.sql @@ -0,0 +1,7 @@ +-- This file is automatically generated using maintenance/generateSchemaChangeSql.php. +-- Source: extensions/CheckUser/schema/abstractSchemaChanges/patch-cu_log-actor.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +ALTER TABLE /*_*/cu_log +ADD cul_actor BIGINT UNSIGNED DEFAULT 0 NOT NULL; +CREATE INDEX cul_actor_time ON /*_*/cu_log (cul_actor, cul_timestamp);
\ No newline at end of file diff --git a/CheckUser/schema/mysql/patch-cu_log-comment_table_for_reason.sql b/CheckUser/schema/mysql/patch-cu_log-comment_table_for_reason.sql new file mode 100644 index 00000000..7c7df1cd --- /dev/null +++ b/CheckUser/schema/mysql/patch-cu_log-comment_table_for_reason.sql @@ -0,0 +1,7 @@ +-- This file is automatically generated using maintenance/generateSchemaChangeSql.php. +-- Source: extensions/CheckUser/schema/abstractSchemaChanges/patch-cu_log-comment_table_for_reason.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +ALTER TABLE /*_*/cu_log +ADD cul_reason_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, +ADD cul_reason_plaintext_id BIGINT UNSIGNED DEFAULT 0 NOT NULL;
\ No newline at end of file diff --git a/CheckUser/schema/mysql/tables-generated.sql b/CheckUser/schema/mysql/tables-generated.sql new file mode 100644 index 00000000..85885551 --- /dev/null +++ b/CheckUser/schema/mysql/tables-generated.sql @@ -0,0 +1,60 @@ +-- This file is automatically generated using maintenance/generateSchemaSql.php. +-- Source: extensions/CheckUser/schema/tables.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +CREATE TABLE /*_*/cu_changes ( + cuc_id INT UNSIGNED AUTO_INCREMENT NOT NULL, + cuc_namespace INT DEFAULT 0 NOT NULL, + cuc_title VARBINARY(255) DEFAULT '' NOT NULL, + cuc_user INT DEFAULT 0 NOT NULL, + cuc_user_text VARCHAR(255) DEFAULT '' NOT NULL, + cuc_actor BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cuc_actiontext VARBINARY(255) DEFAULT '' NOT NULL, + cuc_comment VARBINARY(255) DEFAULT '' NOT NULL, + cuc_comment_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cuc_minor TINYINT(1) DEFAULT 0 NOT NULL, + cuc_page_id INT UNSIGNED DEFAULT 0 NOT NULL, + cuc_this_oldid INT UNSIGNED DEFAULT 0 NOT NULL, + cuc_last_oldid INT UNSIGNED DEFAULT 0 NOT NULL, + cuc_type TINYINT(3) UNSIGNED DEFAULT 0 NOT NULL, + cuc_timestamp BINARY(14) NOT NULL, + cuc_ip VARCHAR(255) DEFAULT '', + cuc_ip_hex VARCHAR(255) DEFAULT NULL, + cuc_xff VARBINARY(255) DEFAULT '', + cuc_xff_hex VARCHAR(255) DEFAULT NULL, + cuc_agent VARBINARY(255) DEFAULT NULL, + cuc_private MEDIUMBLOB DEFAULT NULL, + INDEX cuc_ip_hex_time (cuc_ip_hex, cuc_timestamp), + INDEX cuc_user_ip_time (cuc_user, cuc_ip, cuc_timestamp), + INDEX cuc_xff_hex_time (cuc_xff_hex, cuc_timestamp), + INDEX cuc_timestamp (cuc_timestamp), + INDEX cuc_actor_ip_time (cuc_actor, cuc_ip, cuc_timestamp), + PRIMARY KEY(cuc_id) +) /*$wgDBTableOptions*/; + + +CREATE TABLE /*_*/cu_log ( + cul_id INT UNSIGNED AUTO_INCREMENT NOT NULL, + cul_timestamp BINARY(14) NOT NULL, + cul_user INT UNSIGNED NOT NULL, + cul_user_text VARBINARY(255) NOT NULL, + cul_actor BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cul_reason VARBINARY(255) NOT NULL, + cul_reason_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cul_reason_plaintext_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cul_type VARBINARY(30) NOT NULL, + cul_target_id INT UNSIGNED DEFAULT 0 NOT NULL, + cul_target_text BLOB NOT NULL, + cul_target_hex VARBINARY(255) DEFAULT '' NOT NULL, + cul_range_start VARBINARY(255) DEFAULT '' NOT NULL, + cul_range_end VARBINARY(255) DEFAULT '' NOT NULL, + INDEX cul_user (cul_user, cul_timestamp), + INDEX cul_actor_time (cul_actor, cul_timestamp), + INDEX cul_type_target ( + cul_type, cul_target_id, cul_timestamp + ), + INDEX cul_target_hex (cul_target_hex, cul_timestamp), + INDEX cul_range_start (cul_range_start, cul_timestamp), + INDEX cul_timestamp (cul_timestamp), + PRIMARY KEY(cul_id) +) /*$wgDBTableOptions*/; diff --git a/CheckUser/schema/postgres/patch-cu_changes-pk.sql b/CheckUser/schema/postgres/patch-cu_changes-pk.sql new file mode 100644 index 00000000..5f15aaab --- /dev/null +++ b/CheckUser/schema/postgres/patch-cu_changes-pk.sql @@ -0,0 +1,2 @@ +CREATE INDEX cuc_timestamp ON cu_changes (cuc_timestamp); +ALTER TABLE cu_changes ADD PRIMARY KEY (cuc_id); diff --git a/CheckUser/schema/postgres/patch-cu_log-actor.sql b/CheckUser/schema/postgres/patch-cu_log-actor.sql new file mode 100644 index 00000000..46d76919 --- /dev/null +++ b/CheckUser/schema/postgres/patch-cu_log-actor.sql @@ -0,0 +1,7 @@ +-- This file is automatically generated using maintenance/generateSchemaChangeSql.php. +-- Source: extensions/CheckUser/schema/abstractSchemaChanges/patch-cu_log-actor.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +ALTER TABLE cu_log +ADD cul_actor BIGINT DEFAULT 0 NOT NULL; +CREATE INDEX cul_actor_time ON cu_log (cul_actor, cul_timestamp);
\ No newline at end of file diff --git a/CheckUser/schema/postgres/patch-cu_log-comment_table_for_reason.sql b/CheckUser/schema/postgres/patch-cu_log-comment_table_for_reason.sql new file mode 100644 index 00000000..66afce43 --- /dev/null +++ b/CheckUser/schema/postgres/patch-cu_log-comment_table_for_reason.sql @@ -0,0 +1,8 @@ +-- This file is automatically generated using maintenance/generateSchemaChangeSql.php. +-- Source: extensions/CheckUser/schema/abstractSchemaChanges/patch-cu_log-comment_table_for_reason.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +ALTER TABLE cu_log +ADD cul_reason_id BIGINT DEFAULT 0 NOT NULL; +ALTER TABLE cu_log +ADD cul_reason_plaintext_id BIGINT DEFAULT 0 NOT NULL;
\ No newline at end of file diff --git a/CheckUser/schema/postgres/patch-cu_log-pk.sql b/CheckUser/schema/postgres/patch-cu_log-pk.sql new file mode 100644 index 00000000..69bc063e --- /dev/null +++ b/CheckUser/schema/postgres/patch-cu_log-pk.sql @@ -0,0 +1,9 @@ +DROP INDEX cul_user; +DROP INDEX cul_type_target; +DROP INDEX cul_target_hex; +DROP INDEX cul_range_start; +CREATE INDEX cul_user ON cu_log (cul_user, cul_timestamp); +CREATE INDEX cul_type_target ON cu_log (cul_type, cul_target_id, cul_timestamp); +CREATE INDEX cul_target_hex ON cu_log (cul_target_hex, cul_timestamp); +CREATE INDEX cul_range_start ON cu_log (cul_range_start, cul_timestamp); +ALTER TABLE cu_log ADD PRIMARY KEY (cul_id); diff --git a/CheckUser/schema/postgres/tables-generated.sql b/CheckUser/schema/postgres/tables-generated.sql new file mode 100644 index 00000000..5975f6be --- /dev/null +++ b/CheckUser/schema/postgres/tables-generated.sql @@ -0,0 +1,71 @@ +-- This file is automatically generated using maintenance/generateSchemaSql.php. +-- Source: extensions/CheckUser/schema/tables.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +CREATE TABLE cu_changes ( + cuc_id SERIAL NOT NULL, + cuc_namespace INT DEFAULT 0 NOT NULL, + cuc_title TEXT DEFAULT '' NOT NULL, + cuc_user INT DEFAULT 0 NOT NULL, + cuc_user_text VARCHAR(255) DEFAULT '' NOT NULL, + cuc_actor BIGINT DEFAULT 0 NOT NULL, + cuc_actiontext TEXT DEFAULT '' NOT NULL, + cuc_comment TEXT DEFAULT '' NOT NULL, + cuc_comment_id BIGINT DEFAULT 0 NOT NULL, + cuc_minor SMALLINT DEFAULT 0 NOT NULL, + cuc_page_id INT DEFAULT 0 NOT NULL, + cuc_this_oldid INT DEFAULT 0 NOT NULL, + cuc_last_oldid INT DEFAULT 0 NOT NULL, + cuc_type SMALLINT DEFAULT 0 NOT NULL, + cuc_timestamp TIMESTAMPTZ NOT NULL, + cuc_ip VARCHAR(255) DEFAULT '', + cuc_ip_hex VARCHAR(255) DEFAULT NULL, + cuc_xff TEXT DEFAULT '', + cuc_xff_hex VARCHAR(255) DEFAULT NULL, + cuc_agent TEXT DEFAULT NULL, + cuc_private TEXT DEFAULT NULL, + PRIMARY KEY(cuc_id) +); + +CREATE INDEX cuc_ip_hex_time ON cu_changes (cuc_ip_hex, cuc_timestamp); + +CREATE INDEX cuc_user_ip_time ON cu_changes (cuc_user, cuc_ip, cuc_timestamp); + +CREATE INDEX cuc_xff_hex_time ON cu_changes (cuc_xff_hex, cuc_timestamp); + +CREATE INDEX cuc_timestamp ON cu_changes (cuc_timestamp); + +CREATE INDEX cuc_actor_ip_time ON cu_changes (cuc_actor, cuc_ip, cuc_timestamp); + + +CREATE TABLE cu_log ( + cul_id SERIAL NOT NULL, + cul_timestamp TIMESTAMPTZ NOT NULL, + cul_user INT NOT NULL, + cul_user_text TEXT NOT NULL, + cul_actor BIGINT DEFAULT 0 NOT NULL, + cul_reason TEXT NOT NULL, + cul_reason_id BIGINT DEFAULT 0 NOT NULL, + cul_reason_plaintext_id BIGINT DEFAULT 0 NOT NULL, + cul_type TEXT NOT NULL, + cul_target_id INT DEFAULT 0 NOT NULL, + cul_target_text TEXT NOT NULL, + cul_target_hex TEXT DEFAULT '' NOT NULL, + cul_range_start TEXT DEFAULT '' NOT NULL, + cul_range_end TEXT DEFAULT '' NOT NULL, + PRIMARY KEY(cul_id) +); + +CREATE INDEX cul_user ON cu_log (cul_user, cul_timestamp); + +CREATE INDEX cul_actor_time ON cu_log (cul_actor, cul_timestamp); + +CREATE INDEX cul_type_target ON cu_log ( + cul_type, cul_target_id, cul_timestamp +); + +CREATE INDEX cul_target_hex ON cu_log (cul_target_hex, cul_timestamp); + +CREATE INDEX cul_range_start ON cu_log (cul_range_start, cul_timestamp); + +CREATE INDEX cul_timestamp ON cu_log (cul_timestamp); diff --git a/CheckUser/schema/sqlite/patch-cu_changes-actor-comment.sql b/CheckUser/schema/sqlite/patch-cu_changes-actor-comment.sql new file mode 100644 index 00000000..333478f2 --- /dev/null +++ b/CheckUser/schema/sqlite/patch-cu_changes-actor-comment.sql @@ -0,0 +1,5 @@ +ALTER TABLE /*_*/cu_changes + ADD COLUMN cuc_actor bigint unsigned NOT NULL DEFAULT 0; +ALTER TABLE /*_*/cu_changes + ADD COLUMN cuc_comment_id bigint unsigned NOT NULL DEFAULT 0; +CREATE INDEX /*i*/cuc_actor_ip_time ON /*_*/cu_changes (cuc_actor, cuc_ip, cuc_timestamp);
\ No newline at end of file diff --git a/CheckUser/schema/sqlite/patch-cu_log-actor.sql b/CheckUser/schema/sqlite/patch-cu_log-actor.sql new file mode 100644 index 00000000..5cc4896f --- /dev/null +++ b/CheckUser/schema/sqlite/patch-cu_log-actor.sql @@ -0,0 +1,24 @@ +-- This file is automatically generated using maintenance/generateSchemaChangeSql.php. +-- Source: extensions/CheckUser/schema/abstractSchemaChanges/patch-cu_log-actor.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +DROP INDEX cul_user; +DROP INDEX cul_type_target; +DROP INDEX cul_target_hex; +DROP INDEX cul_range_start; +DROP INDEX cul_timestamp; +CREATE TEMPORARY TABLE /*_*/__temp__cu_log AS +SELECT cul_id, cul_timestamp, cul_user, cul_user_text, cul_reason, cul_reason_id, cul_reason_plaintext_id, cul_type, cul_target_id, cul_target_text, cul_target_hex, cul_range_start, cul_range_end +FROM /*_*/cu_log; +DROP TABLE /*_*/cu_log; +CREATE TABLE /*_*/cu_log ( cul_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, cul_timestamp BLOB NOT NULL, cul_user INTEGER UNSIGNED NOT NULL, cul_user_text BLOB NOT NULL, cul_reason BLOB NOT NULL, cul_reason_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, cul_reason_plaintext_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, cul_type BLOB NOT NULL, cul_target_id INTEGER UNSIGNED DEFAULT 0 NOT NULL, cul_target_text BLOB NOT NULL, cul_target_hex BLOB DEFAULT '' NOT NULL, cul_range_start BLOB DEFAULT '' NOT NULL, cul_range_end BLOB DEFAULT '' NOT NULL, cul_actor BIGINT UNSIGNED DEFAULT 0 NOT NULL ); +INSERT INTO /*_*/cu_log ( cul_id, cul_timestamp, cul_user, cul_user_text, cul_reason, cul_reason_id, cul_reason_plaintext_id, cul_type, cul_target_id, cul_target_text, cul_target_hex, cul_range_start, cul_range_end ) +SELECT cul_id, cul_timestamp, cul_user, cul_user_text, cul_reason, cul_reason_id, cul_reason_plaintext_id, cul_type, cul_target_id, cul_target_text, cul_target_hex, cul_range_start, cul_range_end +FROM /*_*/__temp__cu_log; +DROP TABLE /*_*/__temp__cu_log; +CREATE INDEX cul_user ON /*_*/cu_log (cul_user, cul_timestamp); +CREATE INDEX cul_type_target ON /*_*/cu_log ( cul_type, cul_target_id, cul_timestamp ); +CREATE INDEX cul_target_hex ON /*_*/cu_log (cul_target_hex, cul_timestamp); +CREATE INDEX cul_range_start ON /*_*/cu_log (cul_range_start, cul_timestamp); +CREATE INDEX cul_timestamp ON /*_*/cu_log (cul_timestamp); +CREATE INDEX cul_actor_time ON /*_*/cu_log (cul_actor, cul_timestamp);
\ No newline at end of file diff --git a/CheckUser/schema/sqlite/patch-cu_log-comment_table_for_reason.sql b/CheckUser/schema/sqlite/patch-cu_log-comment_table_for_reason.sql new file mode 100644 index 00000000..4d55a34d --- /dev/null +++ b/CheckUser/schema/sqlite/patch-cu_log-comment_table_for_reason.sql @@ -0,0 +1,8 @@ +-- This file is automatically generated using maintenance/generateSchemaChangeSql.php. +-- Source: extensions/CheckUser/schema/abstractSchemaChanges/patch-cu_log-comment_table_for_reason.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +ALTER TABLE /*_*/cu_log +ADD COLUMN cul_reason_id BIGINT UNSIGNED DEFAULT 0 NOT NULL; +ALTER TABLE /*_*/cu_log +ADD COLUMN cul_reason_plaintext_id BIGINT UNSIGNED DEFAULT 0 NOT NULL;
\ No newline at end of file diff --git a/CheckUser/schema/sqlite/tables-generated.sql b/CheckUser/schema/sqlite/tables-generated.sql new file mode 100644 index 00000000..4b336bbc --- /dev/null +++ b/CheckUser/schema/sqlite/tables-generated.sql @@ -0,0 +1,64 @@ +-- This file is automatically generated using maintenance/generateSchemaSql.php. +-- Source: extensions/CheckUser/schema/tables.json +-- Do not modify this file directly. +-- See https://www.mediawiki.org/wiki/Manual:Schema_changes +CREATE TABLE /*_*/cu_changes ( + cuc_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + cuc_namespace INTEGER DEFAULT 0 NOT NULL, + cuc_title BLOB DEFAULT '' NOT NULL, + cuc_user INTEGER DEFAULT 0 NOT NULL, + cuc_user_text VARCHAR(255) DEFAULT '' NOT NULL, + cuc_actor BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cuc_actiontext BLOB DEFAULT '' NOT NULL, + cuc_comment BLOB DEFAULT '' NOT NULL, + cuc_comment_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cuc_minor SMALLINT DEFAULT 0 NOT NULL, + cuc_page_id INTEGER UNSIGNED DEFAULT 0 NOT NULL, + cuc_this_oldid INTEGER UNSIGNED DEFAULT 0 NOT NULL, + cuc_last_oldid INTEGER UNSIGNED DEFAULT 0 NOT NULL, + cuc_type SMALLINT UNSIGNED DEFAULT 0 NOT NULL, + cuc_timestamp BLOB NOT NULL, + cuc_ip VARCHAR(255) DEFAULT '', + cuc_ip_hex VARCHAR(255) DEFAULT NULL, + cuc_xff BLOB DEFAULT '', + cuc_xff_hex VARCHAR(255) DEFAULT NULL, + cuc_agent BLOB DEFAULT NULL, + cuc_private BLOB DEFAULT NULL +); + +CREATE INDEX cuc_ip_hex_time ON /*_*/cu_changes (cuc_ip_hex, cuc_timestamp); + +CREATE INDEX cuc_user_ip_time ON /*_*/cu_changes (cuc_user, cuc_ip, cuc_timestamp); + +CREATE INDEX cuc_xff_hex_time ON /*_*/cu_changes (cuc_xff_hex, cuc_timestamp); + +CREATE INDEX cuc_timestamp ON /*_*/cu_changes (cuc_timestamp); + +CREATE INDEX cuc_actor_ip_time ON /*_*/cu_changes (cuc_actor, cuc_ip, cuc_timestamp); + + +CREATE TABLE /*_*/cu_log ( + cul_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + cul_timestamp BLOB NOT NULL, cul_user INTEGER UNSIGNED NOT NULL, + cul_user_text BLOB NOT NULL, cul_actor BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cul_reason BLOB NOT NULL, cul_reason_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cul_reason_plaintext_id BIGINT UNSIGNED DEFAULT 0 NOT NULL, + cul_type BLOB NOT NULL, cul_target_id INTEGER UNSIGNED DEFAULT 0 NOT NULL, + cul_target_text BLOB NOT NULL, cul_target_hex BLOB DEFAULT '' NOT NULL, + cul_range_start BLOB DEFAULT '' NOT NULL, + cul_range_end BLOB DEFAULT '' NOT NULL +); + +CREATE INDEX cul_user ON /*_*/cu_log (cul_user, cul_timestamp); + +CREATE INDEX cul_actor_time ON /*_*/cu_log (cul_actor, cul_timestamp); + +CREATE INDEX cul_type_target ON /*_*/cu_log ( + cul_type, cul_target_id, cul_timestamp +); + +CREATE INDEX cul_target_hex ON /*_*/cu_log (cul_target_hex, cul_timestamp); + +CREATE INDEX cul_range_start ON /*_*/cu_log (cul_range_start, cul_timestamp); + +CREATE INDEX cul_timestamp ON /*_*/cu_log (cul_timestamp); diff --git a/CheckUser/schema/tables.json b/CheckUser/schema/tables.json new file mode 100644 index 00000000..97082235 --- /dev/null +++ b/CheckUser/schema/tables.json @@ -0,0 +1,289 @@ +[ + { + "name": "cu_changes", + "columns": [ + { + "name": "cuc_id", + "comment": "Primary key", + "type": "integer", + "options": { "autoincrement": true, "notnull": true, "unsigned": true } + }, + { + "name": "cuc_namespace", + "comment": "When pages are renamed, their RC entries do _not_ change.", + "type": "integer", + "options": { "notnull": true, "default": 0 } + }, + { + "name": "cuc_title", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cuc_user", + "comment": "user.user_id", + "type": "integer", + "options": { "notnull": true, "default": 0 } + }, + { + "name": "cuc_user_text", + "type": "string", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cuc_actor", + "type": "bigint", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cuc_actiontext", + "comment": "Edit summary", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cuc_comment", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cuc_comment_id", + "type": "bigint", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cuc_minor", + "type": "mwtinyint", + "options": { "notnull": true, "length": 1, "default": 0 } + }, + { + "name": "cuc_page_id", + "comment": "Key to page_id (was cur_id prior to 1.5). This will keep links working after moves while retaining the at-the-time name in the changes list.", + "type": "integer", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cuc_this_oldid", + "comment": "rev_id of the given revision", + "type": "integer", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cuc_last_oldid", + "comment": "rev_id of the prior revision, for generating diff links.", + "type": "integer", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cuc_type", + "comment": "RecentChange type identifiers: RC_EDIT, RC_NEW or RC_LOG", + "type": "mwtinyint", + "options": { "notnull": true, "unsigned": true, "length": 3, "default": 0 } + }, + { + "name": "cuc_timestamp", + "comment": "Event timestamp", + "type": "mwtimestamp", + "options": { "notnull": true } + }, + { + "name": "cuc_ip", + "comment": "IP address, visible", + "type": "string", + "options": { "notnull": false, "length": 255, "default": "" } + }, + { + "name": "cuc_ip_hex", + "comment": "IP address as hexidecimal", + "type": "string", + "options": { "notnull": false, "length": 255 } + }, + { + "name": "cuc_xff", + "comment": "XFF header, visible, all data", + "type": "binary", + "options": { "notnull": false, "length": 255, "default": "" } + }, + { + "name": "cuc_xff_hex", + "comment": "XFF header, last IP, as hexidecimal", + "type": "string", + "options": { "notnull": false, "length": 255 } + }, + { + "name": "cuc_agent", + "comment": "User agent", + "type": "binary", + "options": { "notnull": false, "length": 255 } + }, + { + "name": "cuc_private", + "comment": "Private Data", + "type": "blob", + "options": { "notnull": false, "length": 16777215 } + } + ], + "indexes": [ + { + "name": "cuc_ip_hex_time", + "columns": [ "cuc_ip_hex", "cuc_timestamp" ], + "unique": false + }, + { + "name": "cuc_user_ip_time", + "columns": [ "cuc_user", "cuc_ip", "cuc_timestamp" ], + "unique": false + }, + { + "name": "cuc_xff_hex_time", + "columns": [ "cuc_xff_hex", "cuc_timestamp" ], + "unique": false + }, + { + "name": "cuc_timestamp", + "columns": [ "cuc_timestamp" ], + "unique": false + }, + { + "name": "cuc_actor_ip_time", + "columns": [ "cuc_actor", "cuc_ip", "cuc_timestamp" ], + "unique": false + } + ], + "pk": [ "cuc_id" ] + }, + { + "name": "cu_log", + "columns": [ + { + "name": "cul_id", + "comment": "Unique identifier", + "type": "integer", + "options": { "autoincrement": true, "notnull": true, "unsigned": true } + }, + { + "name": "cul_timestamp", + "comment": "Timestamp of CheckUser action", + "type": "mwtimestamp", + "options": { "notnull": true } + }, + { + "name": "cul_user", + "comment": "User who performed the action", + "type": "integer", + "options": { "notnull": true, "unsigned": true } + }, + { + "name": "cul_user_text", + "comment": "User who performed the action", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_actor", + "comment": "User who performed the action", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_reason", + "comment": "Reason given", + "type": "binary", + "options": { "notnull": true, "length": 255 } + }, + { + "name": "cul_reason_id", + "comment": "Reason for the check stored as a comment_id. Default of 0 is used to indicate using cul_reason.", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_reason_plaintext_id", + "comment": "Reason for the check with wikitext removed stored as a comment_id. Default of 0 is used to indicate using cul_reason.", + "type": "bigint", + "options": { + "unsigned": true, + "notnull": true, + "default": 0 + } + }, + { + "name": "cul_type", + "comment": "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", + "type": "binary", + "options": { "notnull": true, "length": 30 } + }, + { + "name": "cul_target_id", + "comment": " Integer target, interpretation depends on cul_type For username targets, this is the user_id", + "type": "integer", + "options": { "notnull": true, "unsigned": true, "default": 0 } + }, + { + "name": "cul_target_text", + "comment": "Text target, interpretation depends on cul_type", + "type": "blob", + "options": { "notnull": true, "length": 65530 } + }, + { + "name": "cul_target_hex", + "comment": "If the target was an IP address, this contains the hexadecimal form of the IP", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_start", + "comment": "If the target was an IP range, this field contain the start, in hex form", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + }, + { + "name": "cul_range_end", + "comment": "If the target was an IP range, this field contain the end, in hex form", + "type": "binary", + "options": { "notnull": true, "length": 255, "default": "" } + } + ], + "indexes": [ + { + "name": "cul_user", + "columns": [ "cul_user", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_actor_time", + "columns": [ "cul_actor", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_type_target", + "columns": [ "cul_type", "cul_target_id", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_target_hex", + "columns": [ "cul_target_hex", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_range_start", + "columns": [ "cul_range_start", "cul_timestamp" ], + "unique": false + }, + { + "name": "cul_timestamp", + "columns": [ "cul_timestamp" ], + "unique": false + } + ], + "pk": [ "cul_id" ] + } +] diff --git a/CheckUser/includes/api/ApiQueryCheckUser.php b/CheckUser/src/Api/ApiQueryCheckUser.php index 7562d090..a61a8cc3 100644 --- a/CheckUser/includes/api/ApiQueryCheckUser.php +++ b/CheckUser/src/Api/ApiQueryCheckUser.php @@ -1,19 +1,57 @@ <?php +namespace MediaWiki\CheckUser\Api; + +use ApiQuery; +use ApiQueryBase; +use ApiResult; +use Exception; +use MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager; +use MediaWiki\CheckUser\CheckUserLogService; use MediaWiki\MediaWikiServices; +use MediaWiki\Revision\RevisionLookup; use MediaWiki\Revision\RevisionRecord; +use MediaWiki\User\UserIdentityLookup; use Wikimedia\IPUtils; +use Wikimedia\ParamValidator\ParamValidator; +use Wikimedia\ParamValidator\TypeDef\IntegerDef; /** * CheckUser API Query Module */ class ApiQueryCheckUser extends ApiQueryBase { - public function __construct( $query, $moduleName ) { + + /** @var UserIdentityLookup */ + private $userIdentityLookup; + + /** @var RevisionLookup */ + private $revisionLookup; + + /** @var CheckUserLogService */ + private $checkUserLogService; + + /** + * @param ApiQuery $query + * @param string $moduleName + * @param UserIdentityLookup $userIdentityLookup + * @param RevisionLookup $revisionLookup + * @param CheckUserLogService $checkUserLogService + */ + public function __construct( + $query, + $moduleName, + UserIdentityLookup $userIdentityLookup, + RevisionLookup $revisionLookup, + CheckUserLogService $checkUserLogService + ) { parent::__construct( $query, $moduleName, 'cu' ); + $this->userIdentityLookup = $userIdentityLookup; + $this->revisionLookup = $revisionLookup; + $this->checkUserLogService = $checkUserLogService; } public function execute() { - $db = $this->getDB(); + $dbr = $this->getDB(); [ 'request' => $request, @@ -31,27 +69,29 @@ class ApiQueryCheckUser extends ApiQueryBase { } $reason = $this->msg( 'checkuser-reason-api', $reason )->inContentLanguage()->text(); - $timeCutoff = strtotime( $timecond ); // absolute time - if ( !$timeCutoff ) { + // absolute time + $timeCutoff = strtotime( $timecond ); + if ( !$timeCutoff || $timeCutoff < 0 || $timeCutoff > time() ) { $this->dieWithError( 'apierror-checkuser-timelimit', 'invalidtime' ); } $this->addTables( 'cu_changes' ); $this->addOption( 'LIMIT', $limit + 1 ); $this->addOption( 'ORDER BY', 'cuc_timestamp DESC' ); - $this->addWhere( "cuc_timestamp > " . $db->addQuotes( $db->timestamp( $timeCutoff ) ) ); + $this->addWhere( "cuc_timestamp > " . $dbr->addQuotes( $dbr->timestamp( $timeCutoff ) ) ); switch ( $request ) { case 'userips': - $user_id = User::idFromName( $target ); - if ( !$user_id ) { + $userIdentity = $this->userIdentityLookup->getUserIdentityByName( $target ); + if ( $userIdentity && $userIdentity->getId() ) { + $user_id = $userIdentity->getId(); + } else { $this->dieWithError( [ 'nosuchusershort', wfEscapeWikiText( $target ) ], 'nosuchuser' ); } $this->addFields( [ 'cuc_timestamp', 'cuc_ip', 'cuc_xff' ] ); - // @phan-suppress-next-line PhanTypeMismatchArgumentNullable T240141 $this->addWhereFld( 'cuc_user', $user_id ); $res = $this->select( __METHOD__ ); $result = $this->getResult(); @@ -78,7 +118,8 @@ class ApiQueryCheckUser extends ApiQueryBase { $resultIPs[] = $data; } - SpecialCheckUser::addLogEntry( 'userips', 'user', $target, $reason, $user_id ); + $this->checkUserLogService->addLogEntry( $this->getUser(), 'userips', + 'user', $target, $reason, $user_id ); $result->addValue( [ 'query', $this->getModuleName() ], 'userips', $resultIPs ); $result->addIndexedTagName( [ @@ -87,7 +128,7 @@ class ApiQueryCheckUser extends ApiQueryBase { case 'edits': if ( IPUtils::isIPAddress( $target ) ) { - $cond = SpecialCheckUser::getIpConds( $db, $target, isset( $xff ) ); + $cond = AbstractCheckUserPager::getIpConds( $dbr, $target, isset( $xff ) ); if ( !$cond ) { $this->dieWithError( 'apierror-badip', 'invalidip' ); } @@ -100,13 +141,14 @@ class ApiQueryCheckUser extends ApiQueryBase { } $log_type[] = 'ip'; } else { - $user_id = User::idFromName( $target ); - if ( $user_id === null ) { + $userIdentity = $this->userIdentityLookup->getUserIdentityByName( $target ); + if ( $userIdentity && $userIdentity->getId() ) { + $user_id = $userIdentity->getId(); + } else { $this->dieWithError( [ 'nosuchusershort', wfEscapeWikiText( $target ) ], 'nosuchuser' ); } - // @phan-suppress-next-line PhanTypeMismatchArgumentNullable T240141 $this->addWhereFld( 'cuc_user', $user_id ); $log_type = [ 'useredits', 'user' ]; } @@ -137,22 +179,19 @@ class ApiQueryCheckUser extends ApiQueryBase { if ( $row->cuc_this_oldid != 0 && ( $row->cuc_type == RC_EDIT || $row->cuc_type == RC_NEW ) ) { - $revRecord = MediaWikiServices::getInstance() - ->getRevisionLookup() + $revRecord = $this->revisionLookup ->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'] - ); + $tmp = $dbr->newSelectQueryBuilder() + ->fields( $queryInfo['fields'] ) + ->tables( $queryInfo['tables'] ) + ->joinConds( $queryInfo['joins'] ) + ->where( [ 'ar_rev_id' => $row->cuc_this_oldid ] ) + ->caller( __METHOD__ ) + ->fetchRow(); if ( $tmp ) { $revRecord = MediaWikiServices::getInstance() ->getRevisionFactory() @@ -185,7 +224,7 @@ class ApiQueryCheckUser extends ApiQueryBase { $edits[] = $edit; } - SpecialCheckUser::addLogEntry( $log_type[0], $log_type[1], + $this->checkUserLogService->addLogEntry( $this->getUser(), $log_type[0], $log_type[1], $target, $reason, $user_id ?? '0' ); $result->addValue( [ 'query', $this->getModuleName() ], 'edits', $edits ); @@ -195,7 +234,7 @@ class ApiQueryCheckUser extends ApiQueryBase { case 'ipusers': if ( IPUtils::isIPAddress( $target ) ) { - $cond = SpecialCheckUser::getIpConds( $db, $target, isset( $xff ) ); + $cond = AbstractCheckUserPager::getIpConds( $dbr, $target, isset( $xff ) ); $this->addWhere( $cond ); $log_type = 'ipusers'; if ( isset( $xff ) ) { @@ -203,7 +242,6 @@ class ApiQueryCheckUser extends ApiQueryBase { } } else { $this->dieWithError( 'apierror-badip', 'invalidip' ); - throw new LogicException(); } $this->addFields( [ @@ -240,13 +278,14 @@ class ApiQueryCheckUser extends ApiQueryBase { $resultUsers = []; foreach ( $users as $userName => $userData ) { $userData['name'] = $userName; - $result->setIndexedTagName( $userData['ips'], 'ip' ); - $result->setIndexedTagName( $userData['agents'], 'agent' ); + ApiResult::setIndexedTagName( $userData['ips'], 'ip' ); + ApiResult::setIndexedTagName( $userData['agents'], 'agent' ); $resultUsers[] = $userData; } - SpecialCheckUser::addLogEntry( $log_type, 'ip', $target, $reason ); + $this->checkUserLogService->addLogEntry( $this->getUser(), $log_type, + 'ip', $target, $reason ); $result->addValue( [ 'query', $this->getModuleName() ], 'ipusers', $resultUsers ); $result->addIndexedTagName( [ @@ -258,37 +297,40 @@ class ApiQueryCheckUser extends ApiQueryBase { } } + /** @inheritDoc */ public function mustBePosted() { return true; } + /** @inheritDoc */ public function isWriteMode() { return true; } + /** @inheritDoc */ public function getAllowedParams() { return [ 'request' => [ - ApiBase::PARAM_REQUIRED => true, - ApiBase::PARAM_TYPE => [ + ParamValidator::PARAM_REQUIRED => true, + ParamValidator::PARAM_TYPE => [ 'userips', 'edits', 'ipusers', ] ], 'target' => [ - ApiBase::PARAM_REQUIRED => true, + ParamValidator::PARAM_REQUIRED => true, ], 'reason' => null, 'limit' => [ - ApiBase::PARAM_DFLT => 500, - ApiBase::PARAM_TYPE => 'limit', - ApiBase::PARAM_MIN => 1, - ApiBase::PARAM_MAX => 500, - ApiBase::PARAM_MAX2 => $this->getConfig()->get( 'CheckUserMaximumRowCount' ), + ParamValidator::PARAM_DEFAULT => 500, + ParamValidator::PARAM_TYPE => 'limit', + IntegerDef::PARAM_MIN => 1, + IntegerDef::PARAM_MAX => 500, + IntegerDef::PARAM_MAX2 => $this->getConfig()->get( 'CheckUserMaximumRowCount' ), ], 'timecond' => [ - ApiBase::PARAM_DFLT => '-2 weeks' + ParamValidator::PARAM_DEFAULT => '-2 weeks' ], 'xff' => null, ]; @@ -307,10 +349,12 @@ class ApiQueryCheckUser extends ApiQueryBase { ]; } + /** @inheritDoc */ public function getHelpUrls() { return 'https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:CheckUser#API'; } + /** @inheritDoc */ public function needsToken() { return 'csrf'; } diff --git a/CheckUser/includes/api/ApiQueryCheckUserLog.php b/CheckUser/src/Api/ApiQueryCheckUserLog.php index 5ef84ca4..2629e793 100644 --- a/CheckUser/includes/api/ApiQueryCheckUserLog.php +++ b/CheckUser/src/Api/ApiQueryCheckUserLog.php @@ -1,9 +1,23 @@ <?php +namespace MediaWiki\CheckUser\Api; + +use ApiBase; +use ApiQuery; +use ApiQueryBase; +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserLogPager; +use Wikimedia\IPUtils; +use Wikimedia\ParamValidator\ParamValidator; +use Wikimedia\ParamValidator\TypeDef\IntegerDef; + /** * CheckUser API Query Module */ class ApiQueryCheckUserLog extends ApiQueryBase { + /** + * @param ApiQuery $query + * @param string $moduleName + */ public function __construct( $query, $moduleName ) { parent::__construct( $query, $moduleName, 'cul' ); } @@ -11,7 +25,6 @@ class ApiQueryCheckUserLog extends ApiQueryBase { public function execute() { $db = $this->getDB(); $params = $this->extractRequestParams(); - $this->checkUserRightsAny( 'checkuser-log' ); $limit = $params['limit']; @@ -22,7 +35,8 @@ class ApiQueryCheckUserLog extends ApiQueryBase { $this->addOption( 'LIMIT', $limit + 1 ); $this->addTimestampWhereRange( 'cul_timestamp', $dir, $params['from'], $params['to'] ); $this->addFields( [ - 'cul_id', 'cul_timestamp', 'cul_user_text', 'cul_reason', 'cul_type', 'cul_target_text' ] ); + 'cul_id', 'cul_timestamp', 'cul_user_text', 'cul_reason', 'cul_type', 'cul_target_text' + ] ); // Order by both timestamp and id $order = ( $dir === 'newer' ? '' : ' DESC' ); @@ -32,12 +46,17 @@ class ApiQueryCheckUserLog extends ApiQueryBase { $this->addWhereFld( 'cul_user_text', $params['user'] ); } if ( isset( $params['target'] ) ) { - $this->addWhereFld( 'cul_target_text', $params['target'] ); + if ( IPUtils::isIPAddress( $params['target'] ) ) { + $cond = CheckUserLogPager::getTargetSearchConds( $params['target'] ); + if ( !$cond ) { + $this->dieWithError( 'apierror-badip', 'invalidip' ); + } + $this->addWhere( $cond ); + } else { + $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' ? '<' : '>'; @@ -59,7 +78,7 @@ class ApiQueryCheckUserLog extends ApiQueryBase { $result = $this->getResult(); $count = 0; - $makeContinue = function ( $row ) { + $makeContinue = static function ( $row ) { return wfTimestamp( TS_ISO_8601, $row->cul_timestamp ) . '|' . $row->cul_id; }; foreach ( $res as $row ) { @@ -84,30 +103,31 @@ class ApiQueryCheckUserLog extends ApiQueryBase { $result->addIndexedTagName( [ 'query', $this->getModuleName(), 'entries' ], 'entry' ); } + /** @inheritDoc */ public function getAllowedParams() { return [ 'user' => null, 'target' => null, 'limit' => [ - ApiBase::PARAM_DFLT => 10, - ApiBase::PARAM_TYPE => 'limit', - ApiBase::PARAM_MIN => 1, - ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1, - ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2, + ParamValidator::PARAM_DEFAULT => 10, + ParamValidator::PARAM_TYPE => 'limit', + IntegerDef::PARAM_MIN => 1, + IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1, + IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2, ], 'dir' => [ - ApiBase::PARAM_DFLT => 'older', - ApiBase::PARAM_TYPE => [ + ParamValidator::PARAM_DEFAULT => 'older', + ParamValidator::PARAM_TYPE => [ 'newer', 'older' ], - ApiBase::PARAM_HELP_MSG => 'api-help-param-direction', + ApiBase::PARAM_HELP_MSG => 'checkuser-api-help-param-direction', ], 'from' => [ - ApiBase::PARAM_TYPE => 'timestamp', + ParamValidator::PARAM_TYPE => 'timestamp', ], 'to' => [ - ApiBase::PARAM_TYPE => 'timestamp', + ParamValidator::PARAM_TYPE => 'timestamp', ], 'continue' => [ ApiBase::PARAM_HELP_MSG => 'api-help-param-continue', @@ -128,6 +148,9 @@ class ApiQueryCheckUserLog extends ApiQueryBase { ]; } + /** + * @inheritDoc + */ public function getHelpUrls() { return 'https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:CheckUser#API'; } diff --git a/CheckUser/src/ChangeService.php b/CheckUser/src/ChangeService.php deleted file mode 100644 index 19b904e2..00000000 --- a/CheckUser/src/ChangeService.php +++ /dev/null @@ -1,142 +0,0 @@ -<?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/CheckUser/CheckUserPagerNavigationBuilder.php b/CheckUser/src/CheckUser/CheckUserPagerNavigationBuilder.php new file mode 100644 index 00000000..5cf02f11 --- /dev/null +++ b/CheckUser/src/CheckUser/CheckUserPagerNavigationBuilder.php @@ -0,0 +1,117 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser; + +use FormOptions; +use Html; +use MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager; +use MediaWiki\CheckUser\TokenQueryManager; +use MediaWiki\Navigation\PagerNavigationBuilder; +use MediaWiki\Session\CsrfTokenSet; +use MediaWiki\User\UserIdentity; +use MessageLocalizer; +use WebRequest; + +class CheckUserPagerNavigationBuilder extends PagerNavigationBuilder { + /** @var FormOptions */ + private $opts; + + /** @var TokenQueryManager */ + private $tokenQueryManager; + + /** @var UserIdentity */ + private $target; + + /** @var WebRequest */ + private $request; + + /** @var CsrfTokenSet */ + private $csrfTokenSet; + + /** + * @param MessageLocalizer $messageLocalizer + * @param TokenQueryManager $tokenQueryManager + * @param CsrfTokenSet $csrfTokenSet + * @param WebRequest $request + * @param FormOptions $opts + * @param UserIdentity $target + */ + public function __construct( + MessageLocalizer $messageLocalizer, + TokenQueryManager $tokenQueryManager, + CsrfTokenSet $csrfTokenSet, + WebRequest $request, + FormOptions $opts, + UserIdentity $target + ) { + parent::__construct( $messageLocalizer ); + $this->opts = $opts; + $this->tokenQueryManager = $tokenQueryManager; + $this->target = $target; + $this->request = $request; + $this->csrfTokenSet = $csrfTokenSet; + } + + /** @inheritDoc */ + protected function makeLink( + ?array $query, ?string $class, string $text, ?string $tooltip, ?string $rel = null + ): string { + if ( $query === null ) { + return Html::element( + 'span', + [ + 'class' => $class + ], + $text + ); + } + $query = array_merge( $this->linkQuery, $query ); + $opts = $this->opts; + $fields = array_filter( AbstractCheckUserPager::TOKEN_MANAGED_FIELDS, static function ( $field ) use ( $opts ) { + return $opts->validateName( $field ); + } ); + $fieldData = []; + foreach ( $fields as $field ) { + if ( !in_array( $field, [ 'dir', 'offset', 'limit' ] ) ) { + $fieldData[$field] = $this->opts->getValue( $field ); + } else { + // Never persist the dir, offset and limit + // as the pagination links are responsible + // for setting or not setting them. + $fieldData[$field] = null; + } + } + + $fieldData['user'] = $this->target->getName(); + if ( $query ) { + foreach ( $query as $queryItem => $queryValue ) { + $fieldData[$queryItem] = $queryValue; + } + } + $formFields = [ Html::hidden( + 'wpEditToken', + $this->csrfTokenSet->getToken(), + [ 'id' => 'wpEditToken' ] + ) ]; + $formFields[] = Html::hidden( + 'token', + $this->tokenQueryManager->updateToken( $this->request, $fieldData ) + ); + $formFields[] = Html::submitButton( + $text, + [ + 'class' => $class . ' mw-checkuser-paging-links' + ] + ); + return Html::rawElement( + 'form', + [ + 'method' => 'post', + 'class' => 'mw-checkuser-paging-links-form', + 'rel' => $rel, + 'title' => $tooltip + ], + implode( '', $formFields ) + ); + } +} diff --git a/CheckUser/src/CheckUser/Pagers/AbstractCheckUserPager.php b/CheckUser/src/CheckUser/Pagers/AbstractCheckUserPager.php new file mode 100644 index 00000000..ad1ac63c --- /dev/null +++ b/CheckUser/src/CheckUser/Pagers/AbstractCheckUserPager.php @@ -0,0 +1,567 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser\Pagers; + +use ActorMigration; +use CentralIdLookup; +use ExtensionRegistry; +use FormOptions; +use Html; +use HtmlArmor; +use IContextSource; +use MediaWiki\Block\AbstractBlock; +use MediaWiki\Block\DatabaseBlock; +use MediaWiki\CheckUser\CheckUser\CheckUserPagerNavigationBuilder; +use MediaWiki\CheckUser\CheckUserLogService; +use MediaWiki\CheckUser\TokenQueryManager; +use MediaWiki\Extension\GlobalBlocking\GlobalBlocking; +use MediaWiki\Linker\LinkRenderer; +use MediaWiki\Navigation\PagerNavigationBuilder; +use MediaWiki\SpecialPage\SpecialPageFactory; +use MediaWiki\User\UserFactory; +use MediaWiki\User\UserGroupManager; +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityLookup; +use RangeChronologicalPager; +use RequestContext; +use SpecialPage; +use TemplateParser; +use Title; +use TitleValue; +use UserGroupMembership; +use Wikimedia\IPUtils; +use Wikimedia\Rdbms\IDatabase; +use Wikimedia\Rdbms\ILoadBalancer; +use Wikimedia\Rdbms\SelectQueryBuilder; +use Wikimedia\Timestamp\ConvertibleTimestamp; + +abstract class AbstractCheckUserPager extends RangeChronologicalPager { + + public const TOKEN_MANAGED_FIELDS = [ + 'reason', + 'checktype', + 'period', + 'dir', + 'limit', + 'offset', + ]; + + /** @var string */ + private $logType; + + /** @var FormOptions */ + protected $opts; + + /** @var UserGroupManager */ + protected $userGroupManager; + + /** @var CentralIdLookup */ + protected $centralIdLookup; + + /** @var UserIdentity */ + protected $target; + + /** @var TokenQueryManager */ + private $tokenQueryManager; + + /** @var SpecialPageFactory */ + private $specialPageFactory; + + /** @var UserIdentityLookup */ + private $userIdentityLookup; + + /** @var ActorMigration */ + private $actorMigration; + + /** + * @var CheckUserLogService + */ + private $checkUserLogService; + + /** @var TemplateParser */ + protected $templateParser; + + /** @var UserFactory */ + private $userFactory; + + /** + * @param FormOptions $opts + * @param UserIdentity $target + * @param string $logType + * @param TokenQueryManager $tokenQueryManager + * @param UserGroupManager $userGroupManager + * @param CentralIdLookup $centralIdLookup + * @param ILoadBalancer $loadBalancer + * @param SpecialPageFactory $specialPageFactory + * @param UserIdentityLookup $userIdentityLookup + * @param ActorMigration $actorMigration + * @param CheckUserLogService $checkUserLogService + * @param UserFactory $userFactory + * @param IContextSource|null $context + * @param LinkRenderer|null $linkRenderer + * @param ?int $limit + */ + public function __construct( + FormOptions $opts, + UserIdentity $target, + string $logType, + TokenQueryManager $tokenQueryManager, + UserGroupManager $userGroupManager, + CentralIdLookup $centralIdLookup, + ILoadBalancer $loadBalancer, + SpecialPageFactory $specialPageFactory, + UserIdentityLookup $userIdentityLookup, + ActorMigration $actorMigration, + CheckUserLogService $checkUserLogService, + UserFactory $userFactory, + IContextSource $context = null, + LinkRenderer $linkRenderer = null, + ?int $limit = null + ) { + $this->opts = $opts; + $this->target = $target; + $this->logType = $logType; + + $this->mDb = $loadBalancer->getConnection( DB_REPLICA ); + + parent::__construct( $context, $linkRenderer ); + + $maximumRowCount = $this->getConfig()->get( 'CheckUserMaximumRowCount' ); + $this->mDefaultLimit = $limit ?? $maximumRowCount; + if ( $this->opts->getValue( 'limit' ) ) { + $this->mLimit = min( + $this->opts->getValue( 'limit' ), + $this->getConfig()->get( 'CheckUserMaximumRowCount' ) + ); + } else { + $this->mLimit = $maximumRowCount; + } + + $this->mLimitsShown = [ + $maximumRowCount / 25, + $maximumRowCount / 10, + $maximumRowCount / 5, + $maximumRowCount / 2, + $maximumRowCount, + ]; + + $this->mLimitsShown = array_map( 'ceil', $this->mLimitsShown ); + $this->mLimitsShown = array_unique( $this->mLimitsShown ); + + $this->userGroupManager = $userGroupManager; + $this->centralIdLookup = $centralIdLookup; + $this->tokenQueryManager = $tokenQueryManager; + $this->specialPageFactory = $specialPageFactory; + $this->userIdentityLookup = $userIdentityLookup; + $this->actorMigration = $actorMigration; + $this->checkUserLogService = $checkUserLogService; + $this->userFactory = $userFactory; + + $this->templateParser = new TemplateParser( __DIR__ . '/../../../templates' ); + + // Get any set token data. Used for paging without adding extra logs + $tokenData = $this->tokenQueryManager->getDataFromRequest( $this->getRequest() ); + if ( !$tokenData ) { + // Log if the token data is not set. A token will only be generated by + // the server for CheckUser for paging links after running a check. + // It will also only be valid if not tampered with as it's encrypted. + // Paging through the entries won't need an extra log entry. + $this->checkUserLogService->addLogEntry( + $this->getUser(), + $this->logType, + $target->getId() ? 'user' : 'ip', + $target->getName(), + $this->opts->getValue( 'reason' ), + $target->getId() + ); + } + + $this->getDateRangeCond( '', '' ); + } + + /** + * Get the cutoff timestamp and add it to the range conditions for the query + * + * @param string $startStamp Ignored. + * @param string $endStamp Ignored. + * @return array the range conditions which are also set in $this->rangeConds + */ + public function getDateRangeCond( $startStamp, $endStamp ): array { + $this->rangeConds = []; + $period = $this->opts->getValue( 'period' ); + if ( $period ) { + $cutoffUnixtime = ConvertibleTimestamp::time() - ( $period * 24 * 3600 ); + $cutoffUnixtime -= $cutoffUnixtime % 86400; + $cutoff = $this->mDb->addQuotes( $this->mDb->timestamp( $cutoffUnixtime ) ); + $this->rangeConds = [ "cuc_timestamp > $cutoff" ]; + } + + return $this->rangeConds; + } + + /** + * Get formatted timestamp(s) to show the time of first and last change. + * If both timestamps are the same, it will be shown only once. + * + * @param string $first Timestamp of the first change + * @param string $last Timestamp of the last change + * @return string + */ + protected function getTimeRangeString( string $first, string $last ): string { + $s = $this->getFormattedTimestamp( $first ); + if ( $first !== $last ) { + // @todo i18n issue - hardcoded string + $s .= ' -- '; + $s .= $this->getFormattedTimestamp( $last ); + } + return $s; + } + + /** + * Get a link to block information about the passed block for displaying to the user. + * + * @param DatabaseBlock $block + * @return string + */ + protected function getBlockFlag( DatabaseBlock $block ): string { + if ( $block->getType() === DatabaseBlock::TYPE_AUTO ) { + $ret = $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'BlockList' ), + $this->msg( 'checkuser-blocked' )->text(), + [], + [ 'wpTarget' => "#{$block->getId()}" ] + ); + } else { + $userPage = Title::makeTitle( NS_USER, $block->getTargetName() ); + $ret = $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'Log' ), + $this->msg( 'checkuser-blocked' )->text(), + [], + [ + 'type' => 'block', + 'page' => $userPage->getPrefixedText() + ] + ); + + // Add the blocked range if the block is on a range + if ( $block->getType() === DatabaseBlock::TYPE_RANGE ) { + $ret .= ' - ' . htmlspecialchars( $block->getTargetName() ); + } + } + + return Html::rawElement( + 'strong', + [ 'class' => 'mw-changeslist-links' ], + $ret + ); + } + + /** + * Get an HTML link (<a> element) to Special:CheckUser + * + * @param string $text content to use within <a> tag + * @param array $params query parameters to use in the URL + * @return string + */ + protected function getSelfLink( string $text, array $params ): string { + $title = $this->getTitleValue(); + return $this->getLinkRenderer()->makeKnownLink( + $title, + new HtmlArmor( '<bdi>' . htmlspecialchars( $text ) . '</bdi>' ), + [], + $params + ); + } + + /** + * @param string $page the string title get the TitleValue for. + * @return TitleValue the associated TitleValue object + */ + protected function getTitleValue( string $page = 'CheckUser' ): TitleValue { + return new TitleValue( + NS_SPECIAL, + $this->specialPageFactory->getLocalNameFor( $page ) + ); + } + + /** + * @param string $page the string title get the Title for. + * @return Title the associated Title object + */ + protected function getPageTitle( string $page = 'CheckUser' ): Title { + return Title::newFromLinkTarget( + $this->getTitleValue( $page ) + ); + } + + /** + * Get a formatted timestamp string in the current language + * for displaying to the user. + * + * @param string $timestamp + * @return string + */ + protected function getFormattedTimestamp( string $timestamp ): string { + return $this->getLanguage()->userTimeAndDate( + wfTimestamp( TS_MW, $timestamp ), $this->getUser() + ); + } + + /** + * Give a "no matches found for X" message. + * If $checkLast, then mention the last edit by this user or IP. + * + * @param string $userName + * @param bool $checkLast + * @return string + */ + protected function noMatchesMessage( string $userName, bool $checkLast = true ): string { + if ( $checkLast ) { + $user = $this->userIdentityLookup->getUserIdentityByName( $userName ); + + $lastEdit = false; + + $revWhere = $this->actorMigration->getWhere( $this->mDb, 'rev_user', $user ); + foreach ( $revWhere['orconds'] as $cond ) { + $lastEdit = max( $lastEdit, $this->mDb->newSelectQueryBuilder() + ->tables( [ 'revision' ] + $revWhere['tables'] ) + ->field( 'rev_timestamp' ) + ->conds( $cond ) + ->orderBy( 'rev_timestamp', SelectQueryBuilder::SORT_DESC ) + ->joinConds( $revWhere['joins'] ) + ->caller( __METHOD__ ) + ->fetchField() + ); + } + $lastEdit = max( $lastEdit, $this->mDb->newSelectQueryBuilder() + ->table( 'logging' ) + ->field( 'log_timestamp' ) + ->orderBy( 'log_timestamp', SelectQueryBuilder::SORT_DESC ) + ->join( 'actor', null, 'actor_id=log_actor' ) + ->where( [ 'actor_name' => $userName ] ) + ->caller( __METHOD__ ) + ->fetchField() + ); + + 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->userDate( $lastEditTime, $contextUser ), + $lang->userTime( $lastEditTime, $contextUser ) + )->parseAsBlock(); + } + } + return $this->msg( 'checkuser-nomatch' )->parseAsBlock(); + } + + /** + * @param string $ip + * @param UserIdentity $user + * @return array + */ + protected function userBlockFlags( string $ip, UserIdentity $user ): array { + $flags = []; + // Needed because User::isBlockedGlobally doesn't seem to have a non User:: method. + $userObj = $this->userFactory->newFromUserIdentity( $user ); + + $block = DatabaseBlock::newFromTarget( $user, $ip ); + if ( $block instanceof DatabaseBlock ) { + // Locally blocked + $flags[] = $this->getBlockFlag( $block ); + } elseif ( + $ip == $user->getName() && + ExtensionRegistry::getInstance()->isLoaded( 'GlobalBlocking' ) && + GlobalBlocking::getUserBlock( + $this->userFactory->newFromUserIdentity( $user ), + $ip + ) instanceof AbstractBlock + ) { + // Globally blocked IP + $flags[] = '<strong>(' . $this->msg( 'checkuser-gblocked' )->escaped() . ')</strong>'; + } elseif ( $this->userWasBlocked( $user->getName() ) ) { + // Previously blocked + $blocklog = $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'Log' ), + $this->msg( 'checkuser-wasblocked' )->text(), + [], + [ + 'type' => 'block', + // @todo Use TitleFormatter and PageReference to avoid the global state + 'page' => Title::makeTitle( NS_USER, $user->getName() )->getPrefixedText() + ] + ); + $flags[] = Html::rawElement( 'strong', [ 'class' => 'mw-changeslist-links' ], $blocklog ); + } + + // Show if account is local only + if ( $user->getId() && + $this->centralIdLookup + ->centralIdFromLocalUser( $user, CentralIdLookup::AUDIENCE_RAW ) === 0 + ) { + $flags[] = Html::rawElement( + 'strong', + [ 'class' => 'mw-changeslist-links' ], + $this->msg( 'checkuser-localonly' )->escaped() + ); + } + // Check for extra user rights... + if ( $user->getId() ) { + if ( $userObj->isLocked() ) { + $flags[] = Html::rawElement( + 'strong', + [ 'class' => 'mw-changeslist-links' ], + $this->msg( 'checkuser-locked' )->escaped() + ); + } + $list = []; + foreach ( $this->userGroupManager->getUserGroups( $user ) as $group ) { + $list[] = self::buildGroupLink( $group ); + } + $groups = $this->getLanguage()->commaList( $list ); + if ( $groups ) { + $flags[] = Html::rawElement( 'i', [ 'class' => 'mw-changeslist-links' ], $groups ); + } + } + + return $flags; + } + + /** + * Format a link to a group description page + * + * @param string $group + * @return string + */ + protected static function buildGroupLink( string $group ): string { + static $cache = []; + if ( !isset( $cache[$group] ) ) { + $cache[$group] = UserGroupMembership::getLink( + $group, RequestContext::getMain(), 'html' + ); + } + return $cache[$group]; + } + + /** + * Get whether the user has ever been blocked. + * + * @param string $name the username + * @return bool whether the user with that username has ever been blocked + */ + protected function userWasBlocked( string $name ): bool { + $userpage = Title::makeTitle( NS_USER, $name ); + + return (bool)$this->mDb->newSelectQueryBuilder() + ->table( 'logging' ) + ->field( '1' ) + ->conds( [ + 'log_type' => [ 'block', 'suppress' ], + 'log_action' => 'block', + 'log_namespace' => $userpage->getNamespace(), + 'log_title' => $userpage->getDBkey() + ] ) + ->useIndex( 'log_page_time' ) + ->caller( __METHOD__ ) + ->fetchField(); + } + + /** + * @param string $target an IP address or CIDR range + * @return bool + */ + public static function isValidRange( string $target ): bool { + $CIDRLimit = RequestContext::getMain()->getConfig()->get( 'CheckUserCIDRLimit' ); + if ( IPUtils::isValidRange( $target ) ) { + [ $ip, $range ] = explode( '/', $target, 2 ); + return !( + ( IPUtils::isIPv4( $ip ) && $range < $CIDRLimit['IPv4'] ) || + ( IPUtils::isIPv6( $ip ) && $range < $CIDRLimit['IPv6'] ) + ); + } + + return IPUtils::isValid( $target ); + } + + /** + * Get the WHERE conditions for an IP address / range, optionally as a XFF. + * + * @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, string $target, $xfor = false ) { + $type = $xfor ? 'xff' : 'ip'; + + 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 ( IPUtils::isValid( $target ) ) { + return [ "cuc_{$type}_hex" => IPUtils::toHex( $target ) ]; + } + // invalid IP + return false; + } + + /** @inheritDoc */ + public function reallyDoQuery( $offset, $limit, $order ) { + list( $tables, $fields, $conds, $fname, $options, $join_conds ) = + $this->buildQueryInfo( $offset, $limit, $order ); + + return $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds ); + } + + /** @inheritDoc */ + protected function getStartBody(): string { + $s = $this->getNavigationBar(); + $s .= '<div id="checkuserresults">'; + + return $s; + } + + /** @inheritDoc */ + protected function getEndBody(): string { + return $this->getNavigationBar(); + } + + /** @inheritDoc */ + public function getNavigationBuilder(): PagerNavigationBuilder { + $pagingQueries = $this->getPagingQueries(); + $baseQuery = array_merge( $this->getDefaultQuery(), [ + // These query parameters are all defined here, even though some are null, + // to ensure consistent order of parameters when they're used. + 'dir' => null, + 'offset' => $this->getOffsetQuery(), + 'limit' => null, + ] ); + + $navBuilder = new CheckUserPagerNavigationBuilder( + $this->getContext(), + $this->tokenQueryManager, + $this->getCsrfTokenSet(), + $this->getRequest(), + $this->opts, + $this->target + ); + $navBuilder + ->setPage( $this->getTitle() ) + ->setLinkQuery( $baseQuery ) + ->setLimits( $this->mLimitsShown ) + ->setLimitLinkQueryParam( 'limit' ) + ->setCurrentLimit( $this->mLimit ) + ->setPrevLinkQuery( $pagingQueries['prev'] ?: null ) + ->setNextLinkQuery( $pagingQueries['next'] ?: null ) + ->setFirstLinkQuery( $pagingQueries['first'] ?: null ) + ->setLastLinkQuery( $pagingQueries['last'] ?: null ); + + return $navBuilder; + } +} diff --git a/CheckUser/src/CheckUser/Pagers/CheckUserGetEditsPager.php b/CheckUser/src/CheckUser/Pagers/CheckUserGetEditsPager.php new file mode 100644 index 00000000..808ef33d --- /dev/null +++ b/CheckUser/src/CheckUser/Pagers/CheckUserGetEditsPager.php @@ -0,0 +1,429 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser\Pagers; + +use ActorMigration; +use CentralIdLookup; +use FormOptions; +use Hooks; +use Html; +use HtmlArmor; +use IContextSource; +use Linker; +use MediaWiki\Cache\LinkBatchFactory; +use MediaWiki\CheckUser\CheckUserLogService; +use MediaWiki\CheckUser\Hooks as CUHooks; +use MediaWiki\CheckUser\TokenQueryManager; +use MediaWiki\CommentFormatter\CommentFormatter; +use MediaWiki\Linker\LinkRenderer; +use MediaWiki\Logger\LoggerFactory; +use MediaWiki\Revision\RevisionStore; +use MediaWiki\SpecialPage\SpecialPageFactory; +use MediaWiki\User\UserEditTracker; +use MediaWiki\User\UserFactory; +use MediaWiki\User\UserGroupManager; +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityLookup; +use MediaWiki\User\UserIdentityValue; +use Psr\Log\LoggerInterface; +use SpecialPage; +use stdClass; +use Title; +use Wikimedia\IPUtils; +use Wikimedia\Rdbms\ILoadBalancer; + +class CheckUserGetEditsPager extends AbstractCheckUserPager { + + /** + * @var string[] Used to cache frequently used messages + */ + protected $message = []; + + /** + * @var array The cached results of AbstractCheckUserPager::userBlockFlags with the key as + * the row's cuc_user_text. + */ + private $flagCache = []; + + /** + * Null if $target is a user. + * Boolean is $target is a IP / range. + * - False if XFF is not appended + * - True if XFF is appended + * + * @var null|bool + */ + protected $xfor = null; + + /** @var array */ + protected $formattedRevisionComments = []; + + /** @var LoggerInterface */ + private $logger; + + /** @var LinkBatchFactory */ + private $linkBatchFactory; + + /** @var RevisionStore */ + private $revisionStore; + + /** @var CommentFormatter */ + private $commentFormatter; + + /** @var UserEditTracker */ + private $userEditTracker; + + /** + * @param FormOptions $opts + * @param UserIdentity $target + * @param bool|null $xfor + * @param string $logType + * @param TokenQueryManager $tokenQueryManager + * @param UserGroupManager $userGroupManager + * @param CentralIdLookup $centralIdLookup + * @param LinkBatchFactory $linkBatchFactory + * @param ILoadBalancer $loadBalancer + * @param SpecialPageFactory $specialPageFactory + * @param UserIdentityLookup $userIdentityLookup + * @param ActorMigration $actorMigration + * @param UserFactory $userFactory + * @param RevisionStore $revisionStore + * @param CheckUserLogService $checkUserLogService + * @param CommentFormatter $commentFormatter + * @param UserEditTracker $userEditTracker + * @param IContextSource|null $context + * @param LinkRenderer|null $linkRenderer + * @param ?int $limit + */ + public function __construct( + FormOptions $opts, + UserIdentity $target, + ?bool $xfor, + string $logType, + TokenQueryManager $tokenQueryManager, + UserGroupManager $userGroupManager, + CentralIdLookup $centralIdLookup, + LinkBatchFactory $linkBatchFactory, + ILoadBalancer $loadBalancer, + SpecialPageFactory $specialPageFactory, + UserIdentityLookup $userIdentityLookup, + ActorMigration $actorMigration, + UserFactory $userFactory, + RevisionStore $revisionStore, + CheckUserLogService $checkUserLogService, + CommentFormatter $commentFormatter, + UserEditTracker $userEditTracker, + IContextSource $context = null, + LinkRenderer $linkRenderer = null, + ?int $limit = null + ) { + parent::__construct( $opts, $target, $logType, $tokenQueryManager, + $userGroupManager, $centralIdLookup, $loadBalancer, $specialPageFactory, + $userIdentityLookup, $actorMigration, $checkUserLogService, $userFactory, + $context, $linkRenderer, $limit ); + $this->logger = LoggerFactory::getInstance( 'CheckUser' ); + $this->xfor = $xfor; + $this->linkBatchFactory = $linkBatchFactory; + $this->revisionStore = $revisionStore; + $this->commentFormatter = $commentFormatter; + $this->userEditTracker = $userEditTracker; + $this->preCacheMessages(); + $this->mGroupByDate = true; + } + + /** + * Get a streamlined recent changes line with IP data + * + * @inheritDoc + */ + public function formatRow( $row ): string { + $templateParams = []; + // Create diff/hist/page links + $templateParams['links'] = $this->getLinksFromRow( $row ); + // Show date + $templateParams['timestamp'] = + $this->getLanguage()->userTime( wfTimestamp( TS_MW, $row->cuc_timestamp ), $this->getUser() ); + // Userlinks + $user = new UserIdentityValue( $row->cuc_user, $row->cuc_user_text ); + if ( !IPUtils::isIPAddress( $user ) && !$user->isRegistered() ) { + $templateParams['userLinkClass'] = 'mw-checkuser-nonexistent-user'; + } + $templateParams['userLink'] = Linker::userLink( $user->getId(), $row->cuc_user_text, $row->cuc_user_text ); + $templateParams['userToolLinks'] = Linker::userToolLinksRedContribs( + $user->getId(), + $row->cuc_user_text, + $this->userEditTracker->getUserEditCount( $user ), + // don't render parentheses in HTML markup (CSS will provide) + false + ); + // Add any block information + $templateParams['flags'] = $this->flagCache[$row->cuc_user_text]; + // Action text, hackish ... + $templateParams['actionText'] = $this->commentFormatter->format( $row->cuc_actiontext ); + // Comment + if ( $row->cuc_type == RC_EDIT || $row->cuc_type == RC_NEW ) { + $templateParams['comment'] = $this->formattedRevisionComments[$row->cuc_this_oldid]; + } else { + $templateParams['comment'] = $this->commentFormatter->formatBlock( $row->cuc_comment ); + } + // IP + $templateParams['ipLink'] = $this->getSelfLink( $row->cuc_ip, + [ + 'user' => $row->cuc_ip, + 'reason' => $this->opts->getValue( 'reason' ) + ] + ); + // XFF + if ( $row->cuc_xff != null ) { + // Flag our trusted proxies + list( $client ) = CUHooks::getClientIPfromXFF( $row->cuc_xff ); + // XFF was trusted if client came from it + $trusted = ( $client === $row->cuc_ip ); + $templateParams['xffTrusted'] = $trusted; + $templateParams['xff'] = $this->getSelfLink( $row->cuc_xff, + [ + 'user' => $client . '/xff', + 'reason' => $this->opts->getValue( 'reason' ) + ] + ); + } + // User agent + $templateParams['userAgent'] = $row->cuc_agent; + + return $this->templateParser->processTemplate( 'GetEditsLine', $templateParams ); + } + + /** + * @param stdClass $row + * @return string diff, hist and page other links related to the change + */ + protected function getLinksFromRow( stdClass $row ): string { + $links = []; + // Log items + // Due to T315224 triple equals for cuc_type does not work for sqlite. + if ( $row->cuc_type == RC_LOG ) { + $title = Title::makeTitle( $row->cuc_namespace, $row->cuc_title ); + $links['log'] = Html::rawElement( + 'span', + [ 'class' => 'mw-changeslist-links' ], + $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'Log' ), + new HtmlArmor( $this->message['log'] ), + [], + [ 'page' => $title->getPrefixedText() ] + ) + ); + } else { + $title = Title::makeTitle( $row->cuc_namespace, $row->cuc_title ); + // New pages + if ( $row->cuc_type == RC_NEW ) { + $links['diffHistLinks'] = Html::rawElement( 'span', [], $this->message['diff'] ); + } else { + // Diff link + $links['diffHistLinks'] = Html::rawElement( 'span', [], + $this->getLinkRenderer()->makeKnownLink( + $title, + new HtmlArmor( $this->message['diff'] ), + [], + [ + 'curid' => $row->cuc_page_id, + 'diff' => $row->cuc_this_oldid, + 'oldid' => $row->cuc_last_oldid + ] + ) + ); + } + // History link + $links['diffHistLinks'] .= ' ' . Html::rawElement( 'span', [], + $this->getLinkRenderer()->makeKnownLink( + $title, + new HtmlArmor( $this->message['hist'] ), + [], + [ + 'curid' => $title->exists() ? $row->cuc_page_id : null, + 'action' => 'history' + ] + ) + ); + $links['diffHistLinks'] = Html::rawElement( + 'span', + [ 'class' => 'mw-changeslist-links' ], + $links['diffHistLinks'] + ); + $links['diffHistLinksSeparator'] = Html::element( + 'span', + [ 'class' => 'mw-changeslist-separator' ] + ); + // Some basic flags + if ( $row->cuc_type == RC_NEW ) { + $links['newpage'] = Html::rawElement( + 'abbr', + [ 'class' => 'newpage' ], + $this->message['newpageletter'] + ); + } + if ( $row->cuc_minor ) { + $links['minor'] = Html::rawElement( + "abbr", + [ 'class' => 'minoredit' ], + $this->message['minoreditletter'] + ); + } + // Page link + $links['title'] = $this->getLinkRenderer()->makeLink( $title ); + } + + Hooks::run( 'SpecialCheckUserGetLinksFromRow', [ $this, $row, &$links ] ); + // @phan-suppress-next-line PhanRedundantCondition May set by hook + if ( is_array( $links ) ) { + return implode( ' ', $links ); + } else { + $this->logger->warning( + __METHOD__ . ': Expected array from SpecialCheckUserGetLinksFromRow $links param,' + . ' but received ' . gettype( $links ) + ); + return ''; + } + } + + /** + * 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 + */ + protected function preCacheMessages() { + if ( $this->message === [] ) { + $msgKeys = [ 'diff', 'hist', 'minoreditletter', 'newpageletter', 'blocklink', 'log' ]; + foreach ( $msgKeys as $msg ) { + $this->message[$msg] = $this->msg( $msg )->escaped(); + } + } + } + + /** @inheritDoc */ + protected function getEmptyBody(): string { + return $this->noMatchesMessage( $this->target->getName(), !$this->xfor ) . "\n"; + } + + /** @inheritDoc */ + public function getQueryInfo(): array { + $queryInfo = [ + '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', + ], + 'tables' => [ 'cu_changes' ], + 'conds' => [], + 'options' => [], + ]; + if ( $this->xfor === null ) { + $queryInfo['conds']['cuc_user'] = $this->target->getId(); + $queryInfo['options']['USE INDEX'] = 'cuc_user_ip_time'; + } else { + $queryInfo['options']['USE INDEX'] = $this->xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time'; + $ipConds = self::getIpConds( $this->mDb, $this->target->getName(), $this->xfor ); + if ( $ipConds ) { + $queryInfo['conds'] = array_merge( $queryInfo['conds'], $ipConds ); + } + } + return $queryInfo; + } + + /** @inheritDoc */ + public function getIndexField() { + return 'cuc_timestamp'; + } + + /** @inheritDoc */ + protected function getEndBody(): string { + return '</ul></div>' . parent::getEndBody(); + } + + /** @inheritDoc */ + protected function getStartBody(): string { + return $this->getNavigationBar() + . '<div id="checkuserresults" class="mw-checkuser-get-edits-results">'; + } + + /** @inheritDoc */ + protected function preprocessResults( $result ) { + $lb = $this->linkBatchFactory->newLinkBatch(); + $lb->setCaller( __METHOD__ ); + $revisions = []; + $missingRevisions = []; + foreach ( $result as $row ) { + if ( $row->cuc_title !== '' ) { + $lb->add( $row->cuc_namespace, $row->cuc_title ); + } + if ( $this->xfor === null ) { + $userText = str_replace( ' ', '_', $row->cuc_user_text ); + $lb->add( NS_USER, $userText ); + $lb->add( NS_USER_TALK, $userText ); + } + // Add the row to the flag cache + if ( !isset( $this->flagCache[$row->cuc_user_text] ) ) { + $user = new UserIdentityValue( $row->cuc_user, $row->cuc_user_text ); + $ip = IPUtils::isIPAddress( $row->cuc_user_text ) ? $row->cuc_user_text : ''; + $flags = $this->userBlockFlags( $ip, $user ); + $this->flagCache[$row->cuc_user_text] = $flags; + } + // Batch process comments + if ( + ( $row->cuc_type == RC_EDIT || $row->cuc_type == RC_NEW ) && + !array_key_exists( $row->cuc_this_oldid, $revisions ) + ) { + $revRecord = $this->revisionStore->getRevisionById( $row->cuc_this_oldid ); + if ( !$revRecord ) { + // Assume revision is deleted + $queryInfo = $this->revisionStore->getArchiveQueryInfo(); + $tmp = $this->mDb->newSelectQueryBuilder() + ->tables( $queryInfo['tables'] ) + ->fields( $queryInfo['fields'] ) + ->conds( [ 'ar_rev_id' => $row->cuc_this_oldid ] ) + ->joinConds( $queryInfo['joins'] ) + ->caller( __METHOD__ ) + ->fetchRow(); + if ( $tmp ) { + $revRecord = $this->revisionStore->newRevisionFromArchiveRow( $tmp ); + } + } + if ( !$revRecord ) { + // This shouldn't happen, CheckUser points to a revision + // that isn't in revision nor archive table? + $this->logger->warning( + "Couldn't fetch revision cu_changes table links to (cuc_this_oldid $row->cuc_this_oldid)" + ); + // Show the comment in this case as the empty string to indicate that it's missing. + $missingRevisions[$row->cuc_this_oldid] = ''; + } else { + $revisions[$row->cuc_this_oldid] = $revRecord; + } + } + } + // Batch format revision comments + $this->formattedRevisionComments = array_replace( + $missingRevisions, + $this->commentFormatter->createRevisionBatch() + ->revisions( $revisions ) + ->authority( $this->getAuthority() ) + ->samePage( false ) + ->useParentheses( false ) + ->indexById() + ->execute() + ); + $lb->execute(); + $result->seek( 0 ); + } + + /** + * Always show the navigation bar on the 'Get edits' screen + * so that the user can reduce the size of the page if they + * are interested in one or two items from the top. The only + * exception to this is when there are no results. + * + * @return bool + */ + protected function isNavigationBarShown(): bool { + return $this->getNumRows() !== 0; + } +} diff --git a/CheckUser/src/CheckUser/Pagers/CheckUserGetIPsPager.php b/CheckUser/src/CheckUser/Pagers/CheckUserGetIPsPager.php new file mode 100644 index 00000000..28a1bcc2 --- /dev/null +++ b/CheckUser/src/CheckUser/Pagers/CheckUserGetIPsPager.php @@ -0,0 +1,132 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser\Pagers; + +use MediaWiki\Block\DatabaseBlock; +use SpecialPage; +use Wikimedia\IPUtils; + +class CheckUserGetIPsPager extends AbstractCheckUserPager { + + /** @inheritDoc */ + public function formatRow( $row ): string { + $lang = $this->getLanguage(); + $ip = $row->cuc_ip; + $templateParams = []; + $templateParams['ipLink'] = $this->getSelfLink( $ip, + [ + 'user' => $ip, + 'reason' => $this->opts->getValue( 'reason' ), + ] + ); + if ( IPUtils::isValidIPv6( $ip ) ) { + $templateParams['ip64Link'] = $this->getSelfLink( '/64', + [ + 'user' => $ip . '/64', + 'reason' => $this->opts->getValue( 'reason' ), + ] + ); + } + $templateParams['blockLink'] = $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'Block', $ip ), + $this->msg( 'blocklink' )->text() + ); + $templateParams['timeRange'] = $this->getTimeRangeString( $row->first, $row->last ); + $templateParams['editCount'] = $lang->formatNum( $row->count ); + + // 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( $row->cuc_ip_hex ); + if ( $ipedits > $row->count ) { + $templateParams['ipEditCount'] = + $this->msg( 'checkuser-ipeditcount' )->numParams( $ipedits )->escaped(); + } + + // If this IP is blocked, give a link to the block log + $templateParams['blockInfo'] = $this->getIPBlockInfo( $ip ); + $templateParams['toolLinks'] = $this->msg( 'checkuser-toollinks', urlencode( $ip ) )->parse(); + return $this->templateParser->processTemplate( 'GetIPsLine', $templateParams ); + } + + /** + * Get information about any active blocks on a IP. + * + * @param string $ip the IP to get block info on. + * @return string + */ + protected function getIPBlockInfo( string $ip ): string { + $block = DatabaseBlock::newFromTarget( null, $ip ); + if ( $block instanceof DatabaseBlock ) { + return $this->getBlockFlag( $block ); + } + return ''; + } + + /** + * Return "checkuser-ipeditcount" number + * + * @param string $ip_hex + * @return int + */ + protected function getCountForIPedits( string $ip_hex ): int { + $conds = array_merge( [ 'cuc_ip_hex' => $ip_hex ], $this->rangeConds ); + + $query = $this->mDb->newSelectQueryBuilder() + ->table( 'cu_changes' ) + ->conds( $conds ) + ->caller( __METHOD__ ); + $ipEdits = $query->estimateRowCount(); + // If small enough, get a more accurate count + if ( $ipEdits <= 1000 ) { + $ipEdits = $query->fetchRowCount(); + } + + return $ipEdits; + } + + /** @inheritDoc */ + public function getQueryInfo(): array { + $this->mExtraSortFields = [ 'last' ]; + return [ + 'fields' => [ + 'cuc_ip', + 'cuc_ip_hex', + 'count' => 'COUNT(*)', + 'first' => 'MIN(cuc_timestamp)', + 'last' => 'MAX(cuc_timestamp)', + ], + 'tables' => [ 'cu_changes' ], + 'conds' => [ 'cuc_user' => $this->target->getId() ], + 'options' => [ 'GROUP BY' => [ 'cuc_ip', 'cuc_ip_hex' ], 'USE INDEX' => 'cuc_user_ip_time' ], + ]; + } + + /** @inheritDoc */ + public function getIndexField() { + return 'last'; + } + + /** @inheritDoc */ + protected function getEmptyBody(): string { + return $this->noMatchesMessage( $this->target->getName() ) . "\n"; + } + + /** @inheritDoc */ + protected function getStartBody(): string { + return parent::getStartBody() . '<ul>'; + } + + /** @inheritDoc */ + protected function getEndBody(): string { + return '</ul></div>' . parent::getEndBody(); + } + + /** + * Temporary measure until Get IPs query is fixed for pagination. + * + * @return bool + */ + protected function isNavigationBarShown() { + return false; + } +} diff --git a/CheckUser/src/CheckUser/Pagers/CheckUserGetUsersPager.php b/CheckUser/src/CheckUser/Pagers/CheckUserGetUsersPager.php new file mode 100644 index 00000000..7fe9a5ba --- /dev/null +++ b/CheckUser/src/CheckUser/Pagers/CheckUserGetUsersPager.php @@ -0,0 +1,551 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser\Pagers; + +use ActorMigration; +use CentralIdLookup; +use Exception; +use ExtensionRegistry; +use FormOptions; +use Html; +use IContextSource; +use Linker; +use ListToggle; +use MediaWiki\Block\BlockPermissionCheckerFactory; +use MediaWiki\CheckUser\CheckUser\Widgets\HTMLFieldsetCheckUser; +use MediaWiki\CheckUser\CheckUserLogService; +use MediaWiki\CheckUser\Hooks as CUHooks; +use MediaWiki\CheckUser\TokenQueryManager; +use MediaWiki\Extension\CentralAuth\User\CentralAuthUser; +use MediaWiki\Linker\LinkRenderer; +use MediaWiki\Permissions\PermissionManager; +use MediaWiki\SpecialPage\SpecialPageFactory; +use MediaWiki\User\UserEditTracker; +use MediaWiki\User\UserFactory; +use MediaWiki\User\UserGroupManager; +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityLookup; +use MediaWiki\User\UserIdentityValue; +use WikiMap; +use Wikimedia\IPUtils; +use Wikimedia\Rdbms\ILoadBalancer; +use Wikimedia\Rdbms\IResultWrapper; +use Xml; + +class CheckUserGetUsersPager extends AbstractCheckUserPager { + + /** + * Boolean is $target is a IP / range. + * - False if XFF is not appended + * - True if XFF is appended + * + * @var bool + */ + protected $xfor = null; + + /** @var bool */ + protected $canPerformBlocks; + + /** @var array[] */ + protected $userSets; + + /** @var false|mixed */ + private $centralAuthToollink; + + /** @var false|mixed */ + private $globalBlockingToollink; + + /** @var array|array[] */ + private $aliases; + + /** @var BlockPermissionCheckerFactory */ + private $blockPermissionCheckerFactory; + + /** @var PermissionManager */ + private $permissionManager; + + /** @var UserEditTracker */ + private $userEditTracker; + + /** + * @param FormOptions $opts + * @param UserIdentity $target + * @param bool $xfor + * @param string $logType + * @param TokenQueryManager $tokenQueryManager + * @param PermissionManager $permissionManager + * @param BlockPermissionCheckerFactory $blockPermissionCheckerFactory + * @param UserGroupManager $userGroupManager + * @param CentralIdLookup $centralIdLookup + * @param ILoadBalancer $loadBalancer + * @param SpecialPageFactory $specialPageFactory + * @param UserIdentityLookup $userIdentityLookup + * @param ActorMigration $actorMigration + * @param UserFactory $userFactory + * @param CheckUserLogService $checkUserLogService + * @param UserEditTracker $userEditTracker + * @param IContextSource|null $context + * @param LinkRenderer|null $linkRenderer + * @param ?int $limit + */ + public function __construct( + FormOptions $opts, + UserIdentity $target, + bool $xfor, + string $logType, + TokenQueryManager $tokenQueryManager, + PermissionManager $permissionManager, + BlockPermissionCheckerFactory $blockPermissionCheckerFactory, + UserGroupManager $userGroupManager, + CentralIdLookup $centralIdLookup, + ILoadBalancer $loadBalancer, + SpecialPageFactory $specialPageFactory, + UserIdentityLookup $userIdentityLookup, + ActorMigration $actorMigration, + UserFactory $userFactory, + CheckUserLogService $checkUserLogService, + UserEditTracker $userEditTracker, + IContextSource $context = null, + LinkRenderer $linkRenderer = null, + ?int $limit = null + ) { + parent::__construct( $opts, $target, $logType, $tokenQueryManager, + $userGroupManager, $centralIdLookup, $loadBalancer, $specialPageFactory, + $userIdentityLookup, $actorMigration, $checkUserLogService, $userFactory, + $context, $linkRenderer, $limit ); + $this->xfor = $xfor; + $this->canPerformBlocks = $permissionManager->userHasRight( $this->getUser(), 'block' ) + && !$this->getUser()->getBlock(); + $this->centralAuthToollink = ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) + ? $this->getConfig()->get( 'CheckUserCAtoollink' ) : false; + $this->globalBlockingToollink = ExtensionRegistry::getInstance()->isLoaded( 'GlobalBlocking' ) + ? $this->getConfig()->get( 'CheckUserGBtoollink' ) : false; + $this->aliases = $this->getLanguage()->getSpecialPageAliases(); + $this->blockPermissionCheckerFactory = $blockPermissionCheckerFactory; + $this->permissionManager = $permissionManager; + $this->userEditTracker = $userEditTracker; + } + + /** + * Returns nothing as formatUserRow + * is instead used. + * + * @inheritDoc + */ + public function formatRow( $row ): string { + return ''; + } + + /** @inheritDoc */ + public function getBody() { + $this->getOutput()->addModuleStyles( $this->getModuleStyles() ); + if ( !$this->mQueryDone ) { + $this->doQuery(); + } + + if ( $this->mResult->numRows() ) { + # Do any special query batches before display + $this->doBatchLookups(); + } + + # Don't use any extra rows returned by the query + $numRows = count( $this->userSets['ids'] ); + + $s = $this->getStartBody(); + if ( $numRows ) { + $keys = array_keys( $this->userSets['ids'] ); + if ( $this->mIsBackwards ) { + $keys = array_reverse( $keys ); + } + foreach ( $keys as $user_text ) { + $s .= $this->formatUserRow( $user_text ); + } + $s .= $this->getFooter(); + } else { + $s .= $this->getEmptyBody(); + } + $s .= $this->getEndBody(); + return $s; + } + + /** + * Gets a row for the results for 'Get users' + * + * @param string $user_text the username for the current row. + * @return string + */ + public function formatUserRow( string $user_text ): string { + $templateParams = []; + $templateParams['canPerformBlocks'] = $this->canPerformBlocks; + $templateParams['userText'] = $user_text; + // Load user object + $user = new UserIdentityValue( $this->userSets['ids'][$user_text], $user_text ); + $userNonExistent = !IPUtils::isIPAddress( $user ) && !$user->isRegistered(); + if ( $userNonExistent ) { + $templateParams['userLinkClass'] = 'mw-checkuser-nonexistent-user'; + } + $templateParams['userLink'] = Linker::userLink( $user->getId(), $user, $user ); + $templateParams['userToolLinks'] = Linker::userToolLinksRedContribs( + $user->getId(), + $user, + $this->userEditTracker->getUserEditCount( $user ), + // don't render parentheses in HTML markup (CSS will provide) + false + ); + $ip = IPUtils::isIPAddress( $user ) ? $user : ''; + if ( $ip ) { + $templateParams['userLinks'] = $this->msg( 'checkuser-userlinks-ip', $user )->parse(); + } elseif ( !$userNonExistent ) { + if ( $this->msg( 'checkuser-userlinks' )->exists() ) { + $templateParams['userLinks'] = + $this->msg( 'checkuser-userlinks', htmlspecialchars( $user ) )->parse(); + } + } + // Add CheckUser link + $templateParams['checkLink'] = $this->getSelfLink( + $this->msg( 'checkuser-check' )->text(), + [ + 'user' => $user, + 'reason' => $this->opts->getValue( 'reason' ) + ] + ); + // Add global user tools links + // Add CentralAuth link for real registered users + if ( $this->centralAuthToollink !== false + && !IPUtils::isIPAddress( $user_text ) + && !$userNonExistent + ) { + // Get CentralAuth SpecialPage name in UserLang from the first Alias name + $spca = $this->aliases['CentralAuth'][0]; + $calinkAlias = str_replace( '_', ' ', $spca ); + $centralCAUrl = WikiMap::getForeignURL( + $this->centralAuthToollink, + 'Special:CentralAuth' + ); + if ( $centralCAUrl === false ) { + throw new Exception( + "Could not retrieve URL for CentralAuth: $this->centralAuthToollink" + ); + } + $linkCA = Html::element( 'a', + [ + 'href' => $centralCAUrl . "/" . $user, + 'title' => $this->msg( 'centralauth' )->text(), + ], + $calinkAlias + ); + $templateParams['centralAuthLink'] = $this->msg( 'parentheses' )->rawParams( $linkCA )->escaped(); + } + // Add GlobalBlocking link to CentralWiki + if ( $this->globalBlockingToollink !== false + && IPUtils::isIPAddress( $user ) + ) { + // Get GlobalBlock SpecialPage name in UserLang from the first Alias name + $centralGBUrl = WikiMap::getForeignURL( + $this->globalBlockingToollink['centralDB'], + 'Special:GlobalBlock' + ); + $spgb = $this->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 global blocking toollink' + ); + } + $linkGB = Html::element( 'a', + [ + 'href' => $centralGBUrl . "/" . $user, + 'title' => $this->msg( 'globalblocking-block-submit' )->text(), + ], + $gblinkAlias + ); + } elseif ( $centralGBUrl !== false ) { + // Case wikimap configured without CentralAuth extension + // Get effective Local user groups since there is a wikimap but there is no CA + $gbUserGroups = $this->userGroupManager->getUserEffectiveGroups( $this->getUser() ); + $linkGB = Html::element( 'a', + [ + 'href' => $centralGBUrl . "/" . $user, + 'title' => $this->msg( 'globalblocking-block-submit' )->text(), + ], + $gblinkAlias + ); + } else { + // Load local user group instead + $gbUserGroups = [ '' ]; + $gbtitle = $this->getPageTitle( 'GlobalBlock' ); + $linkGB = $this->getLinkRenderer()->makeKnownLink( + $gbtitle, + $gblinkAlias, + [ 'title' => $this->msg( 'globalblocking-block-submit' ) ] + ); + $gbUserCanDo = $this->permissionManager->userHasRight( $this->getUser(), 'globalblock' ); + if ( $gbUserCanDo ) { + $this->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( $this->globalBlockingToollink['groups'], $gbUserGroups ) ) ) { + $templateParams['globalBlockLink'] .= $this->msg( 'parentheses' )->rawParams( $linkGB )->escaped(); + } + } + // Show edit time range + $templateParams['timeRange'] = $this->getTimeRangeString( + $this->userSets['first'][$user_text], + $this->userSets['last'][$user_text] + ); + // Total edit count + $templateParams['editCount'] = $this->userSets['edits'][$user_text]; + // Check if this user or IP is blocked. If so, give a link to the block log... + $templateParams['flags'] = $this->userBlockFlags( $ip, $user ); + // List out each IP/XFF combo for this username + $templateParams['infoSets'] = []; + for ( $i = ( count( $this->userSets['infosets'][$user_text] ) - 1 ); $i >= 0; $i-- ) { + // users_infosets[$name][$i] is array of [ $row->cuc_ip, XFF ]; + $row = []; + list( $clientIP, $xffString ) = $this->userSets['infosets'][$user_text][$i]; + // IP link + $row['ipLink'] = $this->getSelfLink( $clientIP, [ 'user' => $clientIP ] ); + // XFF string, link to /xff search + if ( $xffString ) { + // Flag our trusted proxies + list( $client ) = CUHooks::getClientIPfromXFF( $xffString ); + // XFF was trusted if client came from it + $trusted = ( $client === $clientIP ); + $row['xffTrusted'] = $trusted; + $row['xff'] = $this->getSelfLink( $xffString, [ 'user' => $client . '/xff' ] ); + } + $templateParams['infoSets'][] = $row; + } + // List out each agent for this username + for ( $i = ( count( $this->userSets['agentsets'][$user_text] ) - 1 ); $i >= 0; $i-- ) { + $templateParams['agentsList'][] = $this->userSets['agentsets'][$user_text][$i]; + } + return $this->templateParser->processTemplate( 'GetUsersLine', $templateParams ); + } + + /** + * @param IResultWrapper $result + * @return array[] + */ + protected function preprocessResults( $result ): array { + $this->userSets = [ + 'first' => [], + 'last' => [], + 'edits' => [], + 'ids' => [], + 'infosets' => [], + 'agentsets' => [] + ]; + + foreach ( $result as $row ) { + if ( !array_key_exists( $row->cuc_user_text, $this->userSets['edits'] ) ) { + $this->userSets['last'][$row->cuc_user_text] = $row->cuc_timestamp; + $this->userSets['edits'][$row->cuc_user_text] = 0; + $this->userSets['ids'][$row->cuc_user_text] = $row->cuc_user; + $this->userSets['infosets'][$row->cuc_user_text] = []; + $this->userSets['agentsets'][$row->cuc_user_text] = []; + } + $this->userSets['edits'][$row->cuc_user_text]++; + $this->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, $this->userSets['infosets'][$row->cuc_user_text] ) ) { + $this->userSets['infosets'][$row->cuc_user_text][] = $xff_ip_combo; + } + // Add this agent string if it's not already there; 10 max. + if ( count( $this->userSets['agentsets'][$row->cuc_user_text] ) < 10 ) { + if ( !in_array( $row->cuc_agent, $this->userSets['agentsets'][$row->cuc_user_text] ) ) { + $this->userSets['agentsets'][$row->cuc_user_text][] = $row->cuc_agent; + } + } + } + + return $this->userSets; + } + + /** @inheritDoc */ + public function getQueryInfo(): array { + $queryInfo = [ + 'fields' => [ + 'cuc_user_text', 'cuc_timestamp', 'cuc_user', 'cuc_ip', 'cuc_agent', 'cuc_xff', + ], + 'tables' => [ 'cu_changes' ], + 'conds' => [], + 'options' => [ 'USE INDEX' => $this->xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time' ], + ]; + $ipConds = self::getIpConds( $this->mDb, $this->target->getName(), $this->xfor ); + if ( $ipConds ) { + $queryInfo['conds'] = array_merge( $queryInfo['conds'], $ipConds ); + } + return $queryInfo; + } + + /** @inheritDoc */ + public function getIndexField() { + return 'cuc_timestamp'; + } + + /** @inheritDoc */ + protected function getStartBody(): string { + $s = $this->getNavigationBar() + . ( new ListToggle( $this->getOutput() ) )->getHTML(); + if ( $this->canPerformBlocks ) { + $s .= Xml::openElement( + 'form', + [ + 'action' => $this->getPageTitle()->getLocalURL( 'action=block' ), + 'id' => 'checkuserblock', + 'name' => 'checkuserblock', + 'class' => 'mw-htmlform-ooui mw-htmlform', + 'method' => 'post', + ] + ); + } + + $s .= '<div id="checkuserresults"><ul>'; + + return $s; + } + + /** @inheritDoc */ + protected function getEndBody(): string { + $fieldset = new HTMLFieldsetCheckUser( [], $this->getContext(), '' ); + $s = '</ul></div>' + . ( new ListToggle( $this->getOutput() ) )->getHTML(); + // T314217 - cannot have forms inside of forms. + // $s .= $this->getNavigationBar(); + if ( $this->canPerformBlocks ) { + $config = $this->getConfig(); + $checkUserCAMultiLock = $config->get( 'CheckUserCAMultiLock' ); + if ( $checkUserCAMultiLock !== false ) { + if ( !ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) ) { + // $wgCheckUserCAMultiLock shouldn't be enabled if CA is not loaded + throw new Exception( '$wgCheckUserCAMultiLock requires CentralAuth extension.' ); + } + + $caUserGroups = CentralAuthUser::getInstance( $this->getUser() )->getGlobalGroups(); + // Only load the script for users in the configured global group(s) + if ( count( array_intersect( $checkUserCAMultiLock['groups'], $caUserGroups ) ) ) { + $out = $this->getOutput(); + $centralMLUrl = WikiMap::getForeignURL( + $checkUserCAMultiLock['centralDB'], + // Use canonical name instead of local name so that it works + // even if the local language is different from central wiki + 'Special:MultiLock' + ); + if ( $centralMLUrl === false ) { + throw new Exception( + "Could not retrieve URL for {$checkUserCAMultiLock['centralDB']}" + ); + } + $out->addJsConfigVars( 'wgCUCAMultiLockCentral', $centralMLUrl ); + $out->addModules( 'ext.checkUser' ); + } + } + + $fields = [ + 'usetag' => [ + 'type' => 'check', + 'default' => false, + 'label-message' => 'checkuser-blocktag', + 'id' => 'usetag', + 'name' => 'usetag', + 'size' => 46, + ], + 'tag' => [ + 'type' => 'text', + 'id' => 'blocktag', + 'name' => 'blocktag', + ], + 'talkusetag' => [ + 'type' => 'check', + 'default' => false, + 'label-message' => 'checkuser-blocktag-talk', + 'id' => 'usettag', + 'name' => 'usettag', + ], + 'talktag' => [ + 'type' => 'text', + 'id' => 'talktag', + 'name' => 'talktag', + 'size' => 46, + ], + ]; + + $fieldset->addFields( $fields ) + ->setWrapperLegendMsg( 'checkuser-massblock' ) + ->setSubmitTextMsg( 'checkuser-massblock-commit' ) + ->setSubmitId( 'checkuserblocksubmit' ) + ->setSubmitName( 'checkuserblock' ) + ->setHeaderHtml( $this->msg( 'checkuser-massblock-text' )->text() ); + + if ( $config->get( 'BlockAllowsUTEdit' ) ) { + $fieldset->addFields( [ + 'blocktalk' => [ + 'type' => 'check', + 'default' => false, + 'label-message' => 'checkuser-blocktalk', + 'id' => 'blocktalk', + 'name' => 'blocktalk', + ] + ] ); + } + + if ( + $this->blockPermissionCheckerFactory + ->newBlockPermissionChecker( + null, + $this->getUser() + ) + ->checkEmailPermissions() + ) { + $fieldset->addFields( [ + 'blockemail' => [ + 'type' => 'check', + 'default' => false, + 'label-message' => 'checkuser-blockemail', + 'id' => 'blockemail', + 'name' => 'blockemail', + ] + ] ); + } + + $s .= $fieldset + ->addFields( [ + 'reblock' => [ + 'type' => 'check', + 'default' => false, + 'label-message' => 'checkuser-reblock', + 'id' => 'reblock', + 'name' => 'reblock', + ], + 'reason' => [ + 'type' => 'text', + 'label-message' => 'checkuser-reason', + 'size' => 46, + 'maxlength' => 150, + 'id' => 'blockreason', + 'name' => 'blockreason', + 'required' => true + ], + ] ) + ->prepareForm() + ->getHtml( false ); + $s .= '</form>'; + } + + return $s; + } + + /** @inheritDoc */ + protected function getEmptyBody(): string { + return $this->noMatchesMessage( $this->target->getName(), !$this->xfor ) . "\n"; + } +} diff --git a/CheckUser/src/CheckUser/Pagers/CheckUserLogPager.php b/CheckUser/src/CheckUser/Pagers/CheckUserLogPager.php new file mode 100644 index 00000000..54a46a94 --- /dev/null +++ b/CheckUser/src/CheckUser/Pagers/CheckUserLogPager.php @@ -0,0 +1,305 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser\Pagers; + +use CommentStore; +use Html; +use IContextSource; +use Linker; +use MediaWiki\Cache\LinkBatchFactory; +use MediaWiki\CheckUser\CheckUser\SpecialCheckUserLog; +use RangeChronologicalPager; +use SpecialPage; +use Wikimedia\Rdbms\IResultWrapper; + +class CheckUserLogPager extends RangeChronologicalPager { + /** @var array */ + protected $searchConds; + + /** @var LinkBatchFactory */ + private $linkBatchFactory; + + /** @var CommentStore */ + private $commentStore; + + /** @var array */ + private $opts; + + /** + * @param IContextSource $context + * @param array $opts A array of keys that can include 'target', 'initiator', 'start', 'end' + * 'year' and 'month'. Target should be a user, IP address or IP range. Initiator should be a user. + * Start and end should be timestamps. Year and month are converted to end but ignored if end is + * provided. + * @param LinkBatchFactory $linkBatchFactory + * @param CommentStore $commentStore + */ + public function __construct( + IContextSource $context, + array $opts, + LinkBatchFactory $linkBatchFactory, + CommentStore $commentStore + ) { + parent::__construct( $context ); + // Default to all log entries - we'll add conditions below if a target was provided + $targetSearchConds = []; + $initiatorSearchConds = []; + + if ( $opts['target'] !== '' ) { + $targetSearchConds = $this->getTargetSearchConds( $opts['target'] ); + } + + if ( $opts['initiator'] !== '' ) { + $initiatorSearchConds = $this->getPerformerSearchConds( $opts['initiator'] ); + } + + if ( $targetSearchConds === null || $initiatorSearchConds === null ) { + throw new \Exception( 'An invalid initiator or target was provided.' ); + } + + $this->searchConds = array_merge( $targetSearchConds, $initiatorSearchConds ); + + // Date filtering: use timestamp if available - From SpecialContributions.php + $startTimestamp = ''; + $endTimestamp = ''; + if ( isset( $opts['start'] ) && $opts['start'] ) { + $startTimestamp = $opts['start'] . ' 00:00:00'; + } + if ( isset( $opts['end'] ) && $opts['end'] ) { + $endTimestamp = $opts['end'] . ' 23:59:59'; + } + $this->getDateRangeCond( $startTimestamp, $endTimestamp ); + $this->linkBatchFactory = $linkBatchFactory; + $this->commentStore = $commentStore; + $this->opts = $opts; + } + + /** + * If appropriate, generate a link that wraps around the provided date, time, or + * date and time. The date and time is escaped by this function. + * + * @param string $dateAndTime The string representation of the date, time or date and time. + * @param array|\stdClass $row The current row being formatted in formatRow(). + * @return string|null The date and time wrapped in a link if appropriate. + */ + protected function generateTimestampLink( string $dateAndTime, $row ) { + $highlight = $this->getRequest()->getVal( 'highlight' ); + // Add appropriate classes to the date and time. + $dateAndTimeClasses = []; + if ( + $highlight === strval( $row->cul_timestamp ) + ) { + $dateAndTimeClasses[] = 'mw-checkuser-log-highlight-entry'; + } + // If the CU log search has a specified target or initiator then + // provide a link to this log entry without the current filtering + // for these values. + if ( + $this->opts['target'] || + $this->opts['initiator'] + ) { + return $this->getLinkRenderer()->makeLink( + SpecialPage::getTitleFor( 'CheckUserLog' ), + $dateAndTime, + [ + 'class' => $dateAndTimeClasses, + ], + [ + 'offset' => $row->cul_timestamp + 3600, + 'highlight' => $row->cul_timestamp, + ] + ); + } elseif ( $dateAndTimeClasses ) { + return Html::element( + 'span', + [ 'class' => $dateAndTimeClasses ], + $dateAndTime + ); + } else { + return htmlspecialchars( $dateAndTime ); + } + } + + /** + * @inheritDoc + */ + public function formatRow( $row ) { + $user = Linker::userLink( $row->cul_user, $row->user_name ) . + $this->msg( 'word-separator' )->escaped() + . Html::rawElement( 'span', [ 'classes' => 'mw-usertoollinks' ], + $this->msg( 'parentheses' )->params( $this->getLinkRenderer()->makeLink( + SpecialPage::getTitleFor( 'CheckUserLog' ), + $this->msg( 'checkuser-log-checks-by' )->text(), + [], + [ + 'cuInitiator' => $row->user_name, + ] + ) )->text() + ); + + $target = Linker::userLink( $row->cul_target_id, $row->cul_target_text ) . + Linker::userToolLinks( $row->cul_target_id, trim( $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 + // checkuser-log-entry-ipusers-xff, checkuser-log-entry-useredits + $rowContent = $this->msg( + 'checkuser-log-entry-' . $row->cul_type, + $user, + $target, + $this->generateTimestampLink( + $lang->userTimeAndDate( + wfTimestamp( TS_MW, $row->cul_timestamp ), $contextUser + ), + $row + ), + $this->generateTimestampLink( + $lang->userDate( wfTimestamp( TS_MW, $row->cul_timestamp ), $contextUser ), + $row + ), + $this->generateTimestampLink( + $lang->userTime( wfTimestamp( TS_MW, $row->cul_timestamp ), $contextUser ), + $row + ) + )->text(); + $rowContent .= Linker::commentBlock( $row->cul_reason ); + + $attribs = [ + 'data-mw-culogid' => $row->cul_id, + ]; + return Html::rawElement( 'li', $attribs, $rowContent ) . "\n"; + } + + /** + * @return string + */ + public function getStartBody() { + if ( $this->getNumRows() ) { + return '<ul>'; + } + + return ''; + } + + /** + * @return string + */ + public function getEndBody() { + if ( $this->getNumRows() ) { + return '</ul>'; + } + + return ''; + } + + /** + * @return string + */ + public function getEmptyBody() { + return '<p>' . $this->msg( 'checkuser-empty' )->escaped() . '</p>'; + } + + /** + * @inheritDoc + */ + public function getQueryInfo() { + return [ + 'tables' => [ 'cu_log', 'user' ], + 'fields' => $this->selectFields(), + 'conds' => array_merge( $this->searchConds, [ 'user_id = cul_user' ] ) + ]; + } + + /** + * @inheritDoc + */ + public function getIndexField() { + return 'cul_timestamp'; + } + + /** + * @inheritDoc + */ + public function selectFields() { + return [ + 'cul_id', 'cul_timestamp', 'cul_user', 'cul_reason', 'cul_type', + 'cul_target_id', 'cul_target_text', 'user_name' + ]; + } + + /** + * Do a batch query for links' existence and add it to LinkCache + * + * @param IResultWrapper $result + */ + protected function preprocessResults( $result ) { + if ( $this->getNumRows() === 0 ) { + return; + } + + $lb = $this->linkBatchFactory->newLinkBatch(); + $lb->setCaller( __METHOD__ ); + foreach ( $result as $row ) { + // Performer + $lb->add( NS_USER, $row->user_name ); + + if ( $row->cul_type == 'userips' || $row->cul_type == 'useredits' ) { + $lb->add( NS_USER, $row->cul_target_text ); + $lb->add( NS_USER_TALK, $row->cul_target_text ); + } + } + $lb->execute(); + $result->seek( 0 ); + } + + /** + * Get DB search conditions for the initiator + * + * @param string $initiator the username of the initiator. + * @return array|null array if valid target, null if invalid + */ + public static function getPerformerSearchConds( string $initiator ) { + $initiatorObject = SpecialCheckUserLog::verifyInitiator( $initiator ); + if ( $initiatorObject !== false ) { + return [ 'cul_user' => $initiatorObject ]; + } + return null; + } + + /** + * Get DB search conditions according to the CU target given. + * + * @param string $target the username, IP address or range of the target. + * @return array|null array if valid target, null if invalid target given + */ + public static function getTargetSearchConds( string $target ) { + $dbr = wfGetDB( DB_REPLICA ); + $result = SpecialCheckUserLog::verifyTarget( $target ); + if ( is_array( $result ) ) { + switch ( count( $result ) ) { + case 1: + return [ + 'cul_target_hex = ' . $dbr->addQuotes( $result[0] ) . ' OR ' . + '(cul_range_end >= ' . $dbr->addQuotes( $result[0] ) . ' AND ' . + 'cul_range_start <= ' . $dbr->addQuotes( $result[0] ) . ')' + ]; + case 2: + return [ + '(cul_target_hex >= ' . $dbr->addQuotes( $result[0] ) . ' AND ' . + 'cul_target_hex <= ' . $dbr->addQuotes( $result[1] ) . ') OR ' . + '(cul_range_end >= ' . $dbr->addQuotes( $result[0] ) . ' AND ' . + 'cul_range_start <= ' . $dbr->addQuotes( $result[1] ) . ')' + ]; + } + } elseif ( is_int( $result ) ) { + return [ + 'cul_type' => [ 'userips', 'useredits', 'investigate' ], + 'cul_target_id' => $result, + ]; + } + return null; + } +} diff --git a/CheckUser/src/CheckUser/SpecialCheckUser.php b/CheckUser/src/CheckUser/SpecialCheckUser.php new file mode 100644 index 00000000..e02ea647 --- /dev/null +++ b/CheckUser/src/CheckUser/SpecialCheckUser.php @@ -0,0 +1,781 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser; + +use ActorMigration; +use CentralIdLookup; +use FormOptions; +use Html; +use HTMLForm; +use MediaWiki\Block\BlockPermissionCheckerFactory; +use MediaWiki\Block\BlockUserFactory; +use MediaWiki\Cache\LinkBatchFactory; +use MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager; +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetEditsPager; +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetIPsPager; +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetUsersPager; +use MediaWiki\CheckUser\CheckUser\Widgets\HTMLFieldsetCheckUser; +use MediaWiki\CheckUser\CheckUser\Widgets\HTMLTextFieldNoDisabledStyling; +use MediaWiki\CheckUser\CheckUserLogService; +use MediaWiki\CheckUser\TokenQueryManager; +use MediaWiki\CommentFormatter\CommentFormatter; +use MediaWiki\Page\WikiPageFactory; +use MediaWiki\Permissions\PermissionManager; +use MediaWiki\Revision\RevisionStore; +use MediaWiki\User\CentralId\CentralIdLookupFactory; +use MediaWiki\User\UserEditTracker; +use MediaWiki\User\UserFactory; +use MediaWiki\User\UserGroupManager; +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityLookup; +use MediaWiki\User\UserIdentityValue; +use MediaWiki\User\UserNamePrefixSearch; +use MediaWiki\User\UserNameUtils; +use MediaWiki\User\UserRigorOptions; +use Message; +use OOUI\IconWidget; +use SpecialPage; +use Title; +use UserBlockedError; +use Wikimedia\AtEase\AtEase; +use Wikimedia\IPUtils; +use Wikimedia\Rdbms\ILoadBalancer; +use WikitextContent; + +class SpecialCheckUser extends SpecialPage { + /** + * The possible subtypes represented as constants. + * The constants represent the old string values + * for backwards compatibility. + */ + public const SUBTYPE_GET_IPS = 'subuserips'; + + public const SUBTYPE_GET_EDITS = 'subedits'; + + public const SUBTYPE_GET_USERS = 'subipusers'; + + /** + * @var FormOptions the form parameters. + */ + protected $opts; + + /** @var LinkBatchFactory */ + private $linkBatchFactory; + + /** @var BlockPermissionCheckerFactory */ + private $blockPermissionCheckerFactory; + + /** @var BlockUserFactory */ + private $blockUserFactory; + + /** @var UserGroupManager */ + private $userGroupManager; + + /** @var CentralIdLookup */ + private $centralIdLookup; + + /** @var WikiPageFactory */ + private $wikiPageFactory; + + /** @var PermissionManager */ + private $permissionManager; + + /** @var UserIdentityLookup */ + private $userIdentityLookup; + + /** @var TokenQueryManager */ + private $tokenQueryManager; + + /** @var ILoadBalancer */ + private $loadBalancer; + + /** @var ActorMigration */ + private $actorMigration; + + /** @var UserFactory */ + private $userFactory; + + /** @var RevisionStore */ + private $revisionStore; + + /** @var CheckUserLogService */ + private $checkUserLogService; + + /** @var CommentFormatter */ + private $commentFormatter; + + /** @var UserEditTracker */ + private $userEditTracker; + + /** @var UserNamePrefixSearch */ + private $userNamePrefixSearch; + + /** @var UserNameUtils */ + private $userNameUtils; + + /** + * @param LinkBatchFactory $linkBatchFactory + * @param BlockPermissionCheckerFactory $blockPermissionCheckerFactory + * @param BlockUserFactory $blockUserFactory + * @param UserGroupManager $userGroupManager + * @param CentralIdLookupFactory $centralIdLookupFactory + * @param WikiPageFactory $wikiPageFactory + * @param PermissionManager $permissionManager + * @param UserIdentityLookup $userIdentityLookup + * @param TokenQueryManager $tokenQueryManager + * @param ILoadBalancer $loadBalancer + * @param ActorMigration $actorMigration + * @param UserFactory $userFactory + * @param RevisionStore $revisionStore + * @param CheckUserLogService $checkUserLogService + * @param CommentFormatter $commentFormatter + * @param UserEditTracker $userEditTracker + * @param UserNamePrefixSearch $userNamePrefixSearch + * @param UserNameUtils $userNameUtils + */ + public function __construct( + LinkBatchFactory $linkBatchFactory, + BlockPermissionCheckerFactory $blockPermissionCheckerFactory, + BlockUserFactory $blockUserFactory, + UserGroupManager $userGroupManager, + CentralIdLookupFactory $centralIdLookupFactory, + WikiPageFactory $wikiPageFactory, + PermissionManager $permissionManager, + UserIdentityLookup $userIdentityLookup, + TokenQueryManager $tokenQueryManager, + ILoadBalancer $loadBalancer, + ActorMigration $actorMigration, + UserFactory $userFactory, + RevisionStore $revisionStore, + CheckUserLogService $checkUserLogService, + CommentFormatter $commentFormatter, + UserEditTracker $userEditTracker, + UserNamePrefixSearch $userNamePrefixSearch, + UserNameUtils $userNameUtils + ) { + parent::__construct( 'CheckUser', 'checkuser' ); + + $this->linkBatchFactory = $linkBatchFactory; + $this->blockPermissionCheckerFactory = $blockPermissionCheckerFactory; + $this->blockUserFactory = $blockUserFactory; + $this->userGroupManager = $userGroupManager; + $this->centralIdLookup = $centralIdLookupFactory->getLookup(); + $this->wikiPageFactory = $wikiPageFactory; + $this->permissionManager = $permissionManager; + $this->userIdentityLookup = $userIdentityLookup; + $this->tokenQueryManager = $tokenQueryManager; + $this->loadBalancer = $loadBalancer; + $this->actorMigration = $actorMigration; + $this->userFactory = $userFactory; + $this->revisionStore = $revisionStore; + $this->checkUserLogService = $checkUserLogService; + $this->commentFormatter = $commentFormatter; + $this->userEditTracker = $userEditTracker; + $this->userNamePrefixSearch = $userNamePrefixSearch; + $this->userNameUtils = $userNameUtils; + } + + public function doesWrites() { + // logging + return true; + } + + /** @inheritDoc */ + 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) + $block = $this->getUser()->getBlock(); + if ( $block && $block->isSitewide() ) { + throw new UserBlockedError( $block ); + } + + $request = $this->getRequest(); + + $opts = new FormOptions(); + $opts->add( 'reason', '' ); + $opts->add( 'checktype', '' ); + $opts->add( 'period', 0 ); + $opts->add( 'offset', '' ); + $opts->add( 'limit', 0 ); + $opts->add( 'dir', '' ); + $opts->add( 'token', '' ); + $opts->add( 'action', '' ); + $opts->add( 'users', [] ); + $opts->add( 'blockreason', '' ); + $opts->add( 'blocktalk', false ); + $opts->add( 'blockemail', false ); + $opts->add( 'reblock', false ); + $opts->add( 'usetag', false ); + $opts->add( 'usettag', false ); + $opts->add( 'blocktag', '' ); + $opts->add( 'talktag', '' ); + $opts->fetchValuesFromRequest( $request ); + + // If the client has provided a token, they are trying to paginate. + // If the token is valid, then use the values from this and later + // don't log this as a new check. + $tokenData = $this->tokenQueryManager->getDataFromRequest( $this->getRequest() ); + $validatedRequest = $this->getRequest(); + $user = ''; + if ( $tokenData ) { + foreach ( + array_diff( AbstractCheckUserPager::TOKEN_MANAGED_FIELDS, array_keys( $tokenData ) ) as $key + ) { + $opts->reset( $key ); + $validatedRequest->unsetVal( $key ); + } + foreach ( $tokenData as $key => $value ) { + // Update the FormOptions + if ( $key === 'user' ) { + $user = $value; + } else { + $opts->setValue( $key, $value, true ); + } + // Update the actual request so that IndexPager.php reads the validated values. + // (used for dir, offset and limit) + $validatedRequest->setVal( $key, $value ); + } + } else { + $user = trim( + $request->getText( 'user', $request->getText( 'ip', $subPage ?? '' ) ) + ); + } + $this->getContext()->setRequest( $validatedRequest ); + $this->opts = $opts; + + // Normalise 'user' parameter and ignore if not valid (T217713) + // It must be valid when making a link to Special:CheckUserLog/<user>. + $userTitle = Title::makeTitleSafe( NS_USER, $user ); + $user = $userTitle ? $userTitle->getText() : ''; + + $out = $this->getOutput(); + if ( $this->permissionManager->userHasRight( $this->getUser(), 'checkuser-log' ) ) { + $subtitleLink = Html::rawElement( + 'span', + [], + $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'CheckUserLog' ), + $this->msg( 'checkuser-showlog' )->text() + ) + ); + if ( $user !== '' ) { + $subtitleLink .= Html::rawElement( + 'span', + [], + $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'CheckUserLog', $user ), + $this->msg( 'checkuser-recent-checks' )->text() + ) + ); + } + $out->addSubtitle( Html::rawElement( + 'span', + [ 'class' => 'mw-checkuser-links-no-parentheses' ], + $subtitleLink + ) + ); + } + + if ( $this->getConfig()->get( 'CheckUserEnableSpecialInvestigate' ) ) { + $out->enableOOUI(); + $out->addModuleStyles( 'oojs-ui.styles.icons-interactions' ); + $icon = new IconWidget( [ 'icon' => 'lightbulb' ] ); + $investigateLink = $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'Investigate' ), + $this->msg( 'checkuser-link-investigate-label' )->text() + ); + $out->setIndicators( [ 'investigate-link' => $icon . $investigateLink ] ); + } + + $userIdentity = null; + $isIP = false; + $xfor = false; + $m = []; + if ( IPUtils::isIPAddress( $user ) ) { + // A single IP address or an IP range + $userIdentity = UserIdentityValue::newAnonymous( IPUtils::sanitizeIP( $user ) ); + $isIP = true; + } elseif ( preg_match( '/^(.+)\/xff$/', $user, $m ) && IPUtils::isIPAddress( $m[1] ) ) { + // A single IP address or range with XFF string included + $userIdentity = UserIdentityValue::newAnonymous( IPUtils::sanitizeIP( $m[1] ) ); + $xfor = true; + $isIP = true; + } else { + // A user? + if ( $user ) { + $userIdentity = $this->userIdentityLookup->getUserIdentityByName( $user ); + } + } + + $this->showIntroductoryText(); + $this->showForm( $user, $isIP ); + + // Perform one of the various submit operations... + if ( $request->wasPosted() ) { + $checkType = $this->opts->getValue( 'checktype' ); + if ( !$this->getUser()->matchEditToken( $request->getVal( 'wpEditToken' ) ) ) { + $out->wrapWikiMsg( '<div class="error">$1</div>', 'checkuser-token-fail' ); + } elseif ( $this->opts->getValue( 'action' ) === 'block' ) { + $this->doMassUserBlock(); + } elseif ( !$this->checkReason() ) { + $out->addWikiMsg( 'checkuser-noreason' ); + } elseif ( $checkType == self::SUBTYPE_GET_IPS ) { + if ( $isIP || !$user ) { + $out->addWikiMsg( 'nouserspecified' ); + } elseif ( !$userIdentity || !$userIdentity->getId() ) { + $out->addWikiMsg( 'nosuchusershort', $user ); + } else { + $pager = $this->getPager( self::SUBTYPE_GET_IPS, $userIdentity, 'userips' ); + $out->addHtml( $pager->getBody() ); + } + } elseif ( $checkType == self::SUBTYPE_GET_EDITS ) { + if ( $isIP && $userIdentity ) { + // Target is a IP or range + if ( !AbstractCheckUserPager::isValidRange( $userIdentity->getName() ) ) { + $out->addWikiMsg( 'checkuser-range-outside-limit', $userIdentity->getName() ); + } else { + $logType = $xfor ? 'ipedits-xff' : 'ipedits'; + + // Ordered in descent by timestamp. Can cause large filesorts on range scans. + $pager = $this->getPager( self::SUBTYPE_GET_EDITS, $userIdentity, $logType, $xfor ); + $out->addHTML( $pager->getBody() ); + } + } else { + // Target is a username + if ( !$user ) { + $out->addWikiMsg( 'nouserspecified' ); + } elseif ( !$userIdentity || !$userIdentity->getId() ) { + $out->addHTML( $this->msg( 'nosuchusershort', $user )->parseAsBlock() ); + } else { + // Sorting might take some time + AtEase::suppressWarnings(); + set_time_limit( 60 ); + AtEase::restoreWarnings(); + + $pager = $this->getPager( self::SUBTYPE_GET_EDITS, $userIdentity, 'useredits' ); + $out->addHTML( $pager->getBody() ); + } + } + } elseif ( $checkType == self::SUBTYPE_GET_USERS ) { + if ( !$isIP || !$userIdentity ) { + $out->addWikiMsg( 'badipaddress' ); + } elseif ( !AbstractCheckUserPager::isValidRange( $userIdentity->getName() ) ) { + $out->addWikiMsg( 'checkuser-range-outside-limit', $userIdentity->getName() ); + } else { + $logType = $xfor ? 'ipusers-xff' : 'ipusers'; + + $pager = $this->getPager( self::SUBTYPE_GET_USERS, $userIdentity, $logType, $xfor ); + $out->addHTML( $pager->getBody() ); + } + } + } + // Add CIDR calculation convenience JS form + $this->addJsCIDRForm(); + $out->addModules( 'ext.checkUser' ); + $out->addModuleStyles( [ + 'mediawiki.interface.helpers.styles', + 'ext.checkUser.styles', + ] ); + } + + protected function showIntroductoryText() { + $config = $this->getConfig(); + $cidrLimit = $config->get( 'CheckUserCIDRLimit' ); + $maximumRowCount = $config->get( 'CheckUserMaximumRowCount' ); + $this->getOutput()->addWikiMsg( + 'checkuser-summary', + $cidrLimit['IPv4'], + $cidrLimit['IPv6'], + Message::numParam( $maximumRowCount ) + ); + } + + /** + * Show the CheckUser query form + * + * @param string $user + * @param bool $isIP + */ + protected function showForm( string $user, bool $isIP ) { + // Fill in requested type if it makes sense + $ipAllowed = true; + $checktype = $this->opts->getValue( 'checktype' ); + if ( $checktype == self::SUBTYPE_GET_USERS && $isIP ) { + $checkTypeValidated = $checktype; + $ipAllowed = false; + } elseif ( $checktype == self::SUBTYPE_GET_IPS && !$isIP ) { + $checkTypeValidated = $checktype; + } elseif ( $checktype == self::SUBTYPE_GET_EDITS ) { + $checkTypeValidated = $checktype; + // Defaults otherwise + } elseif ( $isIP ) { + $checkTypeValidated = self::SUBTYPE_GET_EDITS; + } else { + $checkTypeValidated = self::SUBTYPE_GET_IPS; + $ipAllowed = false; + } + + $fields = [ + 'target' => [ + 'type' => 'user', + // validation in execute() currently + 'exists' => false, + 'ipallowed' => $ipAllowed, + 'iprange' => $ipAllowed, + 'name' => 'user', + 'label-message' => 'checkuser-target', + 'default' => $user, + 'id' => 'checktarget', + ], + 'radiooptions' => [ + 'type' => 'radio', + 'options-messages' => [ + 'checkuser-ips' => self::SUBTYPE_GET_IPS, + 'checkuser-edits' => self::SUBTYPE_GET_EDITS, + 'checkuser-users' => self::SUBTYPE_GET_USERS, + ], + 'id' => 'checkuserradios', + 'default' => $checkTypeValidated, + 'name' => 'checktype', + 'nodata' => 'yes', + 'flatlist' => true, + ], + 'period' => [ + 'type' => 'select', + 'id' => 'period', + 'label-message' => 'checkuser-period', + 'options-messages' => [ + 'checkuser-week-1' => 7, + 'checkuser-week-2' => 14, + 'checkuser-month' => 30, + 'checkuser-month-2' => 60, + 'checkuser-all' => 0, + ], + 'default' => $this->opts->getValue( 'period' ), + 'name' => 'period', + ], + 'reason' => [ + 'type' => 'text', + 'default' => $this->opts->getValue( 'reason' ), + 'label-message' => 'checkuser-reason', + 'size' => 46, + 'maxlength' => 150, + 'id' => 'checkreason', + 'name' => 'reason', + ], + ]; + + $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() ); + $form->setMethod( 'post' ) + ->setWrapperLegendMsg( 'checkuser-query' ) + ->setSubmitTextMsg( 'checkuser-check' ) + ->setId( 'checkuserform' ) + ->setSubmitId( 'checkusersubmit' ) + ->setSubmitName( 'checkusersubmit' ) + ->prepareForm() + ->displayForm( false ); + } + + /** + * Make a quick JS form for admins to calculate block ranges + */ + protected function addJsCIDRForm() { + $fields = [ + 'iplist' => [ + 'type' => 'textarea', + 'dir' => 'ltr', + 'rows' => 5, + 'id' => 'mw-checkuser-iplist', + ], + 'ipresult' => [ + 'class' => HTMLTextFieldNoDisabledStyling::class, + 'size' => 35, + 'label-message' => 'checkuser-cidr-res', + 'id' => 'mw-checkuser-cidr-res', + 'name' => 'mw-checkuser-cidr-res', + ], + 'ipnote' => [ + 'type' => 'info', + 'id' => 'mw-checkuser-ipnote', + ] + ]; + $fieldset = new HTMLFieldsetCheckUser( $fields, $this->getContext(), '' ); + $s = $fieldset->setWrapperLegendMsg( 'checkuser-cidr-label' ) + ->prepareForm() + ->suppressDefaultSubmit( true ) + ->getHTML( false ); + $s = Html::rawElement( + 'span', + [ + 'class' => [ 'mw-htmlform', 'mw-htmlform-ooui' ], + 'id' => 'mw-checkuser-cidrform', + 'style' => 'display:none;' + ], + $s + ); + $this->getOutput()->addHTML( $s ); + } + + /** + * @return bool + */ + protected function checkReason(): bool { + return ( !$this->getConfig()->get( 'CheckUserForceSummary' ) || strlen( $this->opts->getValue( 'reason' ) ) ); + } + + /** + * Block a list of selected users + * with options provided in the POST request. + */ + protected function doMassUserBlock() { + $users = $this->opts->getValue( 'users' ); + $blockParams = [ + 'reason' => $this->opts->getValue( 'blockreason' ), + 'email' => $this->opts->getValue( 'blockemail' ), + 'talk' => $this->opts->getValue( 'blocktalk' ), + 'reblock' => $this->opts->getValue( 'reblock' ), + ]; + $tag = $this->opts->getValue( 'usetag' ) ? + trim( $this->opts->getValue( 'blocktag' ) ) : ''; + $talkTag = $this->opts->getValue( 'usettag' ) ? + trim( $this->opts->getValue( 'talktag' ) ) : ''; + $usersCount = count( $users ); + + if ( + !$usersCount + || !$this->permissionManager->userHasRight( $this->getUser(), 'block' ) + || $this->getUser()->getBlock() + ) { + $this->getOutput()->addWikiMsg( 'checkuser-block-failure' ); + return; + } + + if ( $usersCount > $this->getConfig()->get( 'CheckUserMaxBlocks' ) ) { + $this->getOutput()->addWikiMsg( 'checkuser-block-limit' ); + return; + } + + if ( !$blockParams['reason'] ) { + $this->getOutput()->addWikiMsg( 'checkuser-block-noreason' ); + return; + } + + $blockedUsers = $this->doMassUserBlockInternal( + $users, + $blockParams, + $tag, + $talkTag + ); + $blockedCount = count( $blockedUsers ); + if ( $blockedCount > 0 ) { + $lang = $this->getLanguage(); + $this->getOutput()->addWikiMsg( 'checkuser-block-success', + $lang->listToText( $blockedUsers ), + $lang->formatNum( $blockedCount ) + ); + } else { + $this->getOutput()->addWikiMsg( 'checkuser-block-failure' ); + } + } + + /** + * Block a list of selected users + * + * @param string[] $users + * @param array $blockParams + * @param string $tag replaces user pages + * @param string $talkTag replaces user talk pages + * @return string[] List of html-safe usernames which were actually were blocked + */ + protected function doMassUserBlockInternal( + array $users, + array $blockParams, + string $tag = '', + string $talkTag = '' + ) { + $safeUsers = []; + foreach ( $users as $name ) { + $u = $this->userFactory->newFromName( $name, UserRigorOptions::RIGOR_NONE ); + // Do some checks to make sure we can block this user first + if ( !$u ) { + // Invalid user + continue; + } + $isIP = IPUtils::isIPAddress( $u->getName() ); + if ( !$u->getId() && !$isIP ) { + // Not a registered user or an IP + continue; + } + + if ( $u->getBlock() && !$blockParams['reblock'] ) { + continue; + } + + if ( + !isset( $blockParams['email'] ) || + $blockParams['email'] === false || + $this->blockPermissionCheckerFactory + ->newBlockPermissionChecker( + $u, + $this->getUser() + ) + ->checkEmailPermissions() + ) { + $res = $this->blockUserFactory->newBlockUser( + $u, + $this->getAuthority(), + $isIP ? '1 week' : 'indefinite', + $blockParams['reason'], + [ + 'isCreateAccountBlocked' => true, + 'isEmailBlocked' => $blockParams['email'] ?? false, + 'isHardBlock' => !$isIP, + 'isAutoblocking' => true, + 'isUserTalkEditBlocked' => $blockParams['talk'] ?? false, + ] + )->placeBlock( $blockParams['reblock'] ); + + if ( $res->isGood() ) { + $userPage = $u->getUserPage(); + + $safeUsers[] = "[[{$userPage->getPrefixedText()}|{$userPage->getText()}]]"; + + // Tag user page and user talk page + if ( $this->opts->getValue( 'usetag' ) ) { + $this->tagPage( $userPage, $tag, $blockParams['reason'] ); + } + if ( $this->opts->getValue( 'usettag' ) ) { + $this->tagPage( $u->getTalkPage(), $talkTag, $blockParams['reason'] ); + } + } + + } + } + + return $safeUsers; + } + + /** + * Make an edit to the given page with the tag provided + * + * @param Title $title + * @param string $tag + * @param string $summary + */ + protected function tagPage( Title $title, string $tag, string $summary ) { + // Check length to avoid mistakes + if ( strlen( $tag ) > 2 ) { + $page = $this->wikiPageFactory->newFromTitle( $title ); + $flags = 0; + if ( $page->exists() ) { + $flags |= EDIT_MINOR; + } + $page->doUserEditContent( + new WikitextContent( $tag ), + $this->getUser(), + $summary, + $flags + ); + } + } + + /** + * Gets the pager for the specific check type. + * Returns null if the checktype is not recognised. + * + * @param string $checkType + * @param UserIdentity $userIdentity + * @param string $logType + * @param bool|null $xfor + * @return AbstractCheckUserPager|null + */ + public function getPager( string $checkType, UserIdentity $userIdentity, string $logType, ?bool $xfor = null ) { + switch ( $checkType ) { + case self::SUBTYPE_GET_IPS: + return new CheckUserGetIPsPager( + $this->opts, + $userIdentity, + $logType, + $this->tokenQueryManager, + $this->userGroupManager, + $this->centralIdLookup, + $this->loadBalancer, + $this->getSpecialPageFactory(), + $this->userIdentityLookup, + $this->actorMigration, + $this->checkUserLogService, + $this->userFactory + ); + case self::SUBTYPE_GET_USERS: + return new CheckUserGetUsersPager( + $this->opts, + $userIdentity, + $xfor ?? false, + $logType, + $this->tokenQueryManager, + $this->permissionManager, + $this->blockPermissionCheckerFactory, + $this->userGroupManager, + $this->centralIdLookup, + $this->loadBalancer, + $this->getSpecialPageFactory(), + $this->userIdentityLookup, + $this->actorMigration, + $this->userFactory, + $this->checkUserLogService, + $this->userEditTracker + ); + case self::SUBTYPE_GET_EDITS: + return new CheckUserGetEditsPager( + $this->opts, + $userIdentity, + $xfor, + $logType, + $this->tokenQueryManager, + $this->userGroupManager, + $this->centralIdLookup, + $this->linkBatchFactory, + $this->loadBalancer, + $this->getSpecialPageFactory(), + $this->userIdentityLookup, + $this->actorMigration, + $this->userFactory, + $this->revisionStore, + $this->checkUserLogService, + $this->commentFormatter, + $this->userEditTracker + ); + default: + return null; + } + } + + /** + * Return an array of subpages beginning with $search that this special page will accept. + * + * @param string $search Prefix to search for + * @param int $limit Maximum number of results to return (usually 10) + * @param int $offset Number of results to skip (usually 0) + * @return string[] Matching subpages + */ + public function prefixSearchSubpages( $search, $limit, $offset ) { + if ( !$this->userNameUtils->isValid( $search ) ) { + // No prefix suggestion for invalid user + return []; + } + // Autocomplete subpage as user list - public to allow caching + return $this->userNamePrefixSearch->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset ); + } + + /** + * @inheritDoc + */ + protected function getGroupName() { + return 'users'; + } +} diff --git a/CheckUser/src/CheckUser/SpecialCheckUserLog.php b/CheckUser/src/CheckUser/SpecialCheckUserLog.php new file mode 100644 index 00000000..2f249d12 --- /dev/null +++ b/CheckUser/src/CheckUser/SpecialCheckUserLog.php @@ -0,0 +1,286 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser; + +use CommentStore; +use ContribsPager; +use Html; +use HTMLForm; +use MediaWiki\Cache\LinkBatchFactory; +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserLogPager; +use MediaWiki\Permissions\PermissionManager; +use SpecialPage; +use Title; +use User; +use UserBlockedError; +use Wikimedia\IPUtils; + +class SpecialCheckUserLog extends SpecialPage { + /** + * @var string[]|null[] an array of nullable string options. + */ + protected $opts; + + /** @var LinkBatchFactory */ + private $linkBatchFactory; + + /** @var PermissionManager */ + private $permissionManager; + + /** @var CommentStore */ + private $commentStore; + + /** + * @param LinkBatchFactory $linkBatchFactory + * @param PermissionManager $permissionManager + * @param CommentStore $commentStore + */ + public function __construct( + LinkBatchFactory $linkBatchFactory, + PermissionManager $permissionManager, + CommentStore $commentStore + ) { + parent::__construct( 'CheckUserLog', 'checkuser-log' ); + $this->linkBatchFactory = $linkBatchFactory; + $this->permissionManager = $permissionManager; + $this->commentStore = $commentStore; + } + + /** + * @inheritDoc + */ + 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(); + $out->addModules( [ 'ext.checkUser' ] ); + $out->addModuleStyles( [ + 'ext.checkUser.styles', + ] ); + $request = $this->getRequest(); + + $this->opts = []; + + // Normalise target parameter and ignore if not valid (T217713) + // It must be valid when making a link to Special:CheckUserLog/<user>. + // Do not normalize an empty target, as that means "everything" (T265606) + $this->opts['target'] = trim( $request->getVal( 'cuSearch', $par ?? '' ) ); + if ( $this->opts['target'] !== '' ) { + $userTitle = Title::makeTitleSafe( NS_USER, $this->opts['target'] ); + $this->opts['target'] = $userTitle ? $userTitle->getText() : ''; + } + + $this->opts['initiator'] = trim( $request->getVal( 'cuInitiator', '' ) ); + + // From SpecialContributions.php + $skip = $request->getText( 'offset' ) || $request->getText( 'dir' ) === 'prev'; + # Offset overrides year/month selection + if ( !$skip ) { + $this->opts['year'] = $request->getIntOrNull( 'year' ); + $this->opts['month'] = $request->getIntOrNull( 'month' ); + + $this->opts['start'] = $request->getVal( 'start' ); + $this->opts['end'] = $request->getVal( 'end' ); + } + + $this->opts = ContribsPager::processDateFilter( $this->opts ); + + $this->addSubtitle(); + + $this->displaySearchForm(); + + $errorMessageKey = null; + + if ( $this->opts['target'] !== '' && self::verifyTarget( $this->opts['target'] ) === false ) { + $errorMessageKey = 'checkuser-target-nonexistent'; + } + if ( $this->opts['initiator'] !== '' && self::verifyInitiator( $this->opts['initiator'] ) === false ) { + $errorMessageKey = 'checkuser-initiator-nonexistent'; + } + + if ( $errorMessageKey !== null ) { + // Invalid target was input so show an error message and stop from here + $out->addHTML( + Html::errorBox( + $out->msg( $errorMessageKey )->parse() + ) + ); + return; + } + + $pager = new CheckUserLogPager( + $this->getContext(), + $this->opts, + $this->linkBatchFactory, + $this->commentStore + ); + + $out->addHTML( + $pager->getNavigationBar() . + $pager->getBody() . + $pager->getNavigationBar() + ); + } + + /** + * Add subtitle links to the page + */ + private function addSubtitle(): void { + if ( $this->permissionManager->userHasRight( $this->getUser(), 'checkuser' ) ) { + $links = [ + $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'CheckUser' ), + $this->msg( 'checkuser-showmain' )->text() + ), + $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'Investigate' ), + $this->msg( 'checkuser-show-investigate' )->text() + ), + ]; + + if ( $this->opts['target'] ) { + $links[] = $this->getLinkRenderer()->makeKnownLink( + // The above if statement will evaluate NULL to false and thus this + // only runs if target is a string. + // @phan-suppress-next-line PhanTypeMismatchArgumentNullable + SpecialPage::getTitleFor( 'CheckUser', $this->opts['target'] ), + $this->msg( 'checkuser-check-this-user' )->text() + ); + + $links[] = $this->getLinkRenderer()->makeKnownLink( + SpecialPage::getTitleFor( 'Investigate' ), + $this->msg( 'checkuser-investigate-this-user' )->text(), + [], + [ 'targets' => $this->opts['target'] ] + ); + } + + $this->getOutput()->addSubtitle( Html::rawElement( + 'span', + [ "class" => "mw-checkuser-links-no-parentheses" ], + Html::openElement( 'span' ) . + implode( + Html::closeElement( 'span' ) . Html::openElement( 'span' ), + $links + ) . + Html::closeElement( 'span' ) + ) + ); + } + } + + /** + * Use an HTMLForm to create and output the search form used on this page. + */ + protected function displaySearchForm() { + $fields = [ + 'target' => [ + 'type' => 'user', + // validation in execute() currently + 'exists' => false, + 'ipallowed' => true, + 'name' => 'cuSearch', + 'size' => 40, + 'label-message' => 'checkuser-log-search-target', + 'default' => $this->opts['target'], + 'id' => 'mw-target-user-or-ip' + ], + 'initiator' => [ + 'type' => 'user', + // validation in execute() currently + 'exists' => false, + 'ipallowed' => false, + 'name' => 'cuInitiator', + 'size' => 40, + 'label-message' => 'checkuser-log-search-initiator', + 'default' => $this->opts['initiator'] + ], + 'start' => [ + 'type' => 'date', + 'default' => '', + 'id' => 'mw-date-start', + 'label' => $this->msg( 'date-range-from' )->text(), + 'name' => 'start' + ], + 'end' => [ + 'type' => 'date', + 'default' => '', + 'id' => 'mw-date-end', + 'label' => $this->msg( 'date-range-to' )->text(), + 'name' => 'end' + ] + ]; + + $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() ); + $form->setMethod( 'get' ) + ->setWrapperLegendMsg( 'checkuser-search' ) + ->setSubmitTextMsg( 'checkuser-search-submit' ) + ->prepareForm() + ->displayForm( false ); + } + + /** + * Verify if the target is a valid IP, IP range or user. + * + * If the target is a user then return the user's ID, + * if the target is a valid IP address then return + * the IP address in hexadecimal and if the target + * is a valid IP range return the start and end + * hexadecimal for that range. These are used + * by CheckUserLogPager. + * + * Otherwise return false for an invalid target. + * + * @param string $target + * @return bool|int|array + */ + public static function verifyTarget( string $target ) { + [ $start, $end ] = IPUtils::parseRange( $target ); + + if ( $start !== false ) { + if ( $start === $end ) { + return [ $start ]; + } + + return [ $start, $end ]; + } + + $user = User::newFromName( $target ); + if ( $user && $user->getId() ) { + return $user->getId(); + } + + return false; + } + + /** + * Verify if the initiator is a valid user. + * + * If it is return their ID otherwise return false. + * + * @param string $initiator + * @return bool|int + */ + public static function verifyInitiator( string $initiator ) { + $initiatorObject = User::newFromName( $initiator ); + if ( $initiatorObject && $initiatorObject->getId() ) { + return $initiatorObject->getId(); + } + return false; + } + + /** + * @inheritDoc + */ + protected function getGroupName() { + return 'changes'; + } +} diff --git a/CheckUser/src/CheckUser/Widgets/HTMLFieldsetCheckUser.php b/CheckUser/src/CheckUser/Widgets/HTMLFieldsetCheckUser.php new file mode 100644 index 00000000..0901d9f5 --- /dev/null +++ b/CheckUser/src/CheckUser/Widgets/HTMLFieldsetCheckUser.php @@ -0,0 +1,46 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser\Widgets; + +use CollapsibleFieldsetLayout; +use OOUI\Element; +use OOUI\FieldsetLayout; +use OOUI\HtmlSnippet; +use OOUI\PanelLayout; +use OOUI\Widget; +use OOUIHTMLForm; + +class HTMLFieldsetCheckUser extends OOUIHTMLForm { + + /** + * This returns the html but not wrapped in a form + * element, so that it can be optionally added by SpecialCheckUser. + * + * @inheritDoc + */ + public function wrapForm( $html ) { + if ( is_string( $this->mWrapperLegend ) ) { + $phpClass = $this->mCollapsible ? CollapsibleFieldsetLayout::class : FieldsetLayout::class; + $content = new $phpClass( [ + 'label' => $this->mWrapperLegend, + 'collapsed' => $this->mCollapsed, + 'items' => [ + new Widget( [ + 'content' => new HtmlSnippet( $html ) + ] ), + ], + ] + Element::configFromHtmlAttributes( $this->mWrapperAttributes ) ); + } else { + $content = new HtmlSnippet( $html ); + } + + // Include a wrapper for style, if requested. + return new PanelLayout( [ + 'classes' => [ 'mw-htmlform-ooui-wrapper' ], + 'expanded' => false, + 'padded' => $this->mWrapperLegend !== false, + 'framed' => $this->mWrapperLegend !== false, + 'content' => $content, + ] ); + } +} diff --git a/CheckUser/src/CheckUser/Widgets/HTMLTextFieldNoDisabledStyling.php b/CheckUser/src/CheckUser/Widgets/HTMLTextFieldNoDisabledStyling.php new file mode 100644 index 00000000..6c98307c --- /dev/null +++ b/CheckUser/src/CheckUser/Widgets/HTMLTextFieldNoDisabledStyling.php @@ -0,0 +1,17 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser\Widgets; + +use HTMLTextField; + +class HTMLTextFieldNoDisabledStyling extends HTMLTextField { + + /** + * @inheritDoc + */ + protected function getInputWidget( $params ) { + // So that the disabled state does not grey out the + // text input as that does not make sense in this context + return new TextInputWidgetNoDisabledStyling( $params ); + } +} diff --git a/CheckUser/src/CheckUser/Widgets/TextInputWidgetNoDisabledStyling.php b/CheckUser/src/CheckUser/Widgets/TextInputWidgetNoDisabledStyling.php new file mode 100644 index 00000000..4ae9d76a --- /dev/null +++ b/CheckUser/src/CheckUser/Widgets/TextInputWidgetNoDisabledStyling.php @@ -0,0 +1,28 @@ +<?php + +namespace MediaWiki\CheckUser\CheckUser\Widgets; + +use OOUI\TextInputWidget; + +class TextInputWidgetNoDisabledStyling extends TextInputWidget { + + /** + * @param array $config + */ + public function __construct( array $config = [] ) { + parent::__construct( $config ); + $this->input->setAttributes( [ 'disabled' => 'disabled' ] ); + } + + /** + * Because this widget is always disabled + * by definition this does nothing. + * + * @param bool $disabled unused + * @return $this + */ + public function setDisabled( $disabled ) { + // Ignore calls to setDisabled as it should always be disabled. + return $this; + } +} diff --git a/CheckUser/src/InvestigateLogPagerFactory.php b/CheckUser/src/CheckUserActorMigration.php index 2f5e5121..92e56ced 100644 --- a/CheckUser/src/InvestigateLogPagerFactory.php +++ b/CheckUser/src/CheckUserActorMigration.php @@ -1,5 +1,4 @@ <?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 @@ -17,26 +16,42 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @ingroup Pager */ namespace MediaWiki\CheckUser; -use IContextSource; -use MediaWiki\Linker\LinkRenderer; +use ActorMigrationBase; +use MediaWiki\MediaWikiServices; +use MediaWiki\User\ActorStoreFactory; -class InvestigateLogPagerFactory implements PagerFactory { - /** @var LinkRenderer */ - private $linkRenderer; +class CheckUserActorMigration extends ActorMigrationBase { + /** + * Field information + * @see ActorMigrationBase::getFieldInfo() + */ + public const FIELD_INFOS = [ + 'cuc_user' => [], + ]; - public function __construct( LinkRenderer $linkRenderer ) { - $this->linkRenderer = $linkRenderer; + /** + * @return self + */ + public static function newMigration() { + return MediaWikiServices::getInstance()->get( 'CheckUserActorMigration' ); } /** - * @inheritDoc + * @param int $stage + * @param ActorStoreFactory $actorStoreFactory */ - public function createPager( IContextSource $context ) : InvestigateLogPager { - return new InvestigateLogPager( $context, $this->linkRenderer ); + public function __construct( + $stage, + ActorStoreFactory $actorStoreFactory + ) { + parent::__construct( + self::FIELD_INFOS, + $stage, + $actorStoreFactory + ); } } diff --git a/CheckUser/src/CheckUserLogService.php b/CheckUser/src/CheckUserLogService.php new file mode 100644 index 00000000..e55de0ab --- /dev/null +++ b/CheckUser/src/CheckUserLogService.php @@ -0,0 +1,89 @@ +<?php + +namespace MediaWiki\CheckUser; + +use DeferredUpdates; +use User; +use Wikimedia\IPUtils; +use Wikimedia\Rdbms\ILoadBalancer; +use Wikimedia\Timestamp\ConvertibleTimestamp; + +class CheckUserLogService { + + /** @var ILoadBalancer */ + private $loadBalancer; + + /** @var int */ + private $culActorMigrationStage; + + /** + * @param ILoadBalancer $loadBalancer + * @param int $culActorMigrationStage + */ + public function __construct( ILoadBalancer $loadBalancer, int $culActorMigrationStage ) { + $this->loadBalancer = $loadBalancer; + $this->culActorMigrationStage = $culActorMigrationStage; + } + + /** + * Adds a log entry to the CheckUserLog. + * + * @param User $user + * @param string $logType + * @param string $targetType + * @param string $target + * @param string $reason + * @param int $targetID + * @return void + */ + public function addLogEntry( + User $user, string $logType, string $targetType, string $target, string $reason, int $targetID = 0 + ) { + if ( $targetType == 'ip' ) { + list( $rangeStart, $rangeEnd ) = IPUtils::parseRange( $target ); + $targetHex = $rangeStart; + if ( $rangeStart == $rangeEnd ) { + $rangeStart = ''; + $rangeEnd = ''; + } + } else { + $targetHex = ''; + $rangeStart = ''; + $rangeEnd = ''; + } + + $timestamp = ConvertibleTimestamp::now(); + $data = [ + 'cul_user' => $user->getId(), + 'cul_user_text' => $user->getName(), + 'cul_reason' => $reason, + 'cul_type' => $logType, + 'cul_target_id' => $targetID, + 'cul_target_text' => trim( $target ), + 'cul_target_hex' => $targetHex, + 'cul_range_start' => $rangeStart, + 'cul_range_end' => $rangeEnd + ]; + + if ( $this->culActorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { + $data['cul_actor'] = $user->getActorId(); + } + + $fname = __METHOD__; + $dbw = $this->loadBalancer->getConnection( DB_PRIMARY ); + + DeferredUpdates::addCallableUpdate( + static function () use ( $data, $timestamp, $fname, $dbw ) { + $dbw->insert( + 'cu_log', + [ + 'cul_timestamp' => $dbw->timestamp( $timestamp ) + ] + $data, + $fname + ); + }, + // fail on error and show no output + DeferredUpdates::PRESEND + ); + } +} diff --git a/CheckUser/src/CompareService.php b/CheckUser/src/CompareService.php deleted file mode 100644 index f1ab687e..00000000 --- a/CheckUser/src/CompareService.php +++ /dev/null @@ -1,220 +0,0 @@ -<?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 deleted file mode 100644 index 8755bb98..00000000 --- a/CheckUser/src/DurationManager.php +++ /dev/null @@ -1,63 +0,0 @@ -<?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/includes/CheckUserEncryptedData.php b/CheckUser/src/EncryptedData.php index 26509acd..87f7e19e 100644 --- a/CheckUser/includes/CheckUserEncryptedData.php +++ b/CheckUser/src/EncryptedData.php @@ -1,19 +1,25 @@ <?php -class CheckUserEncryptedData { +namespace MediaWiki\CheckUser; - // The data symmetrically encrypted with a random key +class EncryptedData { + + /** @var string|null The data symmetrically encrypted with a random key */ public $encString; - // Symmetric key, encrypted with the public key + /** @var string|null Symmetric key, encrypted with the public key */ public $envKeys; - // algorithm name, passed into openssl 'method' param. Kept as a variable here in case - // the class definition needs to change, and we have serialized objects stored. + /** + * @var string algorithm name, passed into openssl 'method' param. Kept as a variable here in case + * the class definition needs to change, and we have serialized objects stored. + */ private $algName; - // Hash of the public key, in case you've used multiple keys, and need to identify the - // correct private key + /** + * @var int Hash of the public key, in case you've used multiple keys, and need to identify the + * correct private key + */ private $keyHash; /** @@ -37,7 +43,7 @@ class CheckUserEncryptedData { * @return string|false plaintext */ public function getPlaintext( $privateKey ) { - $result = openssl_open( + $result = \openssl_open( $this->encString, $plaintextData, $this->envKeys, @@ -45,7 +51,7 @@ class CheckUserEncryptedData { $this->algName ); - if ( $result == false ) { + if ( !$result ) { return false; } @@ -61,7 +67,7 @@ class CheckUserEncryptedData { */ private function encryptData( $data, $publicKey ) { // @phan-suppress-next-line PhanTypeMismatchArgumentInternal - openssl_seal( $data, $encryptedString, $envelopeKeys, [ $publicKey ], $this->algName ); + \openssl_seal( $data, $encryptedString, $envelopeKeys, [ $publicKey ], $this->algName ); $this->encString = $encryptedString; // @phan-suppress-next-line PhanTypeArraySuspiciousNullable $this->envKeys = $envelopeKeys[0]; diff --git a/CheckUser/src/GuidedTour/TourLauncher.php b/CheckUser/src/GuidedTour/TourLauncher.php index bd7ff068..db9186cf 100644 --- a/CheckUser/src/GuidedTour/TourLauncher.php +++ b/CheckUser/src/GuidedTour/TourLauncher.php @@ -3,8 +3,8 @@ namespace MediaWiki\CheckUser\GuidedTour; use ExtensionRegistry; -use GuidedTourLauncher; use HtmlArmor; +use MediaWiki\Extension\GuidedTour\GuidedTourLauncher; use MediaWiki\Linker\LinkRenderer; use MediaWiki\Linker\LinkTarget; @@ -35,7 +35,7 @@ class TourLauncher { * @param string $tourName * @param string $step */ - public function launchTour( string $tourName, string $step ) : void { + public function launchTour( string $tourName, string $step ): void { if ( !$this->extensionRegistry->isLoaded( 'GuidedTour' ) ) { return; } @@ -57,7 +57,7 @@ class TourLauncher { $text = null, array $extraAttribs = [], array $query = [] - ) : string { + ): string { if ( !$this->extensionRegistry->isLoaded( 'GuidedTour' ) ) { return ''; } diff --git a/CheckUser/src/Hook/CheckUserInsertChangesRow.php b/CheckUser/src/Hook/CheckUserInsertChangesRow.php new file mode 100644 index 00000000..6b389ddb --- /dev/null +++ b/CheckUser/src/Hook/CheckUserInsertChangesRow.php @@ -0,0 +1,29 @@ +<?php + +namespace MediaWiki\CheckUser\Hook; + +interface CheckUserInsertChangesRow { + /** + * Use this hook to modify the IP, XFF or other values + * in the row to be inserted into cu_changes. + * + * It is recommended that if the request IP or XFF is + * being changed it is done through the $ip and $xff + * parameters and not the $row as CheckUser will + * calculate a hex value of both to insert into + * cu_changes. + * + * Set the $xff to false to represent no defined XFF. + * + * @since 1.40 + * + * @param string &$ip The users IP + * @param string|false &$xff The XFF for the request + * @param array &$row The row to be inserted (before defaults are applied) + */ + public function onCheckUserInsertChangesRow( + string &$ip, + &$xff, + array &$row + ); +} diff --git a/CheckUser/src/Hook/HookRunner.php b/CheckUser/src/Hook/HookRunner.php index d2e4327f..0fad8430 100644 --- a/CheckUser/src/Hook/HookRunner.php +++ b/CheckUser/src/Hook/HookRunner.php @@ -5,17 +5,18 @@ namespace MediaWiki\CheckUser\Hook; use IContextSource; use MediaWiki\HookContainer\HookContainer; -class HookRunner implements CheckUserFormatRowHook, CheckUserSubtitleLinksHook { +class HookRunner implements CheckUserFormatRowHook, CheckUserSubtitleLinksHook, CheckUserInsertChangesRow { /** @var HookContainer */ private $container; + /** + * @param HookContainer $container + */ public function __construct( HookContainer $container ) { $this->container = $container; } - /** - * @inheritDoc - */ + /** @inheritDoc */ public function onCheckUserFormatRow( IContextSource $context, \stdClass $row, @@ -27,9 +28,7 @@ class HookRunner implements CheckUserFormatRowHook, CheckUserSubtitleLinksHook { ); } - /** - * @inheritDoc - */ + /** @inheritDoc */ public function onCheckUserSubtitleLinks( IContextSource $context, array &$links @@ -39,4 +38,12 @@ class HookRunner implements CheckUserFormatRowHook, CheckUserSubtitleLinksHook { [ $context, &$links ] ); } + + /** @inheritDoc */ + public function onCheckUserInsertChangesRow( string &$ip, &$xff, array &$row ) { + $this->container->run( + 'CheckUserInsertChangesRow', + [ &$ip, &$xff, &$row ] + ); + } } diff --git a/CheckUser/src/Hooks.php b/CheckUser/src/Hooks.php new file mode 100644 index 00000000..fc462825 --- /dev/null +++ b/CheckUser/src/Hooks.php @@ -0,0 +1,935 @@ +<?php + +namespace MediaWiki\CheckUser; + +use AutoCommitUpdate; +use DatabaseUpdater; +use DeferredUpdates; +use ExtensionRegistry; +use LogFormatter; +use MailAddress; +use MediaWiki\Auth\AuthenticationResponse; +use MediaWiki\Auth\Hook\AuthManagerLoginAuthenticateAuditHook; +use MediaWiki\Auth\Hook\LocalUserCreatedHook; +use MediaWiki\Block\DatabaseBlock; +use MediaWiki\Block\Hook\PerformRetroactiveAutoblockHook; +use MediaWiki\CheckUser\Hook\HookRunner; +use MediaWiki\CheckUser\Investigate\SpecialInvestigate; +use MediaWiki\CheckUser\Investigate\SpecialInvestigateBlock; +use MediaWiki\CheckUser\Maintenance\PopulateCucActor; +use MediaWiki\CheckUser\Maintenance\PopulateCulActor; +use MediaWiki\Extension\CentralAuth\User\CentralAuthUser; +use MediaWiki\Extension\Renameuser\RenameuserSQL; +use MediaWiki\Hook\ContributionsToolLinksHook; +use MediaWiki\Hook\EmailUserHook; +use MediaWiki\Hook\RecentChange_saveHook; +use MediaWiki\Hook\UserToolLinksEditHook; +use MediaWiki\Installer\Hook\LoadExtensionSchemaUpdatesHook; +use MediaWiki\MediaWikiServices; +use MediaWiki\SpecialPage\Hook\SpecialPage_initListHook; +use MediaWiki\User\Hook\User__mailPasswordInternalHook; +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityValue; +use MediaWiki\User\UserRigorOptions; +use MessageSpecifier; +use PopulateCheckUserTable; +use RecentChange; +use RequestContext; +use SpecialPage; +use Status; +use Title; +use User; +use WebRequest; +use Wikimedia\IPUtils; +use Wikimedia\Rdbms\IDatabase; +use Wikimedia\Rdbms\SelectQueryBuilder; +use Wikimedia\ScopedCallback; + +class Hooks implements + AuthManagerLoginAuthenticateAuditHook, + ContributionsToolLinksHook, + EmailUserHook, + LoadExtensionSchemaUpdatesHook, + LocalUserCreatedHook, + PerformRetroactiveAutoblockHook, + RecentChange_saveHook, + SpecialPage_initListHook, + UserToolLinksEditHook, + User__mailPasswordInternalHook +{ + + /** + * The maximum number of bytes that fit in CheckUser's text fields + * (cuc_agent,cuc_actiontext,cuc_comment,cuc_xff) + */ + public const TEXT_FIELD_LENGTH = 255; + + /** + * Get user agent for the current request + * + * @return string + */ + private static function getAgent(): string { + $agent = RequestContext::getMain()->getRequest()->getHeader( 'User-Agent' ); + if ( $agent === false ) { + // no agent was present, store as an empty string (otherwise, it would + // end up stored as a zero due to boolean casting done by the DB layer). + $agent = ''; + } + return MediaWikiServices::getInstance()->getContentLanguage() + ->truncateForDatabase( $agent, self::TEXT_FIELD_LENGTH ); + } + + /** + * @param array &$list + * @return bool + */ + public 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', + 'PermissionManager', + 'CheckUserLogService', + ], + ]; + + $list['InvestigateBlock'] = [ + 'class' => SpecialInvestigateBlock::class, + 'services' => [ + 'BlockUserFactory', + 'BlockPermissionCheckerFactory', + 'PermissionManager', + 'TitleFormatter', + 'UserFactory', + 'CheckUserEventLogger', + ] + ]; + } + + return true; + } + + /** + * Hook function for RecentChange_save + * Saves user data into the cu_changes table + * Note that other extensions (like AbuseFilter) may call this function directly + * if they want to send data to CU without creating a recentchanges entry + * @param RecentChange $rc + */ + public static function updateCheckUserData( RecentChange $rc ) { + global $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 ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) { + return; + } + /** + * RC_EXTERNAL recent changes are not triggered by actions on the local wiki. + * Thus there is no reason to store checkuser data about them. + * @see https://phabricator.wikimedia.org/T125664 + */ + if ( $rc->getAttribute( 'rc_type' ) == RC_EXTERNAL ) { + return; + } + + $attribs = $rc->getAttributes(); + // Store the log action text for log events + // $rc_comment should just be the log_comment + // 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(); + + ScopedCallback::consume( $scope ); + } else { + $actionText = ''; + } + + $comment = $rc->getAttribute( 'rc_comment' ); + + $services = MediaWikiServices::getInstance(); + + $dbw = $services->getDBLoadBalancer()->getConnectionRef( DB_PRIMARY ); + + $rcRow = [ + 'cuc_namespace' => $attribs['rc_namespace'], + 'cuc_title' => $attribs['rc_title'], + 'cuc_minor' => $attribs['rc_minor'], + 'cuc_user' => $attribs['rc_user'], + 'cuc_user_text' => $attribs['rc_user_text'], + 'cuc_actiontext' => $actionText, + 'cuc_comment' => $comment, + 'cuc_this_oldid' => $attribs['rc_this_oldid'], + 'cuc_last_oldid' => $attribs['rc_last_oldid'], + 'cuc_type' => $attribs['rc_type'], + 'cuc_timestamp' => $dbw->timestamp( $attribs['rc_timestamp'] ), + ]; + + # On PG, MW unsets cur_id due to schema incompatibilities. So it may not be set! + if ( isset( $attribs['rc_cur_id'] ) ) { + $rcRow['cuc_page_id'] = $attribs['rc_cur_id']; + } + + $services->getHookContainer()->run( 'CheckUserInsertForRecentChange', [ $rc, &$rcRow ] ); + + self::insertIntoCuChangesTable( + $rcRow, + __METHOD__, + new UserIdentityValue( $rcRow['cuc_user'], $rcRow['cuc_user_text'] ) + ); + } + + /** + * Inserts a row into the cu_changes table based on a provided array of cu_change column names to their values. + * + * The $user parameter and $target parameter is used to fill out the column values for the row, but does + * not override any values specified in $row (thus the caller can specify custom row values without them being + * overridden). + * + * @param array $row an array of cu_change table column names to their values. Not overrided except for + * truncating any action text, xff or comment before insertion if too long. + * @param string $method the method name that called this, used for the insertion into the DB. + * @param UserIdentity $user the user who made the request. + * @return void + */ + private static function insertIntoCuChangesTable( + array $row, + string $method, + UserIdentity $user + ) { + $services = MediaWikiServices::getInstance(); + + $dbw = $services->getDBLoadBalancer()->getConnectionRef( DB_PRIMARY ); + + $request = RequestContext::getMain()->getRequest(); + + $ip = $request->getIP(); + $xff = $request->getHeader( 'X-Forwarded-For' ); + // Provide the ip, xff and row to code that hooks onto this so that they can modify the row before + // it's inserted. The ip and xff are provided separately so that the caller doesn't have to set + // the hex versions of the IP and XFF and can therefore leave that to this function. + ( new HookRunner( $services->getHookContainer() ) )->onCheckUserInsertChangesRow( $ip, $xff, $row ); + list( $xff_ip, $isSquidOnly, $xff ) = self::getClientIPfromXFF( $xff ); + + $row = array_merge( + [ + 'cuc_page_id' => 0, + 'cuc_namespace' => 0, + 'cuc_minor' => 0, + 'cuc_title' => '', + 'cuc_user' => $user->getId(), + 'cuc_user_text' => $user->getName(), + 'cuc_actiontext' => '', + 'cuc_comment' => '', + 'cuc_this_oldid' => 0, + 'cuc_last_oldid' => 0, + 'cuc_type' => RC_LOG, + 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ), + 'cuc_ip' => IPUtils::sanitizeIP( $ip ), + 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null, + 'cuc_xff' => !$isSquidOnly ? $xff : '', + 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null, + 'cuc_agent' => self::getAgent(), + ], + $row + ); + + $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 + $row['cuc_actiontext'] = $contLang->truncateForDatabase( + $row['cuc_actiontext'], + self::TEXT_FIELD_LENGTH + ); + $row['cuc_xff'] = $contLang->truncateForDatabase( $row['cuc_xff'], self::TEXT_FIELD_LENGTH ); + $row['cuc_comment'] = $contLang->truncateForDatabase( $row['cuc_comment'], self::TEXT_FIELD_LENGTH ); + + $actorMigrationStage = $services->getMainConfig()->get( 'CheckUserActorMigrationStage' ); + if ( ( $actorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) && !isset( $row['cuc_actor'] ) ) { + $row['cuc_actor'] = $services->getActorStore()->acquireActorId( + $user, + $dbw + ); + } + + $dbw->insert( 'cu_changes', $row, $method ); + } + + /** + * Hook function to store password reset + * Saves user data into the cu_changes table + * + * @param User $user Sender + * @param string $ip + * @param User $account Receiver + */ + public function onUser__mailPasswordInternal( $user, $ip, $account ) { + $accountName = $account->getName(); + self::insertIntoCuChangesTable( + [ + 'cuc_namespace' => NS_USER, + 'cuc_actiontext' => wfMessage( 'checkuser-reset-action', "[[User:$accountName|$accountName]]" ) + ->inContentLanguage()->text(), + ], + __METHOD__, + $user + ); + } + + /** + * Hook function to store email data. + * + * Saves user data into the cu_changes table. + * Uses a deferred update to save the data, because emails can be sent from code paths + * that don't open master connections. + * + * @param MailAddress &$to + * @param MailAddress &$from + * @param string &$subject + * @param string &$text + * @param bool|Status|MessageSpecifier|array &$error + */ + public function onEmailUser( &$to, &$from, &$subject, &$text, &$error ) { + global $wgSecretKey, $wgCUPublicKey; + + $services = MediaWikiServices::getInstance(); + + if ( !$wgSecretKey || $from->name == $to->name ) { + return; + } + + if ( $services->getReadOnlyMode()->isReadOnly() ) { + return; + } + + $userFrom = $services->getUserFactory()->newFromName( $from->name ); + '@phan-var User $userFrom'; + $userTo = $services->getUserFactory()->newFromName( $to->name ); + $hash = md5( $userTo->getEmail() . $userTo->getId() . $wgSecretKey ); + + $row = [ + 'cuc_namespace' => NS_USER, + 'cuc_actiontext' => wfMessage( 'checkuser-email-action', $hash )->inContentLanguage()->text(), + ]; + + if ( trim( $wgCUPublicKey ) != '' ) { + $privateData = $userTo->getEmail() . ":" . $userTo->getId(); + $encryptedData = new EncryptedData( $privateData, $wgCUPublicKey ); + $row['cuc_private'] = serialize( $encryptedData ); + } + + $fname = __METHOD__; + DeferredUpdates::addCallableUpdate( static function () use ( $row, $userFrom, $fname ) { + self::insertIntoCuChangesTable( + $row, + $fname, + $userFrom + ); + } ); + } + + /** + * Hook function to store registration and autocreation data + * Saves user data into the cu_changes table + * + * @param User $user + * @param bool $autocreated + */ + public function onLocalUserCreated( $user, $autocreated ) { + self::insertIntoCuChangesTable( + [ + 'cuc_namespace' => NS_USER, + 'cuc_actiontext' => wfMessage( + $autocreated ? 'checkuser-autocreate-action' : 'checkuser-create-action' + )->inContentLanguage()->text(), + ], + __METHOD__, + $user + ); + } + + /** + * @param AuthenticationResponse $ret + * @param User|null $user + * @param string $username + * @param string[] $extraData + */ + public function onAuthManagerLoginAuthenticateAudit( $ret, $user, $username, $extraData ) { + global $wgCheckUserLogLogins, $wgCheckUserLogSuccessfulBotLogins; + + if ( !$wgCheckUserLogLogins ) { + return; + } + + $services = MediaWikiServices::getInstance(); + + if ( !$user && $username !== null ) { + $user = $services->getUserFactory()->newFromName( $username, UserRigorOptions::RIGOR_USABLE ); + } + + if ( !$user ) { + return; + } + + if ( + $wgCheckUserLogSuccessfulBotLogins !== true && + $ret->status === AuthenticationResponse::PASS + ) { + $userGroups = $services + ->getUserGroupManager() + ->getUserGroups( $user ); + + if ( in_array( 'bot', $userGroups ) ) { + return; + } + } + + $userName = $user->getName(); + + if ( $ret->status === AuthenticationResponse::FAIL ) { + // The login attempt failed so use the IP as the performer + // and checkuser-login-failure as the message. + $msg = 'checkuser-login-failure'; + $performer = UserIdentityValue::newAnonymous( + RequestContext::getMain()->getRequest()->getIP() + ); + + if ( + $ret->failReasons && + ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) && + in_array( CentralAuthUser::AUTHENTICATE_GOOD_PASSWORD, $ret->failReasons ) + ) { + // If the password was correct, then say so in the shown message. + $msg = 'checkuser-login-failure-with-good-password'; + + if ( + in_array( CentralAuthUser::AUTHENTICATE_LOCKED, $ret->failReasons ) && + array_diff( + $ret->failReasons, + [ CentralAuthUser::AUTHENTICATE_LOCKED, CentralAuthUser::AUTHENTICATE_GOOD_PASSWORD ] + ) === [] + ) { + // If + // * The user is locked + // * The password is correct + // * Nothing else caused the request to fail + // then we can assume that if the account was not locked this login attempt + // would have been successful. Therefore, mark the user as the performer + // to indicate this information to the CheckUser and so it shows up when + // checking the locked account. + $performer = $user; + } + } + } elseif ( $ret->status === AuthenticationResponse::PASS ) { + $msg = 'checkuser-login-success'; + $performer = $user; + } else { + // Abstain, Redirect, etc. + return; + } + + $target = "[[User:$userName|$userName]]"; + + self::insertIntoCuChangesTable( + [ + 'cuc_namespace' => NS_USER, + 'cuc_title' => $userName, + 'cuc_actiontext' => wfMessage( $msg )->params( $target )->inContentLanguage()->text(), + ], + __METHOD__, + $performer + ); + } + + /** + * Hook function to prune data from the cu_changes table + */ + private function maybePruneIPData() { + if ( mt_rand( 0, 9 ) != 0 ) { + return; + } + + DeferredUpdates::addUpdate( new AutoCommitUpdate( + MediaWikiServices::getInstance() + ->getDBLoadBalancer() + ->getMaintenanceConnectionRef( DB_PRIMARY ), + __METHOD__, + static function ( IDatabase $dbw, $fname ) { + global $wgCUDMaxAge; + + // per-wiki + $key = "{$dbw->getDomainID()}:PruneCheckUserData"; + $scopedLock = $dbw->getScopedLockAndFlush( $key, $fname, 1 ); + if ( !$scopedLock ) { + return; + } + + $encCutoff = $dbw->addQuotes( $dbw->timestamp( time() - $wgCUDMaxAge ) ); + $ids = $dbw->newSelectQueryBuilder() + ->table( 'cu_changes' ) + ->field( 'cuc_id' ) + ->conds( [ "cuc_timestamp < $encCutoff" ] ) + ->limit( 500 ) + ->caller( $fname ) + ->fetchFieldValues(); + + if ( $ids ) { + $dbw->delete( 'cu_changes', [ 'cuc_id' => $ids ], $fname ); + } + } + ) ); + } + + /** + * Locates the client IP within a given XFF string. + * Unlike the XFF checking to determine a user IP in WebRequest, + * this simply follows the chain and does not account for server trust. + * + * This returns an array containing: + * - The best guess of the client IP + * - Whether all the proxies are just squid/varnish + * - The XFF value, converted to a empty string if false + * + * @param string|bool $xff XFF header value + * @return array (string|null, bool, string) + * @todo move this to a utility class + */ + public static function getClientIPfromXFF( $xff ) { + global $wgUsePrivateIPs; + + if ( $xff === false || !strlen( $xff ) ) { + // If the XFF is empty or not a string return with a + // XFF of the empty string and no results + return [ null, false, '' ]; + } + + # Get the list in the form of <PROXY N, ... PROXY 1, CLIENT> + $ipchain = array_map( 'trim', explode( ',', $xff ) ); + $ipchain = array_reverse( $ipchain ); + + $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup(); + + // best guess of the client IP + $client = null; + + // all proxy servers where site Squid/Varnish servers? + $isSquidOnly = false; + # Step through XFF list and find the last address in the list which is a + # sensible proxy server. Set $ip to the IP address given by that proxy server, + # 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 = IPUtils::canonicalize( + WebRequest::canonicalizeIPv6LoopbackAddress( $curIP ) + ); + if ( $curIP === null ) { + // not a valid IP address + break; + } + $curIsSquid = $proxyLookup->isConfiguredProxy( $curIP ); + if ( $client === null ) { + $client = $curIP; + $isSquidOnly = $curIsSquid; + } + if ( + isset( $ipchain[$i + 1] ) && + IPUtils::isIPAddress( $ipchain[$i + 1] ) && + ( + IPUtils::isPublic( $ipchain[$i + 1] ) || + $wgUsePrivateIPs || + // T50919 + $curIsSquid + ) + ) { + $client = IPUtils::canonicalize( + WebRequest::canonicalizeIPv6LoopbackAddress( $ipchain[$i + 1] ) + ); + $isSquidOnly = ( $isSquidOnly && $curIsSquid ); + continue; + } + break; + } + + return [ $client, $isSquidOnly, $xff ]; + } + + /** + * @param DatabaseUpdater $updater + */ + public function onLoadExtensionSchemaUpdates( $updater ) { + $base = __DIR__ . '/../schema'; + $dbType = $updater->getDB()->getType(); + $isCUInstalled = $updater->tableExists( 'cu_changes' ); + + $updater->addExtensionTable( 'cu_changes', "$base/$dbType/tables-generated.sql" ); + + if ( $dbType === 'mysql' ) { + // 1.35 + $updater->modifyExtensionField( + 'cu_changes', + 'cuc_id', + "$base/$dbType/patch-cu_changes-cuc_id-unsigned.sql" + ); + + // 1.38 + $updater->addExtensionIndex( + 'cu_changes', + 'cuc_actor_ip_time', + "$base/$dbType/patch-cu_changes-actor-comment.sql" + ); + + // 1.39 + $updater->modifyExtensionField( + 'cu_changes', + 'cuc_timestamp', + "$base/$dbType/patch-cu_changes-cuc_timestamp.sql" + ); + $updater->addExtensionField( + 'cu_log', + 'cul_reason_id', + "$base/$dbType/patch-cu_log-comment_table_for_reason.sql" + ); + $updater->addExtensionField( + 'cu_log', + 'cul_actor', + "$base/$dbType/patch-cu_log-actor.sql" + ); + } elseif ( $dbType === 'sqlite' ) { + // 1.39 + $updater->addExtensionIndex( + 'cu_changes', + 'cuc_actor_ip_time', + "$base/$dbType/patch-cu_changes-actor-comment.sql" + ); + $updater->addExtensionField( + 'cu_log', + 'cul_reason_id', + "$base/$dbType/patch-cu_log-comment_table_for_reason.sql" + ); + $updater->addExtensionField( + 'cu_log', + 'cul_actor', + "$base/$dbType/patch-cu_log-actor.sql" + ); + } elseif ( $dbType === 'postgres' ) { + // 1.37 + $updater->addExtensionUpdate( [ 'dropFkey', 'cu_log', 'cul_user' ] ); + $updater->addExtensionUpdate( [ 'dropFkey', 'cu_log', 'cul_target_id' ] ); + $updater->addExtensionUpdate( [ 'dropFkey', 'cu_changes', 'cuc_user' ] ); + $updater->addExtensionUpdate( [ 'dropFkey', 'cu_changes', 'cuc_page_id' ] ); + + // 1.38 + $updater->addExtensionUpdate( + [ 'addPgField', 'cu_changes', 'cuc_actor', 'INTEGER NOT NULL DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'addPgField', 'cu_changes', 'cuc_comment_id', 'INTEGER NOT NULL DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'setDefault', 'cu_changes', 'cuc_user_text', '' ] + ); + $updater->addExtensionUpdate( + [ 'addPgIndex', 'cu_changes', 'cuc_actor_ip_time', '( cuc_actor, cuc_ip, cuc_timestamp )' ] + ); + + // 1.39 + $updater->addExtensionIndex( 'cu_changes', 'cu_changes_pkey', "$base/$dbType/patch-cu_changes-pk.sql" ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_namespace', 'INT', 'cuc_namespace::INT DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'changeNullableField', 'cu_changes', 'cuc_user', 'NOT NULL', true ] + ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_user_text', 'VARCHAR(255)', '' ] + ); + $updater->addExtensionUpdate( + [ 'setDefault', 'cu_changes', 'cuc_user_text', '' ] + ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_actor', 'BIGINT', 'cuc_actor::BIGINT DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_comment_id', 'BIGINT', 'cuc_comment_id::BIGINT DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_minor', 'SMALLINT', 'cuc_minor::SMALLINT DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'changeNullableField', 'cu_changes', 'cuc_page_id', 'NOT NULL', true ] + ); + $updater->addExtensionUpdate( + [ 'setDefault', 'cu_changes', 'cuc_page_id', 0 ] + ); + $updater->addExtensionUpdate( + [ 'changeNullableField', 'cu_changes', 'cuc_timestamp', 'NOT NULL', true ] + ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_ip', 'VARCHAR(255)', '' ] + ); + $updater->addExtensionUpdate( + [ 'setDefault', 'cu_changes', 'cuc_ip', '' ] + ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_ip_hex', 'VARCHAR(255)', '' ] + ); + $updater->addExtensionUpdate( + [ 'setDefault', 'cu_changes', 'cuc_xff', '' ] + ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_xff_hex', 'VARCHAR(255)', '' ] + ); + $updater->addExtensionUpdate( + [ 'changeField', 'cu_changes', 'cuc_private', 'TEXT', '' ] + ); + $updater->addExtensionIndex( 'cu_log', 'cu_log_pkey', "$base/$dbType/patch-cu_log-pk.sql" ); + $updater->addExtensionUpdate( + [ 'changeNullableField', 'cu_log', 'cul_timestamp', 'NOT NULL', true ] + ); + $updater->addExtensionUpdate( + [ 'changeNullableField', 'cu_log', 'cul_user', 'NOT NULL', true ] + ); + $updater->addExtensionUpdate( + [ 'dropDefault', 'cu_log', 'cul_reason' ] + ); + $updater->addExtensionUpdate( + [ 'dropDefault', 'cu_log', 'cul_type' ] + ); + $updater->addExtensionUpdate( + [ 'changeNullableField', 'cu_log', 'cul_target_id', 'NOT NULL', true ] + ); + $updater->addExtensionUpdate( + [ 'setDefault', 'cu_log', 'cul_target_id', 0 ] + ); + $updater->addExtensionUpdate( + [ 'dropDefault', 'cu_log', 'cul_target_text' ] + ); + $updater->addExtensionUpdate( + [ 'addPgField', 'cu_log', 'cul_reason_id', 'INTEGER NOT NULL DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'addPgField', 'cu_log', 'cul_reason_plaintext_id', 'INTEGER NOT NULL DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'addPgField', 'cu_log', 'cul_actor', 'INTEGER NOT NULL DEFAULT 0' ] + ); + $updater->addExtensionUpdate( + [ 'addPgIndex', 'cu_log', 'cul_actor_time', '( cul_actor, cul_timestamp )' ] + ); + } + + $updater->addPostDatabaseUpdateMaintenance( PopulateCucActor::class ); + $updater->addPostDatabaseUpdateMaintenance( PopulateCulActor::class ); + + if ( !$isCUInstalled ) { + // 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::class ); + } + } + + /** + * Add a link to Special:CheckUser and Special:CheckUserLog + * on Special:Contributions/<username> for + * privileged users. + * @param int $id User ID + * @param Title $nt User page title + * @param array &$links Tool links + * @param SpecialPage $sp Special page + */ + public function onContributionsToolLinks( + $id, Title $nt, array &$links, SpecialPage $sp + ) { + $user = $sp->getUser(); + $linkRenderer = $sp->getLinkRenderer(); + $permissionManager = MediaWikiServices::getInstance()->getPermissionManager(); + + if ( $permissionManager->userHasRight( $user, 'checkuser' ) ) { + $links['checkuser'] = $linkRenderer->makeKnownLink( + SpecialPage::getTitleFor( 'CheckUser' ), + $sp->msg( 'checkuser-contribs' )->text(), + [ 'class' => 'mw-contributions-link-check-user' ], + [ 'user' => $nt->getText() ] + ); + } + if ( $permissionManager->userHasRight( $user, 'checkuser-log' ) ) { + $links['checkuser-log'] = $linkRenderer->makeKnownLink( + SpecialPage::getTitleFor( 'CheckUserLog' ), + $sp->msg( 'checkuser-contribs-log' )->text(), + [ 'class' => 'mw-contributions-link-check-user-log' ], + [ + 'cuSearch' => $nt->getText() + ] + ); + if ( $id ) { + $links['checkuser-log-initiator'] = $linkRenderer->makeKnownLink( + SpecialPage::getTitleFor( 'CheckUserLog' ), + $sp->msg( 'checkuser-contribs-log-initiator' )->text(), + [ 'class' => 'mw-contributions-link-check-user-initiator' ], + [ + 'cuInitiator' => $nt->getText() + ] + ); + } + } + } + + /** + * Retroactively autoblocks the last IP used by the user (if it is a user) + * blocked by this block. + * + * @param DatabaseBlock $block + * @param array &$blockIds + * @return bool + */ + public function onPerformRetroactiveAutoblock( $block, &$blockIds ) { + $services = MediaWikiServices::getInstance(); + + $dbr = $services + ->getDBLoadBalancerFactory() + ->getMainLB( $block->getWikiId() ) + ->getConnectionRef( DB_REPLICA, [], $block->getWikiId() ); + + $userIdentityLookup = $services + ->getActorStoreFactory() + ->getUserIdentityLookup( $block->getWikiId() ); + $user = $userIdentityLookup->getUserIdentityByName( $block->getTargetName() ); + if ( !$user->isRegistered() ) { + // user in an IP? + return true; + } + + $res = $dbr->newSelectQueryBuilder() + ->table( 'cu_changes' ) + ->field( 'cuc_ip' ) + ->conds( [ 'cuc_user' => $user->getId( $block->getWikiId() ) ] ) + // just the last IP used + ->limit( 1 ) + ->orderBy( 'cuc_timestamp', SelectQueryBuilder::SORT_DESC ) + ->caller( __METHOD__ ) + ->fetchResultSet(); + + # Iterate through IPs used (this is just one or zero for now) + foreach ( $res as $row ) { + if ( $row->cuc_ip ) { + $id = $block->doAutoblock( $row->cuc_ip ); + if ( $id ) { + $blockIds[] = $id; + } + } + } + + // autoblock handled + return false; + } + + /** + * @param array &$updateFields + * + * @return bool + */ + public static function onUserMergeAccountFields( array &$updateFields ) { + $actorMigrationStage = MediaWikiServices::getInstance() + ->getMainConfig() + ->get( 'CheckUserActorMigrationStage' ); + if ( $actorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { + $updateFields[] = [ + 'cu_changes', + 'batch_key' => 'cuc_id', + 'actorId' => 'cuc_actor', + 'actorStage' => $actorMigrationStage + ]; + } + $culActorMigrationStage = MediaWikiServices::getInstance() + ->getMainConfig() + ->get( 'CheckUserLogActorMigrationStage' ); + if ( $actorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { + $updateFields[] = [ + 'cu_log', + 'batch_key' => 'cul_id', + 'actorId' => 'cul_actor', + 'actorStage' => $culActorMigrationStage + ]; + } + $updateFields[] = [ 'cu_changes', 'cuc_user', 'cuc_user_text' ]; + $updateFields[] = [ 'cu_log', 'cul_user', 'cul_user_text' ]; + $updateFields[] = [ 'cu_log', 'cul_target_id' ]; + + return true; + } + + /** + * For integration with the Renameuser extension. + * + * @param RenameuserSQL $renameUserSQL + * @return bool + */ + public static function onRenameUserSQL( RenameuserSQL $renameUserSQL ) { + $renameUserSQL->tablesJob['cu_changes'] = [ + RenameuserSQL::NAME_COL => 'cuc_user_text', + RenameuserSQL::UID_COL => 'cuc_user', + RenameuserSQL::TIME_COL => 'cuc_timestamp', + 'uniqueKey' => 'cuc_id' + ]; + + $renameUserSQL->tables['cu_log'] = [ 'cul_user_text', 'cul_user' ]; + + return true; + } + + /** + * @param int $userId + * @param string $userText + * @param array &$items + */ + public function onUserToolLinksEdit( $userId, $userText, &$items ) { + $requestTitle = RequestContext::getMain()->getTitle(); + if ( + $requestTitle !== null && + $requestTitle->inNamespace( NS_SPECIAL ) && + MediaWikiServices::getInstance()->getSpecialPageFactory()-> + resolveAlias( $requestTitle->getText() )[0] === 'CheckUserLog' + ) { + $items[] = MediaWikiServices::getInstance()->getLinkRenderer()->makeLink( + SpecialPage::getTitleFor( 'CheckUserLog', $userText ), + wfMessage( 'checkuser-log-checks-on' )->text() + ); + } + } + + /** + * @param RecentChange $recentChange + */ + public function onRecentChange_save( $recentChange ) { + self::updateCheckUserData( $recentChange ); + $this->maybePruneIPData(); + } +} diff --git a/CheckUser/src/ComparePager.php b/CheckUser/src/Investigate/Pagers/ComparePager.php index e3de207c..1b34fcbc 100644 --- a/CheckUser/src/ComparePager.php +++ b/CheckUser/src/Investigate/Pagers/ComparePager.php @@ -20,12 +20,15 @@ * @ingroup Pager */ -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Pagers; use DateTime; use Html; use IContextSource; use Linker; +use MediaWiki\CheckUser\Investigate\Services\CompareService; +use MediaWiki\CheckUser\Investigate\Utilities\DurationManager; +use MediaWiki\CheckUser\TokenQueryManager; use MediaWiki\Linker\LinkRenderer; use TablePager; use Wikimedia\IPUtils; @@ -71,6 +74,13 @@ class ComparePager extends TablePager { /** @var string */ private $start; + /** + * @param IContextSource $context + * @param LinkRenderer $linkRenderer + * @param TokenQueryManager $tokenQueryManager + * @param DurationManager $durationManager + * @param CompareService $compareService + */ public function __construct( IContextSource $context, LinkRenderer $linkRenderer, @@ -125,7 +135,9 @@ class ComparePager extends TablePager { 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 ) { + } + + if ( IPUtils::toHex( $target ) === $row->cuc_ip_hex ) { $attributes['class'] .= ' ext-checkuser-compare-table-cell-target'; break; } @@ -302,7 +314,7 @@ class ComparePager extends TablePager { * * @return string[] Targets whose limits were exceeded (if any) */ - public function getTargetsOverLimit() : array { + public function getTargetsOverLimit(): array { return $this->compareService->getTargetsOverLimit( $this->filteredTargets, $this->excludeTargets, diff --git a/CheckUser/src/ComparePagerFactory.php b/CheckUser/src/Investigate/Pagers/ComparePagerFactory.php index 78cf28cc..3ab818ce 100644 --- a/CheckUser/src/ComparePagerFactory.php +++ b/CheckUser/src/Investigate/Pagers/ComparePagerFactory.php @@ -1,7 +1,10 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Pagers; +use MediaWiki\CheckUser\Investigate\Services\CompareService; +use MediaWiki\CheckUser\Investigate\Utilities\DurationManager; +use MediaWiki\CheckUser\TokenQueryManager; use MediaWiki\Linker\LinkRenderer; class ComparePagerFactory implements PagerFactory { @@ -38,7 +41,7 @@ class ComparePagerFactory implements PagerFactory { /** * @inheritDoc */ - public function createPager( \IContextSource $context ) : ComparePager { + public function createPager( \IContextSource $context ): ComparePager { return new ComparePager( $context, $this->linkRenderer, diff --git a/CheckUser/src/Investigate/Pagers/PagerFactory.php b/CheckUser/src/Investigate/Pagers/PagerFactory.php new file mode 100644 index 00000000..b6b93e2f --- /dev/null +++ b/CheckUser/src/Investigate/Pagers/PagerFactory.php @@ -0,0 +1,14 @@ +<?php + +namespace MediaWiki\CheckUser\Investigate\Pagers; + +use IContextSource; + +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/Investigate/Pagers/PreliminaryCheckPager.php index 30a3c58e..58369803 100644 --- a/CheckUser/src/PreliminaryCheckPager.php +++ b/CheckUser/src/Investigate/Pagers/PreliminaryCheckPager.php @@ -19,14 +19,18 @@ * @ingroup Pager */ -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Pagers; -use CentralAuthUtils; use ExtensionRegistry; use Html; use IContextSource; +use MediaWiki\CheckUser\Investigate\Services\PreliminaryCheckService; +use MediaWiki\CheckUser\TokenQueryManager; +use MediaWiki\Extension\CentralAuth\CentralAuthDatabaseManager; +use MediaWiki\Extension\CentralAuth\CentralAuthServices; use MediaWiki\Linker\LinkRenderer; use NamespaceInfo; +use SpecialPage; use TablePager; use WikiMap; use Wikimedia\Rdbms\FakeResultWrapper; @@ -180,7 +184,7 @@ class PreliminaryCheckPager extends TablePager { ); } else { $formatted = $this->getLinkRenderer()->makeKnownLink( - \SpecialPage::getTitleFor( 'Contributions', $row->name ), + SpecialPage::getTitleFor( 'Contributions', $row->name ), $this->msg( 'checkuser-investigate-preliminary-table-cell-edits', $value @@ -228,12 +232,10 @@ class PreliminaryCheckPager extends TablePager { 'groups' => 'checkuser-investigate-preliminary-table-header-groups', ]; - if ( $this->isGlobalCheck() ) { - $this->fieldNames = $fullFieldNames; - } else { + if ( !$this->isGlobalCheck() ) { unset( $fullFieldNames['wiki'] ); - $this->fieldNames = $fullFieldNames; } + $this->fieldNames = $fullFieldNames; foreach ( $this->fieldNames as $key => $val ) { $this->fieldNames[$key] = $this->msg( $val )->text(); @@ -247,7 +249,7 @@ class PreliminaryCheckPager extends TablePager { */ public function getQueryInfo() { $targets = $this->tokenData['targets'] ?? []; - $users = array_filter( array_map( 'User::newFromName', $targets ), function ( $user ) { + $users = array_filter( array_map( 'User::newFromName', $targets ), static function ( $user ) { return (bool)$user; } ); @@ -268,15 +270,15 @@ class PreliminaryCheckPager extends TablePager { */ public function isGlobalCheck(): bool { return $this->extensionRegistry->isLoaded( 'CentralAuth' ) - && is_callable( [ CentralAuthUtils::class, 'getCentralReplicaDB' ] ); + && class_exists( CentralAuthDatabaseManager::class ); } /** * @return IDatabase|null */ protected function getCentralReplicaDB(): ?IDatabase { - if ( is_callable( [ CentralAuthUtils::class, 'getCentralReplicaDB' ] ) ) { - return CentralAuthUtils::getCentralReplicaDB(); + if ( class_exists( CentralAuthDatabaseManager::class ) ) { + return CentralAuthServices::getDatabaseManager()->getCentralDB( DB_REPLICA ); } return null; } diff --git a/CheckUser/src/PreliminaryCheckPagerFactory.php b/CheckUser/src/Investigate/Pagers/PreliminaryCheckPagerFactory.php index aaee655e..68f89063 100644 --- a/CheckUser/src/PreliminaryCheckPagerFactory.php +++ b/CheckUser/src/Investigate/Pagers/PreliminaryCheckPagerFactory.php @@ -1,17 +1,22 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Pagers; +use ExtensionRegistry; +use IContextSource; +use MediaWiki\CheckUser\Investigate\Services\PreliminaryCheckService; +use MediaWiki\CheckUser\TokenQueryManager; use MediaWiki\Linker\LinkRenderer; +use NamespaceInfo; class PreliminaryCheckPagerFactory implements PagerFactory { /** @var LinkRenderer */ private $linkRenderer; - /** @var \NamespaceInfo */ + /** @var NamespaceInfo */ private $namespaceInfo; - /** @var \ExtensionRegistry */ + /** @var ExtensionRegistry */ private $extensionRegistry; /** @var TokenQueryManager */ @@ -22,15 +27,15 @@ class PreliminaryCheckPagerFactory implements PagerFactory { /** * @param LinkRenderer $linkRenderer - * @param \NamespaceInfo $namespaceInfo - * @param \ExtensionRegistry $extensionRegistry + * @param NamespaceInfo $namespaceInfo + * @param ExtensionRegistry $extensionRegistry * @param TokenQueryManager $tokenQueryManager * @param PreliminaryCheckService $preliminaryCheck */ public function __construct( LinkRenderer $linkRenderer, - \NamespaceInfo $namespaceInfo, - \ExtensionRegistry $extensionRegistry, + NamespaceInfo $namespaceInfo, + ExtensionRegistry $extensionRegistry, TokenQueryManager $tokenQueryManager, PreliminaryCheckService $preliminaryCheck ) { @@ -44,7 +49,7 @@ class PreliminaryCheckPagerFactory implements PagerFactory { /** * @inheritDoc */ - public function createPager( \IContextSource $context ) : PreliminaryCheckPager { + public function createPager( IContextSource $context ): PreliminaryCheckPager { return new PreliminaryCheckPager( $context, $this->linkRenderer, diff --git a/CheckUser/src/TimelinePager.php b/CheckUser/src/Investigate/Pagers/TimelinePager.php index 3252579e..64581e4c 100644 --- a/CheckUser/src/TimelinePager.php +++ b/CheckUser/src/Investigate/Pagers/TimelinePager.php @@ -1,12 +1,16 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Pagers; use Html; use IContextSource; use MediaWiki\CheckUser\Hook\CheckUserFormatRowHook; +use MediaWiki\CheckUser\Investigate\Services\TimelineService; +use MediaWiki\CheckUser\Investigate\Utilities\DurationManager; +use MediaWiki\CheckUser\TokenQueryManager; use MediaWiki\Linker\LinkRenderer; use ParserOutput; +use Psr\Log\LoggerInterface; use ReverseChronologicalPager; class TimelinePager extends ReverseChronologicalPager { @@ -47,6 +51,19 @@ class TimelinePager extends ReverseChronologicalPager { */ private $filteredTargets; + /** @var LoggerInterface */ + private $logger; + + /** + * @param IContextSource $context + * @param LinkRenderer $linkRenderer + * @param CheckUserFormatRowHook $formatRowHookRunner + * @param TokenQueryManager $tokenQueryManager + * @param DurationManager $durationManager + * @param TimelineService $timelineService + * @param TimelineRowFormatter $timelineRowFormatter + * @param LoggerInterface $logger + */ public function __construct( IContextSource $context, LinkRenderer $linkRenderer, @@ -54,13 +71,15 @@ class TimelinePager extends ReverseChronologicalPager { TokenQueryManager $tokenQueryManager, DurationManager $durationManager, TimelineService $timelineService, - TimelineRowFormatter $timelineRowFormatter + TimelineRowFormatter $timelineRowFormatter, + LoggerInterface $logger ) { parent::__construct( $context, $linkRenderer ); $this->formatRowHookRunner = $formatRowHookRunner; $this->timelineService = $timelineService; $this->timelineRowFormatter = $timelineRowFormatter; $this->tokenQueryManager = $tokenQueryManager; + $this->logger = $logger; $tokenData = $tokenQueryManager->getDataFromRequest( $context->getRequest() ); $this->mOffset = $tokenData['offset'] ?? ''; @@ -114,8 +133,7 @@ class TimelinePager extends ReverseChronologicalPager { $this->formatRowHookRunner->onCheckUserFormatRow( $this->getContext(), $row, $rowItems ); if ( !is_array( $rowItems ) || !isset( $rowItems['links'] ) || !isset( $rowItems['info'] ) ) { - wfDebugLog( - __CLASS__, + $this->logger->warning( __METHOD__ . ': Expected array with keys \'links\' and \'info\'' . ' from CheckUserFormatRow $rowItems param' ); @@ -124,7 +142,7 @@ class TimelinePager extends ReverseChronologicalPager { $formattedLinks = implode( ' ', array_filter( $rowItems['links'], - function ( $item ) { + static function ( $item ) { return $item !== ''; } ) ); @@ -133,7 +151,7 @@ class TimelinePager extends ReverseChronologicalPager { array_merge( [ $formattedLinks ], $rowItems['info'] - ), function ( $item ) { + ), static function ( $item ) { return $item !== ''; } ) ); @@ -166,11 +184,11 @@ class TimelinePager extends ReverseChronologicalPager { } /** - * Get the formatted result list, with naviation bars. + * Get the formatted result list, with navigation bars. * * @return ParserOutput */ - public function getFullOutput() : ParserOutput { + public function getFullOutput(): ParserOutput { return new ParserOutput( $this->getNavigationBar() . $this->getBody() . $this->getNavigationBar() ); diff --git a/CheckUser/src/TimelinePagerFactory.php b/CheckUser/src/Investigate/Pagers/TimelinePagerFactory.php index 04d1a37a..e08e28b0 100644 --- a/CheckUser/src/TimelinePagerFactory.php +++ b/CheckUser/src/Investigate/Pagers/TimelinePagerFactory.php @@ -1,10 +1,14 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Pagers; use IContextSource; use MediaWiki\CheckUser\Hook\CheckUserFormatRowHook; +use MediaWiki\CheckUser\Investigate\Services\TimelineService; +use MediaWiki\CheckUser\Investigate\Utilities\DurationManager; +use MediaWiki\CheckUser\TokenQueryManager; use MediaWiki\Linker\LinkRenderer; +use Psr\Log\LoggerInterface; class TimelinePagerFactory implements PagerFactory { /** @var LinkRenderer */ @@ -25,13 +29,26 @@ class TimelinePagerFactory implements PagerFactory { /** @var TimelineRowFormatterFactory */ private $rowFormatterFactory; + /** @var LoggerInterface */ + private $logger; + + /** + * @param LinkRenderer $linkRenderer + * @param CheckUserFormatRowHook $formatRowHookRunner + * @param TokenQueryManager $tokenQueryManager + * @param DurationManager $durationManager + * @param TimelineService $service + * @param TimelineRowFormatterFactory $rowFormatterFactory + * @param LoggerInterface $logger + */ public function __construct( LinkRenderer $linkRenderer, CheckUserFormatRowHook $formatRowHookRunner, TokenQueryManager $tokenQueryManager, DurationManager $durationManager, TimelineService $service, - TimelineRowFormatterFactory $rowFormatterFactory + TimelineRowFormatterFactory $rowFormatterFactory, + LoggerInterface $logger ) { $this->linkRenderer = $linkRenderer; $this->formatRowHookRunner = $formatRowHookRunner; @@ -39,12 +56,13 @@ class TimelinePagerFactory implements PagerFactory { $this->durationManager = $durationManager; $this->service = $service; $this->rowFormatterFactory = $rowFormatterFactory; + $this->logger = $logger; } /** * @inheritDoc */ - public function createPager( IContextSource $context ) : TimelinePager { + public function createPager( IContextSource $context ): TimelinePager { $rowFormatter = $this->rowFormatterFactory->createRowFormatter( $context->getUser(), $context->getLanguage() ); @@ -56,7 +74,8 @@ class TimelinePagerFactory implements PagerFactory { $this->tokenQueryManager, $this->durationManager, $this->service, - $rowFormatter + $rowFormatter, + $this->logger ); } } diff --git a/CheckUser/src/TimelineRowFormatter.php b/CheckUser/src/Investigate/Pagers/TimelineRowFormatter.php index 7b67e4aa..cf21fef4 100644 --- a/CheckUser/src/TimelineRowFormatter.php +++ b/CheckUser/src/Investigate/Pagers/TimelineRowFormatter.php @@ -1,21 +1,23 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Pagers; use Html; use HtmlArmor; use Language; use Linker; +use MediaWiki\CommentFormatter\CommentFormatter; 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 MediaWiki\User\UserFactory; +use MediaWiki\User\UserRigorOptions; use Message; use TitleFormatter; use TitleValue; use User; +use Wikimedia\IPUtils; use Wikimedia\Rdbms\ILoadBalancer; class TimelineRowFormatter { @@ -26,15 +28,9 @@ class TimelineRowFormatter { /** @var ILoadBalancer */ private $loadBalancer; - /** @var RevisionLookup */ - private $revisionLookup; - /** @var RevisionStore */ private $revisionStore; - /** @var RevisionFactory */ - private $revisionFactory; - /** @var TitleFormatter */ private $titleFormatter; @@ -50,24 +46,41 @@ class TimelineRowFormatter { /** @var User */ private $user; + /** @var UserFactory */ + private $userFactory; + + /** @var CommentFormatter */ + private $commentFormatter; + + /** + * @param LinkRenderer $linkRenderer + * @param ILoadBalancer $loadBalancer + * @param RevisionStore $revisionStore + * @param TitleFormatter $titleFormatter + * @param SpecialPageFactory $specialPageFactory + * @param CommentFormatter $commentFormatter + * @param UserFactory $userFactory + * @param User $user + * @param Language $language + */ public function __construct( LinkRenderer $linkRenderer, ILoadBalancer $loadBalancer, - RevisionLookup $revisionLookup, RevisionStore $revisionStore, - RevisionFactory $revisionFactory, TitleFormatter $titleFormatter, SpecialPageFactory $specialPageFactory, + CommentFormatter $commentFormatter, + UserFactory $userFactory, 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->commentFormatter = $commentFormatter; + $this->userFactory = $userFactory; $this->user = $user; $this->language = $language; @@ -81,7 +94,7 @@ class TimelineRowFormatter { * @param \stdClass $row * @return array */ - public function getFormattedRowItems( \stdClass $row ) : array { + public function getFormattedRowItems( \stdClass $row ): array { return [ 'links' => [ 'logLink' => $this->getLogLink( $row ), @@ -96,7 +109,7 @@ class TimelineRowFormatter { 'userLinks' => $this->getUserLinks( $row ), 'actionText' => $this->getActionText( $row->cuc_actiontext ), 'ipInfo' => $this->getIpInfo( $row->cuc_ip ), - 'userAgent' => $this->getUserAgent( $row->cuc_agent ), + 'userAgent' => $this->getUserAgent( $row->cuc_agent ?? '' ), 'comment' => $this->getComment( $row ), ], ]; @@ -109,28 +122,27 @@ class TimelineRowFormatter { * @param \stdClass $row * @return string */ - private function getComment( \stdClass $row ) : 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 ); + $revRecord = $this->revisionStore->getRevisionById( $row->cuc_this_oldid ); if ( !$revRecord ) { // Revision may have been deleted - $db = $this->loadBalancer->getConnectionRef( DB_REPLICA ); + $dbr = $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'] - ); + $archiveRow = $dbr->newSelectQueryBuilder() + ->fields( $queryInfo['fields'] ) + ->tables( $queryInfo['tables'] ) + ->where( [ 'ar_rev_id' => $row->cuc_this_oldid ] ) + ->joinConds( $queryInfo['joins'] ) + ->caller( __METHOD__ ) + ->fetchRow(); if ( $archiveRow ) { - $revRecord = $this->revisionFactory->newRevisionFromArchiveRow( $archiveRow ); + $revRecord = $this->revisionStore->newRevisionFromArchiveRow( $archiveRow ); } } if ( @@ -141,9 +153,9 @@ class TimelineRowFormatter { $this->user ) ) { - $comment = Linker::revComment( $revRecord ); + $comment = $this->commentFormatter->formatRevision( $revRecord, $this->user ); } else { - $comment = Linker::commentBlock( + $comment = $this->commentFormatter->formatBlock( $this->msg( 'rev-deleted-comment' )->text(), null, false, @@ -160,17 +172,17 @@ class TimelineRowFormatter { * @param string $ip * @return string */ - private function getIpInfo( string $ip ) : 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; + return IPUtils::prettifyIP( $ip ); } /** * @param string $userAgent * @return string */ - private function getUserAgent( string $userAgent ) : string { + private function getUserAgent( string $userAgent ): string { return htmlspecialchars( $userAgent ); } @@ -178,15 +190,15 @@ class TimelineRowFormatter { * @param string $actionText * @return string */ - private function getActionText( string $actionText ) : string { - return Linker::formatComment( $actionText ); + private function getActionText( string $actionText ): string { + return $this->commentFormatter->format( $actionText ); } /** * @param \stdClass $row * @return string */ - private function getTitleLink( \stdClass $row ) : string { + private function getTitleLink( \stdClass $row ): string { if ( $row->cuc_type == RC_LOG ) { return ''; } @@ -197,14 +209,18 @@ class TimelineRowFormatter { return ''; } - return $this->linkRenderer->makeLink( $title ); + return $this->linkRenderer->makeLink( + $title, + null, + [ 'class' => 'ext-checkuser-investigate-timeline-row-title' ] + ); } /** * @param \stdClass $row * @return string */ - private function getLogLink( \stdClass $row ) : string { + private function getLogLink( \stdClass $row ): string { if ( $row->cuc_type != RC_LOG ) { return ''; } @@ -229,7 +245,7 @@ class TimelineRowFormatter { * @param \stdClass $row * @return string */ - private function getDiffLink( \stdClass $row ) : string { + private function getDiffLink( \stdClass $row ): string { if ( $row->cuc_type == RC_NEW || $row->cuc_type == RC_LOG ) { return ''; } @@ -259,7 +275,7 @@ class TimelineRowFormatter { * @param \stdClass $row * @return string */ - private function getHistoryLink( \stdClass $row ) : string { + private function getHistoryLink( \stdClass $row ): string { if ( $row->cuc_type == RC_NEW || $row->cuc_type == RC_LOG ) { return ''; } @@ -288,7 +304,7 @@ class TimelineRowFormatter { * @param int $type * @return string */ - private function getNewPageFlag( int $type ) : string { + private function getNewPageFlag( int $type ): string { if ( $type == RC_NEW ) { return Html::rawElement( 'span', [ 'class' => 'newpage' ], @@ -302,7 +318,7 @@ class TimelineRowFormatter { * @param bool $minor * @return string */ - private function getMinorFlag( bool $minor ) : string { + private function getMinorFlag( bool $minor ): string { if ( $minor ) { return Html::rawElement( 'span', @@ -317,7 +333,7 @@ class TimelineRowFormatter { * @param string $timestamp * @return string */ - private function getTime( string $timestamp ) : string { + private function getTime( string $timestamp ): string { return htmlspecialchars( $this->language->userTime( wfTimestamp( TS_MW, $timestamp ), $this->user ) ); @@ -327,11 +343,16 @@ class TimelineRowFormatter { * @param \stdClass $row * @return string */ - private function getUserLinks( \stdClass $row ) : 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(); + $userId = $row->cuc_user; + if ( $userId > 0 ) { + $user = $this->userFactory->newFromId( $userId ); + } else { + // This is an IP + $user = $this->userFactory->newFromName( $row->cuc_user_text, UserRigorOptions::RIGOR_NONE ); + } $links = Html::rawElement( 'span', [], Linker::userLink( $userId, $user->getName() ) @@ -362,7 +383,7 @@ class TimelineRowFormatter { * @param array $params * @return Message */ - private function msg( string $key, array $params = [] ) : 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/Investigate/Pagers/TimelineRowFormatterFactory.php index 847126f6..4f604ab8 100644 --- a/CheckUser/src/TimelineRowFormatterFactory.php +++ b/CheckUser/src/Investigate/Pagers/TimelineRowFormatterFactory.php @@ -1,13 +1,13 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Pagers; use Language; +use MediaWiki\CommentFormatter\CommentFormatter; use MediaWiki\Linker\LinkRenderer; -use MediaWiki\Revision\RevisionFactory; -use MediaWiki\Revision\RevisionLookup; use MediaWiki\Revision\RevisionStore; use MediaWiki\SpecialPage\SpecialPageFactory; +use MediaWiki\User\UserFactory; use TitleFormatter; use User; use Wikimedia\Rdbms\ILoadBalancer; @@ -20,37 +20,46 @@ class TimelineRowFormatterFactory { /** @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 CommentFormatter */ + private $commentFormatter; + + /** @var UserFactory */ + private $userFactory; + + /** + * @param LinkRenderer $linkRenderer + * @param ILoadBalancer $loadBalancer + * @param RevisionStore $revisionStore + * @param TitleFormatter $titleFormatter + * @param SpecialPageFactory $specialPageFactory + * @param CommentFormatter $commentFormatter + * @param UserFactory $userFactory + */ public function __construct( LinkRenderer $linkRenderer, ILoadBalancer $loadBalancer, - RevisionLookup $revisionLookup, RevisionStore $revisionStore, - RevisionFactory $revisionFactory, TitleFormatter $titleFormatter, - SpecialPageFactory $specialPageFactory + SpecialPageFactory $specialPageFactory, + CommentFormatter $commentFormatter, + UserFactory $userFactory ) { $this->linkRenderer = $linkRenderer; $this->loadBalancer = $loadBalancer; - $this->revisionLookup = $revisionLookup; $this->revisionStore = $revisionStore; - $this->revisionFactory = $revisionFactory; $this->titleFormatter = $titleFormatter; $this->specialPageFactory = $specialPageFactory; + $this->commentFormatter = $commentFormatter; + $this->userFactory = $userFactory; } /** @@ -60,15 +69,15 @@ class TimelineRowFormatterFactory { * @param Language $language * @return TimelineRowFormatter */ - public function createRowFormatter( User $user, Language $language ) : 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, + $this->commentFormatter, + $this->userFactory, $user, $language ); diff --git a/CheckUser/src/Investigate/Services/ChangeService.php b/CheckUser/src/Investigate/Services/ChangeService.php new file mode 100644 index 00000000..a73eb094 --- /dev/null +++ b/CheckUser/src/Investigate/Services/ChangeService.php @@ -0,0 +1,150 @@ +<?php + +namespace MediaWiki\CheckUser\Investigate\Services; + +use MediaWiki\User\UserIdentityLookup; +use Wikimedia\IPUtils; +use Wikimedia\Rdbms\Database\DbQuoter; +use Wikimedia\Rdbms\IDatabase; +use Wikimedia\Rdbms\Platform\ISQLPlatform; + +abstract class ChangeService { + /** @var DbQuoter */ + protected $dbQuoter; + + /** @var ISQLPlatform */ + protected $sqlPlatform; + + /** @var UserIdentityLookup */ + private $userIdentityLookup; + + /** + * @param DbQuoter $dbQuoter + * @param ISQLPlatform $sqlPlatform + * @param UserIdentityLookup $userIdentityLookup + */ + public function __construct( + DbQuoter $dbQuoter, + ISQLPlatform $sqlPlatform, + UserIdentityLookup $userIdentityLookup + ) { + $this->dbQuoter = $dbQuoter; + $this->sqlPlatform = $sqlPlatform; + $this->userIdentityLookup = $userIdentityLookup; + } + + /** + * Builds a query predicate depending on what type of + * target is passed in + * + * @param string[] $targets + * @return string[] + */ + protected function buildTargetCondsMultiple( array $targets ): array { + $condSet = array_map( function ( $target ) { + return $this->buildTargetConds( $target ); + }, $targets ); + + if ( !$condSet ) { + return [ + $this->dbQuoter->addQuotes( false ) + ]; + } + + $conds = array_merge_recursive( ...$condSet ); + + if ( !$conds ) { + return [ + $this->dbQuoter->addQuotes( false ) + ]; + } + + return [ + $this->sqlPlatform->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 { + $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[] = $this->sqlPlatform->makeList( [ + 'cuc_ip_hex >= ' . $this->dbQuoter->addQuotes( $range[0] ), + 'cuc_ip_hex <= ' . $this->dbQuoter->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). + $user = $this->userIdentityLookup->getUserIdentityByName( $target ); + if ( $user ) { + $userId = $user->getId(); + if ( $userId !== 0 ) { + $conds['cuc_user'] = $userId; + } + } + } + + return $conds; + } + + /** + * @param string[] $targets + * @return array + */ + protected function buildExcludeTargetsConds( array $targets ): array { + $conds = []; + $ipTargets = []; + $userTargets = []; + + foreach ( $targets as $target ) { + if ( IPUtils::isIpAddress( $target ) ) { + $ipTargets[] = IPUtils::toHex( $target ); + } else { + $user = $this->userIdentityLookup->getUserIdentityByName( $target ); + if ( $user ) { + $userId = $user->getId(); + if ( $userId !== 0 ) { + $userTargets[] = $userId; + } + } + } + } + + if ( count( $ipTargets ) > 0 ) { + $conds[] = 'cuc_ip_hex NOT IN (' . $this->sqlPlatform->makeList( $ipTargets ) . ')'; + } + if ( count( $userTargets ) > 0 ) { + $conds[] = 'cuc_user NOT IN (' . $this->sqlPlatform->makeList( $userTargets ) . ')'; + } + + return $conds; + } + + /** + * Build conditions for the start timestamp. + * + * @param string $start timestamp + * @return array conditions + */ + protected function buildStartConds( string $start ): array { + if ( $start === '' ) { + return []; + } + + return [ + 'cuc_timestamp >= ' . $this->dbQuoter->addQuotes( $start ), + ]; + } +} diff --git a/CheckUser/src/Investigate/Services/CompareService.php b/CheckUser/src/Investigate/Services/CompareService.php new file mode 100644 index 00000000..f4dbbdef --- /dev/null +++ b/CheckUser/src/Investigate/Services/CompareService.php @@ -0,0 +1,240 @@ +<?php + +namespace MediaWiki\CheckUser\Investigate\Services; + +use IDatabase; +use LogicException; +use MediaWiki\Config\ServiceOptions; +use MediaWiki\User\UserIdentityLookup; +use Wikimedia\Rdbms\ILoadBalancer; +use Wikimedia\Rdbms\SelectQueryBuilder; +use Wikimedia\Rdbms\Subquery; + +class CompareService extends ChangeService { + /** @var ServiceOptions */ + private $options; + + /** @var ILoadBalancer */ + private $loadBalancer; + + /** + * @internal For use by ServiceWiring + */ + public const CONSTRUCTOR_OPTIONS = [ + 'CheckUserInvestigateMaximumRowCount', + ]; + + /** @var int */ + private $limit; + + /** + * @param ServiceOptions $options + * @param ILoadBalancer $loadBalancer + * @param UserIdentityLookup $userIdentityLookup + */ + public function __construct( + ServiceOptions $options, + ILoadBalancer $loadBalancer, + UserIdentityLookup $userIdentityLookup + ) { + parent::__construct( + $loadBalancer->getConnection( DB_REPLICA ), + $loadBalancer->getConnection( DB_REPLICA ), + $userIdentityLookup + ); + + $this->loadBalancer = $loadBalancer; + $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS ); + $this->limit = $options->get( 'CheckUserInvestigateMaximumRowCount' ); + } + + /** + * Get edits made from an ip + * + * @param string $ipHex + * @param string|null $excludeUser + * @return int + */ + public function getTotalEditsFromIp( + string $ipHex, + string $excludeUser = null + ): int { + $queryBuilder = $this->loadBalancer->getConnection( DB_REPLICA )->newSelectQueryBuilder() + ->select( 'cuc_id' ) + ->from( 'cu_changes' ) + ->where( [ + 'cuc_ip_hex' => $ipHex, + 'cuc_type' => [ RC_EDIT, RC_NEW ], + ] ) + ->caller( __METHOD__ ); + + if ( $excludeUser ) { + $queryBuilder->where( + 'cuc_user_text != ' . $this->dbQuoter->addQuotes( $excludeUser ) + ); + } + + return $queryBuilder->fetchRowCount(); + } + + /** + * 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 { + $dbr = $this->loadBalancer->getConnection( 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 ) { + $conds = $this->buildCondsForSingleTarget( $target, $excludeTargets, $start ); + if ( $conds !== null ) { + $queryBuilder = $dbr->newSelectQueryBuilder() + ->select( [ + 'cuc_id', + 'cuc_user', + 'cuc_user_text', + 'cuc_ip', + 'cuc_ip_hex', + 'cuc_agent', + 'cuc_timestamp', + ] ) + ->from( 'cu_changes' ) + ->where( $conds ) + ->caller( __METHOD__ ); + if ( $dbr->unionSupportsOrderAndLimit() ) { + $queryBuilder->orderBy( 'cuc_timestamp', SelectQueryBuilder::SORT_DESC ) + ->limit( $limit ); + } + $sqlText[] = $queryBuilder->getSQL(); + } + } + + $derivedTable = $dbr->unionQueries( $sqlText, IDatabase::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', + 'cuc_user_text', + 'cuc_ip', + 'cuc_ip_hex', + 'cuc_agent', + ], + ], + ]; + } + + /** + * Get the query info for a single target. + * + * For the main investigation, this is used in a subquery that contributes to a derived + * table, used by getQueryInfo. + * + * For a limit check, this is used to build a query that 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 + * @return array|null Return null for invalid target + */ + private function buildCondsForSingleTarget( + string $target, + array $excludeTargets, + string $start + ): ?array { + $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, RC_LOG ]; + + return $conds; + } + + /** + * We set a maximum number of rows in cu_changes to be grouped in the Compare table query, + * for performance reasons (see ::getQueryInfo). We share these uniformly between the targets, + * so the maximum number of rows per target is the limit divided by the number of targets. + * + * @param array $targets + * @return int + */ + private function getLimitPerTarget( array $targets ) { + return (int)( $this->limit / count( $targets ) ); + } + + /** + * 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; + } + + $dbr = $this->loadBalancer->getConnection( 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 ( !$dbr->unionSupportsOrderAndLimit() ) { + return []; + } + + $targetsOverLimit = []; + $offset = $this->getLimitPerTarget( $targets ); + + foreach ( $targets as $target ) { + $conds = $this->buildCondsForSingleTarget( $target, $excludeTargets, $start ); + if ( $conds !== null ) { + $limitCheck = $dbr->newSelectQueryBuilder() + ->select( 'cuc_id' ) + ->from( 'cu_changes' ) + ->where( $conds ) + ->offset( $offset ) + ->limit( 1 ) + ->caller( __METHOD__ ); + if ( $limitCheck->fetchRowCount() > 0 ) { + $targetsOverLimit[] = $target; + } + } + } + + return $targetsOverLimit; + } +} diff --git a/CheckUser/src/PreliminaryCheckService.php b/CheckUser/src/Investigate/Services/PreliminaryCheckService.php index 3fae09d1..678aec78 100644 --- a/CheckUser/src/PreliminaryCheckService.php +++ b/CheckUser/src/Investigate/Services/PreliminaryCheckService.php @@ -1,7 +1,9 @@ <?php -namespace MediaWiki\CheckUser; + +namespace MediaWiki\CheckUser\Investigate\Services; use ExtensionRegistry; +use MediaWiki\Block\DatabaseBlock; use MediaWiki\User\UserGroupManagerFactory; use MediaWiki\User\UserIdentityValue; use stdClass; @@ -48,7 +50,7 @@ class PreliminaryCheckService { * @param User[] $users * @return array */ - public function getQueryInfo( array $users ) : array { + public function getQueryInfo( array $users ): array { if ( $this->extensionRegistry->isLoaded( 'CentralAuth' ) ) { $info = $this->getGlobalQueryInfo( $users ); } else { @@ -63,7 +65,7 @@ class PreliminaryCheckService { * @param User[] $users * @return array */ - protected function getGlobalQueryInfo( array $users ) : array { + protected function getGlobalQueryInfo( array $users ): array { return [ 'tables' => 'localuser', 'fields' => [ @@ -80,7 +82,7 @@ class PreliminaryCheckService { * @param User[]|string[] $users * @return array */ - protected function getLocalQueryInfo( array $users ) : array { + protected function getLocalQueryInfo( array $users ): array { return [ 'tables' => 'user', 'fields' => [ @@ -98,7 +100,7 @@ class PreliminaryCheckService { * @param string $field * @return array */ - protected function buildUserConds( array $users, string $field ) : array { + protected function buildUserConds( array $users, string $field ): array { if ( !$users ) { return [ 0 ]; } @@ -111,7 +113,7 @@ class PreliminaryCheckService { * @param string $wikiId * @return IDatabase */ - protected function getLocalDb( $wikiId ) : IDatabase { + protected function getLocalDb( $wikiId ): IDatabase { return $this->lbFactory->getMainLB( $wikiId )->getConnectionRef( DB_REPLICA, [], $wikiId ); } @@ -123,7 +125,7 @@ class PreliminaryCheckService { * @param IResultWrapper $rows * @return array */ - public function preprocessResults( IResultWrapper $rows ) : array { + public function preprocessResults( IResultWrapper $rows ): array { $data = []; foreach ( $rows as $row ) { if ( $this->extensionRegistry->isLoaded( 'CentralAuth' ) ) { @@ -144,14 +146,14 @@ class PreliminaryCheckService { * @return stdClass|bool */ public function getLocalUserData( string $username, string $wikiId ) { - $db = $this->getLocalDb( $wikiId ); + $dbr = $this->getLocalDb( $wikiId ); $queryInfo = $this->getLocalQueryInfo( [ $username ] ); - return $db->selectRow( - $queryInfo['tables'], - $queryInfo['fields'], - $queryInfo['conds'], - __METHOD__ - ); + return $dbr->newSelectQueryBuilder() + ->select( $queryInfo['fields'] ) + ->from( $queryInfo['tables'] ) + ->where( $queryInfo['conds'] ) + ->caller( __METHOD__ ) + ->fetchRow(); } /** @@ -162,19 +164,19 @@ class PreliminaryCheckService { * @param string $wikiId * @return array */ - protected function getAdditionalLocalData( $row, string $wikiId ) : array { - $db = $this->getLocalDb( $wikiId ); + protected function getAdditionalLocalData( $row, string $wikiId ): array { + $dbr = $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 ), + 'blocked' => $this->isUserBlocked( $row->user_id, $dbr ), 'groups' => $this->userGroupManagerFactory ->getUserGroupManager( $wikiId ) ->getUserGroups( - new UserIdentityValue( (int)$row->user_id, $row->user_name, 0 ) + new UserIdentityValue( (int)$row->user_id, $row->user_name ) ), 'wiki' => $wikiId, ]; @@ -182,13 +184,24 @@ class PreliminaryCheckService { /** * @param int $userId - * @param IDatabase $db Database connection + * @param IDatabase $dbr 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; + protected function isUserBlocked( int $userId, IDatabase $dbr ): bool { + // No need to use any other field than ipb_expiry + // so no need to use DatabaseBlock::newFromRow + $expiry = $dbr->newSelectQueryBuilder() + ->field( 'ipb_expiry' ) + ->table( 'ipblocks' ) + ->where( [ 'ipb_user' => $userId ] ) + ->caller( __METHOD__ ) + ->fetchField(); + if ( $expiry ) { + $blockObject = new DatabaseBlock; + $blockObject->setExpiry( $dbr->decodeExpiry( $expiry ) ); + return !$blockObject->isExpired(); + } else { + return false; + } } } diff --git a/CheckUser/src/TimelineService.php b/CheckUser/src/Investigate/Services/TimelineService.php index 4a1c3cec..5aefde47 100644 --- a/CheckUser/src/TimelineService.php +++ b/CheckUser/src/Investigate/Services/TimelineService.php @@ -1,6 +1,6 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Services; class TimelineService extends ChangeService { /** diff --git a/CheckUser/src/SpecialInvestigate.php b/CheckUser/src/Investigate/SpecialInvestigate.php index e9ad4c4a..6df1d73f 100644 --- a/CheckUser/src/SpecialInvestigate.php +++ b/CheckUser/src/Investigate/SpecialInvestigate.php @@ -1,14 +1,22 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate; +use FormSpecialPage; use Html; use HTMLForm; use Language; +use MediaWiki\CheckUser\CheckUserLogService; use MediaWiki\CheckUser\GuidedTour\TourLauncher; use MediaWiki\CheckUser\Hook\CheckUserSubtitleLinksHook; use MediaWiki\CheckUser\HookHandler\Preferences; +use MediaWiki\CheckUser\Investigate\Pagers\PagerFactory; +use MediaWiki\CheckUser\Investigate\Pagers\TimelinePagerFactory; +use MediaWiki\CheckUser\Investigate\Utilities\DurationManager; +use MediaWiki\CheckUser\Investigate\Utilities\EventLogger; +use MediaWiki\CheckUser\TokenQueryManager; use MediaWiki\Linker\LinkRenderer; +use MediaWiki\Permissions\PermissionManager; use MediaWiki\User\UserOptionsManager; use Message; use OOUI\ButtonGroupWidget; @@ -23,11 +31,12 @@ use OOUI\MessageWidget; use OOUI\TabOptionWidget; use OOUI\Tag; use OOUI\Widget; -use SpecialCheckUser; +use ParserOutput; +use Status; use User; use Wikimedia\IPUtils; -class SpecialInvestigate extends \FormSpecialPage { +class SpecialInvestigate extends FormSpecialPage { /** @var Language */ private $contentLanguage; @@ -58,6 +67,12 @@ class SpecialInvestigate extends \FormSpecialPage { /** @var CheckUserSubtitleLinksHook */ private $subtitleLinksHookRunner; + /** @var PermissionManager */ + private $permissionManager; + + /** @var CheckUserLogService */ + private $checkUserLogService; + /** @var IndexLayout|null */ private $layout; @@ -97,6 +112,8 @@ class SpecialInvestigate extends \FormSpecialPage { * @param EventLogger $eventLogger * @param TourLauncher $tourLauncher * @param CheckUserSubtitleLinksHook $subtitleLinksHookRunner + * @param PermissionManager $permissionManager + * @param CheckUserLogService $checkUserLogService */ public function __construct( LinkRenderer $linkRenderer, @@ -109,7 +126,9 @@ class SpecialInvestigate extends \FormSpecialPage { DurationManager $durationManager, EventLogger $eventLogger, TourLauncher $tourLauncher, - CheckUserSubtitleLinksHook $subtitleLinksHookRunner + CheckUserSubtitleLinksHook $subtitleLinksHookRunner, + PermissionManager $permissionManager, + CheckUserLogService $checkUserLogService ) { parent::__construct( 'Investigate', 'checkuser' ); $this->setLinkRenderer( $linkRenderer ); @@ -123,19 +142,22 @@ class SpecialInvestigate extends \FormSpecialPage { $this->eventLogger = $eventLogger; $this->tourLauncher = $tourLauncher; $this->subtitleLinksHookRunner = $subtitleLinksHookRunner; + $this->permissionManager = $permissionManager; + $this->checkUserLogService = $checkUserLogService; } /** * @inheritDoc */ - protected function preText() { + protected function preHtml() { // Add necessary styles $this->getOutput()->addModuleStyles( [ 'mediawiki.widgets.TagMultiselectWidget.styles', + 'ext.checkUser.styles', ] ); // Add button link to the log page on the main form. // Open in the current tab. - $this->addIndicators( /** $newTab */ false, /** $logOnly */ true ); + $this->addIndicators( false ); return ''; } @@ -158,8 +180,7 @@ class SpecialInvestigate extends \FormSpecialPage { return; } - $this->getOutput()->addModuleStyles( 'ext.checkUser.investigate.styles' ); - $this->getOutput()->addModules( [ 'ext.checkUser.investigate' ] ); + $this->getOutput()->addModules( [ 'ext.checkUser' ] ); // Show the tabs if there is any request data. // The tabs should also be shown even if the form was a POST request because @@ -173,7 +194,7 @@ class SpecialInvestigate extends \FormSpecialPage { $this->getOutput()->clearHTML(); } - $this->addIndicators(); + $this->addIndicators( true ); $this->addBlockForm(); $this->addTabs( $par )->addTabContent( $par ); $this->getOutput()->addHTML( $this->getLayout() ); @@ -194,7 +215,7 @@ class SpecialInvestigate extends \FormSpecialPage { * * @return IndexLayout */ - private function getLayout() : IndexLayout { + private function getLayout(): IndexLayout { if ( $this->layout === null ) { $this->getOutput()->enableOOUI(); $this->getOutput()->addModuleStyles( [ @@ -217,11 +238,10 @@ class SpecialInvestigate extends \FormSpecialPage { * @param string $par * @return self */ - private function addTabs( string $par ) : self { + private function addTabs( string $par ): self { $config = []; - [ - 'tabSelectWidget' => $tabSelectWidget, - ] = $this->getLayout()->getConfig( $config ); + $this->getLayout()->getConfig( $config ); + $tabSelectWidget = $config['tabSelectWidget']; $token = $this->getTokenWithoutPaginationData(); @@ -267,11 +287,10 @@ class SpecialInvestigate extends \FormSpecialPage { * @param string $html * @return self */ - private function addHtml( string $html ) : self { + private function addHtml( string $html ): self { $config = []; - [ - 'contentPanel' => $contentPanel - ] = $this->getLayout()->getConfig( $config ); + $this->getLayout()->getConfig( $config ); + $contentPanel = $config['contentPanel']; $contentPanel->addItems( [ new Element( [ @@ -285,10 +304,10 @@ class SpecialInvestigate extends \FormSpecialPage { /** * Add Pager Output to Layout. * - * @param \ParserOutput $parserOutput + * @param ParserOutput $parserOutput * @return self */ - private function addParserOutput( \ParserOutput $parserOutput ) : self { + private function addParserOutput( ParserOutput $parserOutput ): self { $this->getOutput()->addParserOutputMetadata( $parserOutput ); $this->addHTML( $parserOutput->getText() ); @@ -301,7 +320,7 @@ class SpecialInvestigate extends \FormSpecialPage { * @param string $par * @return self */ - private function addTabContent( string $par ) : self { + private function addTabContent( string $par ): self { $startTime = $this->eventLogger->getTime(); switch ( $par ) { @@ -309,7 +328,7 @@ class SpecialInvestigate extends \FormSpecialPage { $pager = $this->preliminaryCheckPagerFactory->createPager( $this->getContext() ); $hasIpTargets = (bool)array_filter( $this->getTokenData()['targets'] ?? [], - function ( $target ) { + static function ( $target ) { return IPUtils::isIPAddress( $target ); } ); @@ -419,7 +438,7 @@ class SpecialInvestigate extends \FormSpecialPage { /** * @param array $logData */ - private function logQuery( array $logData ) : void { + private function logQuery( array $logData ): void { $relevantTargetsCount = count( array_diff( $this->getTokenData()['targets'] ?? [], $this->getTokenData()['exclude-targets'] ?? [] @@ -443,7 +462,7 @@ class SpecialInvestigate extends \FormSpecialPage { * * @return string */ - private function getTabParam( string $tab ) : string { + private function getTabParam( string $tab ): string { $name = $this->getTabMessage( $tab )->inLanguage( $this->contentLanguage )->text(); return str_replace( ' ', '_', $name ); } @@ -455,7 +474,7 @@ class SpecialInvestigate extends \FormSpecialPage { * * @return Message */ - private function getTabMessage( string $tab ) : Message { + private function getTabMessage( string $tab ): Message { return $this->msg( 'checkuser-investigate-tab-' . $tab ); } @@ -481,15 +500,17 @@ class SpecialInvestigate extends \FormSpecialPage { private function addBlockForm() { $targets = $this->getTokenData()['targets'] ?? []; if ( $targets ) { + $userCanBlock = $this->permissionManager->userHasRight( $this->getUser(), 'block' ); $excludeTargets = $this->getTokenData()['exclude-targets'] ?? []; $this->getOutput()->addJsConfigVars( [ 'wgCheckUserInvestigateTargets' => $targets, 'wgCheckUserInvestigateExcludeTargets' => $excludeTargets, + 'wgCheckUserInvestigateCanBlock' => $userCanBlock, ] ); - $targetsText = $this->getLanguage()->listToText( array_map( function ( $target ) { - return Html::rawElement( 'strong', [], htmlspecialchars( $target ) ); + $targetsText = $this->getLanguage()->listToText( array_map( static function ( $target ) { + return Html::rawElement( 'strong', [], Html::rawElement( 'bdi', [], htmlspecialchars( $target ) ) ); }, $targets ) ); $subtitle = $this->msg( 'checkuser-investigate-page-subtitle', $targetsText ); @@ -499,7 +520,8 @@ class SpecialInvestigate extends \FormSpecialPage { $placeholderWidget = new Widget( [ 'classes' => [ 'ext-checkuser-investigate-subtitle-placeholder-widget' ], ] ); - $targetsLayout = new FieldLayout( + $items = []; + $items[] = new FieldLayout( $placeholderWidget, [ 'label' => new HtmlSnippet( $subtitle->parse() ), @@ -510,37 +532,35 @@ class SpecialInvestigate extends \FormSpecialPage { ] ] ); - - $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', + if ( $userCanBlock ) { + $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', + ], + ] ); + $items[] = 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, - ] + 'items' => $items ] ); $this->getOutput()->prependHTML( @@ -550,34 +570,35 @@ class SpecialInvestigate extends \FormSpecialPage { } /** - * Add buttons to start a new investigation and linking - * to InvestigateLog page + * Add buttons to start a new investigation and linking to log 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' : '', - ] ); + * @param bool $onSubpage whether the current page is a subpage of Special:Investigate + * (i.e. whether an investigation is currently happening). + */ + private function addIndicators( bool $onSubpage ) { + $canViewLogs = $this->permissionManager->userHasRight( $this->getUser(), 'checkuser-log' ); + $buttons = []; + if ( $canViewLogs ) { + $buttons[] = new ButtonWidget( [ + 'label' => $this->msg( 'checkuser-investigate-indicator-logs' )->text(), + 'href' => self::getTitleFor( 'CheckUserLog' )->getLinkURL(), + 'target' => $onSubpage ? '_blank' : '', + ] ); + } - if ( $logOnly ) { - $this->getOutput()->setIndicators( [ - 'ext-checkuser-investigation-btns' => $log, + if ( $onSubpage ) { + $buttons[] = new ButtonWidget( [ + 'label' => $this->msg( 'checkuser-investigate-indicator-new-investigation' )->text(), + 'href' => $this->getPageTitle()->getLinkURL(), + 'target' => '_blank', ] ); - } else { + } + + if ( count( $buttons ) > 0 ) { $this->getOutput()->setIndicators( [ 'ext-checkuser-investigation-btns' => new ButtonGroupWidget( [ 'classes' => [ 'ext-checkuser-investigate-indicators' ], - 'items' => [ $newForm, $log ], + 'items' => $buttons, ] ), ] ); } @@ -644,7 +665,7 @@ class SpecialInvestigate extends \FormSpecialPage { 'exists' => true, 'ipallowed' => true, 'iprange' => true, - 'default' => implode( "\n", $data['targets'] ?? [] ), + 'default' => '', 'input' => [ 'autocomplete' => false, ], @@ -691,9 +712,9 @@ class SpecialInvestigate extends \FormSpecialPage { ]; } - if ( $this->par === $timelineTab ) { + // if ( $this->par === $timelineTab ) { // @TODO Add filters specific to the timeline tab. - } + // } return $fields; } @@ -723,7 +744,7 @@ class SpecialInvestigate extends \FormSpecialPage { * * @return array */ - private function getTokenData() : array { + private function getTokenData(): array { if ( $this->tokenData === null ) { $this->tokenData = $this->tokenQueryManager->getDataFromRequest( $this->getRequest() ); } @@ -786,7 +807,7 @@ class SpecialInvestigate extends \FormSpecialPage { 'excludeTargetsCount' => count( $submittedExcludeTargets ?? [] ), ] ); - return \Status::newGood(); + return Status::newGood(); } /** @@ -797,6 +818,7 @@ class SpecialInvestigate extends \FormSpecialPage { */ protected function addLogEntries( array $targets, string $reason ) { $logType = 'investigate'; + $user = $this->getUser(); foreach ( $targets as $target ) { if ( IPUtils::isIPAddress( $target ) ) { @@ -806,9 +828,12 @@ class SpecialInvestigate extends \FormSpecialPage { // The form validated that the user exists on this wiki $targetType = 'user'; $targetId = User::idFromName( $target ); + // The user has been already validated to exist so there will be an ID. + '@phan-var int $targetId'; } - SpecialCheckUser::addLogEntry( + $this->checkUserLogService->addLogEntry( + $user, $logType, $targetType, $target, @@ -834,7 +859,7 @@ class SpecialInvestigate extends \FormSpecialPage { * @param array $update * @return string */ - private function getUpdatedToken( array $update ) : string { + private function getUpdatedToken( array $update ): string { return $this->tokenQueryManager->updateToken( $this->getRequest(), $update @@ -847,10 +872,10 @@ class SpecialInvestigate extends \FormSpecialPage { * @param array $update * @return string */ - private function getRedirectUrl( array $update ) : 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 ) { + $data = array_filter( array_merge( $query, $update ), static function ( $value ) { return $value !== null; } ); $parts['query'] = wfArrayToCgi( $data ); @@ -858,13 +883,13 @@ class SpecialInvestigate extends \FormSpecialPage { } /** - * Get an array of values from a new line seperated field. + * Get an array of values from a new line separated field. * * @param array $data * @param string $field * @return string[] */ - private function getArrayFromField( array $data, string $field ) : array { + private function getArrayFromField( array $data, string $field ): array { if ( !isset( $data[$field] ) ) { return []; } @@ -885,7 +910,7 @@ class SpecialInvestigate extends \FormSpecialPage { * * @return bool */ - private function usingFilters() : bool { + private function usingFilters(): bool { return count( $this->getTokenData()['exclude-targets'] ?? [] ) > 0 || $this->getDuration() !== ''; } @@ -895,7 +920,7 @@ class SpecialInvestigate extends \FormSpecialPage { * * @return string */ - private function getDuration() : string { + private function getDuration(): string { return $this->durationManager->getFromRequest( $this->getRequest() ); } @@ -907,7 +932,7 @@ class SpecialInvestigate extends \FormSpecialPage { * * @return bool If the tour is being relaunched and a redirect was set. */ - public function reLaunchTour() : bool { + public function reLaunchTour(): bool { if ( $this->getRequest()->getMethod() !== 'GET' ) { return false; } @@ -925,12 +950,12 @@ class SpecialInvestigate extends \FormSpecialPage { Preferences::INVESTIGATE_FORM_TOUR_SEEN, Preferences::INVESTIGATE_TOUR_SEEN, ]; - break; + break; case self::TOUR_INVESTIGATE: $options = [ Preferences::INVESTIGATE_TOUR_SEEN, ]; - break; + break; } foreach ( $options as $option ) { @@ -955,12 +980,9 @@ class SpecialInvestigate extends \FormSpecialPage { * @param string $tour * @return void */ - private function launchTour( string $tour ) : 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; @@ -984,7 +1006,7 @@ class SpecialInvestigate extends \FormSpecialPage { /** * Add the subtitle to the page. */ - private function addSubtitle() : void { + private function addSubtitle(): void { $subpage = false; $token = null; $tour = self::TOUR_INVESTIGATE_FORM; @@ -996,7 +1018,10 @@ class SpecialInvestigate extends \FormSpecialPage { } $links = [ - $this->getLinkRenderer()->makeLink( self::getTitleValueFor( 'CheckUser' ) ), + $this->getLinkRenderer()->makeLink( + self::getTitleValueFor( 'CheckUser' ), + $this->msg( 'checkuser-investigate-subtitle-show-checkuser' )->text() + ), $this->tourLauncher->makeTourLink( $tour, $this->getPageTitle( $subpage ), @@ -1011,7 +1036,7 @@ class SpecialInvestigate extends \FormSpecialPage { $this->subtitleLinksHookRunner->onCheckUserSubtitleLinks( $this->getContext(), $links ); - $subtitle = implode( ' | ', array_filter( $links, function ( $link ) { + $subtitle = implode( ' | ', array_filter( $links, static function ( $link ) { return (bool)$link; } ) ); diff --git a/CheckUser/src/SpecialInvestigateBlock.php b/CheckUser/src/Investigate/SpecialInvestigateBlock.php index a406f2ee..520af679 100644 --- a/CheckUser/src/SpecialInvestigateBlock.php +++ b/CheckUser/src/Investigate/SpecialInvestigateBlock.php @@ -1,22 +1,31 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate; use ApiMain; use DerivativeRequest; use Exception; use FormSpecialPage; use Linker; +use MediaWiki\Block\BlockPermissionCheckerFactory; +use MediaWiki\Block\BlockUserFactory; +use MediaWiki\CheckUser\Investigate\Utilities\EventLogger; use MediaWiki\Permissions\PermissionManager; use MediaWiki\User\UserFactory; use MediaWiki\User\UserNameUtils; -use SpecialBlock; +use PermissionsError; use TitleFormatter; use TitleValue; use User; use Wikimedia\IPUtils; class SpecialInvestigateBlock extends FormSpecialPage { + /** @var BlockUserFactory */ + private $blockUserFactory; + + /** @var BlockPermissionCheckerFactory */ + private $blockPermissionCheckerFactory; + /** @var PermissionManager */ private $permissionManager; @@ -35,7 +44,17 @@ class SpecialInvestigateBlock extends FormSpecialPage { /** @var bool */ private $noticesFailed = false; + /** + * @param BlockUserFactory $blockUserFactory + * @param BlockPermissionCheckerFactory $blockPermissionCheckerFactory + * @param PermissionManager $permissionManager + * @param TitleFormatter $titleFormatter + * @param UserFactory $userFactory + * @param EventLogger $eventLogger + */ public function __construct( + BlockUserFactory $blockUserFactory, + BlockPermissionCheckerFactory $blockPermissionCheckerFactory, PermissionManager $permissionManager, TitleFormatter $titleFormatter, UserFactory $userFactory, @@ -43,6 +62,8 @@ class SpecialInvestigateBlock extends FormSpecialPage { ) { parent::__construct( 'InvestigateBlock', 'checkuser' ); + $this->blockUserFactory = $blockUserFactory; + $this->blockPermissionCheckerFactory = $blockPermissionCheckerFactory; $this->permissionManager = $permissionManager; $this->titleFormatter = $titleFormatter; $this->userFactory = $userFactory; @@ -60,6 +81,21 @@ class SpecialInvestigateBlock extends FormSpecialPage { /** * @inheritDoc */ + public function checkPermissions() { + $user = $this->getUser(); + if ( !parent::userCanExecute( $user ) ) { + $this->displayRestrictionError(); + } + + // User is a checkuser, but now to check for if they can block. + if ( !$this->permissionManager->userHasRight( $user, 'block' ) ) { + throw new PermissionsError( 'block' ); + } + } + + /** + * @inheritDoc + */ protected function getDisplayFormat() { return 'ooui'; } @@ -69,11 +105,11 @@ class SpecialInvestigateBlock extends FormSpecialPage { */ public function getFormFields() { $this->getOutput()->addModules( [ - 'ext.checkUser.investigateblock' + 'ext.checkUser' ] ); $this->getOutput()->addModuleStyles( [ 'mediawiki.widgets.TagMultiselectWidget.styles', - 'ext.checkUser.investigateblock.styles', + 'ext.checkUser.styles', ] ); $this->getOutput()->enableOOUI(); @@ -93,7 +129,11 @@ class SpecialInvestigateBlock extends FormSpecialPage { 'section' => 'target', ]; - if ( SpecialBlock::canBlockEmail( $this->getUser() ) ) { + if ( + $this->blockPermissionCheckerFactory + ->newBlockPermissionChecker( null, $this->getUser() ) + ->checkEmailPermissions() + ) { $fields['DisableEmail'] = [ 'type' => 'check', 'label-message' => $prefix . '-email-label', @@ -200,7 +240,6 @@ class SpecialInvestigateBlock extends FormSpecialPage { 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 ); @@ -213,23 +252,22 @@ class SpecialInvestigateBlock extends FormSpecialPage { } $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 ) { + + $status = $this->blockUserFactory->newBlockUser( + $target, + $this->getUser(), + $expiry, + $data['Reason'], + [ + 'isHardBlock' => !$isIP, + 'isCreateAccountBlocked' => true, + 'isAutoblocking' => true, + 'isEmailBlocked' => $data['DisableEmail'] ?? false, + 'isUserTalkEditBlocked' => $data['DisableUTEdit'] ?? false, + ] + )->placeBlock( $data['Reblock'] ); + + if ( $status->isOK() ) { $this->blockedUsers[] = $target; if ( $data['UserPageNotice'] ) { @@ -261,7 +299,9 @@ class SpecialInvestigateBlock extends FormSpecialPage { ] ); if ( $blockedUsersCount === 0 ) { - return $this->getMessagePrefix() . '-failure'; + // Message used here: + // checkuser-investigateblock-failure + return [ $this->getMessagePrefix() . '-failure' ]; } return true; @@ -272,7 +312,11 @@ class SpecialInvestigateBlock extends FormSpecialPage { * @param string $target Must be a valid IP address or a valid user name * @return string */ - private function getTargetPage( int $namespace, string $target ) : string { + private function getTargetPage( int $namespace, string $target ): string { + if ( IPUtils::isValidRange( $target ) ) { + $target = IPUtils::sanitizeRange( $target ); + } + return $this->titleFormatter->getPrefixedText( new TitleValue( $namespace, $target ) ); @@ -292,22 +336,24 @@ class SpecialInvestigateBlock extends FormSpecialPage { string $notice, string $position, string $summary - ) : void { + ): void { $apiParams = [ 'action' => 'edit', 'title' => $title, $position => $notice, 'summary' => $summary, - 'token' => $this->getUser()->getEditToken(), + 'token' => $this->getContext()->getCsrfTokenSet()->getToken(), ]; $api = new ApiMain( new DerivativeRequest( $this->getRequest(), $apiParams, - true // was posted + // was posted + true ), - true // enable write + // enable write + true ); try { diff --git a/CheckUser/src/Investigate/Utilities/DurationManager.php b/CheckUser/src/Investigate/Utilities/DurationManager.php new file mode 100644 index 00000000..efa42d2e --- /dev/null +++ b/CheckUser/src/Investigate/Utilities/DurationManager.php @@ -0,0 +1,70 @@ +<?php + +namespace MediaWiki\CheckUser\Investigate\Utilities; + +use DateInterval; +use DateTime; +use Exception; +use MWTimestamp; +use WebRequest; + +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 { + // @phan-suppress-next-line PhanNoopNew + new DateInterval( $value ); + return true; + } catch ( Exception $e ) { + return false; + } + } +} diff --git a/CheckUser/src/EventLogger.php b/CheckUser/src/Investigate/Utilities/EventLogger.php index d94d9855..106aa758 100644 --- a/CheckUser/src/EventLogger.php +++ b/CheckUser/src/Investigate/Utilities/EventLogger.php @@ -1,9 +1,9 @@ <?php -namespace MediaWiki\CheckUser; +namespace MediaWiki\CheckUser\Investigate\Utilities; -use EventLogging; use ExtensionRegistry; +use MediaWiki\Extension\EventLogging\EventLogging; class EventLogger { /** @var ExtensionRegistry */ @@ -23,12 +23,14 @@ class EventLogger { * * @param array $event */ - public function logEvent( $event ) : void { + 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, + // NOTE: The 'SpecialInvestigate' event was migrated to the Event Platform, and is + // no longer using the legacy EventLogging schema from metawiki. $revId is actually + // overridden by the EventLoggingSchemas extension attribute in extension.json. + -1, $event ); } @@ -39,7 +41,7 @@ class EventLogger { * * @return int */ - public function getTime() : int { + public function getTime(): int { return (int)round( microtime( true ) * 1000 ); } } diff --git a/CheckUser/src/InvestigateLogPager.php b/CheckUser/src/InvestigateLogPager.php deleted file mode 100644 index c1ef047e..00000000 --- a/CheckUser/src/InvestigateLogPager.php +++ /dev/null @@ -1,101 +0,0 @@ -<?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/PagerFactory.php b/CheckUser/src/PagerFactory.php deleted file mode 100644 index c5fa56c3..00000000 --- a/CheckUser/src/PagerFactory.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php - -namespace MediaWiki\CheckUser; - -interface PagerFactory { - /** - * Factory to create the pager - * - * @param \IContextSource $context - */ - public function createPager( \IContextSource $context ); -} diff --git a/CheckUser/src/ServiceWiring.php b/CheckUser/src/ServiceWiring.php new file mode 100644 index 00000000..d6f9185a --- /dev/null +++ b/CheckUser/src/ServiceWiring.php @@ -0,0 +1,150 @@ +<?php + +use MediaWiki\CheckUser\CheckUserActorMigration; +use MediaWiki\CheckUser\CheckUserLogService; +use MediaWiki\CheckUser\GuidedTour\TourLauncher; +use MediaWiki\CheckUser\Hook\HookRunner; +use MediaWiki\CheckUser\Investigate\Pagers\ComparePagerFactory; +use MediaWiki\CheckUser\Investigate\Pagers\PreliminaryCheckPagerFactory; +use MediaWiki\CheckUser\Investigate\Pagers\TimelinePagerFactory; +use MediaWiki\CheckUser\Investigate\Pagers\TimelineRowFormatterFactory; +use MediaWiki\CheckUser\Investigate\Services\CompareService; +use MediaWiki\CheckUser\Investigate\Services\PreliminaryCheckService; +use MediaWiki\CheckUser\Investigate\Services\TimelineService; +use MediaWiki\CheckUser\Investigate\Utilities\DurationManager; +use MediaWiki\CheckUser\Investigate\Utilities\EventLogger; +use MediaWiki\CheckUser\TokenManager; +use MediaWiki\CheckUser\TokenQueryManager; +use MediaWiki\Config\ServiceOptions; +use MediaWiki\Logger\LoggerFactory; +use MediaWiki\MediaWikiServices; + +// PHP unit does not understand code coverage for this file +// as the @covers annotation cannot cover a specific file +// This is fully tested in CheckUserServiceWiringTest.php +// @codeCoverageIgnoreStart + +return [ + 'CheckUserLogService' => static function ( + MediaWikiServices $services + ): CheckUserLogService { + return new CheckUserLogService( + $services->getDBLoadBalancer(), + $services->getMainConfig()->get( 'CheckUserLogActorMigrationStage' ) + ); + }, + 'CheckUserActorMigration' => static function ( + MediaWikiServices $services + ): CheckUserActorMigration { + return new CheckUserActorMigration( + $services->getMainConfig()->get( 'CheckUserActorMigrationStage' ), + $services->getActorStoreFactory() + ); + }, + 'CheckUserPreliminaryCheckService' => static function ( + MediaWikiServices $services + ): PreliminaryCheckService { + return new PreliminaryCheckService( + $services->getDBLoadBalancerFactory(), + ExtensionRegistry::getInstance(), + $services->getUserGroupManagerFactory(), + WikiMap::getCurrentWikiDbDomain()->getId() + ); + }, + 'CheckUserCompareService' => static function ( MediaWikiServices $services ): CompareService { + return new CompareService( + new ServiceOptions( + CompareService::CONSTRUCTOR_OPTIONS, + $services->getMainConfig() + ), + $services->getDBLoadBalancer(), + $services->getUserIdentityLookup() + ); + }, + 'CheckUserTimelineService' => static function ( MediaWikiServices $services ): TimelineService { + return new TimelineService( + $services->getDBLoadBalancer()->getConnection( DB_REPLICA ), + $services->getDBLoadBalancer()->getConnection( DB_REPLICA ), + $services->getUserIdentityLookup() + ); + }, + 'CheckUserTokenManager' => static function ( MediaWikiServices $services ): TokenManager { + return new TokenManager( + $services->getMainConfig()->get( 'SecretKey' ) + ); + }, + 'CheckUserTokenQueryManager' => static function ( MediaWikiServices $services ): TokenQueryManager { + return new TokenQueryManager( + $services->get( 'CheckUserTokenManager' ) + ); + }, + 'CheckUserDurationManager' => static function ( MediaWikiServices $services ): DurationManager { + return new DurationManager(); + }, + 'CheckUserGuidedTourLauncher' => static function ( MediaWikiServices $services ): TourLauncher { + return new TourLauncher( + ExtensionRegistry::getInstance(), + $services->getLinkRenderer() + ); + }, + 'CheckUserPreliminaryCheckPagerFactory' => static function ( + MediaWikiServices $services + ): PreliminaryCheckPagerFactory { + return new PreliminaryCheckPagerFactory( + $services->getLinkRenderer(), + $services->getNamespaceInfo(), + \ExtensionRegistry::getInstance(), + $services->get( 'CheckUserTokenQueryManager' ), + $services->get( 'CheckUserPreliminaryCheckService' ) + ); + }, + 'CheckUserComparePagerFactory' => static function ( MediaWikiServices $services ): ComparePagerFactory { + return new ComparePagerFactory( + $services->getLinkRenderer(), + $services->get( 'CheckUserTokenQueryManager' ), + $services->get( 'CheckUserDurationManager' ), + $services->get( 'CheckUserCompareService' ) + ); + }, + 'CheckUserTimelineRowFormatterFactory' => static function ( + MediaWikiServices $services + ): TimelineRowFormatterFactory { + return new TimelineRowFormatterFactory( + $services->getLinkRenderer(), + $services->getDBLoadBalancer(), + $services->getRevisionStore(), + $services->getTitleFormatter(), + $services->getSpecialPageFactory(), + $services->getCommentFormatter(), + $services->getUserFactory() + ); + }, + 'CheckUserTimelinePagerFactory' => static function ( + MediaWikiServices $services + ): TimelinePagerFactory { + return new TimelinePagerFactory( + $services->getLinkRenderer(), + $services->get( 'CheckUserHookRunner' ), + $services->get( 'CheckUserTokenQueryManager' ), + $services->get( 'CheckUserDurationManager' ), + $services->get( 'CheckUserTimelineService' ), + $services->get( 'CheckUserTimelineRowFormatterFactory' ), + LoggerFactory::getInstance( 'CheckUser' ) + ); + }, + 'CheckUserEventLogger' => static function ( + MediaWikiServices $services + ): EventLogger { + return new EventLogger( + \ExtensionRegistry::getInstance() + ); + }, + 'CheckUserHookRunner' => static function ( + MediaWikiServices $services + ): HookRunner { + return new HookRunner( + $services->getHookContainer() + ); + } +]; +// @codeCoverageIgnoreEnd diff --git a/CheckUser/src/SpecialInvestigateLog.php b/CheckUser/src/SpecialInvestigateLog.php deleted file mode 100644 index 1556f33d..00000000 --- a/CheckUser/src/SpecialInvestigateLog.php +++ /dev/null @@ -1,112 +0,0 @@ -<?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/TokenManager.php b/CheckUser/src/TokenManager.php index e0606df3..cd412eee 100644 --- a/CheckUser/src/TokenManager.php +++ b/CheckUser/src/TokenManager.php @@ -2,8 +2,11 @@ namespace MediaWiki\CheckUser; +use Exception; use Firebase\JWT\JWT; +use FormatJson; use MediaWiki\Session\Session; +use MWTimestamp; class TokenManager { /** @var string */ @@ -22,7 +25,7 @@ class TokenManager { string $secret ) { if ( $secret === '' ) { - throw new \Exception( + throw new Exception( 'CheckUser Token Manager requires $wgSecretKey to be set.' ); } @@ -36,13 +39,14 @@ class TokenManager { * @param array $data * @return string */ - public function encode( Session $session, array $data ) : 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. + // 24 hours from now + 'exp' => MWTimestamp::time() + 86400, + // Encrypt the form data to prevent it from being leaked. 'data' => $this->encrypt( $data, $this->getInitializationVector( $key ) ), ], $this->getSigningKey( $key ), @@ -57,9 +61,9 @@ class TokenManager { * @param string $iv * @return string */ - private function encrypt( $input, string $iv ) : string { + private function encrypt( $input, string $iv ): string { return openssl_encrypt( - \FormatJson::encode( $input ), + FormatJson::encode( $input ), $this->getCipherMethod(), $this->secret, 0, @@ -74,7 +78,7 @@ class TokenManager { * @param string $token * @return array */ - public function decode( Session $session, string $token ) : array { + public function decode( Session $session, string $token ): array { $key = $this->getSessionKey( $session ); $payload = JWT::decode( $token, @@ -95,7 +99,7 @@ class TokenManager { * @param string $iv * @return array */ - private function decrypt( string $input, string $iv ) : array { + private function decrypt( string $input, string $iv ): array { $decrypted = openssl_decrypt( $input, $this->getCipherMethod(), @@ -105,10 +109,10 @@ class TokenManager { ); if ( $decrypted === false ) { - throw new \Exception( 'Decryption Failed' ); + throw new Exception( 'Decryption Failed' ); } - return \FormatJson::parse( $decrypted, \FormatJson::FORCE_ASSOC )->getValue(); + return FormatJson::parse( $decrypted, FormatJson::FORCE_ASSOC )->getValue(); } /** @@ -120,7 +124,7 @@ class TokenManager { * @param string $sessionKey * @return string */ - private function getInitializationVector( string $sessionKey ) : string { + private function getInitializationVector( string $sessionKey ): string { return hash_hmac( 'md5', $sessionKey, $this->secret, true ); } @@ -131,7 +135,7 @@ class TokenManager { * * @return string */ - private function getCipherMethod() : string { + private function getCipherMethod(): string { if ( !$this->cipherMethod ) { $methods = openssl_get_cipher_methods(); if ( in_array( 'aes-256-ctr', $methods, true ) ) { @@ -139,7 +143,7 @@ class TokenManager { } 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()' ); + throw new Exception( 'No valid cipher method found with openssl_get_cipher_methods()' ); } } @@ -159,7 +163,7 @@ class TokenManager { * * @return string */ - private function getSessionKey( Session $session ) : string { + private function getSessionKey( Session $session ): string { $key = $session->get( 'CheckUserTokenKey' ); if ( $key === null ) { $key = base64_encode( random_bytes( 16 ) ); @@ -175,7 +179,7 @@ class TokenManager { * @param string $sessionKey * @return string */ - private function getSigningKey( string $sessionKey ) : 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 index 937c27d9..a7f343cb 100644 --- a/CheckUser/src/TokenQueryManager.php +++ b/CheckUser/src/TokenQueryManager.php @@ -23,7 +23,7 @@ class TokenQueryManager { * @param array $queries * @return array */ - public function getPagingQueries( WebRequest $request, array $queries ) : array { + public function getPagingQueries( WebRequest $request, array $queries ): array { $tokenData = $this->getDataFromRequest( $request ); foreach ( $queries as &$query ) { if ( $query === false ) { @@ -51,9 +51,9 @@ class TokenQueryManager { * @param array $update * @return string */ - public function updateToken( WebRequest $request, array $update ) : string { + public function updateToken( WebRequest $request, array $update ): string { $tokenData = $this->getDataFromRequest( $request ); - $data = array_filter( array_merge( $tokenData, $update ), function ( $value ) { + $data = array_filter( array_merge( $tokenData, $update ), static function ( $value ) { return $value !== null; } ); @@ -66,7 +66,7 @@ class TokenQueryManager { * @param WebRequest $request * @return array */ - public function getDataFromRequest( WebRequest $request ) : array { + public function getDataFromRequest( WebRequest $request ): array { $token = $request->getVal( 'token' ); if ( empty( $token ) ) { diff --git a/CheckUser/src/ToolLinksMessages.php b/CheckUser/src/ToolLinksMessages.php index 7b4bf1db..34e6c005 100644 --- a/CheckUser/src/ToolLinksMessages.php +++ b/CheckUser/src/ToolLinksMessages.php @@ -3,12 +3,19 @@ namespace MediaWiki\CheckUser; use Config; -use ResourceLoaderContext; +use MediaWiki\ResourceLoader\Context; class ToolLinksMessages { + /** + * @param Context $context + * @param Config $config + * @param string $messageKey + * + * @return array + */ public static function getParsedMessage( - ResourceLoaderContext $context, + Context $context, Config $config, string $messageKey ) { diff --git a/CheckUser/src/UserManager.php b/CheckUser/src/UserManager.php deleted file mode 100644 index f5a0a6f9..00000000 --- a/CheckUser/src/UserManager.php +++ /dev/null @@ -1,27 +0,0 @@ -<?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/templates/GetEditsLine.mustache b/CheckUser/templates/GetEditsLine.mustache new file mode 100644 index 00000000..e21bf132 --- /dev/null +++ b/CheckUser/templates/GetEditsLine.mustache @@ -0,0 +1,20 @@ +<li> + {{{links}}} + <span class="mw-changeslist-separator"></span> + {{timestamp}} + <span class="mw-changeslist-separator"></span> + <span{{#userLinkClass}} class="{{userLinkClass}}"{{/userLinkClass}}> + {{{userLink}}} + </span> + {{{userToolLinks}}} + {{#flags}} + {{{ . }}} + {{/flags}} + {{{actionText}}} + {{{comment}}} + <div class="mw-checkuser-indented"><small> + <strong>IP</strong>: {{{ipLink}}}{{#xff}}   + <span class="mw-checkuser-xff{{#xffTrusted}} mw-checkuser-xff-trusted{{/xffTrusted}}"><strong>XFF</strong>: {{{ . }}}</span>{{/xff}} +   <span class="mw-checkuser-agent">{{{userAgent}}}</span> + </small></div> +</li> diff --git a/CheckUser/templates/GetIPsLine.mustache b/CheckUser/templates/GetIPsLine.mustache new file mode 100644 index 00000000..6b2ce62f --- /dev/null +++ b/CheckUser/templates/GetIPsLine.mustache @@ -0,0 +1,14 @@ +<li> + {{{ipLink}}} + {{#ip64Link}} + <span class="mw-changeslist-links">{{{ip64Link}}}</span> + {{/ip64Link}} + <span class="mw-changeslist-links">{{{blockLink}}}</span> + <span class="mw-changeslist-links">{{timeRange}}</span> + <strong class="mw-checkuser-edits-count">{{editCount}}</strong> + {{#ipEditCount}} + <i class="mw-changeslist-links">{{ipEditCount}}</i> + {{/ipEditCount}} + {{{blockInfo}}} + <div class="mw-checkuser-indented"><small>{{{toolLinks}}}</small></div> +</li> diff --git a/CheckUser/templates/GetUsersLine.mustache b/CheckUser/templates/GetUsersLine.mustache new file mode 100644 index 00000000..0b6e3594 --- /dev/null +++ b/CheckUser/templates/GetUsersLine.mustache @@ -0,0 +1,31 @@ +<li> + {{#canPerformBlocks}} + <input type="checkbox" name="users[]" value="{{{userText}}}"/> + {{/canPerformBlocks}} + <span{{#userLinkClass}} class="{{userLinkClass}}"{{/userLinkClass}}> + {{{userLink}}} + </span> + {{{userToolLinks}}} + {{{userLinks}}} + <span class="mw-changeslist-links">{{{checkLink}}}</span> + {{{centralAuthLink}}} + {{{globalBlockLink}}} + <span class="mw-changeslist-links">{{timeRange}}</span> + <strong class="mw-checkuser-edits-count">{{editCount}}</strong><br/> + {{#flags}} + {{{ . }}} + {{/flags}} + <ol> + {{#infoSets}} + <li> + {{{ipLink}}}{{#xff}}  <span class="mw-checkuser-xff{{#xffTrusted}} mw-checkuser-xff-trusted{{/xffTrusted}}"><strong>XFF</strong>: {{{ . }}}</span>{{/xff}} + </li> + {{/infoSets}} + </ol><br><ol> + {{#agentsList}} + <li> + <i dir="ltr" class="mw-checkuser-agent">{{ . }}</i> + </li> + {{/agentsList}} + </ol> +</li> diff --git a/CheckUser/tests/phpunit/CheckUserIntegrationTestCaseTest.php b/CheckUser/tests/phpunit/CheckUserIntegrationTestCaseTest.php new file mode 100644 index 00000000..b2450c10 --- /dev/null +++ b/CheckUser/tests/phpunit/CheckUserIntegrationTestCaseTest.php @@ -0,0 +1,22 @@ +<?php + +namespace MediaWiki\CheckUser\Tests; + +use MediaWikiIntegrationTestCase; + +class CheckUserIntegrationTestCaseTest extends MediaWikiIntegrationTestCase { + + /** + * Needed because there is no way using TestUser.php + * to get a user guaranteed to not exist. + * + * @return \User a non-existent user or a fail. + */ + public function getNonExistentTestUser() { + $testUser = $this->getServiceContainer()->getUserFactory()->newFromName( 'NonexistentUser 1234' ); + if ( $testUser->getId() !== 0 ) { + $this->fail( 'User:NonexistentUser 1234 exists. Are you sure you are using a test DB?' ); + } + return $testUser; + } +} diff --git a/CheckUser/tests/phpunit/CheckUserPagerCommonTest.php b/CheckUser/tests/phpunit/CheckUserPagerCommonTest.php new file mode 100644 index 00000000..04d7a0ef --- /dev/null +++ b/CheckUser/tests/phpunit/CheckUserPagerCommonTest.php @@ -0,0 +1,56 @@ +<?php + +namespace MediaWiki\CheckUser\Tests; + +use FormOptions; +use MediaWiki\User\UserIdentity; +use MediaWikiIntegrationTestCase; +use Wikimedia\TestingAccessWrapper; + +abstract class CheckUserPagerCommonTest extends MediaWikiIntegrationTestCase { + + /** @var string One of the SpecialCheckUser::SUBTYPE_... constants */ + protected $checkSubtype; + + /** @var UserIdentity the default UserIdentity to be used as the target in tests. */ + protected $defaultUserIdentity; + + /** @var string the default check type to be used in tests. */ + protected $defaultCheckType; + + /** + * Gets the default values for a row from the DB. + * + * @return array + */ + abstract protected function getDefaultRowFieldValues(): array; + + /** + * Set up the object for the pager that is being tested + * wrapped in a TestingAccessWrapper so that the tests + * can modify and access protected / private methods and + * properties. + * + * @param UserIdentity|null $userIdentity the target for the check + * @param string|null $checkType the check type (e.g. ipedits). + * @return TestingAccessWrapper + */ + protected function setUpObject( ?UserIdentity $userIdentity = null, ?string $checkType = null ) { + $opts = new FormOptions(); + $opts->add( 'reason', '' ); + $opts->add( 'period', 0 ); + $opts->add( 'limit', '' ); + $opts->add( 'dir', '' ); + $opts->add( 'offset', '' ); + $specialCheckUser = TestingAccessWrapper::newFromObject( + $this->getServiceContainer()->getSpecialPageFactory()->getPage( 'CheckUser' ) + ); + $specialCheckUser->opts = $opts; + $object = $specialCheckUser->getPager( + $this->checkSubtype, + $userIdentity ?? $this->defaultUserIdentity, + $checkType ?? $this->defaultCheckType + ); + return TestingAccessWrapper::newFromObject( $object ); + } +} diff --git a/CheckUser/tests/phpunit/CheckUserServiceWiringTest.php b/CheckUser/tests/phpunit/CheckUserServiceWiringTest.php new file mode 100644 index 00000000..2fdf3969 --- /dev/null +++ b/CheckUser/tests/phpunit/CheckUserServiceWiringTest.php @@ -0,0 +1,28 @@ +<?php + +/** + * Copy of CentralAuth's CentralAuthServiceWiringTest.php + * as it could not be included as it's in another extension. + */ + +use MediaWiki\MediaWikiServices; + +/** + * @coversNothing + */ +class CheckUserServiceWiringTest extends MediaWikiIntegrationTestCase { + /** + * @dataProvider provideService + */ + public function testService( string $name ) { + MediaWikiServices::getInstance()->get( $name ); + $this->addToAssertionCount( 1 ); + } + + public function provideService() { + $wiring = require __DIR__ . '/../../src/ServiceWiring.php'; + foreach ( $wiring as $name => $_ ) { + yield $name => [ $name ]; + } + } +} diff --git a/CheckUser/tests/phpunit/SpecialCheckUserTest.php b/CheckUser/tests/phpunit/SpecialCheckUserTest.php deleted file mode 100644 index 2f012efa..00000000 --- a/CheckUser/tests/phpunit/SpecialCheckUserTest.php +++ /dev/null @@ -1,161 +0,0 @@ -<?php - -namespace MediaWiki\CheckUser\Tests; - -use MediaWikiIntegrationTestCase; -use ReflectionClass; -use SpecialCheckUser; - -/** - * Test class for SpecialCheckUser class - * - * @group CheckUser - * @group Database - * - * @covers SpecialCheckUser - */ -class SpecialCheckUserTest extends MediaWikiIntegrationTestCase { - - /** - * @var int - */ - private $lowerThanLimitIPv4; - - /** - * @var int - */ - private $lowerThanLimitIPv6; - - public function __construct( $name = null, array $data = [], $dataName = '' ) { - parent::__construct( $name, $data, $dataName ); - - $this->tablesUsed = array_merge( - $this->tablesUsed, - [ - 'page', - 'revision', - 'ip_changes', - 'text', - 'archive', - 'recentchanges', - 'logging', - 'page_props', - 'cu_changes', - ] - ); - } - - protected function setUp() : void { - parent::setUp(); - - $this->setMwGlobals( [ - 'wgCheckUserCIDRLimit' => [ - 'IPv4' => 16, - 'IPv6' => 19, - ] - ] ); - - $CIDRLimit = \RequestContext::getMain()->getConfig()->get( 'CheckUserCIDRLimit' ); - $this->lowerThanLimitIPv4 = $CIDRLimit['IPv4'] - 1; - $this->lowerThanLimitIPv6 = $CIDRLimit['IPv6'] - 1; - } - - /** - * @covers SpecialCheckUser::getIpConds - * @dataProvider provideGetIpConds - */ - public function testGetIpConds( $target, $expected ) { - $dbr = wfGetDB( DB_REPLICA ); - - $this->assertEquals( - $expected, - SpecialCheckUser::getIpConds( $dbr, $target ) - ); - } - - /** - * Test cases for SpecialCheckUser::getIpConds - * @return array - */ - public function provideGetIpConds() { - return [ - [ - '212.35.31.121', - [ 'cuc_ip_hex' => 'D4231F79' ], - ], - [ - '212.35.31.121/32', - [ 0 => 'cuc_ip_hex BETWEEN \'D4231F79\' AND \'D4231F79\'' ], - ], - [ - '::e:f:2001', - [ 'cuc_ip_hex' => 'v6-00000000000000000000000E000F2001' ], - ], - [ - '::e:f:2001/96', - [ 0 => 'cuc_ip_hex BETWEEN \'v6-00000000000000000000000E00000000\'' . - ' AND \'v6-00000000000000000000000EFFFFFFFF\'' ], - ], - [ "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/integration/Api/ApiQueryCheckUserLogTest.php b/CheckUser/tests/phpunit/integration/Api/ApiQueryCheckUserLogTest.php new file mode 100644 index 00000000..9330bd1b --- /dev/null +++ b/CheckUser/tests/phpunit/integration/Api/ApiQueryCheckUserLogTest.php @@ -0,0 +1,121 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Integration\Api; + +use ApiMain; +use ApiQuery; +use ApiTestCase; +use HashConfig; +use MediaWiki\CheckUser\Api\ApiQueryCheckUser; +use MediaWiki\Permissions\Authority; +use Wikimedia\TestingAccessWrapper; + +/** + * @group API + * @group medium + * @group Database + * + * @covers \MediaWiki\CheckUser\Api\ApiQueryCheckUser + */ +class ApiQueryCheckUserLogTest extends ApiTestCase { + + private const INITIAL_API_PARAMS = [ + 'action' => 'query', + 'list' => 'checkuserlog', + ]; + + public function doCheckUserLogApiRequest( array $params = [], array $session = null, Authority $performer = null ) { + return $this->doApiRequest( self::INITIAL_API_PARAMS + $params, $session, false, $performer ); + } + + /** + * @param string $action + * @param string $moduleName + * @return TestingAccessWrapper + */ + public function setUpObject( string $action = '', string $moduleName = '' ) { + $services = $this->getServiceContainer(); + $query = new ApiQuery( + new ApiMain( $this->apiContext, true ), + $action, + $services->getObjectFactory(), + $services->getDBLoadBalancer(), + $services->getWikiExporterFactory() + ); + return TestingAccessWrapper::newFromObject( new ApiQueryCheckUser( + $query, $moduleName, $services->getUserIdentityLookup(), + $services->getRevisionLookup(), $services->get( 'CheckUserLogService' ) + ) ); + } + + /** + * @dataProvider provideRequiredGroupAccess + */ + public function testRequiredRightsByGroup( $groups, $allowed ) { + $testUser = $this->getTestUser( $groups ); + if ( !$allowed ) { + $this->setExpectedApiException( + [ 'apierror-permissiondenied', wfMessage( 'action-checkuser-log' )->text() ] + ); + } + $result = $this->doCheckUserLogApiRequest( + [], + null, + $testUser->getUser() + ); + $this->assertNotNull( $result ); + } + + public function provideRequiredGroupAccess() { + return [ + 'No user groups' => [ '', false ], + 'Checkuser only' => [ 'checkuser', true ], + 'Checkuser and sysop' => [ [ 'checkuser', 'sysop' ], true ], + ]; + } + + /** + * @dataProvider provideRequiredRights + */ + public function testRequiredRights( $groups, $allowed ) { + if ( $groups === "checkuser-log" ) { + $this->overrideMwServices( + new HashConfig( + [ 'GroupPermissions' => + [ 'checkuser-log' => [ 'checkuser-log' => true, 'read' => true ] ] + ] + ) + ); + } + $this->testRequiredRightsByGroup( $groups, $allowed ); + } + + public function provideRequiredRights() { + return [ + 'No user groups' => [ '', false ], + 'checkuser-log right only' => [ 'checkuser-log', true ], + ]; + } + + /** + * Tests that the function returns valid URLs. + * Does not test that the URL is correct as if + * the URL is changed in a proposed commit the + * reviewer should check the URL points to the + * right place. + * + * @covers \MediaWiki\CheckUser\Api\ApiQueryCheckUserLog::getHelpUrls + */ + public function testGetHelpUrls() { + $helpUrls = $this->setUpObject()->getHelpUrls(); + if ( !is_string( $helpUrls ) && !is_array( $helpUrls ) ) { + $this->fail( 'getHelpUrls should return an array of URLs or a URL' ); + } + if ( is_string( $helpUrls ) ) { + $helpUrls = [ $helpUrls ]; + } + foreach ( $helpUrls as $helpUrl ) { + $this->assertIsArray( parse_url( $helpUrl ) ); + } + } +} diff --git a/CheckUser/tests/phpunit/integration/Api/ApiQueryCheckUserTest.php b/CheckUser/tests/phpunit/integration/Api/ApiQueryCheckUserTest.php new file mode 100644 index 00000000..391f00eb --- /dev/null +++ b/CheckUser/tests/phpunit/integration/Api/ApiQueryCheckUserTest.php @@ -0,0 +1,230 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Integration\Api; + +use ApiMain; +use ApiQuery; +use ApiQueryTokens; +use ApiTestCase; +use HashConfig; +use MediaWiki\CheckUser\Api\ApiQueryCheckUser; +use MediaWiki\Permissions\Authority; +use MediaWiki\Session\SessionManager; +use Wikimedia\TestingAccessWrapper; + +/** + * @group API + * @group medium + * @group Database + * + * @covers \MediaWiki\CheckUser\Api\ApiQueryCheckUser + */ +class ApiQueryCheckUserTest extends ApiTestCase { + + private const INITIAL_API_PARAMS = [ + 'action' => 'query', + 'list' => 'checkuser', + ]; + + /** + * Modified version of doApiRequestWithToken + * that appends 'cutoken' instead of 'token' + * as the token type. Does not accept the + * auto token type. Should not need to use + * any token type than the csrf token type + * for this purpose, but does accept any + * named token type that doApiRequestWith + * Token would take. + * + * @inheritDoc + */ + public function doApiRequestWithToken( + array $params, array $session = null, + Authority $performer = null, $tokenType = 'csrf', $paramPrefix = null + ) { + // From ApiTestCase::doApiRequest() but modified + global $wgRequest; + $session = $wgRequest->getSessionArray(); + $sessionObj = SessionManager::singleton()->getEmptySession(); + + if ( $session !== null ) { + foreach ( $session as $key => $value ) { + $sessionObj->set( $key, $value ); + } + } + + // set up global environment + if ( $performer ) { + $legacyUser = $this->getServiceContainer()->getUserFactory()->newFromAuthority( $performer ); + $contextUser = $legacyUser; + } else { + $contextUser = $this->getTestUser( 'checkuser' )->getUser(); + $performer = $contextUser; + } + + $sessionObj->setUser( $contextUser ); + + $params['cutoken'] = ApiQueryTokens::getToken( + $contextUser, + $sessionObj, + ApiQueryTokens::getTokenTypeSalts()[$tokenType] + )->toString(); + return parent::doApiRequestWithToken( $params, $session, $performer, null, $paramPrefix ); + } + + public function doCheckUserApiRequest( array $params = [], array $session = null, Authority $performer = null ) { + return $this->doApiRequestWithToken( self::INITIAL_API_PARAMS + $params, $session, $performer ); + } + + /** + * @param string $action + * @param string $moduleName + * @return TestingAccessWrapper + */ + public function setUpObject( string $action = '', string $moduleName = '' ) { + $services = $this->getServiceContainer(); + $query = new ApiQuery( + new ApiMain( $this->apiContext, true ), + $action, + $services->getObjectFactory(), + $services->getDBLoadBalancer(), + $services->getWikiExporterFactory() + ); + return TestingAccessWrapper::newFromObject( new ApiQueryCheckUser( + $query, $moduleName, $services->getUserIdentityLookup(), + $services->getRevisionLookup(), $services->get( 'CheckUserLogService' ) + ) ); + } + + /** + * @dataProvider provideTestInvalidTimeCond + */ + public function testInvalidTimeCond( $timeCond ) { + $this->setExpectedApiException( 'apierror-checkuser-timelimit', 'invalidtime' ); + $this->doCheckUserApiRequest( + [ + 'curequest' => 'edits', + 'cutarget' => $this->getTestUser()->getUserIdentity()->getName(), + 'cutimecond' => $timeCond, + ] + ); + } + + public function provideTestInvalidTimeCond() { + return [ + [ '-2000000000 years' ], + [ '1 week' ], + [ '2000000000 weeks' ], + [ '-45 weeks ago' ], + ]; + } + + public function testMissingRequiredReason() { + // enable required reason + $this->setMwGlobals( 'wgCheckUserForceSummary', true ); + $this->setExpectedApiException( 'apierror-checkuser-missingsummary', 'missingdata' ); + $this->doCheckUserApiRequest( + [ + 'curequest' => 'edits', + 'cutarget' => $this->getTestUser()->getUserIdentity()->getName() + ] + ); + } + + /** + * @dataProvider provideRequiredGroupAccess + */ + public function testRequiredRightsByGroup( $groups, $allowed ) { + $testUser = $this->getTestUser( $groups ); + if ( !$allowed ) { + $this->setExpectedApiException( [ 'apierror-permissiondenied', wfMessage( 'action-checkuser' )->text() ] ); + } + $result = $this->doCheckUserApiRequest( + [ + 'curequest' => 'edits', + 'cutarget' => $this->getTestUser()->getUserIdentity()->getName(), + ], + null, + $testUser->getUser() + ); + $this->assertNotNull( $result ); + } + + public function provideRequiredGroupAccess() { + return [ + 'No user groups' => [ '', false ], + 'Checkuser only' => [ 'checkuser', true ], + 'Checkuser and sysop' => [ [ 'checkuser', 'sysop' ], true ], + ]; + } + + /** + * @dataProvider provideRequiredRights + */ + public function testRequiredRights( $groups, $allowed ) { + if ( $groups === "checkuser-right" ) { + $this->overrideMwServices( + new HashConfig( + [ 'GroupPermissions' => + [ 'checkuser-right' => [ 'checkuser' => true, 'read' => true ] ] + ] + ) + ); + } + $this->testRequiredRightsByGroup( $groups, $allowed ); + } + + public function provideRequiredRights() { + return [ + 'No user groups' => [ '', false ], + 'checkuser right only' => [ 'checkuser-right', true ], + ]; + } + + /** @covers \MediaWiki\CheckUser\Api\ApiQueryCheckUser::isWriteMode */ + public function testIsWriteMode() { + $this->assertTrue( + $this->setUpObject()->isWriteMode(), + 'The checkuser API writes to the cu_log table so write mode is needed.' + ); + } + + /** @covers \MediaWiki\CheckUser\Api\ApiQueryCheckUser::mustBePosted */ + public function testMustBePosted() { + $this->assertTrue( + $this->setUpObject()->mustBePosted(), + 'The checkuser API, like Special:CheckUser, must be posted.' + ); + } + + /** @covers \MediaWiki\CheckUser\Api\ApiQueryCheckUser::needsToken */ + public function testNeedsToken() { + $this->assertSame( + 'csrf', + $this->setUpObject()->needsToken(), + 'The checkuser API requires the csrf token.' + ); + } + + /** + * Tests that the function returns valid URLs. + * Does not test that the URL is correct as if + * the URL is changed in a proposed commit the + * reviewer should check the URL points to the + * right place. + * + * @covers \MediaWiki\CheckUser\Api\ApiQueryCheckUser::getHelpUrls + */ + public function testGetHelpUrls() { + $helpUrls = $this->setUpObject()->getHelpUrls(); + if ( !is_string( $helpUrls ) && !is_array( $helpUrls ) ) { + $this->fail( 'getHelpUrls should return an array of URLs or a URL' ); + } + if ( is_string( $helpUrls ) ) { + $helpUrls = [ $helpUrls ]; + } + foreach ( $helpUrls as $helpUrl ) { + $this->assertIsArray( parse_url( $helpUrl ) ); + } + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUser/Pagers/AbstractCheckUserPagerTest.php b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/AbstractCheckUserPagerTest.php new file mode 100644 index 00000000..67b3e08e --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/AbstractCheckUserPagerTest.php @@ -0,0 +1,251 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Integration\CheckUser\Pagers; + +use FormOptions; +use MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager; +use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait; +use MediaWiki\User\UserIdentityValue; +use MediaWikiIntegrationTestCase; +use Wikimedia\TestingAccessWrapper; +use Wikimedia\Timestamp\ConvertibleTimestamp; + +/** + * Test class for AbstractCheckUserPager class + * + * @group CheckUser + * @group Database + * + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager + */ +class AbstractCheckUserPagerTest extends MediaWikiIntegrationTestCase { + + use MockAuthorityTrait; + + /** + * @var int + */ + private $lowerThanLimitIPv4; + + /** + * @var int + */ + private $lowerThanLimitIPv6; + + protected function setUp(): void { + parent::setUp(); + + $this->tablesUsed = array_merge( + $this->tablesUsed, + [ + 'page', + 'actor', + 'revision', + 'ip_changes', + 'text', + 'archive', + 'recentchanges', + 'logging', + 'page_props', + 'cu_changes', + 'cu_log', + ] + ); + + $this->setMwGlobals( [ + 'wgCheckUserCIDRLimit' => [ + 'IPv4' => 16, + 'IPv6' => 19, + ] + ] ); + + $this->lowerThanLimitIPv4 = 15; + $this->lowerThanLimitIPv6 = 18; + } + + /** + * @return TestingAccessWrapper + */ + protected function setUpObject() { + $opts = new FormOptions(); + $opts->add( 'reason', '' ); + $opts->add( 'period', 0 ); + $opts->add( 'limit', '' ); + $opts->add( 'dir', '' ); + $opts->add( 'offset', '' ); + $services = $this->getServiceContainer(); + $object = new DeAbstractedCheckUserPagerTest( + $opts, + UserIdentityValue::newAnonymous( '1.2.3.4' ), + 'userips', + $services->getService( 'CheckUserTokenQueryManager' ), + $services->getUserGroupManager(), + $services->getCentralIdLookup(), + $services->getDBLoadBalancer(), + $services->getSpecialPageFactory(), + $services->getUserIdentityLookup(), + $services->getActorMigration(), + $services->getService( 'CheckUserLogService' ), + $services->getUserFactory() + ); + return TestingAccessWrapper::newFromObject( $object ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager::getIpConds + * @dataProvider provideGetIpConds + */ + public function testGetIpConds( $target, $expected ) { + $this->assertEquals( + $expected, + AbstractCheckUserPager::getIpConds( $this->db, $target ) + ); + } + + /** + * Test cases for SpecialCheckUser::getIpConds + * @return array + */ + public function provideGetIpConds() { + return [ + 'Single IPv4 address' => [ + '212.35.31.121', + [ 'cuc_ip_hex' => 'D4231F79' ], + ], + 'Single IPv4 address notated as a /32' => [ + '212.35.31.121/32', + [ 0 => 'cuc_ip_hex BETWEEN \'D4231F79\' AND \'D4231F79\'' ], + ], + 'Single IPv6 address' => [ + '::e:f:2001', + [ 'cuc_ip_hex' => 'v6-00000000000000000000000E000F2001' ], + ], + 'IPv6 /96 range' => [ + '::e:f:2001/96', + [ 0 => 'cuc_ip_hex BETWEEN \'v6-00000000000000000000000E00000000\'' . + ' AND \'v6-00000000000000000000000EFFFFFFFF\'' ], + ], + 'Invalid IP address' => [ 'abcedf', false ] + ]; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager::getIpConds + */ + public function testGetIpCondsLowerThanLimit() { + // Need to not have these in a dataProvider as $this->lowerThanLimit... isn't set when + // the data is returned. + $this->testGetIpConds( "0.17.184.5/$this->lowerThanLimitIPv4", false ); + $this->testGetIpConds( "2000::/$this->lowerThanLimitIPv6", false ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager::isValidRange + * @dataProvider provideIsValidRange + */ + public function testIsValidRange( $target, $expected ) { + $object = $this->setUpObject(); + $this->assertSame( + $expected, + $object->isValidRange( $target ) + ); + } + + /** + * Test cases for AbstractCheckUserPager::isValid + * @return array + */ + public function provideIsValidRange() { + return [ + 'Single IPv4 address' => [ '212.35.31.121', true ], + 'Single IPv4 address notated as a /32' => [ '212.35.31.121/32', true ], + 'Single IPv6 address' => [ '::e:f:2001', true ], + 'IPv6 /96 range' => [ '::e:f:2001/96', true ], + 'Invalid IP address' => [ 'abcedf', false ] + ]; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager::isValidRange + */ + public function testIsValidRangeLowerThanLimit() { + $this->testIsValidRange( "0.17.184.5/{$this->lowerThanLimitIPv4}", false ); + $this->testIsValidRange( "2000::/{$this->lowerThanLimitIPv6}", false ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager::getDateRangeCond + * @dataProvider provideGetDateRangeCond + */ + public function testGetDateRangeCond( $period, $fakeTime, $expected ) { + ConvertibleTimestamp::setFakeTime( $fakeTime ); + $object = $this->setUpObject(); + $object->opts->add( 'period', $period ); + if ( $expected ) { + $condition = 'cuc_timestamp > ' . $this->db->addQuotes( $this->db->timestamp( $expected ) ); + $this->assertArrayEquals( + [ $condition ], + $object->getDateRangeCond( '', '' ), + false, + false, + 'A different time condition was generated than expected.' + ); + } else { + $this->assertCount( + 0, + $object->getDateRangeCond( '', '' ), + 'Conditions were generated when they were not supposed to be.' + ); + } + } + + /** @return array[] */ + public function provideGetDateRangeCond(): array { + return [ + 'Empty period' => [ '', '1653047635', false ], + 'Period value for all' => [ 0, '1653047635', false ], + 'Period value for 7 days' => [ 7, '1653077137', '20220513000000' ], + 'Period value for 30 days' => [ 30, '1653047635', '20220420000000' ], + ]; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager::userWasBlocked + * @dataProvider provideUserWasBlocked + */ + public function testUserWasBlocked( $block ) { + $testUser = $this->getTestUser()->getUser(); + if ( $block ) { + $userAuthority = $this->mockRegisteredUltimateAuthority(); + $this->getServiceContainer()->getBlockUserFactory()->newBlockUser( + $testUser, + $userAuthority, + '1 second' + )->placeBlock(); + } + $object = $this->setUpObject(); + $this->assertSame( + $block, + $object->userWasBlocked( $testUser->getName() ) + ); + } + + public function provideUserWasBlocked() { + return [ + 'User was previously blocked' => [ true ], + 'User never previously blocked' => [ false ] + ]; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager::noMatchesMessage + */ + public function testNoMatchesMessageNoCheckLast() { + $object = $this->setUpObject(); + $this->assertSame( + wfMessage( 'checkuser-nomatch' )->parseAsBlock(), + $object->noMatchesMessage( 'test', false ), + 'The checkuser-nomatch message should have been returned.' + ); + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserGetEditsPagerTest.php b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserGetEditsPagerTest.php new file mode 100644 index 00000000..969917e1 --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserGetEditsPagerTest.php @@ -0,0 +1,166 @@ +<?php + +namespace MediaWiki\CheckUser\Tests; + +use MediaWiki\CheckUser\CheckUser\SpecialCheckUser; +use MediaWiki\User\UserIdentityValue; + +/** + * Test class for CheckUserGetEditsPager class + * + * @group CheckUser + * @group Database + * + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetEditsPager + */ +class CheckUserGetEditsPagerTest extends CheckUserPagerCommonTest { + + protected function setUp(): void { + parent::setUp(); + + $this->tablesUsed = array_merge( + $this->tablesUsed, + [ + 'cu_changes', + 'cu_log', + ] + ); + + $this->checkSubtype = SpecialCheckUser::SUBTYPE_GET_EDITS; + $this->defaultUserIdentity = UserIdentityValue::newAnonymous( '127.0.0.1' ); + $this->defaultCheckType = 'ipedits'; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetEditsPager::isNavigationBarShown + * @dataProvider provideIsNavigationBarShown + */ + public function testIsNavigationBarShown( $results, $shown ) { + $object = $this->setUpObject(); + $object->mResult = new \FakeResultWrapper( $results ); + $object->mQueryDone = true; + if ( $shown ) { + $this->assertTrue( + $object->isNavigationBarShown(), + 'Navigation bar is not showing when it\'s supposed to' + ); + } else { + $this->assertFalse( + $object->isNavigationBarShown(), + 'Navigation bar is showing when it is not supposed to' + ); + } + } + + public function provideIsNavigationBarShown() { + return [ + [ [], false ], + [ [ [ 'test' ] ], true ] + ]; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetEditsPager::preCacheMessages + * @dataProvider providePreCacheMessages + */ + public function testPreCacheMessages( $messageKeys ) { + $object = $this->setUpObject(); + $this->assertArrayEquals( + $messageKeys, + array_keys( $object->message ), + false, + false, + 'preCacheMessage has missed or has too many message keys to cache.' + ); + foreach ( $messageKeys as $key ) { + $this->assertSame( + wfMessage( $key )->escaped(), + $object->message[$key], + 'preCacheMessage did not cache the correct message.' + ); + } + } + + public function providePreCacheMessages() { + return [ + [ [ 'diff', 'hist', 'minoreditletter', 'newpageletter', 'blocklink', 'log' ] ] + ]; + } + + /** + * Tests that the template parameters provided to the GetEditsLine.mustache match + * the expected values. Does not test the mustache file which includes some + * conditional logic, HTML and whitespace. + * + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetEditsPager::formatRow + * @dataProvider provideFormatRow + */ + public function testFormatRow( $row, $flagCache, $expectedTemplateParams ) { + $object = $this->setUpObject(); + $object->templateParser = new TemplateParserMockTest(); + $row = array_merge( $this->getDefaultRowFieldValues(), $row ); + $object->flagCache = $flagCache; + $object->formatRow( (object)$row ); + $this->assertNotNull( + $object->templateParser->lastCalledWith, + 'The template parser was not called by formatRow.' + ); + $this->assertSame( + 'GetEditsLine', + $object->templateParser->lastCalledWith[0], + 'formatRow did not call the correct mustache file.' + ); + $this->assertArrayEquals( + $expectedTemplateParams, + array_filter( + $object->templateParser->lastCalledWith[1], + static function ( $key ) use ( $expectedTemplateParams ) { + return array_key_exists( $key, $expectedTemplateParams ); + }, + ARRAY_FILTER_USE_KEY + ), + $expectedTemplateParams, + 'The template parameters do not match the expected template parameters. If changes have been + made to the template parameters make sure you update the tests.' + ); + } + + public function provideFormatRow() { + // @todo test the rest of the template parameters. + return [ + 'Test agent' => [ + [ 'cuc_agent' => 'Testing' ], + [ '127.0.0.1' => '' ], + [ 'userAgent' => 'Testing' ] + ], + 'Test user link class' => [ + [ 'cuc_user' => 0, 'cuc_user_text' => 'Non existent user 1234' ], + [ 'Non existent user 1234' => '' ], + [ 'userLinkClass' => 'mw-checkuser-nonexistent-user' ] + ], + ]; + } + + /** @inheritDoc */ + public function getDefaultRowFieldValues(): array { + return [ + 'cuc_namespace' => 0, + 'cuc_title' => '', + 'cuc_user' => 0, + 'cuc_user_text' => '127.0.0.1', + 'cuc_actor' => 0, + 'cuc_actiontext' => '', + 'cuc_comment' => '', + 'cuc_comment_id' => 0, + 'cuc_minor' => 0, + 'cuc_page_id' => 0, + 'cuc_this_oldid' => 0, + 'cuc_last_oldid' => 0, + 'cuc_type' => RC_LOG, + 'cuc_timestamp' => $this->db->timestamp(), + 'cuc_ip' => '127.0.0.1', + 'cuc_xff' => '', + 'cuc_agent' => '', + ]; + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserGetIPsPagerTest.php b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserGetIPsPagerTest.php new file mode 100644 index 00000000..cc0f8357 --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserGetIPsPagerTest.php @@ -0,0 +1,128 @@ +<?php + +namespace MediaWiki\CheckUser\Tests; + +use MediaWiki\CheckUser\CheckUser\SpecialCheckUser; +use MediaWiki\CheckUser\Hooks; +use MediaWiki\User\UserIdentityValue; +use Wikimedia\IPUtils; +use Wikimedia\TestingAccessWrapper; + +/** + * Test class for CheckUserGetIPsPager class + * + * @group CheckUser + * @group Database + * + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetIPsPager + */ +class CheckUserGetIPsPagerTest extends CheckUserPagerCommonTest { + + protected function setUp(): void { + parent::setUp(); + + $this->tablesUsed = array_merge( + $this->tablesUsed, + [ + 'cu_changes', + 'cu_log', + ] + ); + + $this->checkSubtype = SpecialCheckUser::SUBTYPE_GET_IPS; + $this->defaultUserIdentity = $this->getTestUser()->getUserIdentity(); + $this->defaultCheckType = 'userips'; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetIPsPager::getCountForIPedits + * @dataProvider provideGetCountForIPEdits + */ + public function testGetCountForIPEdits( $ips, $expectedCount ) { + $object = $this->setUpObject(); + $hooks = TestingAccessWrapper::newFromClass( Hooks::class ); + foreach ( $ips as $ip ) { + $row = [ 'cuc_ip' => $ip, 'cuc_ip_hex' => IPUtils::toHex( $ip ) ]; + $hooks->insertIntoCuChangesTable( $row, __METHOD__, UserIdentityValue::newAnonymous( $ip ) ); + } + $this->assertSame( + $expectedCount, + $object->getCountForIPedits( IPUtils::toHex( '127.0.0.1' ) ), + 'The expected count for edits made by the IP was not returned.' + ); + } + + public function provideGetCountForIPEdits() { + // @todo test estimated row count? + return [ + [ + array_fill( 0, 3, '127.0.0.1' ), + 3 + ], + [ + array_merge( + array_fill( 0, 2, '127.0.0.1' ), + array_fill( 0, 3, '127.0.0.2' ) + ), + 2 + ] + ]; + } + + /** + * Tests that the template parameters provided to the GetIPsLine.mustache match + * the expected values. Does not test the mustache file which includes some + * conditional logic, HTML and whitespace. + * + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetIPsPager::formatRow + * @dataProvider provideFormatRow + */ + public function testFormatRow( $row, $expectedTemplateParams ) { + $object = $this->setUpObject(); + $object->templateParser = new TemplateParserMockTest(); + $row = array_merge( $this->getDefaultRowFieldValues(), $row ); + $object->formatRow( (object)$row ); + $this->assertNotNull( + $object->templateParser->lastCalledWith, + 'The template parser was not called by formatRow.' + ); + $this->assertSame( + 'GetIPsLine', + $object->templateParser->lastCalledWith[0], + 'formatRow did not call the correct mustache file.' + ); + $this->assertArrayEquals( + $expectedTemplateParams, + array_filter( + $object->templateParser->lastCalledWith[1], + static function ( $key ) use ( $expectedTemplateParams ) { + return array_key_exists( $key, $expectedTemplateParams ); + }, + ARRAY_FILTER_USE_KEY + ), + 'The template parameters do not match the expected template parameters. If changes have been + made to the template parameters make sure you update the tests.' + ); + } + + public function provideFormatRow() { + // @todo test the rest of the template parameters. + return [ + 'Test edit count' => [ + [ 'count' => 555 ], + [ 'editCount' => 555 ] + ], + ]; + } + + /** @inheritDoc */ + public function getDefaultRowFieldValues(): array { + return [ + 'cuc_ip' => '127.0.0.1', + 'cuc_ip_hex' => IPUtils::toHex( '127.0.0.1' ), + 'count' => 1, + 'first' => $this->db->timestamp(), + 'last' => $this->db->timestamp(), + ]; + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserLogPagerTest.php b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserLogPagerTest.php new file mode 100644 index 00000000..9f9d6581 --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/CheckUserLogPagerTest.php @@ -0,0 +1,149 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Integration\CheckUser\Pagers; + +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserLogPager; +use MediaWiki\CheckUser\Tests\CheckUserIntegrationTestCaseTest; + +/** + * Test class for CheckUserLogPager class + * + * @group CheckUser + * @group Database + * + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserLogPager + */ +class CheckUserLogPagerTest extends CheckUserIntegrationTestCaseTest { + + protected function setUp(): void { + parent::setUp(); + + $this->tablesUsed = array_merge( + $this->tablesUsed, + [ + 'cu_log', + ] + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserLogPager::getPerformerSearchConds + */ + public function testGetPerformerSearchConds() { + // PHPUnit doesn't allow mocking static methods so having to + // use SpecialCheckUserLog::verifyInitiator without mocking. + + // Existing user + $testUser = $this->getTestUser()->getUser(); + $this->assertTrue( $testUser->getUser()->isRegistered() ); + $this->assertArrayEquals( + [ 'cul_user' => $testUser->getId() ], + CheckUserLogPager::getPerformerSearchConds( $testUser->getName() ), + false, + true, + 'For an existing user the valid search cond should be returned.' + ); + + // Non-existent user with a valid username + $testUser = $this->getNonExistentTestUser(); + $this->assertNull( + CheckUserLogPager::getPerformerSearchConds( $testUser->getName() ), + 'Non-existent users should not be a valid performer.' + ); + + // Only registered users can be performers, so test an + // IP address as the username. + $this->assertNull( + CheckUserLogPager::getPerformerSearchConds( '1.2.3.4' ), + 'Only registered users can be valid performers.' + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserLogPager::getTargetSearchConds + */ + public function testGetTargetSearchCondsUser() { + // Existing user + $testUser = $this->getTestUser()->getUser(); + $this->assertTrue( $testUser->getUser()->isRegistered() ); + $this->assertArrayEquals( + $this->getExpectedGetTargetSearchConds( 'user', $testUser->getId() ), + CheckUserLogPager::getTargetSearchConds( $testUser->getName() ), + false, + true, + 'For an existing user the valid search cond should be returned.' + ); + + // Non-existent user with a valid username + $testUser = $this->getNonExistentTestUser(); + $this->assertNull( + CheckUserLogPager::getTargetSearchConds( $testUser->getName() ), + 'Non-existent users should not be a valid target.' + ); + + // Invalid username + $this->assertNull( + CheckUserLogPager::getTargetSearchConds( '/' ), + 'Invalid usernames should not be a valid target.' + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\Pagers\CheckUserLogPager::getTargetSearchConds + * @dataProvider provideGetTargetSearchCondsIP + */ + public function testGetTargetSearchCondsIP( $target, $type, $start, $end ) { + $this->assertArrayEquals( + $this->getExpectedGetTargetSearchConds( $type, null, $start, $end ), + CheckUserLogPager::getTargetSearchConds( $target ), + false, + true, + 'Valid IP addresses should have associated search conditions.' + ); + } + + public function provideGetTargetSearchCondsIP(): array { + return [ + 'Single IP' => [ '124.0.0.0', 'ip', '7C000000', '7C000000' ], + '/24 IP range' => [ '124.0.0.0/24', 'range', '7C000000', '7C0000FF' ], + '/16 IP range' => [ '124.0.0.0/16', 'range', '7C000000', '7C00FFFF' ], + 'Single IP notated as a /32 range' => [ '1.2.3.4/32', 'ip', '01020304', '01020304' ], + 'Single IPv6' => [ '::e:f:2001', 'ip', + 'v6-00000000000000000000000E000F2001', + 'v6-00000000000000000000000E000F2001' + ], + '/96 IPv6 range' => [ '::e:f:2001/96', 'range', + 'v6-00000000000000000000000E00000000', + 'v6-00000000000000000000000EFFFFFFFF' + ], + ]; + } + + private function getExpectedGetTargetSearchConds( $type, $id, $start = 0, $end = 0 ) { + switch ( $type ) { + case 'ip': + return [ + 'cul_target_hex = ' . $this->db->addQuotes( $start ) . ' OR ' . + '(cul_range_end >= ' . $this->db->addQuotes( $start ) . ' AND ' . + 'cul_range_start <= ' . $this->db->addQuotes( $start ) . ')' + ]; + case 'range': + return [ + '(cul_target_hex >= ' . $this->db->addQuotes( $start ) . ' AND ' . + 'cul_target_hex <= ' . $this->db->addQuotes( $end ) . ') OR ' . + '(cul_range_end >= ' . $this->db->addQuotes( $start ) . ' AND ' . + 'cul_range_start <= ' . $this->db->addQuotes( $end ) . ')' + ]; + case 'user': + if ( $id === null ) { + return null; + } + return [ + 'cul_type' => [ 'userips', 'useredits', 'investigate' ], + 'cul_target_id' => $id, + ]; + default: + $this->fail( 'getExpectedGetTargetSearchConds() got an unexpected type.' ); + } + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUser/Pagers/DeAbstractedCheckUserPagerTest.php b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/DeAbstractedCheckUserPagerTest.php new file mode 100644 index 00000000..bf7890f4 --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/DeAbstractedCheckUserPagerTest.php @@ -0,0 +1,31 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Integration\CheckUser\Pagers; + +use MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager; + +/** + * A helper class for AbstractCheckUserPagerTest.php. + * Because AbstractCheckUserPager is an abstract class + * it has to be extended first if an object is wanted. + * + * This implements the abstracted methods by returning + * an empty response (as testing these methods should + * be done for classes that extend AbstractCheckUserPager). + * + * @coversNothing + */ +class DeAbstractedCheckUserPagerTest extends AbstractCheckUserPager { + + public function formatRow( $row ) { + return ''; + } + + public function getQueryInfo() { + return []; + } + + public function getIndexField() { + return []; + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUser/Pagers/Mocks/TemplateParserMockTest.php b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/Mocks/TemplateParserMockTest.php new file mode 100644 index 00000000..02811c35 --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUser/Pagers/Mocks/TemplateParserMockTest.php @@ -0,0 +1,29 @@ +<?php + +namespace MediaWiki\CheckUser\Tests; + +use TemplateParser; + +class TemplateParserMockTest extends TemplateParser { + + /** + * @var array|null the parameters provided on the last call to processTemplate. + */ + public $lastCalledWith; + + /** + * Mocked processTemplate that returns an empty string. + * Does not test the actual processing of the template + * but used to unit test the formatRow by validating + * that the template parameters are as expected. + * + * It saves the arguments from the last call to a + * property for later access. + * + * @inheritDoc + */ + public function processTemplate( $templateName, $args, array $scopes = [] ) { + $this->lastCalledWith = [ $templateName, $args, $scopes ]; + return ''; + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUser/SpecialCheckUserTest.php b/CheckUser/tests/phpunit/integration/CheckUser/SpecialCheckUserTest.php new file mode 100644 index 00000000..c3f95220 --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUser/SpecialCheckUserTest.php @@ -0,0 +1,203 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Integration\CheckUser; + +use FormOptions; +use HashConfig; +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetEditsPager; +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetIPsPager; +use MediaWiki\CheckUser\CheckUser\Pagers\CheckUserGetUsersPager; +use MediaWiki\CheckUser\CheckUser\SpecialCheckUser; +use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait; +use MediaWiki\User\UserIdentityValue; +use MediaWikiIntegrationTestCase; +use Wikimedia\TestingAccessWrapper; + +/** + * Test class for SpecialCheckUser class + * + * @group CheckUser + * @group Database + * + * @covers \MediaWiki\CheckUser\CheckUser\SpecialCheckUser + */ +class SpecialCheckUserTest extends MediaWikiIntegrationTestCase { + + use MockAuthorityTrait; + + protected function setUp(): void { + parent::setUp(); + + $this->tablesUsed = array_merge( + $this->tablesUsed, + [ + 'page', + 'revision', + 'ip_changes', + 'text', + 'archive', + 'recentchanges', + 'logging', + 'page_props', + 'cu_changes', + ] + ); + } + + /** @return TestingAccessWrapper */ + protected function setUpObject() { + $object = $this->getServiceContainer()->getSpecialPageFactory()->getPage( 'CheckUser' ); + $testingWrapper = TestingAccessWrapper::newFromObject( $object ); + $testingWrapper->opts = new FormOptions(); + return $testingWrapper; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\SpecialCheckUser::checkReason + * @dataProvider provideCheckReason + */ + public function testCheckReason( $config, $reason, $expected ) { + $this->setMwGlobals( 'wgCheckUserForceSummary', $config ); + $object = $this->setUpObject(); + $object->opts->add( 'reason', $expected ); + $this->assertSame( + $expected, + $object->checkReason() + ); + } + + /** + * Test cases for SpecialCheckUser::checkReason + * @return array + */ + public function provideCheckReason() { + return [ + 'Empty reason with wgCheckUserForceSummary as false' => [ false, '', true ], + 'Non-empty reason with wgCheckUserForceSummary as false' => [ false, 'Test Reason', true ], + 'Empty reason with wgCheckUserForceSummary as true' => [ true, '', false ], + 'Non-empty reason with wgCheckUserForceSummary as true' => [ true, 'Test Reason', true ] + ]; + } + + /** @covers \MediaWiki\CheckUser\CheckUser\SpecialCheckUser::doesWrites */ + public function testDoesWrites() { + $this->assertTrue( + $this->setUpObject()->doesWrites(), + 'Special:CheckUser writes to the cu_log table so it does writes.' + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\SpecialCheckUser::getPager + * @dataProvider provideGetPager + */ + public function testGetPager( $checkType, $userIdentity, $xfor = null ) { + $object = $this->setUpObject(); + $object->opts->add( 'limit', 0 ); + $object->opts->add( 'reason', '' ); + $object->opts->add( 'period', 0 ); + if ( $checkType === SpecialCheckUser::SUBTYPE_GET_IPS ) { + $this->assertTrue( + $object->getPager( $checkType, $userIdentity, 'untested', $xfor ) + instanceof CheckUserGetIPsPager, + 'The Get IPs checktype should return the Get IPs pager.' + ); + } elseif ( $checkType === SpecialCheckUser::SUBTYPE_GET_EDITS ) { + $this->assertTrue( + $object->getPager( $checkType, $userIdentity, 'untested', $xfor ) + instanceof CheckUserGetEditsPager, + 'The Get edits checktype should return the Get edits pager.' + ); + } elseif ( $checkType === SpecialCheckUser::SUBTYPE_GET_USERS ) { + $this->assertTrue( + $object->getPager( $checkType, $userIdentity, 'untested', $xfor ) + instanceof CheckUserGetUsersPager, + 'The Get users checktype should return the Get users pager.' + ); + } else { + $this->assertNull( + $object->getPager( $checkType, $userIdentity, 'untested' ), + 'An unrecognised check type should return no pager.' + ); + } + } + + public function provideGetPager() { + return [ + 'Get IPs checktype' => + [ SpecialCheckUser::SUBTYPE_GET_IPS, UserIdentityValue::newRegistered( 1, 'test' ) ], + 'Get edits checktype with a registered user' => + [ SpecialCheckUser::SUBTYPE_GET_EDITS, UserIdentityValue::newRegistered( 1, 'test' ) ], + 'Get edits checktype with a IP' => + [ SpecialCheckUser::SUBTYPE_GET_EDITS, UserIdentityValue::newAnonymous( '127.0.0.1' ), false ], + 'Get edits checktype with a XFF IP' => + [ SpecialCheckUser::SUBTYPE_GET_EDITS, UserIdentityValue::newAnonymous( '127.0.0.1' ), true ], + 'Get users checktype with a IP' => + [ SpecialCheckUser::SUBTYPE_GET_USERS, UserIdentityValue::newAnonymous( '127.0.0.1' ), false ], + 'Get users checktype with a XFF IP' => + [ SpecialCheckUser::SUBTYPE_GET_USERS, UserIdentityValue::newAnonymous( '127.0.0.1' ), true ], + 'An invalid checktype' => [ '', UserIdentityValue::newRegistered( 1, 'test' ) ], + ]; + } + + /** + * @dataProvider provideRequiredGroupAccess + */ + public function testRequiredRightsByGroup( $groups, $allowed ) { + $checkUserLog = $this->getServiceContainer()->getSpecialPageFactory() + ->getPage( 'CheckUser' ); + if ( $checkUserLog === null ) { + $this->fail( 'CheckUser special page does not exist' ); + } + $requiredRight = $checkUserLog->getRestriction(); + if ( !is_array( $groups ) ) { + $groups = [ $groups ]; + } + $rightsGivenInGroups = $this->getServiceContainer()->getGroupPermissionsLookup() + ->getGroupPermissions( $groups ); + if ( $allowed ) { + $this->assertContains( + $requiredRight, + $rightsGivenInGroups, + 'Groups/rights given to the test user should allow it to access CheckUser.' + ); + } else { + $this->assertNotContains( + $requiredRight, + $rightsGivenInGroups, + 'Groups/rights given to the test user should not include access to CheckUser.' + ); + } + } + + public function provideRequiredGroupAccess() { + return [ + 'No user groups' => [ '', false ], + 'Checkuser only' => [ 'checkuser', true ], + 'Checkuser and sysop' => [ [ 'checkuser', 'sysop' ], true ], + ]; + } + + /** + * @dataProvider provideRequiredRights + */ + public function testRequiredRights( $groups, $allowed ) { + if ( ( is_array( $groups ) && isset( $groups['checkuser-log'] ) ) || $groups === "checkuser-log" ) { + $this->overrideMwServices( + new HashConfig( + [ 'GroupPermissions' => + [ 'checkuser-log' => [ 'checkuser-log' => true, 'read' => true ] ] + ] + ) + ); + } + $this->testRequiredRightsByGroup( $groups, $allowed ); + } + + public function provideRequiredRights() { + return [ + 'No user groups' => [ '', false ], + 'checkuser right only' => [ 'checkuser', true ], + ]; + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUser/SpecialTestCheckUserLogTest.php b/CheckUser/tests/phpunit/integration/CheckUser/SpecialTestCheckUserLogTest.php new file mode 100644 index 00000000..ce83a275 --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUser/SpecialTestCheckUserLogTest.php @@ -0,0 +1,174 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Integration\CheckUser; + +use HashConfig; +use MediaWiki\CheckUser\CheckUser\SpecialCheckUserLog; +use MediaWiki\CheckUser\Tests\CheckUserIntegrationTestCaseTest; + +/** + * Test class for SpecialCheckUserLog class + * + * @group CheckUser + * @group Database + * + * @covers \MediaWiki\CheckUser\CheckUser\SpecialCheckUserLog + */ +class SpecialTestCheckUserLogTest extends CheckUserIntegrationTestCaseTest { + + protected function setUp(): void { + parent::setUp(); + + $this->tablesUsed = array_merge( + $this->tablesUsed, + [ + 'cu_log', + ] + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\SpecialCheckUserLog::verifyInitiator + */ + public function testVerifyInitiator() { + // Existing user + $testUser = $this->getTestUser()->getUser(); + $this->assertTrue( $testUser->getUser()->isRegistered() ); + $this->assertSame( + $testUser->getId(), + SpecialCheckUserLog::verifyInitiator( $testUser->getName() ), + 'For an existing user it\'s ID should be returned.' + ); + + // Non-existent user with a valid username + $testUser = $this->getNonExistentTestUser(); + $this->assertFalse( + SpecialCheckUserLog::verifyInitiator( $testUser->getName() ), + 'Non-existent users should not be a valid initiator.' + ); + + // Only registered users can be performers/initiators, + // so test an IP address as the username. + $this->assertFalse( + SpecialCheckUserLog::verifyInitiator( '1.2.3.4' ), + 'Only registered users can be valid performers.' + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\SpecialCheckUserLog::verifyTarget + */ + public function testVerifyTargetUser() { + // Existing user + $testUser = $this->getTestUser()->getUser(); + $this->assertTrue( $testUser->getUser()->isRegistered() ); + $this->assertSame( + $testUser->getId(), + SpecialCheckUserLog::verifyTarget( $testUser->getName() ), + 'For an existing user it\'s ID should be returned.' + ); + + // Non-existent user with a valid username + $testUser = $this->getNonExistentTestUser(); + $this->assertFalse( + SpecialCheckUserLog::verifyTarget( $testUser->getName() ), + 'Non-existent users should not be a valid target.' + ); + + // Invalid username + $this->assertFalse( + SpecialCheckUserLog::verifyTarget( '/' ), + 'Invalid usernames should not be a valid target.' + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUser\SpecialCheckUserLog::verifyTarget + * @dataProvider provideVerifyTargetIP + */ + public function testVerifyTargetIP( $target, $expected ) { + $this->assertArrayEquals( + $expected, + SpecialCheckUserLog::verifyTarget( $target ), + true, + false, + 'Valid IP addresses should be seen as valid targets and parsed as a IP or IP range.' + ); + } + + public function provideVerifyTargetIP() { + return [ + 'Single IP' => [ '124.0.0.0', [ '7C000000' ] ], + '/24 IP range' => [ '124.0.0.0/24', [ '7C000000', '7C0000FF' ] ], + '/16 IP range' => [ '124.0.0.0/16', [ '7C000000', '7C00FFFF' ] ], + 'Single IP notated as a /32 range' => [ '1.2.3.4/32', [ '01020304' ] ], + 'Single IPv6' => [ '::e:f:2001', [ 'v6-00000000000000000000000E000F2001' ] ], + '/96 IPv6 range' => [ '::e:f:2001/96', [ + 'v6-00000000000000000000000E00000000', + 'v6-00000000000000000000000EFFFFFFFF' + ] + ], + ]; + } + + /** + * @dataProvider provideRequiredGroupAccess + */ + public function testRequiredRightsByGroup( $groups, $allowed ) { + $checkUserLog = $this->getServiceContainer()->getSpecialPageFactory() + ->getPage( 'CheckUserLog' ); + if ( $checkUserLog === null ) { + $this->fail( 'CheckUserLog special page does not exist' ); + } + $requiredRight = $checkUserLog->getRestriction(); + if ( !is_array( $groups ) ) { + $groups = [ $groups ]; + } + $rightsGivenInGroups = $this->getServiceContainer()->getGroupPermissionsLookup() + ->getGroupPermissions( $groups ); + if ( $allowed ) { + $this->assertContains( + $requiredRight, + $rightsGivenInGroups, + 'Groups/rights given to the test user should allow it to access the CheckUserLog.' + ); + } else { + $this->assertNotContains( + $requiredRight, + $rightsGivenInGroups, + 'Groups/rights given to the test user should not include access to the CheckUserLog.' + ); + } + } + + public function provideRequiredGroupAccess() { + return [ + 'No user groups' => [ '', false ], + 'Checkuser only' => [ 'checkuser', true ], + 'Checkuser and sysop' => [ [ 'checkuser', 'sysop' ], true ], + ]; + } + + /** + * @dataProvider provideRequiredRights + */ + public function testRequiredRights( $groups, $allowed ) { + if ( ( is_array( $groups ) && isset( $groups['checkuser-log'] ) ) || $groups === "checkuser-log" ) { + $this->overrideMwServices( + new HashConfig( + [ 'GroupPermissions' => + [ 'checkuser-log' => [ 'checkuser-log' => true, 'read' => true ] ] + ] + ) + ); + } + $this->testRequiredRightsByGroup( $groups, $allowed ); + } + + public function provideRequiredRights() { + return [ + 'No user groups' => [ '', false ], + 'checkuser-log right only' => [ 'checkuser-log', true ], + ]; + } +} diff --git a/CheckUser/tests/phpunit/integration/CheckUserLogServiceTest.php b/CheckUser/tests/phpunit/integration/CheckUserLogServiceTest.php new file mode 100644 index 00000000..222b9086 --- /dev/null +++ b/CheckUser/tests/phpunit/integration/CheckUserLogServiceTest.php @@ -0,0 +1,169 @@ +<?php + +namespace MediaWiki\CheckUser\Tests; + +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityValue; +use MediaWikiIntegrationTestCase; +use Wikimedia\TestingAccessWrapper; +use Wikimedia\Timestamp\ConvertibleTimestamp; + +/** + * Test class for CheckUserLogService + * + * @group CheckUser + * @group Database + * + * @covers \MediaWiki\CheckUser\CheckUserLogService + */ +class CheckUserLogServiceTest extends MediaWikiIntegrationTestCase { + protected function setUp(): void { + parent::setUp(); + + $this->tablesUsed = array_merge( + $this->tablesUsed, + [ + 'cu_log', + ] + ); + + $this->truncateTable( 'cu_log' ); + } + + /** @return TestingAccessWrapper */ + protected function setUpObject() { + return TestingAccessWrapper::newFromObject( $this->getServiceContainer()->get( 'CheckUserLogService' ) ); + } + + public function commonTestAddLogEntry( + $logType, $targetType, $target, $reason, $targetID, $assertSelectFieldNames, $assertSelectFieldValues + ) { + $object = $this->setUpObject(); + $object->addLogEntry( + $this->getTestUser( 'checkuser' )->getUser(), $logType, $targetType, $target, $reason, $targetID + ); + \DeferredUpdates::doUpdates(); + $this->assertSelect( + 'cu_log', + $assertSelectFieldNames, + [], + [ $assertSelectFieldValues ] + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUserLogService::addLogEntry + * @dataProvider provideAddLogEntryIPs + */ + public function testAddLogEntryIPs( + $logType, $target, $reason, $assertSelectFieldValues + ) { + $this->commonTestAddLogEntry( $logType, 'ip', $target, $reason, 0, + [ 'cul_target_id', 'cul_type', 'cul_target_text', 'cul_target_hex', 'cul_range_start', 'cul_range_end' ], + array_merge( [ 0 ], $assertSelectFieldValues ) + ); + } + + public function provideAddLogEntryIPs() { + return [ + [ + 'ipusers', '127.0.0.1', 'test', + [ 'ipusers', '127.0.0.1', '7F000001', '', '' ], + ], + [ + 'ipedits', '1.2.3.4', 'testing', + [ 'ipedits', '1.2.3.4', '01020304', '', '' ], + ], + [ + 'ipedits', '1.2.3.4/21', 'testing', + [ 'ipedits', '1.2.3.4/21', '01020000', '01020000', '010207FF' ], + ], + ]; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUserLogService::addLogEntry + * @dataProvider provideAddLogEntryUsers + */ + public function testAddLogEntryUser( + $logType, UserIdentity $target, $reason, $assertSelectFieldValues + ) { + $this->commonTestAddLogEntry( $logType, 'user', $target->getName(), $reason, $target->getId(), + [ 'cul_target_hex', 'cul_range_start', 'cul_range_end', 'cul_type', 'cul_target_text', 'cul_target_id' ], + array_merge( [ '', '', '' ], $assertSelectFieldValues ) + ); + } + + public function provideAddLogEntryUsers() { + return [ + [ + 'userips', UserIdentityValue::newRegistered( 3, 'Test' ), 'test', + [ 'userips', 'Test', 3 ], + ], + [ + 'useredits', UserIdentityValue::newRegistered( 10, 'Testing' ), 'test', + [ 'useredits', 'Testing', 10 ], + ], + [ + 'useredits', UserIdentityValue::newRegistered( 2, 'Testing1234' ), 'test', + [ 'useredits', 'Testing1234', 2 ], + ], + ]; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUserLogService::addLogEntry + * @dataProvider provideAddLogEntryTimestamp + */ + public function testAddLogEntryTimestamp( $timestamp ) { + ConvertibleTimestamp::setFakeTime( $timestamp ); + $testUser = $this->getTestUser()->getUserIdentity(); + $this->commonTestAddLogEntry( + 'ipusers', 'user', $testUser->getName(), 'testing', $testUser->getId(), + [ 'cul_timestamp' ], [ $this->db->timestamp( $timestamp ) ] + ); + } + + public function provideAddLogEntryTimestamp() { + return [ + [ '1653047635' ], + [ '1653042345' ] + ]; + } + + /** + * @covers \MediaWiki\CheckUser\CheckUserLogService::addLogEntry + */ + public function testAddLogEntryPerformer() { + $object = $this->setUpObject(); + $testUser = $this->getTestUser( 'checkuser' )->getUser(); + $object->addLogEntry( $testUser, 'ipusers', 'ip', '127.0.0.1', '', 0 ); + \DeferredUpdates::doUpdates(); + $this->assertSelect( + 'cu_log', + [ 'cul_user', 'cul_user_text' ], + [], + [ [ $testUser->getId(), $testUser->getName() ] ] + ); + } + + /** + * @covers \MediaWiki\CheckUser\CheckUserLogService::addLogEntry + */ + public function testAddLogEntryActor() { + $object = $this->setUpObject(); + if ( $object->culActorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { + $testUser = $this->getTestUser( 'checkuser' )->getUser(); + $object->addLogEntry( $testUser, 'ipusers', 'ip', '127.0.0.1', '', 0 ); + \DeferredUpdates::doUpdates(); + $this->assertSelect( + 'cu_log', + [ 'cul_actor' ], + [], + [ [ $testUser->getActorId() ] ] + ); + } else { + $this->expectNotToPerformAssertions(); + } + } +} diff --git a/CheckUser/tests/phpunit/integration/HooksTest.php b/CheckUser/tests/phpunit/integration/HooksTest.php new file mode 100644 index 00000000..e8ae2b2a --- /dev/null +++ b/CheckUser/tests/phpunit/integration/HooksTest.php @@ -0,0 +1,592 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Integration; + +use MailAddress; +use MediaWiki\Block\DatabaseBlock; +use MediaWiki\CheckUser\Hooks; +use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait; +use MediaWiki\User\UserIdentityValue; +use MediaWikiIntegrationTestCase; +use RecentChange; +use RequestContext; +use Wikimedia\TestingAccessWrapper; + +/** + * @group CheckUser + * @group Database + * @coversDefaultClass \MediaWiki\CheckUser\Hooks + */ +class HooksTest extends MediaWikiIntegrationTestCase { + + use MockAuthorityTrait; + + public function setUp(): void { + parent::setUp(); + + $this->tablesUsed = [ + 'cu_changes', + 'user', + 'logging', + 'ipblocks', + 'ipblocks_restrictions', + 'recentchanges' + ]; + + $this->setMwGlobals( [ + 'wgCheckUserActorMigrationStage' => 3, + 'wgCheckUserLogActorMigrationStage' => 3 + ] ); + } + + /** + * @return TestingAccessWrapper + */ + protected function setUpObject(): TestingAccessWrapper { + return TestingAccessWrapper::newFromClass( Hooks::class ); + } + + /** + * @covers ::onUserMergeAccountFields + * @todo test that the values returned by the hook are correct or not invalid? + */ + public function testOnUserMergeAccountFields() { + $updateFields = []; + $expectedCount = 3; + $actorMigrationStage = $this->getServiceContainer()->getMainConfig()->get( 'CheckUserActorMigrationStage' ); + if ( ( $actorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) { + $expectedCount++; + } + $actorMigrationStage = $this->getServiceContainer()->getMainConfig()->get( 'CheckUserLogActorMigrationStage' ); + if ( ( $actorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) { + $expectedCount++; + } + Hooks::onUserMergeAccountFields( $updateFields ); + $this->assertCount( + $expectedCount, + $updateFields, + '3 updates were added' + ); + } + + /** + * @covers ::getAgent + * @dataProvider provideGetAgent + */ + public function testGetAgent( $userAgent, $expected ) { + $request = TestingAccessWrapper::newFromObject( new \WebRequest() ); + $request->headers = [ 'USER-AGENT' => $userAgent ]; + RequestContext::getMain()->setRequest( $request->object ); + $this->assertEquals( + $expected, + $this->setUpObject()->getAgent(), + 'The expected user agent was not returned.' + ); + } + + public function provideGetAgent() { + return [ + [ false, '' ], + [ '', '' ], + [ 'Test', 'Test' ], + [ + str_repeat( 'q', Hooks::TEXT_FIELD_LENGTH ), + str_repeat( 'q', Hooks::TEXT_FIELD_LENGTH ) + ], + [ + str_repeat( 'q', Hooks::TEXT_FIELD_LENGTH + 10 ), + str_repeat( 'q', Hooks::TEXT_FIELD_LENGTH - 3 ) . '...' + ] + ]; + } + + /** + * @todo Need to test xff and timestamp(?) + * + * @covers ::insertIntoCuChangesTable + * @dataProvider provideInsertIntoCuChangesTable + */ + public function testInsertIntoCuChangesTable( $row, $fields, $expectedRow ) { + $this->setUpObject()->insertIntoCuChangesTable( $row, __METHOD__, $this->getTestUser()->getUserIdentity() ); + $this->assertSelect( + 'cu_changes', + $fields, + '', + [ $expectedRow ] + ); + } + + /** + * @covers ::insertIntoCuChangesTable + * @dataProvider provideTestTruncationInsertIntoCuChangesTable + */ + public function testTruncationInsertIntoCuChangesTable( $field ) { + $this->testInsertIntoCuChangesTable( + [ $field => str_repeat( 'q', Hooks::TEXT_FIELD_LENGTH + 9 ) ], + [ $field ], + [ str_repeat( 'q', Hooks::TEXT_FIELD_LENGTH - 3 ) . '...' ] + ); + } + + public function provideTestTruncationInsertIntoCuChangesTable() { + return [ + [ 'cuc_comment' ], + [ 'cuc_actiontext' ], + [ 'cuc_xff' ] + ]; + } + + /** + * @covers ::insertIntoCuChangesTable + */ + public function testUserInsertIntoCuChangesTable() { + $user = $this->getTestUser()->getUserIdentity(); + $this->setUpObject()->insertIntoCuChangesTable( [], __METHOD__, $user ); + $this->assertSelect( + 'cu_changes', + [ 'cuc_user', 'cuc_user_text' ], + '', + [ [ $user->getId(), $user->getName() ] ] + ); + } + + public function provideInsertIntoCuChangesTable() { + return [ + [ [], [ 'cuc_ip' ], [ '127.0.0.1' ] ], + ]; + } + + /** + * @covers ::insertIntoCuChangesTable + */ + public function testActorInsertIntoCuChangesTable() { + $actorMigrationStage = $this->getServiceContainer()->getMainConfig()->get( 'CheckUserActorMigrationStage' ); + if ( ( $actorMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) { + $user = $this->getTestUser(); + $this->setUpObject()->insertIntoCuChangesTable( [], __METHOD__, $user->getUserIdentity() ); + $this->assertSelect( + 'cu_changes', + [ 'cuc_actor' ], + '', + [ [ $user->getUser()->getActorId() ] ] + ); + } else { + $this->expectNotToPerformAssertions(); + } + } + + /** + * A function to remove duplication for common tests + * across all the updateCheckUserData tests below. + * Called by the individual tests themselves. + * + * @param array $rcAttribs The attribs for the RecentChange object + * @param array $fields The fields to select from the DB when using assertSelect() + * @param array &$expectedRow The expected values for the fields from the DB when using assertSelect() + * @return RecentChange + */ + public function commonTestsUpdateCheckUserData( + array $rcAttribs, array $fields, array &$expectedRow + ): RecentChange { + $rc = new RecentChange; + $rc->setAttribs( $rcAttribs ); + $this->setUpObject()->updateCheckUserData( $rc ); + foreach ( $fields as $index => $field ) { + if ( $field === 'cuc_timestamp' ) { + $expectedRow[$index] = $this->db->timestamp( $expectedRow[$index] ); + } + } + return $rc; + } + + /** + * @covers ::updateCheckUserData + * @dataProvider provideUpdateCheckUserData + */ + public function testUpdateCheckUserData( $rcAttribs, $fields, $expectedRow ) { + $this->commonTestsUpdateCheckUserData( $rcAttribs, $fields, $expectedRow ); + $this->assertSelect( + 'cu_changes', + $fields, + '', + [ $expectedRow ] + ); + } + + /** + * @covers ::updateCheckUserData + * @dataProvider provideUpdateCheckUserDataNoSave + */ + public function testUpdateCheckUserDataNoSave( $rcAttribs ) { + $expectedRow = []; + $this->commonTestsUpdateCheckUserData( $rcAttribs, [], $expectedRow ); + $this->assertSame( + 0, + $this->db->newSelectQueryBuilder() + ->field( 'cuc_ip' ) + ->table( 'cu_changes' ) + ->fetchRowCount(), + 'A row was inserted to cu_changes when it should not have been.' + ); + } + + public function getDefaultRecentChangeAttribs() { + // From RecentChangeTest.php's provideAttribs + return [ + 'rc_timestamp' => wfTimestamp( TS_MW ), + 'rc_namespace' => NS_USER, + 'rc_title' => 'Tony', + 'rc_type' => RC_EDIT, + 'rc_source' => RecentChange::SRC_EDIT, + 'rc_minor' => 0, + 'rc_cur_id' => 77, + 'rc_user' => 858173476, + 'rc_user_text' => 'Tony', + 'rc_comment' => '', + 'rc_comment_text' => '', + 'rc_comment_data' => null, + 'rc_this_oldid' => 70, + 'rc_last_oldid' => 71, + 'rc_bot' => 0, + 'rc_ip' => '', + 'rc_patrolled' => 0, + 'rc_new' => 0, + 'rc_old_len' => 80, + 'rc_new_len' => 88, + 'rc_deleted' => 0, + 'rc_logid' => 0, + 'rc_log_type' => null, + 'rc_log_action' => '', + 'rc_params' => '', + ]; + } + + public function provideUpdateCheckUserData() { + // From RecentChangeTest.php's provideAttribs but modified + $attribs = $this->getDefaultRecentChangeAttribs(); + yield 'anon user' => [ + array_merge( $attribs, [ + 'rc_type' => RC_EDIT, + 'rc_user' => 0, + 'rc_user_text' => '192.168.0.1', + ] ), + [ 'cuc_user_text', 'cuc_user', 'cuc_type' ], + [ '192.168.0.1', 0, RC_EDIT ] + ]; + + yield 'registered user' => [ + array_merge( $attribs, [ + 'rc_type' => RC_EDIT, + 'rc_user' => 5, + 'rc_user_text' => 'Test', + ] ), + [ 'cuc_user_text', 'cuc_user' ], + [ 'Test', 5 ] + ]; + + yield 'special title' => [ + array_merge( $attribs, [ + 'rc_namespace' => NS_SPECIAL, + 'rc_title' => 'Log', + 'rc_type' => RC_LOG, + ] ), + [ 'cuc_title', 'cuc_timestamp', 'cuc_namespace', 'cuc_type' ], + [ 'Log', $attribs['rc_timestamp'], NS_SPECIAL, RC_LOG ] + ]; + } + + public function provideUpdateCheckUserDataNoSave() { + // From RecentChangeTest.php's provideAttribs but modified + $attribs = $this->getDefaultRecentChangeAttribs(); + yield 'external user' => [ + array_merge( $attribs, [ + 'rc_type' => RC_EXTERNAL, + 'rc_user' => 0, + 'rc_user_text' => 'm>External User', + ] ), + [ 'cuc_ip' ], + [] + ]; + + yield 'categorize' => [ + array_merge( $attribs, [ + 'rc_namespace' => NS_MAIN, + 'rc_title' => '', + 'rc_type' => RC_CATEGORIZE, + ] ), + [ 'cuc_ip' ], + [] + ]; + } + + /** + * @covers ::onUser__mailPasswordInternal + */ + public function testonUser__mailPasswordInternal() { + $performer = $this->getTestUser()->getUser(); + $account = $this->getTestSysop()->getUser(); + ( new Hooks() )->onUser__mailPasswordInternal( $performer, 'IGNORED', $account ); + $this->assertSame( + 1, + $this->db->newSelectQueryBuilder() + ->table( 'cu_changes' ) + ->where( [ + 'cuc_user' => $performer->getId(), + 'cuc_user_text' => $performer->getName(), + 'cuc_actiontext' . $this->db->buildLike( + $this->db->anyString(), + '[[User:', $account->getName(), '|', $account->getName(), ']]', + $this->db->anyString() + ) + ] ) + ->fetchRowCount(), + 'The row was not inserted or was inserted with the wrong data' + ); + } + + /** + * @covers ::onLocalUserCreated + * @dataProvider provideOnLocalUserCreated + */ + public function testOnLocalUserCreated( $autocreated ) { + $user = $this->getTestUser()->getUser(); + ( new Hooks() )->onLocalUserCreated( $user, $autocreated ); + $this->assertSelect( + 'cu_changes', + [ 'cuc_namespace', 'cuc_actiontext', 'cuc_user', 'cuc_user_text' ], + [], + [ [ + NS_USER, + wfMessage( + $autocreated ? 'checkuser-autocreate-action' : 'checkuser-create-action' + )->inContentLanguage()->text(), + $user->getId(), + $user->getName() + ] ] + ); + } + + public function provideOnLocalUserCreated() { + return [ + [ true ], + [ false ] + ]; + } + + /** + * @covers ::onEmailUser + * @dataProvider provideTestOnEmailUserNoSave + */ + public function testOnEmailUserNoSave( $to, $from ) { + $subject = ''; + $text = ''; + $error = false; + ( new Hooks() )->onEmailUser( $to, $from, $subject, $text, $error ); + $this->assertSame( + 0, + $this->db->newSelectQueryBuilder() + ->field( 'cuc_ip' ) + ->table( 'cu_changes' ) + ->fetchRowCount(), + 'A row was inserted to cu_changes when it should not have been.' + ); + } + + public function provideTestOnEmailUserNoSave() { + return [ + [ + new MailAddress( 'test@test.com', 'Test' ), + new MailAddress( 'test@test.com', 'Test' ), + ] + ]; + } + + /** + * @covers ::onEmailUser + */ + public function testOnEmailUserNoSecretKey() { + $this->setMwGlobals( [ + 'wgSecretKey' => null + ] ); + $to = new MailAddress( 'test@test.com', 'Test' ); + $from = new MailAddress( 'testing@test.com', 'Testing' ); + $this->testOnEmailUserNoSave( $to, $from ); + } + + /** + * @covers ::onEmailUser + */ + public function testOnEmailUserReadOnlyMode() { + $this->setMwGlobals( [ + 'wgReadOnly' => true + ] ); + $to = new MailAddress( 'test@test.com', 'Test' ); + $from = new MailAddress( 'testing@test.com', 'Testing' ); + $this->testOnEmailUserNoSave( $to, $from ); + } + + public function commonOnEmailUser( $to, $from, $fields, $expectedValues ) { + $subject = 'Test subject'; + $text = 'Test text'; + $error = false; + ( new Hooks() )->onEmailUser( $to, $from, $subject, $text, $error ); + \DeferredUpdates::doUpdates(); + $fields[] = 'cuc_namespace'; + $expectedValues[] = NS_USER; + $this->assertSelect( + 'cu_changes', + $fields, + [], + [ $expectedValues ] + ); + } + + /** + * @covers ::onEmailUser + */ + public function testOnEmailUserFrom() { + $userTo = $this->getTestUser()->getUserIdentity(); + $userFrom = $this->getTestSysop()->getUserIdentity(); + $this->commonOnEmailUser( + new MailAddress( 'test@test.com', $userTo->getName() ), + new MailAddress( 'testing@test.com', $userFrom->getName() ), + [ 'cuc_user', 'cuc_user_text' ], + [ $userFrom->getId(), $userFrom->getName() ] + ); + } + + /** + * @covers ::onEmailUser + */ + public function testOnEmailUserActionText() { + global $wgSecretKey; + $userTo = $this->getTestUser()->getUser(); + $userFrom = $this->getTestSysop()->getUserIdentity(); + $expectedActionText = wfMessage( + 'checkuser-email-action', + md5( $userTo->getEmail() . $userTo->getId() . $wgSecretKey ) + )->inContentLanguage()->text(); + $this->commonOnEmailUser( + new MailAddress( 'test@test.com', $userTo->getName() ), + new MailAddress( 'testing@test.com', $userFrom->getName() ), + [ 'cuc_actiontext' ], + [ $expectedActionText ] + ); + } + + /** + * @covers ::onRecentChange_save + * @dataProvider provideUpdateCheckUserData + * @todo test that maybePruneIPData() is called? + */ + public function testonRecentChange_save( $rcAttribs, $fields, $expectedRow ) { + $rc = new RecentChange; + $rc->setAttribs( $rcAttribs ); + ( new Hooks() )->onRecentChange_save( $rc ); + foreach ( $fields as $index => $field ) { + if ( $field === 'cuc_timestamp' ) { + $expectedRow[$index] = $this->db->timestamp( $expectedRow[$index] ); + } + } + $this->assertSelect( + 'cu_changes', + $fields, + '', + [ $expectedRow ] + ); + } + + /** + * @covers ::onPerformRetroactiveAutoblock + * @dataProvider provideOnPerformRetroactiveAutoblock + * @todo test that the $blockIds variable is correct after calling the hook + */ + public function testOnPerformRetroactiveAutoblock( $isIP, $hasCUChangesRow, $shouldAutoblock ) { + if ( $isIP ) { + $target = UserIdentityValue::newAnonymous( '127.0.0.1' ); + // Need to create an actor ID for the IP in case it makes no edits as part of the test. + $this->getServiceContainer()->getActorStore()->createNewActor( $target, $this->db ); + } else { + $target = $this->getTestUser()->getUserIdentity(); + } + $this->setTemporaryHook( + 'CheckUserInsertChangesRow', + static function ( string &$ip, string &$xff, array &$row ) { + $ip = '127.0.0.2'; + } + ); + if ( $hasCUChangesRow ) { + $rc = new RecentChange(); + $rc->setAttribs( + array_merge( $this->getDefaultRecentChangeAttribs(), [ + 'rc_user' => $target->getId(), + 'rc_user_text' => $target->getName() + ] ) + ); + $rc->setExtra( [ + 'pageStatus' => 'changed' + ] ); + $rc->save(); + } + $userAuthority = $this->mockRegisteredUltimateAuthority(); + $this->getServiceContainer()->getBlockUserFactory()->newBlockUser( + $target, + $userAuthority, + '1 week' + )->placeBlock(); + $block = DatabaseBlock::newFromTarget( $target->getName() ); + $result = ( new Hooks() )->onPerformRetroactiveAutoblock( $block, $blockIds ); + $blockManager = $this->getServiceContainer()->getBlockManager(); + $ipBlock = $blockManager->getIpBlock( '127.0.0.2', false ); + if ( $shouldAutoblock ) { + $this->assertNotNull( + $ipBlock, + 'One autoblock should have been placed on the IP.' + ); + $this->assertFalse( + $result, + 'The hook applied autoblocks so it should have returned false to stop further execution.' + ); + } else { + $this->assertNull( + $ipBlock, + 'No autoblock should have been placed on the IP.' + ); + if ( $isIP ) { + $this->assertTrue( + $result, + 'The hook shouldn\'t have applied autoblocks so it should not stop execution of further hooks.' + ); + } else { + $this->assertFalse( + $result, + 'The hook should have attempted to autoblock, found no IPs to block and returned false.' + ); + } + } + } + + /** + * Returns an array of arrays with each second + * level array containing boolean values to + * represent test conditions as follows: + * * The first is whether the target of the block + * that was previously applied is an IP. + * * The second is whether the the target of the + * block will have made any actions to store + * an entry in cu_changes before the retroactive + * autoblock. + * * The third is whether the hook should apply a + * retroactive autoblock to the IP used. + * + * @return array[] + */ + public function provideOnPerformRetroactiveAutoblock() { + return [ + [ true, false, false ], + [ true, true, false ], + [ false, false, false ], + [ false, true, true ], + ]; + } +} diff --git a/CheckUser/tests/phpunit/ComparePagerTest.php b/CheckUser/tests/phpunit/integration/Investigate/Pagers/ComparePagerTest.php index 70e08181..1eaa7f48 100644 --- a/CheckUser/tests/phpunit/ComparePagerTest.php +++ b/CheckUser/tests/phpunit/integration/Investigate/Pagers/ComparePagerTest.php @@ -1,23 +1,27 @@ <?php -namespace MediaWiki\CheckUser\Tests; +namespace MediaWiki\CheckUser\Tests\Integration\Investigate\Pagers; -use MediaWiki\CheckUser\ComparePager; -use MediaWiki\CheckUser\CompareService; -use MediaWiki\CheckUser\DurationManager; +use LoggedServiceOptions; +use MediaWiki\CheckUser\Investigate\Pagers\ComparePager; +use MediaWiki\CheckUser\Investigate\Services\CompareService; +use MediaWiki\CheckUser\Investigate\Utilities\DurationManager; use MediaWiki\CheckUser\TokenQueryManager; -use MediaWiki\CheckUser\UserManager; use MediaWiki\MediaWikiServices; +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityLookup; use MediaWikiIntegrationTestCase; use RequestContext; +use TestAllServiceOptionsUsed; use Wikimedia\IPUtils; /** * @group CheckUser * @group Database - * @covers \MediaWiki\CheckUser\ComparePager + * @covers \MediaWiki\CheckUser\Investigate\Pagers\ComparePager */ class ComparePagerTest extends MediaWikiIntegrationTestCase { + use TestAllServiceOptionsUsed; /** * @dataProvider provideDoQuery @@ -27,7 +31,7 @@ class ComparePagerTest extends MediaWikiIntegrationTestCase { $tokenQueryManager = $this->getMockBuilder( TokenQueryManager::class ) ->disableOriginalConstructor() - ->setMethods( [ 'getDataFromRequest' ] ) + ->onlyMethods( [ 'getDataFromRequest' ] ) ->getMock(); $tokenQueryManager->method( 'getDataFromRequest' ) ->willReturn( [ @@ -35,21 +39,38 @@ class ComparePagerTest extends MediaWikiIntegrationTestCase { '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 ] - ] ) + $user = $this->createMock( UserIdentity::class ); + $user->method( 'getId' ) + ->willReturn( 11111 ); + + $user2 = $this->createMock( UserIdentity::class ); + $user2->method( 'getId' ) + ->willReturn( 22222 ); + + $user3 = $this->createMock( UserIdentity::class ); + $user3->method( 'getId' ) + ->willReturn( 0 ); + + $userIdentityLookup = $this->createMock( UserIdentityLookup::class ); + $userIdentityLookup->method( 'getUserIdentityByName' ) + ->willReturnMap( + [ + [ 'User1', 0, $user, ], + [ 'User2', 0, $user2, ], + [ 'InvalidUser', 0, $user3, ], + [ '', 0, $user3, ], + [ '1.2.3.9/120', 0, $user3, ] + ] ); $compareService = new CompareService( + new LoggedServiceOptions( + self::$serviceOptionsAccessLog, + CompareService::CONSTRUCTOR_OPTIONS, + $services->getMainConfig() + ), $services->getDBLoadBalancer(), - $userManager + $userIdentityLookup ); $durationManager = $this->createMock( DurationManager::class ); @@ -146,7 +167,7 @@ class ComparePagerTest extends MediaWikiIntegrationTestCase { 'cuc_title' => 'Foo_Page', 'cuc_minor' => 0, 'cuc_page_id' => 1, - 'cuc_timestamp' => '', + 'cuc_timestamp' => $this->db->timestamp(), 'cuc_xff' => 0, 'cuc_xff_hex' => null, 'cuc_actiontext' => '', diff --git a/CheckUser/tests/phpunit/PreliminaryCheckPagerTest.php b/CheckUser/tests/phpunit/integration/Investigate/Pagers/PreliminaryCheckPagerTest.php index 51af6ac4..e4c58de7 100644 --- a/CheckUser/tests/phpunit/PreliminaryCheckPagerTest.php +++ b/CheckUser/tests/phpunit/integration/Investigate/Pagers/PreliminaryCheckPagerTest.php @@ -3,18 +3,19 @@ namespace MediaWiki\CheckUser\Tests; use ExtensionRegistry; -use MediaWiki\CheckUser\PreliminaryCheckPager; -use MediaWiki\CheckUser\PreliminaryCheckService; +use MediaWiki\CheckUser\Investigate\Pagers\PreliminaryCheckPager; +use MediaWiki\CheckUser\Investigate\Services\PreliminaryCheckService; use MediaWiki\CheckUser\TokenQueryManager; use MediaWiki\MediaWikiServices; use MediaWiki\User\UserGroupManagerFactory; use MediaWikiIntegrationTestCase; +use PHPUnit\Framework\MockObject\MockObject; use RequestContext; use Wikimedia\Rdbms\ILBFactory; /** * @group CheckUser - * @covers \MediaWiki\CheckUser\PreliminaryCheckPager + * @covers \MediaWiki\CheckUser\Investigate\Pagers\PreliminaryCheckPager */ class PreliminaryCheckPagerTest extends MediaWikiIntegrationTestCase { @@ -108,7 +109,7 @@ class PreliminaryCheckPagerTest extends MediaWikiIntegrationTestCase { $registry, $preliminaryCheckService ] ) - ->setMethods( [ 'isGlobalCheck' ] ) + ->onlyMethods( [ 'isGlobalCheck' ] ) ->getMock(); $pager->method( 'isGlobalCheck' )->willReturn( true ); diff --git a/CheckUser/tests/phpunit/CompareServiceTest.php b/CheckUser/tests/phpunit/integration/Investigate/Services/CompareServiceTest.php index 074d9274..8a803fbf 100644 --- a/CheckUser/tests/phpunit/CompareServiceTest.php +++ b/CheckUser/tests/phpunit/integration/Investigate/Services/CompareServiceTest.php @@ -1,19 +1,25 @@ <?php -namespace MediaWiki\CheckUser\Tests; +namespace MediaWiki\CheckUser\Tests\Integration\Investigate\Services; -use MediaWiki\CheckUser\CompareService; -use MediaWiki\CheckUser\UserManager; +use MediaWiki\CheckUser\Investigate\Services\CompareService; +use MediaWiki\Config\ServiceOptions; use MediaWiki\MediaWikiServices; +use MediaWiki\Tests\Unit\Libs\Rdbms\AddQuoterMock; +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityLookup; use MediaWikiIntegrationTestCase; use Wikimedia\IPUtils; use Wikimedia\Rdbms\Database; use Wikimedia\Rdbms\ILoadBalancer; +use Wikimedia\Rdbms\Platform\MySQLPlatform; +use Wikimedia\TestingAccessWrapper; +use Wikimedia\Timestamp\ConvertibleTimestamp; /** * @group CheckUser * @group Database - * @covers \MediaWiki\CheckUser\CompareService + * @covers \MediaWiki\CheckUser\Investigate\Services\CompareService */ class CompareServiceTest extends MediaWikiIntegrationTestCase { @@ -43,8 +49,12 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { * @dataProvider provideGetQueryInfo */ public function testGetQueryInfo( $options, $expected ) { + $serviceOptions = $this->createMock( ServiceOptions::class ); + $serviceOptions->method( 'get' ) + ->willReturn( $options['limit'] ); + $db = $this->getMockBuilder( Database::class ) - ->setMethods( [ + ->onlyMethods( [ 'dbSchema', 'tablePrefix', ] ) @@ -56,21 +66,34 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { ->willReturn( '' ); $db->method( 'tablePrefix' ) ->willReturn( '' ); + $wdb = TestingAccessWrapper::newFromObject( $db ); + $wdb->platform = new MySQLPlatform( new AddQuoterMock() ); $loadBalancer = $this->createMock( ILoadBalancer::class ); - $loadBalancer->method( 'getConnectionRef' ) + $loadBalancer->method( 'getConnection' ) ->willReturn( $db ); - $userManager = $this->createMock( UserManager::class ); - $userManager->method( 'idFromName' ) - ->will( $this->returnValueMap( [ - [ 'User1', 11111, ], - [ 'User2', 22222, ], - ] ) ); + $user = $this->createMock( UserIdentity::class ); + $user->method( 'getId' ) + ->willReturn( 11111 ); + + $user2 = $this->createMock( UserIdentity::class ); + $user2->method( 'getId' ) + ->willReturn( 22222 ); + + $userIdentityLookup = $this->createMock( UserIdentityLookup::class ); + $userIdentityLookup->method( 'getUserIdentityByName' ) + ->willReturnMap( + [ + [ 'User1', 0, $user, ], + [ 'User2', 0, $user2, ], + ] + ); $compareService = new CompareService( + $serviceOptions, $loadBalancer, - $userManager + $userIdentityLookup ); $queryInfo = $compareService->getQueryInfo( @@ -103,6 +126,7 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { [ 'targets' => [ 'User1' ], 'excludeTargets' => [ '0:0:0:0:0:0:0:1' ], + 'limit' => 100000, 'start' => '' ], [ @@ -116,12 +140,13 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { [ 'targets' => [ 'User1' ], 'excludeTargets' => [ '0:0:0:0:0:0:0:1' ], + 'limit' => 10000, 'start' => '111' ], [ 'targets' => [ '11111' ], 'excludeTargets' => [ 'v6-00000000000000000000000000000001' ], - 'limit' => '100000', + 'limit' => '10000', 'start' => '111' ], ], @@ -129,6 +154,7 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { [ 'targets' => [ '0:0:0:0:0:0:0:1' ], 'excludeTargets' => [ 'User1' ], + 'limit' => 100000, 'start' => '' ], [ @@ -142,12 +168,13 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { [ 'targets' => [ 'User1', '1.2.3.4' ], 'excludeTargets' => [ 'User2', '1.2.3.5' ], + 'limit' => 100, 'start' => '' ], [ 'targets' => [ '11111', '01020304' ], 'excludeTargets' => [ '22222', '01020305' ], - 'limit' => '50000', + 'limit' => '50', 'start' => '' ], ], @@ -155,6 +182,7 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { [ 'targets' => [ '0:0:0:0:0:0:0:1', '1.2.3.4' ], 'excludeTargets' => [], + 'limit' => 100000, 'start' => '' ], [ @@ -175,6 +203,7 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { '1.2.3.4/16', ], 'excludeTargets' => [], + 'limit' => 100000, 'start' => '' ], [ @@ -194,100 +223,96 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { 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' ) + $loadBalancer->method( 'getConnection' ) ->willReturn( $db ); - $compareServcice = new CompareService( + $compareService = new CompareService( + $this->createMock( ServiceOptions::class ), $loadBalancer, - $this->createMock( UserManager::class ) + $this->createMock( UserIdentityLookup::class ) ); - $info = $compareServcice->getQueryInfoForSingleTarget( - '1.2.3.4', - [], - '', - $options['limitPerTarget'], - $options['limitCheck'] + $compareService->getQueryInfo( [], [], '' ); + } + + /** + * @dataProvider provideTotalEditsFromIp + */ + public function testGetTotalEditsFromIp( $data, $expected ) { + $result = $this->getCompareService()->getTotalEditsFromIp( + $data['ip'], $data['excludeUser'] ?? null ); - $this->assertSame( $expected['orderBy'], $info['options']['ORDER BY'] ); - $this->assertSame( $expected['limit'], $info['options']['LIMIT'] ); - $this->assertSame( $expected['offset'], $info['options']['OFFSET'] ); + $this->assertEquals( $expected, $result ); } - public function provideGetQueryInfoForSingleTarget() { - $limitPerTarget = 100; + public function provideTotalEditsFromIp() { return [ - 'Main investigation' => [ + 'IP address with multiple users' => [ [ - 'limitPerTarget' => $limitPerTarget, - 'limitCheck' => false, + 'ip' => IPUtils::toHex( '1.2.3.5' ) ], - [ - 'orderBy' => 'cuc_timestamp DESC', - 'offset' => null, - 'limit' => $limitPerTarget - ] + 3, ], - 'Limit check' => [ + 'IP address with multiple users, excluding a user' => [ [ - 'limitPerTarget' => $limitPerTarget, - 'limitCheck' => true, + 'ip' => IPUtils::toHex( '1.2.3.4' ), + 'excludeUser' => 'User1' ], - [ - 'orderBy' => null, - 'offset' => $limitPerTarget, - 'limit' => 1 - ] + 4, ], ]; } /** - * @dataProvider provideTotalEditsFromIp() + * @dataProvider provideGetTargetsOverLimit */ - public function testGetTotalEditsFromIp( $data, $expected ) { - $result = $this->getCompareService()->getTotalEditsFromIp( - $data['ip'], $data['excludeUser'] ?? null + public function testGetTargetsOverLimit( $data, $expected ) { + if ( isset( $data['limit'] ) ) { + $this->overrideConfigValue( 'CheckUserInvestigateMaximumRowCount', $data['limit'] ); + } + + $result = $this->getCompareService()->getTargetsOverLimit( + $data['targets'] ?? [], + $data['excludeTargets'] ?? [], + $this->db->timestamp() ); $this->assertEquals( $expected, $result ); } - public function provideTotalEditsFromIp() { + public function provideGetTargetsOverLimit() { return [ - 'IP address with multiple users' => [ + 'Empty targets array' => [ + [], + [], + ], + 'Targets are all within limits' => [ [ - 'ip' => IPUtils::toHex( '1.2.3.5' ) + 'targets' => [ '1.2.3.4', 'User1', '1.2.3.5' ], + 'limit' => 100, ], - 3, + [], ], - 'IP address with multiple users, excluding a user' => [ + 'One target is over limit' => [ [ - 'ip' => IPUtils::toHex( '1.2.3.4' ), - 'excludeUser' => 'User1' + 'targets' => [ '1.2.3.4', 'User1', '1.2.3.5' ], + 'excludeTargets' => [ '1.2.3.5' ], + 'limit' => 4 ], - 4, + [ '1.2.3.4' ], + ], + 'Two targets are over limit' => [ + [ + 'targets' => [ '1.2.3.4', '1.2.3.5' ], + 'limit' => 1, + ], + [ '1.2.3.4', '1.2.3.5' ], ], ]; } @@ -353,12 +378,15 @@ class CompareServiceTest extends MediaWikiIntegrationTestCase { ], ]; + // Pin time to avoid failure when next second starts - T317411 + ConvertibleTimestamp::setFakeTime( '20220904094043' ); + $commonData = [ 'cuc_namespace' => NS_MAIN, 'cuc_title' => 'Foo_Page', 'cuc_minor' => 0, 'cuc_page_id' => 1, - 'cuc_timestamp' => '', + 'cuc_timestamp' => $this->db->timestamp(), 'cuc_xff' => 0, 'cuc_xff_hex' => null, 'cuc_actiontext' => '', diff --git a/CheckUser/tests/phpunit/DurationManagerTest.php b/CheckUser/tests/phpunit/integration/Investigate/Services/DurationManagerTest.php index 501c1a06..b3587bd7 100644 --- a/CheckUser/tests/phpunit/DurationManagerTest.php +++ b/CheckUser/tests/phpunit/integration/Investigate/Services/DurationManagerTest.php @@ -1,26 +1,27 @@ <?php -namespace MediaWiki\CheckUser\Tests; +namespace MediaWiki\CheckUser\Tests\Integration; use FauxRequest; -use MediaWiki\CheckUser\DurationManager; +use MediaWiki\CheckUser\Investigate\Utilities\DurationManager; use MediaWikiIntegrationTestCase; +use MWTimestamp; /** * @group CheckUser - * @covers \MediaWiki\CheckUser\DurationManager + * @covers \MediaWiki\CheckUser\Investigate\Utilities\DurationManager */ class DurationManagerTest extends MediaWikiIntegrationTestCase { - public function setUp() : void { + public function setUp(): void { parent::setUp(); - \MWTimestamp::setFakeTime( 0 ); + MWTimestamp::setFakeTime( 0 ); } /** * @dataProvider provideDuration */ - public function testGetFromRequest( string $duration, string $timestamp ) : void { + public function testGetFromRequest( string $duration, string $timestamp ): void { $valid = ( $timestamp !== '' ); $durationManager = new DurationManager(); @@ -34,7 +35,7 @@ class DurationManagerTest extends MediaWikiIntegrationTestCase { /** * @dataProvider provideDuration */ - public function testIsValid( string $duration, string $timestamp ) : void { + public function testIsValid( string $duration, string $timestamp ): void { $valid = ( $timestamp !== '' ); $durationManager = new DurationManager(); @@ -44,7 +45,7 @@ class DurationManagerTest extends MediaWikiIntegrationTestCase { /** * @dataProvider provideDuration */ - public function testGetTimestampFromRequest( string $duration, string $timestamp ) : void { + public function testGetTimestampFromRequest( string $duration, string $timestamp ): void { $durationManager = new DurationManager(); $request = new FauxRequest( [ @@ -57,7 +58,7 @@ class DurationManagerTest extends MediaWikiIntegrationTestCase { /** * Provides durations. */ - public function provideDuration() : array { + public function provideDuration(): array { return [ 'Valid duration' => [ 'P1W', diff --git a/CheckUser/tests/phpunit/PreliminaryCheckServiceTest.php b/CheckUser/tests/phpunit/integration/Investigate/Services/PreliminaryCheckServiceTest.php index a88521a8..3ba89cd2 100644 --- a/CheckUser/tests/phpunit/PreliminaryCheckServiceTest.php +++ b/CheckUser/tests/phpunit/integration/Investigate/Services/PreliminaryCheckServiceTest.php @@ -1,22 +1,24 @@ <?php -namespace MediaWiki\CheckUser\Tests; +namespace MediaWiki\CheckUser\Tests\Integration\Investigate\Services; use ExtensionRegistry; -use MediaWiki\CheckUser\PreliminaryCheckService; +use MediaWiki\CheckUser\Investigate\Services\PreliminaryCheckService; use MediaWiki\User\UserGroupManager; use MediaWiki\User\UserGroupManagerFactory; use MediaWikiIntegrationTestCase; +use PHPUnit\Framework\MockObject\MockObject; use Wikimedia\Rdbms\FakeResultWrapper; use Wikimedia\Rdbms\IDatabase; use Wikimedia\Rdbms\ILBFactory; use Wikimedia\Rdbms\ILoadBalancer; +use Wikimedia\Rdbms\SelectQueryBuilder; /** * Test class for PreliminaryCheckService class * * @group CheckUser - * @covers \MediaWiki\CheckUser\PreliminaryCheckService + * @covers \MediaWiki\CheckUser\Investigate\Services\PreliminaryCheckService */ class PreliminaryCheckServiceTest extends MediaWikiIntegrationTestCase { /** @@ -56,6 +58,9 @@ class PreliminaryCheckServiceTest extends MediaWikiIntegrationTestCase { */ public function testPreprocessResults( $user, $options, $expected ) { $dbRef = $this->getMockDb(); + $queryBuilder = new SelectQueryBuilder( $dbRef ); + $dbRef->method( 'newSelectQueryBuilder' ) + ->willReturn( $queryBuilder ); $dbRef->method( 'selectRow' ) ->willReturn( (object)[ @@ -86,19 +91,15 @@ class PreliminaryCheckServiceTest extends MediaWikiIntegrationTestCase { $ugmf, $options['localWikiId'] ] ) - ->setMethods( [ 'getCentralAuthDB', 'isUserBlocked', 'getUserGroups' ] ) + ->onlyMethods( [ 'isUserBlocked' ] ) ->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 ) { + static function ( $wiki ) use ( $user ) { return (object)[ 'lu_name' => $user['name'], 'lu_wiki' => $wiki, diff --git a/CheckUser/tests/phpunit/TimelineServiceTest.php b/CheckUser/tests/phpunit/integration/Investigate/Services/TimelineServiceTest.php index e2ea68fa..ff701d37 100644 --- a/CheckUser/tests/phpunit/TimelineServiceTest.php +++ b/CheckUser/tests/phpunit/integration/Investigate/Services/TimelineServiceTest.php @@ -1,17 +1,18 @@ <?php -namespace MediaWiki\CheckUser\Tests; +namespace MediaWiki\CheckUser\Tests\Integration\Investigate\Services; -use MediaWiki\CheckUser\TimelineService; -use MediaWiki\CheckUser\UserManager; +use MediaWiki\CheckUser\Investigate\Services\TimelineService; +use MediaWiki\Tests\Unit\Libs\Rdbms\AddQuoterMock; +use MediaWiki\User\UserIdentity; +use MediaWiki\User\UserIdentityLookup; use MediaWikiIntegrationTestCase; use Wikimedia\IPUtils; -use Wikimedia\Rdbms\Database; -use Wikimedia\Rdbms\ILoadBalancer; +use Wikimedia\Rdbms\Platform\SQLPlatform; /** * @group CheckUser - * @covers \MediaWiki\CheckUser\TimelineService + * @covers \MediaWiki\CheckUser\Investigate\Services\TimelineService */ class TimelineServiceTest extends MediaWikiIntegrationTestCase { @@ -19,23 +20,23 @@ 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 ) ); + $user = $this->createMock( UserIdentity::class ); + $user->method( 'getId' ) + ->willReturn( 11111 ); - $loadBalancer = $this->createMock( ILoadBalancer::class ); - $loadBalancer->method( 'getConnectionRef' ) - ->willReturn( $db ); - - $userManager = $this->createMock( UserManager::class ); - $userManager->method( 'idFromName' ) - ->will( $this->returnValueMap( [ - [ 'User1', 11111, ], - ] ) ); + $userIdentityLookup = $this->createMock( UserIdentityLookup::class ); + $userIdentityLookup->method( 'getUserIdentityByName' ) + ->willReturnMap( + [ + [ 'User1', 0, $user, ], + ] + ); - $timelineService = new TimelineService( $loadBalancer, $userManager ); + $timelineService = new TimelineService( + new AddQuoterMock(), + new SQLPlatform( new AddQuoterMock() ), + $userIdentityLookup + ); $q = $timelineService->getQueryInfo( $targets, [], $start ); diff --git a/CheckUser/tests/phpunit/TokenManagerTest.php b/CheckUser/tests/phpunit/integration/TokenManagerTest.php index a8ba2a55..b7e84e20 100644 --- a/CheckUser/tests/phpunit/TokenManagerTest.php +++ b/CheckUser/tests/phpunit/integration/TokenManagerTest.php @@ -1,11 +1,12 @@ <?php -namespace MediaWiki\CheckUser\Tests; +namespace MediaWiki\CheckUser\Tests\Integration; use Firebase\JWT\JWT; use MediaWiki\CheckUser\TokenManager; use MediaWiki\Session\SessionManager; use MediaWikiIntegrationTestCase; +use MWTimestamp; /** * Test class for TokenManager class @@ -16,15 +17,15 @@ use MediaWikiIntegrationTestCase; */ class TokenManagerTest extends MediaWikiIntegrationTestCase { - public function setUp() : void { + public function setUp(): void { parent::setUp(); - \MWTimestamp::setFakeTime( 0 ); + MWTimestamp::setFakeTime( 0 ); JWT::$timestamp = 60; } - public function tearDown() : void { + public function tearDown(): void { parent::tearDown(); - \MWTimestamp::setFakeTime( null ); + MWTimestamp::setFakeTime( null ); JWT::$timestamp = null; } @@ -54,7 +55,7 @@ class TokenManagerTest extends MediaWikiIntegrationTestCase { $encoded = $tokenManager->encode( $session, [] ); $tokenManager = new TokenManager( 'abcdef2' ); - $decoded = $tokenManager->decode( $session, $encoded ); + $tokenManager->decode( $session, $encoded ); } public function testDecodeSessionFailure() { @@ -62,6 +63,6 @@ class TokenManagerTest extends MediaWikiIntegrationTestCase { $tokenManager = new TokenManager( 'abcdef' ); $encoded = $tokenManager->encode( SessionManager::singleton()->getEmptySession(), [] ); - $decoded = $tokenManager->decode( SessionManager::singleton()->getEmptySession(), $encoded ); + $tokenManager->decode( SessionManager::singleton()->getEmptySession(), $encoded ); } } diff --git a/CheckUser/tests/phpunit/TokenQueryManagerTest.php b/CheckUser/tests/phpunit/integration/TokenQueryManagerTest.php index 762daed0..1ef44386 100644 --- a/CheckUser/tests/phpunit/TokenQueryManagerTest.php +++ b/CheckUser/tests/phpunit/integration/TokenQueryManagerTest.php @@ -1,11 +1,12 @@ <?php -namespace MediaWiki\CheckUser\Tests; +namespace MediaWiki\CheckUser\Tests\Integration; use FauxRequest; use MediaWiki\CheckUser\TokenManager; use MediaWiki\CheckUser\TokenQueryManager; use MediaWikiIntegrationTestCase; +use PHPUnit\Framework\MockObject\MockObject; /** * Test class for TokenQueryManager class @@ -28,7 +29,7 @@ class TokenQueryManagerTest extends MediaWikiIntegrationTestCase { $tokenManager = $this->getMockTokenManager(); $tokenQueryManager = $this->getMockBuilder( TokenQueryManager::class ) ->setConstructorArgs( [ $tokenManager ] ) - ->setMethods( [ 'getDataFromRequest' ] ) + ->onlyMethods( [ 'getDataFromRequest' ] ) ->getMock(); $tokenData = [ 'foo' => true, 'bar' => false, 'baz' => 'test' ]; diff --git a/CheckUser/tests/phpunit/unit/HookHandler/PreferencesTest.php b/CheckUser/tests/phpunit/unit/HookHandler/PreferencesTest.php new file mode 100644 index 00000000..6a264f4a --- /dev/null +++ b/CheckUser/tests/phpunit/unit/HookHandler/PreferencesTest.php @@ -0,0 +1,31 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Unit\HookHandler; + +use MediaWiki\CheckUser\HookHandler\Preferences; +use MediaWikiUnitTestCase; +use User; + +/** + * @author DannyS712 + * @group CheckUser + * @coversDefaultClass \MediaWiki\CheckUser\HookHandler\Preferences + */ +class PreferencesTest extends MediaWikiUnitTestCase { + + /** + * @covers ::onGetPreferences + */ + public function testOnGetPreferences() { + $user = $this->createMock( User::class ); + $prefs = []; + + ( new Preferences() )->onGetPreferences( $user, $prefs ); + + $this->assertNotEmpty( + $prefs, + 'Preferences array should no longer be empty, preferences should be added' + ); + } + +} diff --git a/CheckUser/tests/phpunit/unit/HooksTest.php b/CheckUser/tests/phpunit/unit/HooksTest.php new file mode 100644 index 00000000..4df5758e --- /dev/null +++ b/CheckUser/tests/phpunit/unit/HooksTest.php @@ -0,0 +1,67 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Unit; + +use MediaWiki\CheckUser\Hooks; +use MediaWikiUnitTestCase; + +/** + * @author DannyS712 + * @group CheckUser + * @coversDefaultClass \MediaWiki\CheckUser\Hooks + */ +class HooksTest extends MediaWikiUnitTestCase { + + /** + * @covers ::onSpecialPage_initList + */ + public function testOnSpecialPageInitList_withInvestigate() { + // Need to manipulate the globals, can't use setMwGlobals since its a unit test, + // but other than that no integration is needed so its not worth putting this in an + // integration test + global $wgCheckUserEnableSpecialInvestigate; + $oldEnableInvestigate = $wgCheckUserEnableSpecialInvestigate; + + // Case #1: $wgCheckUserEnableSpecialInvestigate is true + $list = []; + $wgCheckUserEnableSpecialInvestigate = true; + ( new Hooks() )->onSpecialPage_initList( $list ); + + $this->assertArrayHasKey( + 'Investigate', + $list, + 'Hooks added Special:Investigate to the array of special pages passed by reference' + ); + $this->assertArrayHasKey( + 'InvestigateBlock', + $list, + 'Hooks added Special:Investigate to the array of special pages passed by reference' + ); + + // Restore old value + $wgCheckUserEnableSpecialInvestigate = $oldEnableInvestigate; + } + + /** + * @covers ::onSpecialPage_initList + */ + public function testOnSpecialPageInitList_noInvestigate() { + // See explanation above for using globals + global $wgCheckUserEnableSpecialInvestigate; + $oldEnableInvestigate = $wgCheckUserEnableSpecialInvestigate; + + // Case #2: $wgCheckUserEnableSpecialInvestigate is false + $list = []; + $wgCheckUserEnableSpecialInvestigate = false; + ( new Hooks() )->onSpecialPage_initList( $list ); + + $this->assertEquals( + [], + $list, + 'If wgCheckUserEnableSpecialInvestigate is false, no extra special pages added' + ); + + // Restore old value + $wgCheckUserEnableSpecialInvestigate = $oldEnableInvestigate; + } +} diff --git a/CheckUser/tests/phpunit/unit/ToolLinksMessagesTest.php b/CheckUser/tests/phpunit/unit/ToolLinksMessagesTest.php new file mode 100644 index 00000000..ad0bc916 --- /dev/null +++ b/CheckUser/tests/phpunit/unit/ToolLinksMessagesTest.php @@ -0,0 +1,41 @@ +<?php + +namespace MediaWiki\CheckUser\Tests\Unit; + +use HashConfig; +use MediaWiki\CheckUser\ToolLinksMessages; +use MediaWiki\ResourceLoader\Context; +use MediaWikiUnitTestCase; +use Message; + +/** + * @author DannyS712 + * @group CheckUser + * @coversDefaultClass \MediaWiki\CheckUser\ToolLinksMessages + */ +class ToolLinksMessagesTest extends MediaWikiUnitTestCase { + + /** + * @covers ::getParsedMessage + */ + public function testGetParsedMessage() { + $msg = $this->createMock( Message::class ); + $msg->method( 'parse' )->willReturn( 'Parsed result' ); + + $context = $this->createMock( Context::class ); + $context->method( 'msg' ) + ->with( 'message key' ) + ->willReturn( $msg ); + + $res = ToolLinksMessages::getParsedMessage( + $context, + new HashConfig( [] ), + 'message key' + ); + $this->assertEquals( + [ 'message key' => 'Parsed result' ], + $res + ); + } + +} diff --git a/CheckUser/tests/selenium/.eslintrc.json b/CheckUser/tests/selenium/.eslintrc.json new file mode 100644 index 00000000..b27406cf --- /dev/null +++ b/CheckUser/tests/selenium/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "root": true, + "extends": [ + "wikimedia/selenium" + ] +} diff --git a/CheckUser/tests/selenium/README.md b/CheckUser/tests/selenium/README.md new file mode 100644 index 00000000..2b23bbe4 --- /dev/null +++ b/CheckUser/tests/selenium/README.md @@ -0,0 +1,21 @@ +# Selenium tests + +For more information see https://www.mediawiki.org/wiki/Selenium + +## Setup + +See https://www.mediawiki.org/wiki/MediaWiki-Docker/Extension/Examples + +## Run all specs + + npm run selenium-test + +## Run specific tests + +Filter by file name: + + npm run selenium-test -- --spec tests/selenium/specs/[FILE-NAME] + +Filter by file name and test name: + + npm run selenium-test -- --spec tests/selenium/specs/[FILE-NAME] --mochaOpts.grep [TEST-NAME] diff --git a/CheckUser/tests/selenium/pageobjects/checkuserlog.page.js b/CheckUser/tests/selenium/pageobjects/checkuserlog.page.js new file mode 100644 index 00000000..b750173f --- /dev/null +++ b/CheckUser/tests/selenium/pageobjects/checkuserlog.page.js @@ -0,0 +1,13 @@ +'use strict'; + +const Page = require( 'wdio-mediawiki/Page' ); + +class CheckUserLogPage extends Page { + get hasPermissionErrors() { return $( '.permissions-errors' ); } + + open() { + super.openTitle( 'Special:CheckUserLog' ); + } +} + +module.exports = new CheckUserLogPage(); diff --git a/CheckUser/tests/selenium/pageobjects/version.page.js b/CheckUser/tests/selenium/pageobjects/version.page.js new file mode 100644 index 00000000..b0307295 --- /dev/null +++ b/CheckUser/tests/selenium/pageobjects/version.page.js @@ -0,0 +1,13 @@ +'use strict'; + +const Page = require( 'wdio-mediawiki/Page' ); + +class VersionPage extends Page { + get checkuserExtension() { return $( '#mw-version-ext-specialpage-CheckUser' ); } + + open() { + super.openTitle( 'Special:Version' ); + } +} + +module.exports = new VersionPage(); diff --git a/CheckUser/tests/selenium/specs/checkuserlog.js b/CheckUser/tests/selenium/specs/checkuserlog.js new file mode 100644 index 00000000..bdb0eb26 --- /dev/null +++ b/CheckUser/tests/selenium/specs/checkuserlog.js @@ -0,0 +1,12 @@ +'use strict'; + +const assert = require( 'assert' ), + CheckUserLogPage = require( '../pageobjects/checkuserlog.page' ); + +describe( 'CheckUserLog', function () { + it( 'Should display permission error to logged-out user', function () { + CheckUserLogPage.open(); + + assert( CheckUserLogPage.hasPermissionErrors.isExisting() ); + } ); +} ); diff --git a/CheckUser/tests/selenium/specs/version.js b/CheckUser/tests/selenium/specs/version.js new file mode 100644 index 00000000..2d2f8689 --- /dev/null +++ b/CheckUser/tests/selenium/specs/version.js @@ -0,0 +1,12 @@ +'use strict'; + +const assert = require( 'assert' ), + VersionPage = require( '../pageobjects/version.page' ); + +describe( 'CheckUser on Version page', function () { + it( 'CheckUser is listed in the version page under the special page category', function () { + VersionPage.open(); + + assert( VersionPage.checkuserExtension.isExisting() ); + } ); +} ); diff --git a/CheckUser/tests/selenium/wdio.conf.js b/CheckUser/tests/selenium/wdio.conf.js new file mode 100644 index 00000000..18d71e2d --- /dev/null +++ b/CheckUser/tests/selenium/wdio.conf.js @@ -0,0 +1,11 @@ +'use strict'; + +const { config } = require( 'wdio-mediawiki/wdio-defaults.conf.js' ); + +exports.config = { ...config + // Override, or add to, the setting from wdio-mediawiki. + // Learn more at https://webdriver.io/docs/configurationfile/ + // + // Example: + // logLevel: 'info', +}; |