mediawiki/extensions/MediaUploader: main (log #1936714)

sourcepatches

This run took 110 seconds.

From 1457af7bc5ac356a42dca4340daf6416b69533cd Mon Sep 17 00:00:00 2001
From: libraryupgrader <tools.libraryupgrader@tools.wmflabs.org>
Date: Mon, 9 Jun 2025 02:04:43 +0000
Subject: [PATCH] build: Updating dependencies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

composer:
* mediawiki/mediawiki-codesniffer: 45.0.0 → 47.0.0

npm:
* eslint-config-wikimedia: 0.28.2 → 0.30.0
  The following rules are failing and were disabled:
  * prefer-const
  * implicit-arrow-linebreak
  * no-redeclare
  * no-mixed-spaces-and-tabs
  * no-jquery/no-done-fail
  * tests/qunit:
    * prefer-const
    * no-jquery/no-done-fail
* stylelint-config-wikimedia: 0.17.2 → 0.18.0
* cross-spawn: 7.0.3 → 7.0.6
  * https://github.com/advisories/GHSA-3xgq-45jj-v275

Additional changes:
* eslint: Replaced `wikimedia/client-es5` with `wikimedia/client`.
* Enable stylelint caching.

Change-Id: I92b0c69af575439577c117a721c6cb226aa1967f
---
 .eslintrc.json                                |    9 +-
 .gitignore                                    |    1 +
 Gruntfile.js                                  |    5 +-
 composer.json                                 |    2 +-
 package-lock.json                             | 1283 +++++++----------
 package.json                                  |    4 +-
 resources/controller/uw.controller.Deed.js    |   18 +-
 resources/controller/uw.controller.Details.js |   54 +-
 resources/controller/uw.controller.Step.js    |   42 +-
 resources/controller/uw.controller.Thanks.js  |    4 +-
 .../controller/uw.controller.Tutorial.js      |   12 +-
 resources/controller/uw.controller.Upload.js  |   28 +-
 resources/deed/uw.deed.OwnWork.js             |   32 +-
 resources/deed/uw.deed.ThirdParty.js          |    8 +-
 .../details/uw.CategoriesDetailsWidget.js     |   40 +-
 resources/details/uw.DateDetailsWidget.js     |   14 +-
 .../details/uw.DeedChooserDetailsWidget.js    |    4 +-
 resources/details/uw.DropdownWidget.js        |    8 +-
 .../details/uw.LanguageDropdownWidget.js      |   16 +-
 resources/details/uw.LocationDetailsWidget.js |   26 +-
 .../details/uw.MultipleLanguageInputWidget.js |   42 +-
 .../details/uw.SingleLanguageInputWidget.js   |   10 +-
 resources/details/uw.TextWidget.js            |    4 +-
 resources/details/uw.TitleDetailsWidget.js    |   28 +-
 resources/details/uw.UlsWidget.js             |    8 +-
 resources/ext.mediaUploader.campaignEditor.js |    2 +-
 .../handlers/mw.ApiUploadFormDataHandler.js   |   12 +-
 resources/handlers/mw.ApiUploadHandler.js     |   56 +-
 .../jquery.arrowSteps/jquery.arrowSteps.js    |    6 +-
 resources/jquery/jquery.morphCrossfade.js     |   12 +-
 resources/mw.DestinationChecker.js            |   36 +-
 resources/mw.Escaper.js                       |   20 +-
 resources/mw.GroupProgressBar.js              |   24 +-
 resources/mw.QuickTitleChecker.js             |    8 +-
 resources/mw.UploadWizard.js                  |   22 +-
 resources/mw.UploadWizardDeedChooser.js       |   22 +-
 resources/mw.UploadWizardDetails.js           |   88 +-
 resources/mw.UploadWizardLicenseInput.js      |   56 +-
 resources/mw.UploadWizardPage.js              |    6 +-
 resources/mw.UploadWizardUpload.js            |   74 +-
 resources/mw.UploadWizardUploadInterface.js   |   16 +-
 resources/mw.fileApi.js                       |    6 +-
 resources/transports/mw.FormDataTransport.js  |   36 +-
 resources/ui/steps/uw.ui.Deed.js              |    4 +-
 resources/ui/steps/uw.ui.Details.js           |   16 +-
 resources/ui/steps/uw.ui.Thanks.js            |   12 +-
 resources/ui/steps/uw.ui.Tutorial.js          |   10 +-
 resources/ui/steps/uw.ui.Upload.js            |   36 +-
 resources/ui/uw.ui.DeedPreview.js             |    4 +-
 resources/ui/uw.ui.Step.js                    |   14 +-
 resources/ui/uw.ui.Wizard.js                  |   14 +-
 resources/uw.ConcurrentQueue.js               |    8 +-
 resources/uw.CopyMetadataWidget.js            |   14 +-
 resources/uw.FieldLayout.js                   |    2 +-
 resources/uw.LicenseGroup.js                  |   58 +-
 resources/uw.LicensePreviewDialog.js          |    8 +-
 resources/uw.ValidationMessageElement.js      |    8 +-
 resources/uw.units.js                         |    4 +-
 tests/qunit/.eslintrc.json                    |    4 +
 .../controller/uw.controller.Deed.test.js     |    6 +-
 .../controller/uw.controller.Details.test.js  |   20 +-
 .../controller/uw.controller.Step.test.js     |    4 +-
 .../controller/uw.controller.Thanks.test.js   |   10 +-
 .../controller/uw.controller.Tutorial.test.js |    6 +-
 .../controller/uw.controller.Upload.test.js   |   12 +-
 .../qunit/mw.UploadWizardLicenseInput.test.js |   12 +-
 tests/qunit/mw.UploadWizardUpload.test.js     |   10 +-
 tests/qunit/mw.fileApi.test.js                |    4 +-
 .../transports/mw.FormDataTransport.test.js   |   34 +-
 tests/qunit/uw.ConcurrentQueue.test.js        |   70 +-
 tests/qunit/uw.TitleDetailsWidget.test.js     |   10 +-
 71 files changed, 1164 insertions(+), 1454 deletions(-)

diff --git a/.eslintrc.json b/.eslintrc.json
index feb9364..66461eb 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,7 +1,7 @@
 {
 	"root": true,
 	"extends": [
-		"wikimedia/client-es5",
+		"wikimedia/client",
 		"wikimedia/jquery",
 		"wikimedia/mediawiki"
 	],
@@ -23,6 +23,11 @@
 		"es-x/no-regexp-u-flag": "warn",
 		"es-x/no-typed-arrays": "warn",
 		"no-unused-vars": "warn",
-		"es-x/no-object-assign": "warn"
+		"es-x/no-object-assign": "warn",
+		"no-mixed-spaces-and-tabs": "warn",
+		"prefer-const": "warn",
+		"implicit-arrow-linebreak": "warn",
+		"no-jquery/no-done-fail": "warn",
+		"no-redeclare": "warn"
 	}
 }
diff --git a/.gitignore b/.gitignore
index de0ffeb..39e6140 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ vendor
 composer.lock
 .DS_Store
 .eslintcache
+/.stylelintcache
diff --git a/Gruntfile.js b/Gruntfile.js
index d870d7c..3b065aa 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -5,7 +5,7 @@
 /* eslint-env node */
 
 module.exports = function ( grunt ) {
-	var conf = grunt.file.readJSON( 'extension.json' );
+	const conf = grunt.file.readJSON( 'extension.json' );
 
 	grunt.loadNpmTasks( 'grunt-banana-checker' );
 	grunt.loadNpmTasks( 'grunt-contrib-watch' );
@@ -21,6 +21,9 @@ module.exports = function ( grunt ) {
 			all: '.'
 		},
 		stylelint: {
+			options: {
+				cache: true
+			},
 			all: 'resources/{**/,}*.{css,less}'
 		},
 		banana: conf.MessagesDirs,
diff --git a/composer.json b/composer.json
index ca9ae93..3e0546b 100644
--- a/composer.json
+++ b/composer.json
@@ -5,7 +5,7 @@
 		"ext-json": "*"
 	},
 	"require-dev": {
-		"mediawiki/mediawiki-codesniffer": "45.0.0",
+		"mediawiki/mediawiki-codesniffer": "47.0.0",
 		"mediawiki/mediawiki-phan-config": "0.15.1",
 		"mediawiki/minus-x": "1.1.3",
 		"php-parallel-lint/php-console-highlighter": "1.0.0",
diff --git a/package-lock.json b/package-lock.json
index 89c6fb1..3b9381f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,13 +6,13 @@
 		"": {
 			"name": "MediaUploader",
 			"devDependencies": {
-				"eslint-config-wikimedia": "0.28.2",
+				"eslint-config-wikimedia": "0.30.0",
 				"grunt": "1.6.1",
 				"grunt-banana-checker": "0.13.0",
 				"grunt-contrib-watch": "1.1.0",
 				"grunt-eslint": "24.3.0",
 				"grunt-stylelint": "0.20.1",
-				"stylelint-config-wikimedia": "0.17.2"
+				"stylelint-config-wikimedia": "0.18.0"
 			}
 		},
 		"node_modules/@babel/code-frame": {
@@ -124,9 +124,9 @@
 			}
 		},
 		"node_modules/@csstools/css-parser-algorithms": {
-			"version": "2.7.1",
-			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz",
-			"integrity": "sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==",
+			"version": "3.0.5",
+			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
+			"integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
 			"dev": true,
 			"funding": [
 				{
@@ -139,16 +139,16 @@
 				}
 			],
 			"engines": {
-				"node": "^14 || ^16 || >=18"
+				"node": ">=18"
 			},
 			"peerDependencies": {
-				"@csstools/css-tokenizer": "^2.4.1"
+				"@csstools/css-tokenizer": "^3.0.4"
 			}
 		},
 		"node_modules/@csstools/css-tokenizer": {
-			"version": "2.4.1",
-			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.4.1.tgz",
-			"integrity": "sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==",
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
+			"integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
 			"dev": true,
 			"funding": [
 				{
@@ -161,36 +161,13 @@
 				}
 			],
 			"engines": {
-				"node": "^14 || ^16 || >=18"
+				"node": ">=18"
 			}
 		},
 		"node_modules/@csstools/media-query-list-parser": {
-			"version": "2.1.13",
-			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.13.tgz",
-			"integrity": "sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==",
-			"dev": true,
-			"funding": [
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/csstools"
-				},
-				{
-					"type": "opencollective",
-					"url": "https://opencollective.com/csstools"
-				}
-			],
-			"engines": {
-				"node": "^14 || ^16 || >=18"
-			},
-			"peerDependencies": {
-				"@csstools/css-parser-algorithms": "^2.7.1",
-				"@csstools/css-tokenizer": "^2.4.1"
-			}
-		},
-		"node_modules/@csstools/selector-specificity": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz",
-			"integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==",
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz",
+			"integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==",
 			"dev": true,
 			"funding": [
 				{
@@ -203,10 +180,11 @@
 				}
 			],
 			"engines": {
-				"node": "^14 || ^16 || >=18"
+				"node": ">=18"
 			},
 			"peerDependencies": {
-				"postcss-selector-parser": "^6.0.13"
+				"@csstools/css-parser-algorithms": "^3.0.1",
+				"@csstools/css-tokenizer": "^3.0.1"
 			}
 		},
 		"node_modules/@dual-bundle/import-meta-resolve": {
@@ -397,40 +375,40 @@
 			}
 		},
 		"node_modules/@stylistic/stylelint-config": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-config/-/stylelint-config-1.0.1.tgz",
-			"integrity": "sha512-JgFP88HZEyo34k9RpWVdcQJtLPrMxYE58IO3qypXhmvE/NmZohj+xjDtQ8UfaarnYsLecnldw57/GHum07Ctdw==",
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-config/-/stylelint-config-2.0.0.tgz",
+			"integrity": "sha512-8J4YAxggy2Nzkb8KJIOLbtMXTPZ5gpKVmyhiiuKEUgCl9XFND5lM0e/ZZBMGEYZ68h5qcsS/jgg1wh235erRAw==",
 			"dev": true,
 			"dependencies": {
-				"@stylistic/stylelint-plugin": "^2.0.0"
+				"@stylistic/stylelint-plugin": "^3.0.0"
 			},
 			"engines": {
 				"node": "^18.12 || >=20.9"
 			},
 			"peerDependencies": {
-				"stylelint": "^16.0.2"
+				"stylelint": "^16.8.0"
 			}
 		},
 		"node_modules/@stylistic/stylelint-plugin": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.0.0.tgz",
-			"integrity": "sha512-dHKuT6PGd1WGZLOTuozAM7GdQzdmlmnFXYzvV1jYJXXpcCpV/OJ3+n8TXpMkoOeKHpJydY43EOoZTO1W/FOA4Q==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.1.tgz",
+			"integrity": "sha512-XagAHHIa528EvyGybv8EEYGK5zrVW74cHpsjhtovVATbhDRuJYfE+X4HCaAieW9lCkwbX6L+X0I4CiUG3w/hFw==",
 			"dev": true,
 			"dependencies": {
-				"@csstools/css-parser-algorithms": "^2.3.2",
-				"@csstools/css-tokenizer": "^2.2.1",
-				"@csstools/media-query-list-parser": "^2.1.5",
+				"@csstools/css-parser-algorithms": "^3.0.1",
+				"@csstools/css-tokenizer": "^3.0.1",
+				"@csstools/media-query-list-parser": "^3.0.1",
 				"is-plain-object": "^5.0.0",
-				"postcss-selector-parser": "^6.0.13",
+				"postcss-selector-parser": "^6.1.2",
 				"postcss-value-parser": "^4.2.0",
 				"style-search": "^0.1.0",
-				"stylelint": "^16.0.2"
+				"stylelint": "^16.8.2"
 			},
 			"engines": {
 				"node": "^18.12 || >=20.9"
 			},
 			"peerDependencies": {
-				"stylelint": "^16.0.2"
+				"stylelint": "^16.8.0"
 			}
 		},
 		"node_modules/@stylistic/stylelint-plugin/node_modules/is-plain-object": {
@@ -442,6 +420,19 @@
 				"node": ">=0.10.0"
 			}
 		},
+		"node_modules/@stylistic/stylelint-plugin/node_modules/postcss-selector-parser": {
+			"version": "6.1.2",
+			"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+			"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+			"dev": true,
+			"dependencies": {
+				"cssesc": "^3.0.0",
+				"util-deprecate": "^1.0.2"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
 		"node_modules/@types/eslint": {
 			"version": "8.56.10",
 			"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
@@ -804,9 +795,9 @@
 			}
 		},
 		"node_modules/browserslist": {
-			"version": "4.23.0",
-			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
-			"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
+			"version": "4.25.0",
+			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz",
+			"integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==",
 			"dev": true,
 			"funding": [
 				{
@@ -823,10 +814,10 @@
 				}
 			],
 			"dependencies": {
-				"caniuse-lite": "^1.0.30001587",
-				"electron-to-chromium": "^1.4.668",
-				"node-releases": "^2.0.14",
-				"update-browserslist-db": "^1.0.13"
+				"caniuse-lite": "^1.0.30001718",
+				"electron-to-chromium": "^1.5.160",
+				"node-releases": "^2.0.19",
+				"update-browserslist-db": "^1.1.3"
 			},
 			"bin": {
 				"browserslist": "cli.js"
@@ -882,9 +873,9 @@
 			}
 		},
 		"node_modules/caniuse-lite": {
-			"version": "1.0.30001612",
-			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
-			"integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
+			"version": "1.0.30001721",
+			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz",
+			"integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==",
 			"dev": true,
 			"funding": [
 				{
@@ -1085,9 +1076,9 @@
 			}
 		},
 		"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==",
+			"version": "7.0.6",
+			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+			"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
 			"dev": true,
 			"dependencies": {
 				"path-key": "^3.1.0",
@@ -1114,9 +1105,9 @@
 			}
 		},
 		"node_modules/css-functions-list": {
-			"version": "3.2.2",
-			"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz",
-			"integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==",
+			"version": "3.2.3",
+			"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz",
+			"integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==",
 			"dev": true,
 			"engines": {
 				"node": ">=12 || >=16"
@@ -1133,12 +1124,12 @@
 			}
 		},
 		"node_modules/css-tree": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
-			"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
+			"integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==",
 			"dev": true,
 			"dependencies": {
-				"mdn-data": "2.0.30",
+				"mdn-data": "2.12.2",
 				"source-map-js": "^1.0.1"
 			},
 			"engines": {
@@ -1167,12 +1158,12 @@
 			}
 		},
 		"node_modules/debug": {
-			"version": "4.3.5",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
-			"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+			"version": "4.4.1",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+			"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
 			"dev": true,
 			"dependencies": {
-				"ms": "2.1.2"
+				"ms": "^2.1.3"
 			},
 			"engines": {
 				"node": ">=6.0"
@@ -1223,20 +1214,19 @@
 			}
 		},
 		"node_modules/doiuse": {
-			"version": "6.0.2",
-			"resolved": "https://registry.npmjs.org/doiuse/-/doiuse-6.0.2.tgz",
-			"integrity": "sha512-eBTs23NOX+EAYPr4RbCR6J4DRW/TML3uMo37y0X1whlkersDYFCk9HmCl09KX98cis22VKsV1QaxfVNauJ3NBw==",
+			"version": "6.0.5",
+			"resolved": "https://registry.npmjs.org/doiuse/-/doiuse-6.0.5.tgz",
+			"integrity": "sha512-ljuf9ndGqKST0GlPAYyCg04hbQAeR1xIIWVDjQaDDkoTY/Y1Vb+8FNoy6NuVuJIEEKe/nKUH8NRWjG7JJxZ9Eg==",
 			"dev": true,
 			"dependencies": {
-				"browserslist": "^4.21.5",
-				"caniuse-lite": "^1.0.30001487",
+				"browserslist": "^4.24.0",
+				"caniuse-lite": "^1.0.30001669",
 				"css-tokenize": "^1.0.1",
-				"duplexify": "^4.1.2",
-				"ldjson-stream": "^1.2.1",
+				"duplexify": "^4.1.3",
 				"multimatch": "^5.0.0",
-				"postcss": "^8.4.21",
+				"postcss": "^8.4.47",
 				"source-map": "^0.7.4",
-				"yargs": "^17.7.1"
+				"yargs": "^17.7.2"
 			},
 			"bin": {
 				"doiuse": "bin/cli.js"
@@ -1287,9 +1277,9 @@
 			}
 		},
 		"node_modules/domutils": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
-			"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+			"version": "3.2.2",
+			"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+			"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
 			"dev": true,
 			"dependencies": {
 				"dom-serializer": "^2.0.0",
@@ -1336,9 +1326,9 @@
 			}
 		},
 		"node_modules/electron-to-chromium": {
-			"version": "1.4.750",
-			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.750.tgz",
-			"integrity": "sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==",
+			"version": "1.5.165",
+			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.165.tgz",
+			"integrity": "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==",
 			"dev": true
 		},
 		"node_modules/emoji-regex": {
@@ -1410,9 +1400,9 @@
 			}
 		},
 		"node_modules/escalade": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-			"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+			"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
 			"dev": true,
 			"engines": {
 				"node": ">=6"
@@ -1501,9 +1491,9 @@
 			}
 		},
 		"node_modules/eslint-config-wikimedia": {
-			"version": "0.28.2",
-			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.28.2.tgz",
-			"integrity": "sha512-5+rdnT7wH1gpKAO6tHYThg78eMhZMruJzvqku3Y5iaEY/A7kSKLFpA/vOj/snys9fKjDHC9BXmArQh+agkOoJQ==",
+			"version": "0.30.0",
+			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.30.0.tgz",
+			"integrity": "sha512-i8ESzSoo0x3Jur/0JhAgCVPxbV51zfdI3MN3MVQPnjiFdmo21CNKmiBBmw8JnJ3fx/d5zHDrBa+yDjxSLpnDlA==",
 			"dev": true,
 			"dependencies": {
 				"browserslist-config-wikimedia": "^0.7.0",
@@ -1516,13 +1506,16 @@
 				"eslint-plugin-mediawiki": "^0.7.0",
 				"eslint-plugin-mocha": "^10.4.3",
 				"eslint-plugin-n": "^17.7.0",
-				"eslint-plugin-no-jquery": "^3.0.1",
+				"eslint-plugin-no-jquery": "^3.1.1",
 				"eslint-plugin-qunit": "^8.1.1",
 				"eslint-plugin-security": "^1.7.1",
 				"eslint-plugin-unicorn": "^53.0.0",
 				"eslint-plugin-vue": "^9.26.0",
 				"eslint-plugin-wdio": "^8.24.12",
 				"eslint-plugin-yml": "^1.14.0"
+			},
+			"engines": {
+				"node": ">=18 <23"
 			}
 		},
 		"node_modules/eslint-plugin-compat": {
@@ -1720,9 +1713,9 @@
 			}
 		},
 		"node_modules/eslint-plugin-no-jquery": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.0.2.tgz",
-			"integrity": "sha512-n/+6p6PFhWDNPVLJj1463hw4OTIRBbROGcbhmtOHTgw7yihSKzkwZiQ00EJTneyeR3jRiw5lpWSMCCBhtb8t2g==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
+			"integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
 			"dev": true,
 			"peerDependencies": {
 				"eslint": ">=8.0.0"
@@ -2167,10 +2160,20 @@
 			"dev": true
 		},
 		"node_modules/fast-uri": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
-			"integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==",
-			"dev": true
+			"version": "3.0.6",
+			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
+			"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/fastify"
+				},
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/fastify"
+				}
+			]
 		},
 		"node_modules/fastest-levenshtein": {
 			"version": "1.0.16",
@@ -3156,21 +3159,11 @@
 			}
 		},
 		"node_modules/known-css-properties": {
-			"version": "0.34.0",
-			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz",
-			"integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
+			"version": "0.35.0",
+			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz",
+			"integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==",
 			"dev": true
 		},
-		"node_modules/ldjson-stream": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz",
-			"integrity": "sha512-xw/nNEXafuPSLu8NjjG3+atVVw+8U1APZAQylmwQn19Hgw6rC7QjHvP6MupnHWCrzSm9m0xs5QWkCLuRvBPjgQ==",
-			"dev": true,
-			"dependencies": {
-				"split2": "^0.2.1",
-				"through2": "^0.6.1"
-			}
-		},
 		"node_modules/levn": {
 			"version": "0.4.1",
 			"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -3301,9 +3294,9 @@
 			}
 		},
 		"node_modules/mdn-data": {
-			"version": "2.0.30",
-			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
-			"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+			"version": "2.12.2",
+			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
+			"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
 			"dev": true
 		},
 		"node_modules/meow": {
@@ -3362,9 +3355,9 @@
 			}
 		},
 		"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==",
+			"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/multimatch": {
@@ -3387,9 +3380,9 @@
 			}
 		},
 		"node_modules/nanoid": {
-			"version": "3.3.7",
-			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
-			"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+			"version": "3.3.11",
+			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+			"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
 			"dev": true,
 			"funding": [
 				{
@@ -3411,9 +3404,9 @@
 			"dev": true
 		},
 		"node_modules/node-releases": {
-			"version": "2.0.14",
-			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
-			"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
+			"version": "2.0.19",
+			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+			"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
 			"dev": true
 		},
 		"node_modules/nopt": {
@@ -3738,9 +3731,9 @@
 			}
 		},
 		"node_modules/picocolors": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
-			"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+			"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
 			"dev": true
 		},
 		"node_modules/picomatch": {
@@ -3765,9 +3758,9 @@
 			}
 		},
 		"node_modules/postcss": {
-			"version": "8.4.39",
-			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz",
-			"integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==",
+			"version": "8.5.4",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
+			"integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
 			"dev": true,
 			"funding": [
 				{
@@ -3784,22 +3777,22 @@
 				}
 			],
 			"dependencies": {
-				"nanoid": "^3.3.7",
-				"picocolors": "^1.0.1",
-				"source-map-js": "^1.2.0"
+				"nanoid": "^3.3.11",
+				"picocolors": "^1.1.1",
+				"source-map-js": "^1.2.1"
 			},
 			"engines": {
 				"node": "^10 || ^12 || >=14"
 			}
 		},
 		"node_modules/postcss-html": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.6.0.tgz",
-			"integrity": "sha512-OWgQ9/Pe23MnNJC0PL4uZp8k0EDaUvqpJFSiwFxOLClAhmD7UEisyhO3x5hVsD4xFrjReVTXydlrMes45dJ71w==",
+			"version": "1.7.0",
+			"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.7.0.tgz",
+			"integrity": "sha512-MfcMpSUIaR/nNgeVS8AyvyDugXlADjN9AcV7e5rDfrF1wduIAGSkL4q2+wgrZgA3sHVAHLDO9FuauHhZYW2nBw==",
 			"dev": true,
 			"dependencies": {
 				"htmlparser2": "^8.0.0",
-				"js-tokens": "^8.0.0",
+				"js-tokens": "^9.0.0",
 				"postcss": "^8.4.0",
 				"postcss-safe-parser": "^6.0.0"
 			},
@@ -3808,27 +3801,11 @@
 			}
 		},
 		"node_modules/postcss-html/node_modules/js-tokens": {
-			"version": "8.0.3",
-			"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz",
-			"integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==",
+			"version": "9.0.1",
+			"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+			"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
 			"dev": true
 		},
-		"node_modules/postcss-html/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-less": {
 			"version": "6.0.0",
 			"resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-6.0.0.tgz",
@@ -3842,35 +3819,25 @@
 			}
 		},
 		"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=",
+			"version": "0.1.6",
+			"resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz",
+			"integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==",
 			"dev": true
 		},
 		"node_modules/postcss-safe-parser": {
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz",
-			"integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==",
+			"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,
-			"funding": [
-				{
-					"type": "opencollective",
-					"url": "https://opencollective.com/postcss/"
-				},
-				{
-					"type": "tidelift",
-					"url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
-				},
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/ai"
-				}
-			],
 			"engines": {
-				"node": ">=18.0"
+				"node": ">=12.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/postcss/"
 			},
 			"peerDependencies": {
-				"postcss": "^8.4.31"
+				"postcss": "^8.3.3"
 			}
 		},
 		"node_modules/postcss-selector-parser": {
@@ -4409,9 +4376,9 @@
 			}
 		},
 		"node_modules/source-map-js": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
-			"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+			"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
 			"dev": true,
 			"engines": {
 				"node": ">=0.10.0"
@@ -4459,15 +4426,6 @@
 			"integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==",
 			"dev": true
 		},
-		"node_modules/split2": {
-			"version": "0.2.1",
-			"resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz",
-			"integrity": "sha512-D/oTExYAkC9nWleOCTOyNmAuzfAT/6rHGBA9LIK7FVnGo13CSvrKCUzKenwH6U1s2znY9MqH6v0UQTEDa3vJmg==",
-			"dev": true,
-			"dependencies": {
-				"through2": "~0.6.1"
-			}
-		},
 		"node_modules/sprintf-js": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -4549,9 +4507,9 @@
 			"dev": true
 		},
 		"node_modules/stylelint": {
-			"version": "16.7.0",
-			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.7.0.tgz",
-			"integrity": "sha512-Q1ATiXlz+wYr37a7TGsfvqYn2nSR3T/isw3IWlZQzFzCNoACHuGBb6xBplZXz56/uDRJHIygxjh7jbV/8isewA==",
+			"version": "16.12.0",
+			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.12.0.tgz",
+			"integrity": "sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg==",
 			"dev": true,
 			"funding": [
 				{
@@ -4564,44 +4522,43 @@
 				}
 			],
 			"dependencies": {
-				"@csstools/css-parser-algorithms": "^2.7.1",
-				"@csstools/css-tokenizer": "^2.4.1",
-				"@csstools/media-query-list-parser": "^2.1.13",
-				"@csstools/selector-specificity": "^3.1.1",
+				"@csstools/css-parser-algorithms": "^3.0.4",
+				"@csstools/css-tokenizer": "^3.0.3",
+				"@csstools/media-query-list-parser": "^4.0.2",
+				"@csstools/selector-specificity": "^5.0.0",
 				"@dual-bundle/import-meta-resolve": "^4.1.0",
 				"balanced-match": "^2.0.0",
 				"colord": "^2.9.3",
 				"cosmiconfig": "^9.0.0",
-				"css-functions-list": "^3.2.2",
-				"css-tree": "^2.3.1",
-				"debug": "^4.3.5",
+				"css-functions-list": "^3.2.3",
+				"css-tree": "^3.0.1",
+				"debug": "^4.3.7",
 				"fast-glob": "^3.3.2",
 				"fastest-levenshtein": "^1.0.16",
-				"file-entry-cache": "^9.0.0",
+				"file-entry-cache": "^9.1.0",
 				"global-modules": "^2.0.0",
 				"globby": "^11.1.0",
 				"globjoin": "^0.1.4",
 				"html-tags": "^3.3.1",
-				"ignore": "^5.3.1",
+				"ignore": "^6.0.2",
 				"imurmurhash": "^0.1.4",
 				"is-plain-object": "^5.0.0",
-				"known-css-properties": "^0.34.0",
+				"known-css-properties": "^0.35.0",
 				"mathml-tag-names": "^2.1.3",
 				"meow": "^13.2.0",
-				"micromatch": "^4.0.7",
+				"micromatch": "^4.0.8",
 				"normalize-path": "^3.0.0",
-				"picocolors": "^1.0.1",
-				"postcss": "^8.4.39",
-				"postcss-resolve-nested-selector": "^0.1.1",
-				"postcss-safe-parser": "^7.0.0",
-				"postcss-selector-parser": "^6.1.0",
+				"picocolors": "^1.1.1",
+				"postcss": "^8.4.49",
+				"postcss-resolve-nested-selector": "^0.1.6",
+				"postcss-safe-parser": "^7.0.1",
+				"postcss-selector-parser": "^7.0.0",
 				"postcss-value-parser": "^4.2.0",
 				"resolve-from": "^5.0.0",
 				"string-width": "^4.2.3",
-				"strip-ansi": "^7.1.0",
-				"supports-hyperlinks": "^3.0.0",
+				"supports-hyperlinks": "^3.1.0",
 				"svg-tags": "^1.0.0",
-				"table": "^6.8.2",
+				"table": "^6.9.0",
 				"write-file-atomic": "^5.0.1"
 			},
 			"bin": {
@@ -4612,200 +4569,105 @@
 			}
 		},
 		"node_modules/stylelint-config-recommended": {
-			"version": "14.0.0",
-			"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.0.tgz",
-			"integrity": "sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==",
+			"version": "14.0.1",
+			"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz",
+			"integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==",
 			"dev": true,
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/stylelint"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/stylelint"
+				}
+			],
 			"engines": {
 				"node": ">=18.12.0"
 			},
 			"peerDependencies": {
-				"stylelint": "^16.0.0"
+				"stylelint": "^16.1.0"
 			}
 		},
 		"node_modules/stylelint-config-wikimedia": {
-			"version": "0.17.2",
-			"resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.17.2.tgz",
-			"integrity": "sha512-cc3PYhe1O/GTgsMOp+Ri3ru579YBbZ3Me0oU7xNb06n4iwyXYPz8qO5G4iQ13UH19UW2NIS8Tk0goPRrJ1RAfw==",
+			"version": "0.18.0",
+			"resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.18.0.tgz",
+			"integrity": "sha512-Lr45NIe7pG8i7BPcMc6EddO1pRK8/KNG8gp4o/oOG1Ez10hglJuJb/QT17BlzX8NPkhtP2KdY63NS2f/Wcj6Ww==",
 			"dev": true,
 			"dependencies": {
-				"@stylistic/stylelint-config": "1.0.1",
-				"@stylistic/stylelint-plugin": "2.0.0",
+				"@stylistic/stylelint-config": "2.0.0",
+				"@stylistic/stylelint-plugin": "3.1.1",
 				"browserslist-config-wikimedia": "0.7.0",
-				"postcss-html": "1.6.0",
+				"postcss-html": "1.7.0",
 				"postcss-less": "6.0.0",
-				"stylelint": "16.2.0",
-				"stylelint-config-recommended": "14.0.0",
-				"stylelint-no-unsupported-browser-features": "8.0.1"
+				"stylelint": "16.12.0",
+				"stylelint-config-recommended": "14.0.1",
+				"stylelint-no-unsupported-browser-features": "8.0.2"
 			},
 			"peerDependencies": {
 				"postcss-less": "^6.0.0"
 			}
 		},
-		"node_modules/stylelint-config-wikimedia/node_modules/ansi-regex": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-			"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-			"dev": true,
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/ansi-regex?sponsor=1"
-			}
-		},
-		"node_modules/stylelint-config-wikimedia/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-config-wikimedia/node_modules/file-entry-cache": {
-			"version": "8.0.0",
-			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
-			"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
-			"dev": true,
-			"dependencies": {
-				"flat-cache": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=16.0.0"
-			}
-		},
-		"node_modules/stylelint-config-wikimedia/node_modules/flat-cache": {
-			"version": "4.0.1",
-			"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
-			"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
-			"dev": true,
-			"dependencies": {
-				"flatted": "^3.2.9",
-				"keyv": "^4.5.4"
-			},
-			"engines": {
-				"node": ">=16"
-			}
-		},
-		"node_modules/stylelint-config-wikimedia/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-config-wikimedia/node_modules/known-css-properties": {
-			"version": "0.29.0",
-			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz",
-			"integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==",
-			"dev": true
-		},
-		"node_modules/stylelint-config-wikimedia/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/stylelint-config-wikimedia/node_modules/strip-ansi": {
-			"version": "7.1.0",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-			"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
-			"dev": true,
-			"dependencies": {
-				"ansi-regex": "^6.0.1"
-			},
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/strip-ansi?sponsor=1"
-			}
-		},
-		"node_modules/stylelint-config-wikimedia/node_modules/stylelint": {
-			"version": "16.2.0",
-			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.2.0.tgz",
-			"integrity": "sha512-gwqU5AkIb52wrAzzn+359S3NIJDMl02TXLUaV2tzA/L6jUdpTwNt+MCxHlc8+Hb2bUHlYVo92YeSIryF2gJthA==",
+		"node_modules/stylelint-no-unsupported-browser-features": {
+			"version": "8.0.2",
+			"resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-8.0.2.tgz",
+			"integrity": "sha512-4PY2qJ3ZTEje9RgGfaQ82eJoPioXxs6hazeKpji/wzLNVzTX2wd4b0Ds3ewdLkH3ID+o63IInuTquU2MNJO3YQ==",
 			"dev": true,
 			"dependencies": {
-				"@csstools/css-parser-algorithms": "^2.5.0",
-				"@csstools/css-tokenizer": "^2.2.3",
-				"@csstools/media-query-list-parser": "^2.1.7",
-				"@csstools/selector-specificity": "^3.0.1",
-				"balanced-match": "^2.0.0",
-				"colord": "^2.9.3",
-				"cosmiconfig": "^9.0.0",
-				"css-functions-list": "^3.2.1",
-				"css-tree": "^2.3.1",
-				"debug": "^4.3.4",
-				"fast-glob": "^3.3.2",
-				"fastest-levenshtein": "^1.0.16",
-				"file-entry-cache": "^8.0.0",
-				"global-modules": "^2.0.0",
-				"globby": "^11.1.0",
-				"globjoin": "^0.1.4",
-				"html-tags": "^3.3.1",
-				"ignore": "^5.3.0",
-				"imurmurhash": "^0.1.4",
-				"is-plain-object": "^5.0.0",
-				"known-css-properties": "^0.29.0",
-				"mathml-tag-names": "^2.1.3",
-				"meow": "^13.1.0",
-				"micromatch": "^4.0.5",
-				"normalize-path": "^3.0.0",
-				"picocolors": "^1.0.0",
-				"postcss": "^8.4.33",
-				"postcss-resolve-nested-selector": "^0.1.1",
-				"postcss-safe-parser": "^7.0.0",
-				"postcss-selector-parser": "^6.0.15",
-				"postcss-value-parser": "^4.2.0",
-				"resolve-from": "^5.0.0",
-				"string-width": "^4.2.3",
-				"strip-ansi": "^7.1.0",
-				"supports-hyperlinks": "^3.0.0",
-				"svg-tags": "^1.0.0",
-				"table": "^6.8.1",
-				"write-file-atomic": "^5.0.1"
-			},
-			"bin": {
-				"stylelint": "bin/stylelint.mjs"
+				"doiuse": "^6.0.5",
+				"postcss": "^8.4.32"
 			},
 			"engines": {
 				"node": ">=18.12.0"
 			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/stylelint"
+			"peerDependencies": {
+				"stylelint": "^16.0.2"
 			}
 		},
-		"node_modules/stylelint-no-unsupported-browser-features": {
-			"version": "8.0.1",
-			"resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-8.0.1.tgz",
-			"integrity": "sha512-tc8Xn5DaqJhxTmbA4H8gZbYdAz027NfuSZv5+cVieQb7BtBrF/1/iKYdpcGwXPl3GtqkQrisiXuGqKkKnzWcLw==",
+		"node_modules/stylelint/node_modules/@csstools/media-query-list-parser": {
+			"version": "4.0.3",
+			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz",
+			"integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==",
 			"dev": true,
-			"dependencies": {
-				"doiuse": "^6.0.2",
-				"postcss": "^8.4.32"
-			},
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/csstools"
+				},
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/csstools"
+				}
+			],
 			"engines": {
-				"node": ">=18.12.0"
+				"node": ">=18"
 			},
 			"peerDependencies": {
-				"stylelint": "^16.0.2"
+				"@csstools/css-parser-algorithms": "^3.0.5",
+				"@csstools/css-tokenizer": "^3.0.4"
 			}
 		},
-		"node_modules/stylelint/node_modules/ansi-regex": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-			"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+		"node_modules/stylelint/node_modules/@csstools/selector-specificity": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz",
+			"integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==",
 			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/csstools"
+				},
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/csstools"
+				}
+			],
 			"engines": {
-				"node": ">=12"
+				"node": ">=18"
 			},
-			"funding": {
-				"url": "https://github.com/chalk/ansi-regex?sponsor=1"
+			"peerDependencies": {
+				"postcss-selector-parser": "^7.0.0"
 			}
 		},
 		"node_modules/stylelint/node_modules/balanced-match": {
@@ -4815,9 +4677,9 @@
 			"dev": true
 		},
 		"node_modules/stylelint/node_modules/file-entry-cache": {
-			"version": "9.0.0",
-			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz",
-			"integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==",
+			"version": "9.1.0",
+			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz",
+			"integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==",
 			"dev": true,
 			"dependencies": {
 				"flat-cache": "^5.0.0"
@@ -4839,6 +4701,15 @@
 				"node": ">=18"
 			}
 		},
+		"node_modules/stylelint/node_modules/ignore": {
+			"version": "6.0.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz",
+			"integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==",
+			"dev": true,
+			"engines": {
+				"node": ">= 4"
+			}
+		},
 		"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",
@@ -4848,28 +4719,52 @@
 				"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==",
+		"node_modules/stylelint/node_modules/postcss-safe-parser": {
+			"version": "7.0.1",
+			"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
+			"integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
 			"dev": true,
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/postcss/"
+				},
+				{
+					"type": "tidelift",
+					"url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
 			"engines": {
-				"node": ">=8"
+				"node": ">=18.0"
+			},
+			"peerDependencies": {
+				"postcss": "^8.4.31"
 			}
 		},
-		"node_modules/stylelint/node_modules/strip-ansi": {
+		"node_modules/stylelint/node_modules/postcss-selector-parser": {
 			"version": "7.1.0",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-			"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+			"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+			"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
 			"dev": true,
 			"dependencies": {
-				"ansi-regex": "^6.0.1"
+				"cssesc": "^3.0.0",
+				"util-deprecate": "^1.0.2"
 			},
 			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/strip-ansi?sponsor=1"
+				"node": ">=4"
+			}
+		},
+		"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/supports-color": {
@@ -4885,9 +4780,9 @@
 			}
 		},
 		"node_modules/supports-hyperlinks": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz",
-			"integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==",
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz",
+			"integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==",
 			"dev": true,
 			"dependencies": {
 				"has-flag": "^4.0.0",
@@ -4895,6 +4790,9 @@
 			},
 			"engines": {
 				"node": ">=14.18"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/supports-hyperlinks?sponsor=1"
 			}
 		},
 		"node_modules/supports-preserve-symlinks-flag": {
@@ -4916,9 +4814,9 @@
 			"dev": true
 		},
 		"node_modules/table": {
-			"version": "6.8.2",
-			"resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
-			"integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
+			"version": "6.9.0",
+			"resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
+			"integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==",
 			"dev": true,
 			"dependencies": {
 				"ajv": "^8.0.1",
@@ -4968,28 +4866,6 @@
 			"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
 			"dev": true
 		},
-		"node_modules/through2": {
-			"version": "0.6.5",
-			"resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
-			"integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==",
-			"dev": true,
-			"dependencies": {
-				"readable-stream": ">=1.0.33-1 <1.1.0-0",
-				"xtend": ">=4.0.0 <4.1.0-0"
-			}
-		},
-		"node_modules/through2/node_modules/readable-stream": {
-			"version": "1.0.34",
-			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
-			"integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
-			"dev": true,
-			"dependencies": {
-				"core-util-is": "~1.0.0",
-				"inherits": "~2.0.1",
-				"isarray": "0.0.1",
-				"string_decoder": "~0.10.x"
-			}
-		},
 		"node_modules/tiny-lr": {
 			"version": "1.1.1",
 			"resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz",
@@ -5108,9 +4984,9 @@
 			}
 		},
 		"node_modules/update-browserslist-db": {
-			"version": "1.0.13",
-			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
-			"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+			"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
 			"dev": true,
 			"funding": [
 				{
@@ -5127,8 +5003,8 @@
 				}
 			],
 			"dependencies": {
-				"escalade": "^3.1.1",
-				"picocolors": "^1.0.0"
+				"escalade": "^3.2.0",
+				"picocolors": "^1.1.1"
 			},
 			"bin": {
 				"update-browserslist-db": "cli.js"
@@ -5471,29 +5347,22 @@
 			}
 		},
 		"@csstools/css-parser-algorithms": {
-			"version": "2.7.1",
-			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz",
-			"integrity": "sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==",
+			"version": "3.0.5",
+			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
+			"integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
 			"dev": true,
 			"requires": {}
 		},
 		"@csstools/css-tokenizer": {
-			"version": "2.4.1",
-			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.4.1.tgz",
-			"integrity": "sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==",
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
+			"integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
 			"dev": true
 		},
 		"@csstools/media-query-list-parser": {
-			"version": "2.1.13",
-			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.13.tgz",
-			"integrity": "sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==",
-			"dev": true,
-			"requires": {}
-		},
-		"@csstools/selector-specificity": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz",
-			"integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==",
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz",
+			"integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==",
 			"dev": true,
 			"requires": {}
 		},
@@ -5637,28 +5506,28 @@
 			}
 		},
 		"@stylistic/stylelint-config": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-config/-/stylelint-config-1.0.1.tgz",
-			"integrity": "sha512-JgFP88HZEyo34k9RpWVdcQJtLPrMxYE58IO3qypXhmvE/NmZohj+xjDtQ8UfaarnYsLecnldw57/GHum07Ctdw==",
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-config/-/stylelint-config-2.0.0.tgz",
+			"integrity": "sha512-8J4YAxggy2Nzkb8KJIOLbtMXTPZ5gpKVmyhiiuKEUgCl9XFND5lM0e/ZZBMGEYZ68h5qcsS/jgg1wh235erRAw==",
 			"dev": true,
 			"requires": {
-				"@stylistic/stylelint-plugin": "^2.0.0"
+				"@stylistic/stylelint-plugin": "^3.0.0"
 			}
 		},
 		"@stylistic/stylelint-plugin": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.0.0.tgz",
-			"integrity": "sha512-dHKuT6PGd1WGZLOTuozAM7GdQzdmlmnFXYzvV1jYJXXpcCpV/OJ3+n8TXpMkoOeKHpJydY43EOoZTO1W/FOA4Q==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.1.tgz",
+			"integrity": "sha512-XagAHHIa528EvyGybv8EEYGK5zrVW74cHpsjhtovVATbhDRuJYfE+X4HCaAieW9lCkwbX6L+X0I4CiUG3w/hFw==",
 			"dev": true,
 			"requires": {
-				"@csstools/css-parser-algorithms": "^2.3.2",
-				"@csstools/css-tokenizer": "^2.2.1",
-				"@csstools/media-query-list-parser": "^2.1.5",
+				"@csstools/css-parser-algorithms": "^3.0.1",
+				"@csstools/css-tokenizer": "^3.0.1",
+				"@csstools/media-query-list-parser": "^3.0.1",
 				"is-plain-object": "^5.0.0",
-				"postcss-selector-parser": "^6.0.13",
+				"postcss-selector-parser": "^6.1.2",
 				"postcss-value-parser": "^4.2.0",
 				"style-search": "^0.1.0",
-				"stylelint": "^16.0.2"
+				"stylelint": "^16.8.2"
 			},
 			"dependencies": {
 				"is-plain-object": {
@@ -5666,6 +5535,16 @@
 					"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
 					"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
 					"dev": true
+				},
+				"postcss-selector-parser": {
+					"version": "6.1.2",
+					"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+					"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+					"dev": true,
+					"requires": {
+						"cssesc": "^3.0.0",
+						"util-deprecate": "^1.0.2"
+					}
 				}
 			}
 		},
@@ -5939,15 +5818,15 @@
 			}
 		},
 		"browserslist": {
-			"version": "4.23.0",
-			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
-			"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
+			"version": "4.25.0",
+			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz",
+			"integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==",
 			"dev": true,
 			"requires": {
-				"caniuse-lite": "^1.0.30001587",
-				"electron-to-chromium": "^1.4.668",
-				"node-releases": "^2.0.14",
-				"update-browserslist-db": "^1.0.13"
+				"caniuse-lite": "^1.0.30001718",
+				"electron-to-chromium": "^1.5.160",
+				"node-releases": "^2.0.19",
+				"update-browserslist-db": "^1.1.3"
 			}
 		},
 		"browserslist-config-wikimedia": {
@@ -5985,9 +5864,9 @@
 			"dev": true
 		},
 		"caniuse-lite": {
-			"version": "1.0.30001612",
-			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
-			"integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
+			"version": "1.0.30001721",
+			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz",
+			"integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==",
 			"dev": true
 		},
 		"chalk": {
@@ -6124,9 +6003,9 @@
 			}
 		},
 		"cross-spawn": {
-			"version": "7.0.3",
-			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-			"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+			"version": "7.0.6",
+			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+			"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
 			"dev": true,
 			"requires": {
 				"path-key": "^3.1.0",
@@ -6146,9 +6025,9 @@
 			}
 		},
 		"css-functions-list": {
-			"version": "3.2.2",
-			"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz",
-			"integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==",
+			"version": "3.2.3",
+			"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz",
+			"integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==",
 			"dev": true
 		},
 		"css-tokenize": {
@@ -6162,12 +6041,12 @@
 			}
 		},
 		"css-tree": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
-			"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
+			"integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==",
 			"dev": true,
 			"requires": {
-				"mdn-data": "2.0.30",
+				"mdn-data": "2.12.2",
 				"source-map-js": "^1.0.1"
 			}
 		},
@@ -6184,12 +6063,12 @@
 			"dev": true
 		},
 		"debug": {
-			"version": "4.3.5",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
-			"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+			"version": "4.4.1",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+			"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
 			"dev": true,
 			"requires": {
-				"ms": "2.1.2"
+				"ms": "^2.1.3"
 			}
 		},
 		"deep-is": {
@@ -6223,20 +6102,19 @@
 			}
 		},
 		"doiuse": {
-			"version": "6.0.2",
-			"resolved": "https://registry.npmjs.org/doiuse/-/doiuse-6.0.2.tgz",
-			"integrity": "sha512-eBTs23NOX+EAYPr4RbCR6J4DRW/TML3uMo37y0X1whlkersDYFCk9HmCl09KX98cis22VKsV1QaxfVNauJ3NBw==",
+			"version": "6.0.5",
+			"resolved": "https://registry.npmjs.org/doiuse/-/doiuse-6.0.5.tgz",
+			"integrity": "sha512-ljuf9ndGqKST0GlPAYyCg04hbQAeR1xIIWVDjQaDDkoTY/Y1Vb+8FNoy6NuVuJIEEKe/nKUH8NRWjG7JJxZ9Eg==",
 			"dev": true,
 			"requires": {
-				"browserslist": "^4.21.5",
-				"caniuse-lite": "^1.0.30001487",
+				"browserslist": "^4.24.0",
+				"caniuse-lite": "^1.0.30001669",
 				"css-tokenize": "^1.0.1",
-				"duplexify": "^4.1.2",
-				"ldjson-stream": "^1.2.1",
+				"duplexify": "^4.1.3",
 				"multimatch": "^5.0.0",
-				"postcss": "^8.4.21",
+				"postcss": "^8.4.47",
 				"source-map": "^0.7.4",
-				"yargs": "^17.7.1"
+				"yargs": "^17.7.2"
 			}
 		},
 		"dom-serializer": {
@@ -6266,9 +6144,9 @@
 			}
 		},
 		"domutils": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
-			"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+			"version": "3.2.2",
+			"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+			"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
 			"dev": true,
 			"requires": {
 				"dom-serializer": "^2.0.0",
@@ -6311,9 +6189,9 @@
 			}
 		},
 		"electron-to-chromium": {
-			"version": "1.4.750",
-			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.750.tgz",
-			"integrity": "sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==",
+			"version": "1.5.165",
+			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.165.tgz",
+			"integrity": "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==",
 			"dev": true
 		},
 		"emoji-regex": {
@@ -6373,9 +6251,9 @@
 			}
 		},
 		"escalade": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-			"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+			"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
 			"dev": true
 		},
 		"escape-string-regexp": {
@@ -6475,9 +6353,9 @@
 			}
 		},
 		"eslint-config-wikimedia": {
-			"version": "0.28.2",
-			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.28.2.tgz",
-			"integrity": "sha512-5+rdnT7wH1gpKAO6tHYThg78eMhZMruJzvqku3Y5iaEY/A7kSKLFpA/vOj/snys9fKjDHC9BXmArQh+agkOoJQ==",
+			"version": "0.30.0",
+			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.30.0.tgz",
+			"integrity": "sha512-i8ESzSoo0x3Jur/0JhAgCVPxbV51zfdI3MN3MVQPnjiFdmo21CNKmiBBmw8JnJ3fx/d5zHDrBa+yDjxSLpnDlA==",
 			"dev": true,
 			"requires": {
 				"browserslist-config-wikimedia": "^0.7.0",
@@ -6490,7 +6368,7 @@
 				"eslint-plugin-mediawiki": "^0.7.0",
 				"eslint-plugin-mocha": "^10.4.3",
 				"eslint-plugin-n": "^17.7.0",
-				"eslint-plugin-no-jquery": "^3.0.1",
+				"eslint-plugin-no-jquery": "^3.1.1",
 				"eslint-plugin-qunit": "^8.1.1",
 				"eslint-plugin-security": "^1.7.1",
 				"eslint-plugin-unicorn": "^53.0.0",
@@ -6625,9 +6503,9 @@
 			}
 		},
 		"eslint-plugin-no-jquery": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.0.2.tgz",
-			"integrity": "sha512-n/+6p6PFhWDNPVLJj1463hw4OTIRBbROGcbhmtOHTgw7yihSKzkwZiQ00EJTneyeR3jRiw5lpWSMCCBhtb8t2g==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
+			"integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
 			"dev": true,
 			"requires": {}
 		},
@@ -6914,9 +6792,9 @@
 			"dev": true
 		},
 		"fast-uri": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
-			"integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==",
+			"version": "3.0.6",
+			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
+			"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
 			"dev": true
 		},
 		"fastest-levenshtein": {
@@ -7659,21 +7537,11 @@
 			"dev": true
 		},
 		"known-css-properties": {
-			"version": "0.34.0",
-			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz",
-			"integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
+			"version": "0.35.0",
+			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz",
+			"integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==",
 			"dev": true
 		},
-		"ldjson-stream": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz",
-			"integrity": "sha512-xw/nNEXafuPSLu8NjjG3+atVVw+8U1APZAQylmwQn19Hgw6rC7QjHvP6MupnHWCrzSm9m0xs5QWkCLuRvBPjgQ==",
-			"dev": true,
-			"requires": {
-				"split2": "^0.2.1",
-				"through2": "^0.6.1"
-			}
-		},
 		"levn": {
 			"version": "0.4.1",
 			"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -7781,9 +7649,9 @@
 			"dev": true
 		},
 		"mdn-data": {
-			"version": "2.0.30",
-			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
-			"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+			"version": "2.12.2",
+			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
+			"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
 			"dev": true
 		},
 		"meow": {
@@ -7824,9 +7692,9 @@
 			}
 		},
 		"ms": {
-			"version": "2.1.2",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+			"version": "2.1.3",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+			"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
 			"dev": true
 		},
 		"multimatch": {
@@ -7843,9 +7711,9 @@
 			}
 		},
 		"nanoid": {
-			"version": "3.3.7",
-			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
-			"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+			"version": "3.3.11",
+			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+			"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
 			"dev": true
 		},
 		"natural-compare": {
@@ -7855,9 +7723,9 @@
 			"dev": true
 		},
 		"node-releases": {
-			"version": "2.0.14",
-			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
-			"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
+			"version": "2.0.19",
+			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+			"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
 			"dev": true
 		},
 		"nopt": {
@@ -8100,9 +7968,9 @@
 			"dev": true
 		},
 		"picocolors": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
-			"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+			"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
 			"dev": true
 		},
 		"picomatch": {
@@ -8118,40 +7986,33 @@
 			"dev": true
 		},
 		"postcss": {
-			"version": "8.4.39",
-			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz",
-			"integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==",
+			"version": "8.5.4",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
+			"integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
 			"dev": true,
 			"requires": {
-				"nanoid": "^3.3.7",
-				"picocolors": "^1.0.1",
-				"source-map-js": "^1.2.0"
+				"nanoid": "^3.3.11",
+				"picocolors": "^1.1.1",
+				"source-map-js": "^1.2.1"
 			}
 		},
 		"postcss-html": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.6.0.tgz",
-			"integrity": "sha512-OWgQ9/Pe23MnNJC0PL4uZp8k0EDaUvqpJFSiwFxOLClAhmD7UEisyhO3x5hVsD4xFrjReVTXydlrMes45dJ71w==",
+			"version": "1.7.0",
+			"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.7.0.tgz",
+			"integrity": "sha512-MfcMpSUIaR/nNgeVS8AyvyDugXlADjN9AcV7e5rDfrF1wduIAGSkL4q2+wgrZgA3sHVAHLDO9FuauHhZYW2nBw==",
 			"dev": true,
 			"requires": {
 				"htmlparser2": "^8.0.0",
-				"js-tokens": "^8.0.0",
+				"js-tokens": "^9.0.0",
 				"postcss": "^8.4.0",
 				"postcss-safe-parser": "^6.0.0"
 			},
 			"dependencies": {
 				"js-tokens": {
-					"version": "8.0.3",
-					"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz",
-					"integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==",
+					"version": "9.0.1",
+					"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+					"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
 					"dev": true
-				},
-				"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,
-					"requires": {}
 				}
 			}
 		},
@@ -8163,15 +8024,15 @@
 			"requires": {}
 		},
 		"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=",
+			"version": "0.1.6",
+			"resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz",
+			"integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==",
 			"dev": true
 		},
 		"postcss-safe-parser": {
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz",
-			"integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==",
+			"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,
 			"requires": {}
 		},
@@ -8544,9 +8405,9 @@
 			"dev": true
 		},
 		"source-map-js": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
-			"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+			"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
 			"dev": true
 		},
 		"spdx-correct": {
@@ -8593,15 +8454,6 @@
 			"integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==",
 			"dev": true
 		},
-		"split2": {
-			"version": "0.2.1",
-			"resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz",
-			"integrity": "sha512-D/oTExYAkC9nWleOCTOyNmAuzfAT/6rHGBA9LIK7FVnGo13CSvrKCUzKenwH6U1s2znY9MqH6v0UQTEDa3vJmg==",
-			"dev": true,
-			"requires": {
-				"through2": "~0.6.1"
-			}
-		},
 		"sprintf-js": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -8668,57 +8520,64 @@
 			"dev": true
 		},
 		"stylelint": {
-			"version": "16.7.0",
-			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.7.0.tgz",
-			"integrity": "sha512-Q1ATiXlz+wYr37a7TGsfvqYn2nSR3T/isw3IWlZQzFzCNoACHuGBb6xBplZXz56/uDRJHIygxjh7jbV/8isewA==",
+			"version": "16.12.0",
+			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.12.0.tgz",
+			"integrity": "sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg==",
 			"dev": true,
 			"requires": {
-				"@csstools/css-parser-algorithms": "^2.7.1",
-				"@csstools/css-tokenizer": "^2.4.1",
-				"@csstools/media-query-list-parser": "^2.1.13",
-				"@csstools/selector-specificity": "^3.1.1",
+				"@csstools/css-parser-algorithms": "^3.0.4",
+				"@csstools/css-tokenizer": "^3.0.3",
+				"@csstools/media-query-list-parser": "^4.0.2",
+				"@csstools/selector-specificity": "^5.0.0",
 				"@dual-bundle/import-meta-resolve": "^4.1.0",
 				"balanced-match": "^2.0.0",
 				"colord": "^2.9.3",
 				"cosmiconfig": "^9.0.0",
-				"css-functions-list": "^3.2.2",
-				"css-tree": "^2.3.1",
-				"debug": "^4.3.5",
+				"css-functions-list": "^3.2.3",
+				"css-tree": "^3.0.1",
+				"debug": "^4.3.7",
 				"fast-glob": "^3.3.2",
 				"fastest-levenshtein": "^1.0.16",
-				"file-entry-cache": "^9.0.0",
+				"file-entry-cache": "^9.1.0",
 				"global-modules": "^2.0.0",
 				"globby": "^11.1.0",
 				"globjoin": "^0.1.4",
 				"html-tags": "^3.3.1",
-				"ignore": "^5.3.1",
+				"ignore": "^6.0.2",
 				"imurmurhash": "^0.1.4",
 				"is-plain-object": "^5.0.0",
-				"known-css-properties": "^0.34.0",
+				"known-css-properties": "^0.35.0",
 				"mathml-tag-names": "^2.1.3",
 				"meow": "^13.2.0",
-				"micromatch": "^4.0.7",
+				"micromatch": "^4.0.8",
 				"normalize-path": "^3.0.0",
-				"picocolors": "^1.0.1",
-				"postcss": "^8.4.39",
-				"postcss-resolve-nested-selector": "^0.1.1",
-				"postcss-safe-parser": "^7.0.0",
-				"postcss-selector-parser": "^6.1.0",
+				"picocolors": "^1.1.1",
+				"postcss": "^8.4.49",
+				"postcss-resolve-nested-selector": "^0.1.6",
+				"postcss-safe-parser": "^7.0.1",
+				"postcss-selector-parser": "^7.0.0",
 				"postcss-value-parser": "^4.2.0",
 				"resolve-from": "^5.0.0",
 				"string-width": "^4.2.3",
-				"strip-ansi": "^7.1.0",
-				"supports-hyperlinks": "^3.0.0",
+				"supports-hyperlinks": "^3.1.0",
 				"svg-tags": "^1.0.0",
-				"table": "^6.8.2",
+				"table": "^6.9.0",
 				"write-file-atomic": "^5.0.1"
 			},
 			"dependencies": {
-				"ansi-regex": {
-					"version": "6.0.1",
-					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-					"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-					"dev": true
+				"@csstools/media-query-list-parser": {
+					"version": "4.0.3",
+					"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz",
+					"integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==",
+					"dev": true,
+					"requires": {}
+				},
+				"@csstools/selector-specificity": {
+					"version": "5.0.0",
+					"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz",
+					"integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==",
+					"dev": true,
+					"requires": {}
 				},
 				"balanced-match": {
 					"version": "2.0.0",
@@ -8727,9 +8586,9 @@
 					"dev": true
 				},
 				"file-entry-cache": {
-					"version": "9.0.0",
-					"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz",
-					"integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==",
+					"version": "9.1.0",
+					"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz",
+					"integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==",
 					"dev": true,
 					"requires": {
 						"flat-cache": "^5.0.0"
@@ -8745,165 +8604,73 @@
 						"keyv": "^4.5.4"
 					}
 				},
+				"ignore": {
+					"version": "6.0.2",
+					"resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz",
+					"integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==",
+					"dev": true
+				},
 				"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
 				},
-				"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
+				"postcss-safe-parser": {
+					"version": "7.0.1",
+					"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
+					"integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
+					"dev": true,
+					"requires": {}
 				},
-				"strip-ansi": {
+				"postcss-selector-parser": {
 					"version": "7.1.0",
-					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-					"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+					"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+					"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
 					"dev": true,
 					"requires": {
-						"ansi-regex": "^6.0.1"
+						"cssesc": "^3.0.0",
+						"util-deprecate": "^1.0.2"
 					}
+				},
+				"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
 				}
 			}
 		},
 		"stylelint-config-recommended": {
-			"version": "14.0.0",
-			"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.0.tgz",
-			"integrity": "sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==",
+			"version": "14.0.1",
+			"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz",
+			"integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==",
 			"dev": true,
 			"requires": {}
 		},
 		"stylelint-config-wikimedia": {
-			"version": "0.17.2",
-			"resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.17.2.tgz",
-			"integrity": "sha512-cc3PYhe1O/GTgsMOp+Ri3ru579YBbZ3Me0oU7xNb06n4iwyXYPz8qO5G4iQ13UH19UW2NIS8Tk0goPRrJ1RAfw==",
+			"version": "0.18.0",
+			"resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.18.0.tgz",
+			"integrity": "sha512-Lr45NIe7pG8i7BPcMc6EddO1pRK8/KNG8gp4o/oOG1Ez10hglJuJb/QT17BlzX8NPkhtP2KdY63NS2f/Wcj6Ww==",
 			"dev": true,
 			"requires": {
-				"@stylistic/stylelint-config": "1.0.1",
-				"@stylistic/stylelint-plugin": "2.0.0",
+				"@stylistic/stylelint-config": "2.0.0",
+				"@stylistic/stylelint-plugin": "3.1.1",
 				"browserslist-config-wikimedia": "0.7.0",
-				"postcss-html": "1.6.0",
+				"postcss-html": "1.7.0",
 				"postcss-less": "6.0.0",
-				"stylelint": "16.2.0",
-				"stylelint-config-recommended": "14.0.0",
-				"stylelint-no-unsupported-browser-features": "8.0.1"
-			},
-			"dependencies": {
-				"ansi-regex": {
-					"version": "6.0.1",
-					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-					"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-					"dev": true
-				},
-				"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
-				},
-				"file-entry-cache": {
-					"version": "8.0.0",
-					"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
-					"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
-					"dev": true,
-					"requires": {
-						"flat-cache": "^4.0.0"
-					}
-				},
-				"flat-cache": {
-					"version": "4.0.1",
-					"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
-					"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
-					"dev": true,
-					"requires": {
-						"flatted": "^3.2.9",
-						"keyv": "^4.5.4"
-					}
-				},
-				"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
-				},
-				"known-css-properties": {
-					"version": "0.29.0",
-					"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz",
-					"integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==",
-					"dev": true
-				},
-				"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": "7.1.0",
-					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-					"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
-					"dev": true,
-					"requires": {
-						"ansi-regex": "^6.0.1"
-					}
-				},
-				"stylelint": {
-					"version": "16.2.0",
-					"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.2.0.tgz",
-					"integrity": "sha512-gwqU5AkIb52wrAzzn+359S3NIJDMl02TXLUaV2tzA/L6jUdpTwNt+MCxHlc8+Hb2bUHlYVo92YeSIryF2gJthA==",
-					"dev": true,
-					"requires": {
-						"@csstools/css-parser-algorithms": "^2.5.0",
-						"@csstools/css-tokenizer": "^2.2.3",
-						"@csstools/media-query-list-parser": "^2.1.7",
-						"@csstools/selector-specificity": "^3.0.1",
-						"balanced-match": "^2.0.0",
-						"colord": "^2.9.3",
-						"cosmiconfig": "^9.0.0",
-						"css-functions-list": "^3.2.1",
-						"css-tree": "^2.3.1",
-						"debug": "^4.3.4",
-						"fast-glob": "^3.3.2",
-						"fastest-levenshtein": "^1.0.16",
-						"file-entry-cache": "^8.0.0",
-						"global-modules": "^2.0.0",
-						"globby": "^11.1.0",
-						"globjoin": "^0.1.4",
-						"html-tags": "^3.3.1",
-						"ignore": "^5.3.0",
-						"imurmurhash": "^0.1.4",
-						"is-plain-object": "^5.0.0",
-						"known-css-properties": "^0.29.0",
-						"mathml-tag-names": "^2.1.3",
-						"meow": "^13.1.0",
-						"micromatch": "^4.0.5",
-						"normalize-path": "^3.0.0",
-						"picocolors": "^1.0.0",
-						"postcss": "^8.4.33",
-						"postcss-resolve-nested-selector": "^0.1.1",
-						"postcss-safe-parser": "^7.0.0",
-						"postcss-selector-parser": "^6.0.15",
-						"postcss-value-parser": "^4.2.0",
-						"resolve-from": "^5.0.0",
-						"string-width": "^4.2.3",
-						"strip-ansi": "^7.1.0",
-						"supports-hyperlinks": "^3.0.0",
-						"svg-tags": "^1.0.0",
-						"table": "^6.8.1",
-						"write-file-atomic": "^5.0.1"
-					}
-				}
+				"stylelint": "16.12.0",
+				"stylelint-config-recommended": "14.0.1",
+				"stylelint-no-unsupported-browser-features": "8.0.2"
 			}
 		},
 		"stylelint-no-unsupported-browser-features": {
-			"version": "8.0.1",
-			"resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-8.0.1.tgz",
-			"integrity": "sha512-tc8Xn5DaqJhxTmbA4H8gZbYdAz027NfuSZv5+cVieQb7BtBrF/1/iKYdpcGwXPl3GtqkQrisiXuGqKkKnzWcLw==",
+			"version": "8.0.2",
+			"resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-8.0.2.tgz",
+			"integrity": "sha512-4PY2qJ3ZTEje9RgGfaQ82eJoPioXxs6hazeKpji/wzLNVzTX2wd4b0Ds3ewdLkH3ID+o63IInuTquU2MNJO3YQ==",
 			"dev": true,
 			"requires": {
-				"doiuse": "^6.0.2",
+				"doiuse": "^6.0.5",
 				"postcss": "^8.4.32"
 			}
 		},
@@ -8917,9 +8684,9 @@
 			}
 		},
 		"supports-hyperlinks": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz",
-			"integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==",
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz",
+			"integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==",
 			"dev": true,
 			"requires": {
 				"has-flag": "^4.0.0",
@@ -8939,9 +8706,9 @@
 			"dev": true
 		},
 		"table": {
-			"version": "6.8.2",
-			"resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
-			"integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
+			"version": "6.9.0",
+			"resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
+			"integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==",
 			"dev": true,
 			"requires": {
 				"ajv": "^8.0.1",
@@ -8983,30 +8750,6 @@
 			"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
 			"dev": true
 		},
-		"through2": {
-			"version": "0.6.5",
-			"resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
-			"integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==",
-			"dev": true,
-			"requires": {
-				"readable-stream": ">=1.0.33-1 <1.1.0-0",
-				"xtend": ">=4.0.0 <4.1.0-0"
-			},
-			"dependencies": {
-				"readable-stream": {
-					"version": "1.0.34",
-					"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
-					"integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
-					"dev": true,
-					"requires": {
-						"core-util-is": "~1.0.0",
-						"inherits": "~2.0.1",
-						"isarray": "0.0.1",
-						"string_decoder": "~0.10.x"
-					}
-				}
-			}
-		},
 		"tiny-lr": {
 			"version": "1.1.1",
 			"resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz",
@@ -9093,13 +8836,13 @@
 			"dev": true
 		},
 		"update-browserslist-db": {
-			"version": "1.0.13",
-			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
-			"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+			"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
 			"dev": true,
 			"requires": {
-				"escalade": "^3.1.1",
-				"picocolors": "^1.0.0"
+				"escalade": "^3.2.0",
+				"picocolors": "^1.1.1"
 			}
 		},
 		"uri-js": {
diff --git a/package.json b/package.json
index ee929ed..6bb576e 100644
--- a/package.json
+++ b/package.json
@@ -6,12 +6,12 @@
 		"test-fix": "grunt test --fix"
 	},
 	"devDependencies": {
-		"eslint-config-wikimedia": "0.28.2",
+		"eslint-config-wikimedia": "0.30.0",
 		"grunt": "1.6.1",
 		"grunt-banana-checker": "0.13.0",
 		"grunt-contrib-watch": "1.1.0",
 		"grunt-eslint": "24.3.0",
 		"grunt-stylelint": "0.20.1",
-		"stylelint-config-wikimedia": "0.17.2"
+		"stylelint-config-wikimedia": "0.18.0"
 	}
 }
diff --git a/resources/controller/uw.controller.Deed.js b/resources/controller/uw.controller.Deed.js
index d843eaf..533e591 100644
--- a/resources/controller/uw.controller.Deed.js
+++ b/resources/controller/uw.controller.Deed.js
@@ -40,7 +40,7 @@
 	OO.inheritClass( uw.controller.Deed, uw.controller.Step );
 
 	uw.controller.Deed.prototype.moveNext = function () {
-		var
+		let
 			deedController = this,
 			valid, fields, validityPromises;
 
@@ -52,10 +52,10 @@
 		valid = this.deedChooser.valid();
 		if ( valid ) {
 			fields = this.deedChooser.deed.getFields();
-			validityPromises = fields.map( function ( fieldLayout ) {
+			validityPromises = fields.map( ( fieldLayout ) =>
 				// Update any error/warning messages
-				return fieldLayout.checkValidity( true );
-			} );
+				 fieldLayout.checkValidity( true )
+			 );
 			if ( validityPromises.length === 1 ) {
 				// validityPromises will hold all promises for all uploads;
 				// adding a bogus promise (no warnings & errors) to
@@ -73,7 +73,7 @@
 
 				// TODO Handle warnings with a confirmation dialog
 
-				var i;
+				let i;
 				for ( i = 0; i < arguments.length; i++ ) {
 					if ( arguments[ i ][ 1 ].length ) {
 						// One of the fields has errors; refuse to proceed!
@@ -87,10 +87,10 @@
 	};
 
 	uw.controller.Deed.prototype.unload = function () {
-		var deedController = this;
+		const deedController = this;
 		uw.controller.Step.prototype.unload.call( this );
 
-		Object.keys( this.deeds ).forEach( function ( name ) {
+		Object.keys( this.deeds ).forEach( ( name ) => {
 			deedController.deeds[ name ].unload();
 		} );
 	};
@@ -101,7 +101,7 @@
 	 * @param {mw.UploadWizardUpload[]} uploads
 	 */
 	uw.controller.Deed.prototype.load = function ( uploads ) {
-		var customDeed, previousDeed;
+		let customDeed, previousDeed;
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 
@@ -130,7 +130,7 @@
 			.insertBefore( this.deedChooser.$selector.find( '.mediauploader-deed-ownwork' ) )
 			.msg( 'mediauploader-deeds-macro-prompt', this.uploads.length, mw.user );
 
-		uploads.forEach( function ( upload ) {
+		uploads.forEach( ( upload ) => {
 			// Add previews and details to the DOM
 			upload.deedPreview = new uw.ui.DeedPreview( upload );
 		} );
diff --git a/resources/controller/uw.controller.Details.js b/resources/controller/uw.controller.Details.js
index 843a65b..82aa27b 100644
--- a/resources/controller/uw.controller.Details.js
+++ b/resources/controller/uw.controller.Details.js
@@ -51,15 +51,15 @@
 	 * @param {mw.UploadWizardUpload[]} uploads List of uploads being carried forward.
 	 */
 	uw.controller.Details.prototype.load = function ( uploads ) {
-		var controller = this;
+		const controller = this;
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 
 		// make sure queue is empty before starting this step
 		this.queue.abortExecuting();
 
-		this.uploads.forEach( function ( upload ) {
-			var serialized;
+		this.uploads.forEach( ( upload ) => {
+			let serialized;
 
 			// get existing details
 			serialized = upload.details ? upload.details.getSerialized() : null;
@@ -90,7 +90,7 @@
 	};
 
 	uw.controller.Details.prototype.addCopyMetadataFeature = function () {
-		var first,
+		let first,
 			// uploads can only be edited when they're in a certain state:
 			// a flat out upload failure or a completed upload can not be edited
 			invalidStates = [ 'aborted', 'error', 'complete' ],
@@ -107,8 +107,8 @@
 		// rest failed because of abusefilter (or another recoverable error), in
 		// which case we'll want the "copy" feature to appear below the 2nd
 		// upload (or the first not-yet-completed not flat-out-failed upload)
-		this.uploads.some( function ( upload ) {
-			if ( upload && invalidStates.indexOf( upload.state ) === -1 ) {
+		this.uploads.some( ( upload ) => {
+			if ( upload && !invalidStates.includes( upload.state ) ) {
 				first = upload;
 				return true; // Break Array.some loop
 			}
@@ -148,9 +148,9 @@
 	 * TODO move the rest of the logic here from mw.UploadWizard
 	 */
 	uw.controller.Details.prototype.startDetails = function () {
-		var details = this;
+		const details = this;
 
-		this.valid().done( function ( valid ) {
+		this.valid().done( ( valid ) => {
 			if ( valid ) {
 				details.ui.hideEndButtons();
 				details.submit();
@@ -166,7 +166,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.controller.Details.prototype.valid = function () {
-		var detailsController = this,
+		const detailsController = this,
 			// validityPromises will hold all promises for all uploads;
 			// prefilling with a bogus promise (no warnings & errors) to
 			// ensure $.when always resolves with an array of multiple
@@ -176,14 +176,14 @@
 			validityPromises = [ $.Deferred().resolve( [], [] ).promise() ],
 			titles = [];
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			// Update any error/warning messages about all DetailsWidgets
-			var promise = upload.details.checkValidity( true ).then( function () {
-				var warnings = [],
+			const promise = upload.details.checkValidity( true ).then( function () {
+				let warnings = [],
 					errors = [],
 					title;
 
-				Array.prototype.forEach.call( arguments, function ( result ) {
+				Array.prototype.forEach.call( arguments, ( result ) => {
 					warnings = warnings.concat( result[ 0 ] );
 					errors = errors.concat( result[ 1 ] );
 				} );
@@ -211,10 +211,10 @@
 		// validityPromises is an array of promises that each resolve with [warnings, errors]
 		// for each upload - now iterate them all to figure out if we can proceed
 		return $.when.apply( $, validityPromises ).then( function () {
-			var warnings = [],
+			let warnings = [],
 				errors = [];
 
-			Array.prototype.forEach.call( arguments, function ( result ) {
+			Array.prototype.forEach.call( arguments, ( result ) => {
 				warnings = warnings.concat( result[ 0 ] );
 				errors = errors.concat( result[ 1 ] );
 			} );
@@ -234,19 +234,15 @@
 	};
 
 	uw.controller.Details.prototype.confirmationDialog = function ( warnings ) {
-		var i,
+		let i,
 			$message = $( '<p>' ).text( mw.message( 'mediauploader-dialog-warning' ).text() ),
 			$ul = $( '<ul>' );
 
 		// parse warning messages
-		warnings = warnings.map( function ( warning ) {
-			return warning.text();
-		} );
+		warnings = warnings.map( ( warning ) => warning.text() );
 
 		// omit duplicates
-		warnings = warnings.filter( function ( warning, j, warningsOld ) {
-			return warningsOld.indexOf( warning ) === j;
-		} );
+		warnings = warnings.filter( ( warning, j, warningsOld ) => warningsOld.indexOf( warning ) === j );
 
 		for ( i = 0; i < warnings.length; i++ ) {
 			$ul.append( $( '<li>' ).text( warnings[ i ] ) );
@@ -265,9 +261,7 @@
 					label: mw.msg( 'mediauploader-dialog-continue' )
 				}
 			]
-		} ).closed.then( function ( data ) {
-			return !!( data && data.action === 'continue' );
-		} );
+		} ).closed.then( ( data ) => !!( data && data.action === 'continue' ) );
 	};
 
 	uw.controller.Details.prototype.canTransition = function ( upload ) {
@@ -293,11 +287,11 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.controller.Details.prototype.transitionAll = function () {
-		var
+		const
 			deferred = $.Deferred(),
 			details = this;
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			if ( details.canTransition( upload ) ) {
 				details.queue.addItem( upload );
 			}
@@ -315,9 +309,9 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.controller.Details.prototype.submit = function () {
-		var details = this;
+		const details = this;
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			// Clear error state
 			if ( upload.state === 'error' || upload.state === 'recoverable-error' ) {
 				upload.state = details.stepName;
@@ -331,7 +325,7 @@
 		this.ui.disableEdits();
 		this.removeCopyMetadataFeature();
 
-		return this.transitionAll().then( function () {
+		return this.transitionAll().then( () => {
 			details.showErrors();
 
 			if ( details.showNext() ) {
diff --git a/resources/controller/uw.controller.Step.js b/resources/controller/uw.controller.Step.js
index f981299..fcea7f8 100644
--- a/resources/controller/uw.controller.Step.js
+++ b/resources/controller/uw.controller.Step.js
@@ -26,7 +26,7 @@
 	 * @param {Object} config UploadWizard config object.
 	 */
 	uw.controller.Step = function UWControllerStep( ui, api, config ) {
-		var step = this;
+		const step = this;
 
 		OO.EventEmitter.call( this );
 
@@ -60,11 +60,11 @@
 			'remove-upload': this.removeUpload
 		};
 
-		this.ui.on( 'next-step', function () {
+		this.ui.on( 'next-step', () => {
 			step.moveNext();
 		} );
 
-		this.ui.on( 'previous-step', function () {
+		this.ui.on( 'previous-step', () => {
 			step.movePrevious();
 		} );
 
@@ -109,7 +109,7 @@
 	 * @param {mw.UploadWizardUpload[]} uploads List of uploads being carried forward.
 	 */
 	uw.controller.Step.prototype.load = function ( uploads ) {
-		var step = this;
+		const step = this;
 
 		this.emit( 'load' );
 
@@ -120,7 +120,7 @@
 			test: step.hasData.bind( this )
 		} );
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			upload.state = step.stepName;
 
 			step.bindUploadHandlers( upload );
@@ -133,9 +133,9 @@
 	 * Cleanup this step.
 	 */
 	uw.controller.Step.prototype.unload = function () {
-		var step = this;
+		const step = this;
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			step.unbindUploadHandlers( upload );
 		} );
 
@@ -173,10 +173,10 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.controller.Step.prototype.bindUploadHandlers = function ( upload ) {
-		var controller = this;
+		const controller = this;
 
-		Object.keys( this.uploadHandlers ).forEach( function ( event ) {
-			var callback = controller.uploadHandlers[ event ];
+		Object.keys( this.uploadHandlers ).forEach( ( event ) => {
+			const callback = controller.uploadHandlers[ event ];
 			upload.on( event, callback, [ upload ], controller );
 		} );
 	};
@@ -187,10 +187,10 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.controller.Step.prototype.unbindUploadHandlers = function ( upload ) {
-		var controller = this;
+		const controller = this;
 
-		Object.keys( this.uploadHandlers ).forEach( function ( event ) {
-			var callback = controller.uploadHandlers[ event ];
+		Object.keys( this.uploadHandlers ).forEach( ( event ) => {
+			const callback = controller.uploadHandlers[ event ];
 			upload.off( event, callback, controller );
 		} );
 	};
@@ -220,7 +220,7 @@
 	 * @return {boolean} Whether all of the uploads are in a successful state.
 	 */
 	uw.controller.Step.prototype.showNext = function () {
-		var okCount = this.getUploadStatesCount( this.finishState ),
+		let okCount = this.getUploadStatesCount( this.finishState ),
 			$buttons;
 
 		// abort if all uploads have been removed
@@ -256,13 +256,13 @@
 	 * @return {number}
 	 */
 	uw.controller.Step.prototype.getUploadStatesCount = function ( states ) {
-		var count = 0;
+		let count = 0;
 
 		// normalize to array of states, even though input can be 1 string
 		states = Array.isArray( states ) ? states : [ states ];
 
-		this.uploads.forEach( function ( upload ) {
-			if ( states.indexOf( upload.state ) > -1 ) {
+		this.uploads.forEach( ( upload ) => {
+			if ( states.includes( upload.state ) ) {
 				count++;
 			}
 		} );
@@ -302,7 +302,7 @@
 	 */
 	uw.controller.Step.prototype.removeUpload = function ( upload ) {
 		// remove the upload from the uploads array
-		var index = this.uploads.indexOf( upload );
+		const index = this.uploads.indexOf( upload );
 		if ( index !== -1 ) {
 			this.uploads.splice( index, 1 );
 		}
@@ -317,7 +317,7 @@
 	 * @param {mw.UploadWizardUpload[]} uploads
 	 */
 	uw.controller.Step.prototype.removeUploads = function ( uploads ) {
-		var i,
+		let i,
 			// clone the array of uploads, just to be sure it's not a reference
 			// to this.uploads, which will be modified (and we can't have that
 			// while we're looping it)
@@ -334,8 +334,8 @@
 	uw.controller.Step.prototype.removeErrorUploads = function () {
 		// We must not remove items from an array while iterating over it with $.each (it causes the
 		// next item to be skipped). Find and queue them first, then remove them.
-		var toRemove = [];
-		this.uploads.forEach( function ( upload ) {
+		const toRemove = [];
+		this.uploads.forEach( ( upload ) => {
 			if ( upload.state === 'error' || upload.state === 'recoverable-error' ) {
 				toRemove.push( upload );
 			}
diff --git a/resources/controller/uw.controller.Thanks.js b/resources/controller/uw.controller.Thanks.js
index 45a81ac..e660395 100644
--- a/resources/controller/uw.controller.Thanks.js
+++ b/resources/controller/uw.controller.Thanks.js
@@ -38,7 +38,7 @@
 	OO.inheritClass( uw.controller.Thanks, uw.controller.Step );
 
 	uw.controller.Thanks.prototype.load = function ( uploads ) {
-		var thanks = this;
+		const thanks = this;
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 
@@ -48,7 +48,7 @@
 			return;
 		}
 
-		uploads.forEach( function ( upload ) {
+		uploads.forEach( ( upload ) => {
 			thanks.ui.addUpload( upload );
 		} );
 	};
diff --git a/resources/controller/uw.controller.Tutorial.js b/resources/controller/uw.controller.Tutorial.js
index 2aee890..5c26eb8 100644
--- a/resources/controller/uw.controller.Tutorial.js
+++ b/resources/controller/uw.controller.Tutorial.js
@@ -26,7 +26,7 @@
 	 * @param {Object} config UploadWizard config object.
 	 */
 	uw.controller.Tutorial = function UWControllerTutorial( api, config ) {
-		var controller = this;
+		const controller = this;
 
 		this.skipPreference = Boolean( mw.user.options.get( 'upwiz_skiptutorial' ) );
 		this.newSkipPreference = this.skipPreference;
@@ -35,7 +35,7 @@
 		uw.controller.Step.call(
 			this,
 			new uw.ui.Tutorial()
-				.on( 'skip-tutorial-click', function ( skipped ) {
+				.on( 'skip-tutorial-click', ( skipped ) => {
 					// indicate that the skip preference has changed, so we can
 					// alter the preference when we move to another step
 					controller.newSkipPreference = skipped;
@@ -57,23 +57,23 @@
 	 * @param {boolean} skip
 	 */
 	uw.controller.Tutorial.prototype.setSkipPreference = function ( skip ) {
-		var controller = this,
+		const controller = this,
 			allowCloseWindow = mw.confirmCloseWindow();
 
 		this.api.postWithToken( 'options', {
 			action: 'options',
 			change: skip ? 'upwiz_skiptutorial=1' : 'upwiz_skiptutorial'
-		} ).done( function () {
+		} ).done( () => {
 			allowCloseWindow.release();
 			controller.skipPreference = skip;
-		} ).fail( function ( code, err ) {
+		} ).fail( ( code, err ) => {
 			mw.notify( err.textStatus );
 		} );
 	};
 
 	uw.controller.Tutorial.prototype.load = function ( uploads ) {
 		// tutorial can be skipped via preference, or config (e.g. campaign config)
-		var shouldSkipTutorial = this.skipPreference || ( this.config.tutorial && this.config.tutorial.skip );
+		const shouldSkipTutorial = this.skipPreference || ( this.config.tutorial && this.config.tutorial.skip );
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 
diff --git a/resources/controller/uw.controller.Upload.js b/resources/controller/uw.controller.Upload.js
index 1fb75e2..43d416e 100644
--- a/resources/controller/uw.controller.Upload.js
+++ b/resources/controller/uw.controller.Upload.js
@@ -26,7 +26,7 @@
 	 * @param {Object} config UploadWizard config object.
 	 */
 	uw.controller.Upload = function UWControllerUpload( api, config ) {
-		var step = this;
+		const step = this;
 
 		uw.controller.Step.call(
 			this,
@@ -47,8 +47,8 @@
 		} );
 		this.queue.on( 'complete', this.showNext.bind( this ) );
 
-		this.ui.on( 'files-added', function ( files ) {
-			var totalFiles = files.length + step.uploads.length,
+		this.ui.on( 'files-added', ( files ) => {
+			const totalFiles = files.length + step.uploads.length,
 				tooManyFiles = totalFiles > step.config.maxUploads;
 
 			if ( tooManyFiles ) {
@@ -65,7 +65,7 @@
 	 * Updates the upload step data when a file is added or removed.
 	 */
 	uw.controller.Upload.prototype.updateFileCounts = function () {
-		var fewerThanMax, haveUploads,
+		let fewerThanMax, haveUploads,
 			max = this.config.maxUploads;
 
 		haveUploads = this.uploads.length > 0;
@@ -76,7 +76,7 @@
 	};
 
 	uw.controller.Upload.prototype.load = function ( uploads ) {
-		var controller = this;
+		const controller = this;
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 		this.updateFileCounts();
@@ -96,7 +96,7 @@
 			 * with new uploads, and still understand the existing files that
 			 * we've just reset the state for.
 			 */
-			uploads.forEach( function ( upload ) {
+			uploads.forEach( ( upload ) => {
 				upload.state = upload.fileKey === undefined ? 'error' : controller.finishState;
 			} );
 
@@ -167,7 +167,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.controller.Upload.prototype.transitionOne = function ( upload ) {
-		var promise = upload.start();
+		const promise = upload.start();
 		this.maybeStartProgressBar();
 		return promise;
 	};
@@ -191,9 +191,9 @@
 	};
 
 	uw.controller.Upload.prototype.retry = function () {
-		var controller = this;
+		const controller = this;
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			if ( upload.state === 'error' ) {
 				// reset any uploads in error state back to be shiny & new
 				upload.state = 'new';
@@ -214,7 +214,7 @@
 	 * @return {mw.UploadWizardUpload|boolean} The new upload, or false if it can't be added
 	 */
 	uw.controller.Upload.prototype.addFile = function ( file ) {
-		var upload;
+		let upload;
 
 		if ( this.uploads.length >= this.config.maxUploads ) {
 			return false;
@@ -244,7 +244,7 @@
 	 * @param {FileList} files
 	 */
 	uw.controller.Upload.prototype.addFiles = function ( files ) {
-		var
+		let
 			uploadObj,
 			i,
 			file,
@@ -302,7 +302,7 @@
 	 * @return {boolean} Error in [code, info] format, or empty [] for no errors
 	 */
 	uw.controller.Upload.prototype.validateFile = function ( upload ) {
-		var extension,
+		let extension,
 			i,
 			actualMaxSize = mw.UploadWizard.config.maxMwUploadSize,
 
@@ -322,7 +322,7 @@
 		// check if the filename is valid
 		upload.setTitle( basename );
 		if ( !upload.title ) {
-			if ( basename.indexOf( '.' ) === -1 ) {
+			if ( !basename.includes( '.' ) ) {
 				this.ui.showMissingExtensionError( filename );
 				return false;
 			} else {
@@ -340,7 +340,7 @@
 
 		if (
 			mw.UploadWizard.config.fileExtensions !== null &&
-			mw.UploadWizard.config.fileExtensions.indexOf( extension.toLowerCase() ) === -1
+			!mw.UploadWizard.config.fileExtensions.includes( extension.toLowerCase() )
 		) {
 			this.ui.showBadExtensionError( filename, extension );
 			return false;
diff --git a/resources/deed/uw.deed.OwnWork.js b/resources/deed/uw.deed.OwnWork.js
index 50881cb..f287b98 100644
--- a/resources/deed/uw.deed.OwnWork.js
+++ b/resources/deed/uw.deed.OwnWork.js
@@ -26,7 +26,7 @@
 	 * @param {mw.Api} api API object - useful for doing previews
 	 */
 	uw.deed.OwnWork = function UWDeedOwnWork( config, uploads, api ) {
-		var deed = this,
+		let deed = this,
 			prefAuthName = mw.user.options.get( 'upwiz_licensename' );
 
 		uw.deed.Abstract.call( this, 'ownwork', config );
@@ -49,7 +49,7 @@
 			value: prefAuthName,
 			classes: [ 'mediauploader-sign' ]
 		} );
-		this.authorInput.on( 'change', function () {
+		this.authorInput.on( 'change', () => {
 			deed.fakeAuthorInput.setValue( deed.authorInput.getValue() );
 		} );
 
@@ -80,7 +80,7 @@
 	};
 
 	uw.deed.OwnWork.prototype.setFormFields = function ( $selector ) {
-		var $customDiv, $formFields, $toggler, crossfaderWidget, defaultLicense,
+		let $customDiv, $formFields, $toggler, crossfaderWidget, defaultLicense,
 			defaultLicenseURL, $defaultLicenseLink, $standardDiv, $crossfader,
 			deed, languageCode, defaultLicConfig;
 
@@ -141,7 +141,7 @@
 
 		this.authorInputField = new uw.FieldLayout( crossfaderWidget );
 		// Aggregate 'change' event
-		this.authorInput.on( 'change', OO.ui.debounce( function () {
+		this.authorInput.on( 'change', OO.ui.debounce( () => {
 			crossfaderWidget.emit( 'change' );
 		}, 500 ) );
 
@@ -152,7 +152,7 @@
 		$toggler = $( '<p>' ).addClass( 'mwe-more-options' ).css( 'text-align', 'right' )
 			.append( $( '<a>' )
 				.msg( 'mediauploader-license-show-all' )
-				.on( 'click', function () {
+				.on( 'click', () => {
 					if ( $crossfader.data( 'crossfadeDisplay' ).get( 0 ) === $customDiv.get( 0 ) ) {
 						deed.standardLicense();
 					} else {
@@ -171,8 +171,8 @@
 	};
 
 	uw.deed.OwnWork.prototype.setDefaultLicenses = function () {
-		var defaultLicenses = {};
-		this.getDefaultLicenses().forEach( function ( licName ) {
+		const defaultLicenses = {};
+		this.getDefaultLicenses().forEach( ( licName ) => {
 			defaultLicenses[ licName ] = true;
 		} );
 		this.licenseInput.setValues( defaultLicenses );
@@ -189,10 +189,10 @@
 	 * @inheritdoc
 	 */
 	uw.deed.OwnWork.prototype.getAuthorWikiText = function () {
-		var author = this.authorInput.getValue(),
+		let author = this.authorInput.getValue(),
 			userPageTitle;
 
-		if ( author.indexOf( '[' ) >= 0 || author.indexOf( '{' ) >= 0 ) {
+		if ( author.includes( '[' ) || author.includes( '{' ) ) {
 			return author;
 		}
 
@@ -236,7 +236,7 @@
 	};
 
 	uw.deed.OwnWork.prototype.swapNodes = function ( a, b ) {
-		var
+		const
 			parentA = a.parentNode,
 			parentB = b.parentNode,
 			nextA = a.nextSibling,
@@ -252,7 +252,7 @@
 	 * @return {string[]}
 	 */
 	uw.deed.OwnWork.prototype.getDefaultLicenses = function () {
-		var license, ownWork = this.config.licensing.ownWork;
+		let license, ownWork = this.config.licensing.ownWork;
 
 		if ( this.config.licensing.defaultType === 'ownWork' ) {
 			license = ownWork.defaults;
@@ -267,7 +267,7 @@
 	};
 
 	uw.deed.OwnWork.prototype.standardLicense = function () {
-		var deed = this,
+		const deed = this,
 			$crossfader = this.$selector.find( '.mediauploader-crossfader' ),
 			$standardDiv = this.$selector.find( '.mediauploader-standard' ),
 			$toggler = this.$selector.find( '.mwe-more-options a' );
@@ -275,7 +275,7 @@
 		this.setDefaultLicenses();
 
 		$crossfader.morphCrossfade( $standardDiv )
-			.promise().done( function () {
+			.promise().done( () => {
 				deed.swapNodes( deed.authorInput.$element[ 0 ], deed.fakeAuthorInput.$element[ 0 ] );
 			} );
 
@@ -289,13 +289,13 @@
 	};
 
 	uw.deed.OwnWork.prototype.customLicense = function () {
-		var deed = this,
+		const deed = this,
 			$crossfader = this.$selector.find( '.mediauploader-crossfader' ),
 			$customDiv = this.$selector.find( '.mediauploader-custom' ),
 			$toggler = this.$selector.find( '.mwe-more-options a' );
 
 		$crossfader.morphCrossfade( $customDiv )
-			.promise().done( function () {
+			.promise().done( () => {
 				deed.swapNodes( deed.authorInput.$element[ 0 ], deed.fakeAuthorInput.$element[ 0 ] );
 			} );
 
@@ -313,7 +313,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.deed.OwnWork.prototype.getAuthorErrors = function ( input ) {
-		var
+		const
 			errors = [],
 			minLength = this.config.minAuthorLength,
 			maxLength = this.config.maxAuthorLength,
diff --git a/resources/deed/uw.deed.ThirdParty.js b/resources/deed/uw.deed.ThirdParty.js
index 0d70235..e2eebf8 100644
--- a/resources/deed/uw.deed.ThirdParty.js
+++ b/resources/deed/uw.deed.ThirdParty.js
@@ -26,7 +26,7 @@
 	 * @param {mw.Api} api API object - useful for doing previews
 	 */
 	uw.deed.ThirdParty = function UWDeedThirdParty( config, uploads, api ) {
-		var deed = this;
+		const deed = this;
 
 		uw.deed.Abstract.call( this, 'thirdparty', config );
 
@@ -40,7 +40,7 @@
 		this.sourceInput.$input.attr( 'id', 'mwe-source-' + this.getInstanceCount() );
 		// See uw.DetailsWidget
 		this.sourceInput.getErrors = function () {
-			var
+			const
 				errors = [],
 				minLength = deed.config.minSourceLength,
 				maxLength = deed.config.maxSourceLength,
@@ -74,7 +74,7 @@
 		this.authorInput.$input.attr( 'id', 'mwe-author-' + this.getInstanceCount() );
 		// See uw.DetailsWidget
 		this.authorInput.getErrors = function () {
-			var
+			const
 				errors = [],
 				minLength = deed.config.minAuthorLength,
 				maxLength = deed.config.maxAuthorLength,
@@ -127,7 +127,7 @@
 	};
 
 	uw.deed.ThirdParty.prototype.setFormFields = function ( $selector ) {
-		var $formFields = $( '<div>' ).addClass( 'mediauploader-deed-form-internal' );
+		const $formFields = $( '<div>' ).addClass( 'mediauploader-deed-form-internal' );
 
 		this.$form = $( '<form>' );
 
diff --git a/resources/details/uw.CategoriesDetailsWidget.js b/resources/details/uw.CategoriesDetailsWidget.js
index 1d12511..90c456a 100644
--- a/resources/details/uw.CategoriesDetailsWidget.js
+++ b/resources/details/uw.CategoriesDetailsWidget.js
@@ -1,6 +1,6 @@
 ( function ( uw ) {
 
-	var NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;
+	const NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;
 
 	/**
 	 * A categories field in UploadWizard's "Details" step form.
@@ -9,7 +9,7 @@
 	 * @param {Object} config
 	 */
 	uw.CategoriesDetailsWidget = function UWCategoriesDetailsWidget( config ) {
-		var catDetails = this;
+		const catDetails = this;
 		this.config = config;
 
 		uw.CategoriesDetailsWidget.parent.call( this, this.config );
@@ -19,7 +19,7 @@
 		} );
 
 		this.categoriesWidget.createTagItemWidget = function ( data ) {
-			var widget = this.constructor.prototype.createTagItemWidget.call( this, data );
+			const widget = this.constructor.prototype.createTagItemWidget.call( this, data );
 			if ( !widget ) {
 				return null;
 			}
@@ -43,7 +43,7 @@
 	 * @inheritdoc
 	 */
 	uw.CategoriesDetailsWidget.prototype.getErrors = function () {
-		var errors = [];
+		const errors = [];
 
 		if ( this.config.required && this.categoriesWidget.getItems().length === 0 ) {
 			errors.push( mw.message( 'mediauploader-error-blank' ) );
@@ -56,12 +56,10 @@
 	 * @inheritdoc
 	 */
 	uw.CategoriesDetailsWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.categoriesWidget.getItems().length === 0, warnings );
 
-		if ( this.categoriesWidget.getItems().some( function ( item ) {
-			return item.missing;
-		} ) ) {
+		if ( this.categoriesWidget.getItems().some( ( item ) => item.missing ) ) {
 			warnings.push( mw.message( 'mediauploader-categories-missing' ) );
 		}
 		return $.Deferred().resolve( warnings ).promise();
@@ -71,7 +69,7 @@
 	 * @inheritdoc
 	 */
 	uw.CategoriesDetailsWidget.prototype.getWikiText = function () {
-		var hiddenCats, missingCatsWikiText, categories, wikiText;
+		let hiddenCats, missingCatsWikiText, categories, wikiText;
 
 		hiddenCats = [];
 		if ( this.config.hiddenDefault ) {
@@ -84,10 +82,10 @@
 				hiddenCats.push( mw.UploadWizard.config.trackingCategory.campaign );
 			}
 		}
-		hiddenCats = hiddenCats.filter( function ( cat ) {
+		hiddenCats = hiddenCats.filter( ( cat ) =>
 			// Keep only valid titles
-			return !!mw.Title.makeTitle( NS_CATEGORY, cat );
-		} );
+			 !!mw.Title.makeTitle( NS_CATEGORY, cat )
+		 );
 
 		missingCatsWikiText = null;
 		if (
@@ -97,15 +95,11 @@
 			missingCatsWikiText = this.config.missingWikitext;
 		}
 
-		categories = this.categoriesWidget.getItems().map( function ( item ) {
-			return item.data;
-		} );
+		categories = this.categoriesWidget.getItems().map( ( item ) => item.data );
 
 		// add all categories
 		wikiText = categories.concat( hiddenCats )
-			.map( function ( cat ) {
-				return '[[' + mw.Title.makeTitle( NS_CATEGORY, cat ).getPrefixedText() + ']]';
-			} )
+			.map( ( cat ) => '[[' + mw.Title.makeTitle( NS_CATEGORY, cat ).getPrefixedText() + ']]' )
 			.join( '\n' );
 
 		// if so configured, and there are no user-visible categories, add warning
@@ -121,9 +115,7 @@
 	 * @return {Object} See #setSerialized
 	 */
 	uw.CategoriesDetailsWidget.prototype.getSerialized = function () {
-		return this.categoriesWidget.getItems().map( function ( item ) {
-			return item.data;
-		} );
+		return this.categoriesWidget.getItems().map( ( item ) => item.data );
 	};
 
 	/**
@@ -131,10 +123,10 @@
 	 * @param {string[]} serialized List of categories
 	 */
 	uw.CategoriesDetailsWidget.prototype.setSerialized = function ( serialized ) {
-		var categories = ( serialized || [] ).filter( function ( cat ) {
+		const categories = ( serialized || [] ).filter( ( cat ) =>
 			// Keep only valid titles
-			return !!mw.Title.makeTitle( NS_CATEGORY, cat );
-		} );
+			 !!mw.Title.makeTitle( NS_CATEGORY, cat )
+		 );
 		this.categoriesWidget.setValue( categories );
 	};
 
diff --git a/resources/details/uw.DateDetailsWidget.js b/resources/details/uw.DateDetailsWidget.js
index 198e7e2..f2fabc5 100644
--- a/resources/details/uw.DateDetailsWidget.js
+++ b/resources/details/uw.DateDetailsWidget.js
@@ -31,10 +31,10 @@
 			disabled: this.config.disabled
 		} )
 			.selectItemByData( 'calendar' )
-			.on( 'choose', function ( selectedItem ) {
+			.on( 'choose', ( selectedItem ) => {
 				this.setupDateInput( selectedItem.getData() );
 				this.dateInputWidget.focus();
-			}.bind( this ) );
+			} );
 
 		this.$element.addClass( 'mediauploader-dateDetailsWidget' );
 		this.$element.append(
@@ -52,7 +52,7 @@
 	 * @private
 	 */
 	uw.DateDetailsWidget.prototype.setupDateInput = function ( mode ) {
-		var
+		const
 			oldDateInputWidget = this.dateInputWidget;
 
 		if ( mode === undefined ) {
@@ -75,13 +75,13 @@
 			} );
 			// If the user types '{{', assume that they are trying to input template wikitext and switch
 			// to 'arbitrary' mode. This might help confused power-users (T110026#1567714).
-			this.dateInputWidget.textInput.on( 'change', function ( value ) {
+			this.dateInputWidget.textInput.on( 'change', ( value ) => {
 				if ( value === '{{' ) {
 					this.setupDateInput( 'arbitrary' );
 					this.dateInputWidget.setValue( '{{' );
 					this.dateInputWidget.moveCursorToEnd();
 				}
-			}.bind( this ) );
+			} );
 		}
 
 		if ( oldDateInputWidget ) {
@@ -121,7 +121,7 @@
 	 * @inheritdoc
 	 */
 	uw.DateDetailsWidget.prototype.getWarnings = function () {
-		var warnings = [],
+		const warnings = [],
 			dateVal = Date.parse( this.dateInputWidget.getValue().trim() ),
 			now = new Date();
 
@@ -143,7 +143,7 @@
 	 * @inheritdoc
 	 */
 	uw.DateDetailsWidget.prototype.getErrors = function () {
-		var errors = [];
+		const errors = [];
 
 		if ( this.config.required && this.dateInputWidget.getValue().trim() === '' ) {
 			errors.push( mw.message( 'mediauploader-error-blank' ) );
diff --git a/resources/details/uw.DeedChooserDetailsWidget.js b/resources/details/uw.DeedChooserDetailsWidget.js
index 94e4fd9..1560271 100644
--- a/resources/details/uw.DeedChooserDetailsWidget.js
+++ b/resources/details/uw.DeedChooserDetailsWidget.js
@@ -25,7 +25,7 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.DeedChooserDetailsWidget.prototype.useCustomDeedChooser = function ( upload ) {
-		var $deedDiv;
+		let $deedDiv;
 
 		// Defining own deedChooser for uploads coming from external service
 		if ( upload.file.fromURL ) {
@@ -74,7 +74,7 @@
 	 * @inheritdoc
 	 */
 	uw.DeedChooserDetailsWidget.prototype.getErrors = function () {
-		var errors = [];
+		const errors = [];
 		if ( this.deedChooser ) {
 			if ( !this.deedChooser.deed ) {
 				errors.push( mw.message( 'mediauploader-deeds-need-deed' ) );
diff --git a/resources/details/uw.DropdownWidget.js b/resources/details/uw.DropdownWidget.js
index ab6ec70..17db404 100644
--- a/resources/details/uw.DropdownWidget.js
+++ b/resources/details/uw.DropdownWidget.js
@@ -17,9 +17,7 @@
 		this.wikitext = config.wikitext;
 		this.input = new OO.ui.DropdownInputWidget( {
 			classes: [ 'mwe-idfield', 'mediauploader-dropdownWidget-input' ],
-			options: Object.keys( config.options ).map( function ( key ) {
-				return { data: key, label: config.options[ key ] };
-			} )
+			options: Object.keys( config.options ).map( ( key ) => ( { data: key, label: config.options[ key ] } ) )
 		} );
 
 		// Aggregate 'change' event
@@ -37,7 +35,7 @@
 	 * @inheritdoc
 	 */
 	uw.DropdownWidget.prototype.getErrors = function () {
-		var errors = [];
+		const errors = [];
 		if ( this.required && this.input.getValue().trim() === '' ) {
 			errors.push( mw.message( 'mediauploader-error-blank' ) );
 		}
@@ -48,7 +46,7 @@
 	 * @inheritdoc
 	 */
 	uw.DropdownWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.input.getValue().trim() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
diff --git a/resources/details/uw.LanguageDropdownWidget.js b/resources/details/uw.LanguageDropdownWidget.js
index 8865ae8..b9e163d 100644
--- a/resources/details/uw.LanguageDropdownWidget.js
+++ b/resources/details/uw.LanguageDropdownWidget.js
@@ -28,15 +28,13 @@
 	 * @param {Object} languages
 	 */
 	uw.LanguageDropdownWidget.prototype.updateLanguages = function ( languages ) {
-		var menu = this.languageDropdown.getMenu(),
+		const menu = this.languageDropdown.getMenu(),
 			currentMenuItems = menu.getItems(),
 			currentValue = this.getValue();
 
 		// remove all items except the one currently selected (don't want
 		// to trigger another select by removing it)
-		menu.removeItems( currentMenuItems.filter( function ( item ) {
-			return !item.isSelected();
-		} ) );
+		menu.removeItems( currentMenuItems.filter( ( item ) => !item.isSelected() ) );
 
 		// and add the rest of the languages back in there
 		delete languages[ currentValue ];
@@ -72,12 +70,10 @@
 	 * @return {OO.ui.MenuOptionWidget[]}
 	 */
 	uw.LanguageDropdownWidget.prototype.getLanguageMenuOptionWidgets = function ( languages ) {
-		return Object.keys( languages ).map( function ( code ) {
-			return new OO.ui.MenuOptionWidget( {
-				data: code,
-				label: languages[ code ]
-			} );
-		} );
+		return Object.keys( languages ).map( ( code ) => new OO.ui.MenuOptionWidget( {
+			data: code,
+			label: languages[ code ]
+		} ) );
 	};
 
 }( mw.uploadWizard ) );
diff --git a/resources/details/uw.LocationDetailsWidget.js b/resources/details/uw.LocationDetailsWidget.js
index 76a0c18..b89a46e 100644
--- a/resources/details/uw.LocationDetailsWidget.js
+++ b/resources/details/uw.LocationDetailsWidget.js
@@ -68,10 +68,10 @@
 		this.connect( this, { change: 'onChange' } );
 
 		this.mapButton.toggle( false );
-		mw.loader.using( [ 'ext.kartographer.box', 'ext.kartographer.editing' ] ).done( function () {
+		mw.loader.using( [ 'ext.kartographer.box', 'ext.kartographer.editing' ] ).done( () => {
 			// Kartographer is installed and we'll be able to show the map. Display the button.
 			this.mapButton.toggle( true );
-		}.bind( this ) );
+		} );
 	};
 
 	OO.inheritClass( uw.LocationDetailsWidget, uw.DetailsWidget );
@@ -80,8 +80,8 @@
 	 * @private
 	 */
 	uw.LocationDetailsWidget.prototype.onChange = function () {
-		var widget = this;
-		this.getErrors().done( function ( errors ) {
+		const widget = this;
+		this.getErrors().done( ( errors ) => {
 			widget.mapButton.setDisabled( !( errors.length === 0 && widget.getWikiText() !== '' ) );
 		} );
 	};
@@ -90,7 +90,7 @@
 	 * @private
 	 */
 	uw.LocationDetailsWidget.prototype.onMapButtonClick = function () {
-		var coords = this.getSerializedParsed();
+		const coords = this.getSerializedParsed();
 
 		// Disable clipping because it doesn't play nicely with the map
 		this.mapButton.getPopup().toggleClipping( false );
@@ -112,7 +112,7 @@
 	 * @inheritdoc
 	 */
 	uw.LocationDetailsWidget.prototype.getErrors = function () {
-		var errors = [],
+		let errors = [],
 			serialized = this.getSerialized(),
 			parsed = this.getSerializedParsed(),
 			field;
@@ -132,13 +132,13 @@
 		// coordinates that were derived from the input are 0, without a 0 even
 		// being present in the input
 		if ( this.config.showField.latitude && serialized.latitude ) {
-			if ( isNaN( parsed.latitude ) || parsed.latitude > 90 || parsed.latitude < -90 || ( parsed.latitude === 0 && serialized.latitude.indexOf( '0' ) < 0 ) ) {
+			if ( isNaN( parsed.latitude ) || parsed.latitude > 90 || parsed.latitude < -90 || ( parsed.latitude === 0 && !serialized.latitude.includes( '0' ) ) ) {
 				errors.push( mw.message( 'mediauploader-error-latitude' ) );
 			}
 		}
 
 		if ( this.config.showField.longitude && serialized.longitude ) {
-			if ( isNaN( parsed.longitude ) || parsed.longitude > 180 || parsed.longitude < -180 || ( parsed.longitude === 0 && serialized.longitude.indexOf( '0' ) < 0 ) ) {
+			if ( isNaN( parsed.longitude ) || parsed.longitude > 180 || parsed.longitude < -180 || ( parsed.longitude === 0 && !serialized.longitude.includes( '0' ) ) ) {
 				errors.push( mw.message( 'mediauploader-error-longitude' ) );
 			}
 		}
@@ -160,7 +160,7 @@
 	 * @inheritdoc
 	 */
 	uw.LocationDetailsWidget.prototype.getWikiText = function () {
-		var field,
+		let field,
 			result = '',
 			serialized = this.getSerializedParsed();
 
@@ -190,7 +190,7 @@
 	 * @return {Object} See #setSerialized
 	 */
 	uw.LocationDetailsWidget.prototype.getSerialized = function () {
-		var field,
+		let field,
 			result = {};
 
 		for ( field in this.config.showField ) {
@@ -206,7 +206,7 @@
 	 * @return {Object} Serialized, parsed values of the subfields (numbers)
 	 */
 	uw.LocationDetailsWidget.prototype.getSerializedParsed = function () {
-		var field,
+		let field,
 			result = {},
 			serialized = this.getSerialized();
 
@@ -232,7 +232,7 @@
 	 * @param {string} serialized.heading Heading value
 	 */
 	uw.LocationDetailsWidget.prototype.setSerialized = function ( serialized ) {
-		var field;
+		let field;
 
 		for ( field in this.config.showField ) {
 			if ( serialized[ field ] !== undefined ) {
@@ -255,7 +255,7 @@
 	 * @return {number}
 	 */
 	uw.LocationDetailsWidget.prototype.normalizeCoordinate = function ( coordinate ) {
-		var sign = coordinate.match( /[sw]/i ) ? -1 : 1,
+		let sign = coordinate.match( /[sw]/i ) ? -1 : 1,
 			parts, value;
 
 		// fix commonly used character alternatives
diff --git a/resources/details/uw.MultipleLanguageInputWidget.js b/resources/details/uw.MultipleLanguageInputWidget.js
index 7816114..e3dcf27 100644
--- a/resources/details/uw.MultipleLanguageInputWidget.js
+++ b/resources/details/uw.MultipleLanguageInputWidget.js
@@ -57,7 +57,7 @@
 	 * @param {string} [text]
 	 */
 	uw.MultipleLanguageInputWidget.prototype.addLanguageInput = function ( config, text ) {
-		var allLanguages = this.config.languages,
+		let allLanguages = this.config.languages,
 			unusedLanguages = this.getUnusedLanguages(),
 			languages = {},
 			item;
@@ -97,7 +97,7 @@
 	 * with the updated language selections.
 	 */
 	uw.MultipleLanguageInputWidget.prototype.onChangeLanguages = function () {
-		var allLanguages = this.config.languages,
+		let allLanguages = this.config.languages,
 			unusedLanguages = this.getUnusedLanguages(),
 			items = this.getItems(),
 			languages,
@@ -123,11 +123,11 @@
 	 * @return {Object}
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getUsedLanguages = function () {
-		var allLanguages = this.config.languages,
+		const allLanguages = this.config.languages,
 			items = this.getItems();
 
-		return items.reduce( function ( obj, item ) {
-			var languageCode = item.getLanguage();
+		return items.reduce( ( obj, item ) => {
+			const languageCode = item.getLanguage();
 			obj[ languageCode ] = allLanguages[ languageCode ];
 			return obj;
 		}, {} );
@@ -140,11 +140,11 @@
 	 * @return {Object}
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getUnusedLanguages = function () {
-		var allLanguages = this.config.languages,
+		const allLanguages = this.config.languages,
 			usedLanguageCodes = Object.keys( this.getUsedLanguages() );
 
-		return Object.keys( allLanguages ).reduce( function ( remaining, language ) {
-			if ( usedLanguageCodes.indexOf( language ) < 0 ) {
+		return Object.keys( allLanguages ).reduce( ( remaining, language ) => {
+			if ( !usedLanguageCodes.includes( language ) ) {
 				remaining[ language ] = allLanguages[ language ];
 			}
 			return remaining;
@@ -155,7 +155,7 @@
 	 * Update the button label after adding or removing inputs.
 	 */
 	uw.MultipleLanguageInputWidget.prototype.recount = function () {
-		var text = this.getLabelText(),
+		const text = this.getLabelText(),
 			unusedLanguages = this.getUnusedLanguages();
 
 		this.addButton.setLabel( text );
@@ -174,7 +174,7 @@
 	 * @inheritdoc
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.getWikiText() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
@@ -185,12 +185,10 @@
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getErrors = function () {
 		// Gather errors from each item
-		var errorPromises = this.getItems().map( function ( item ) {
-			return item.getErrors();
-		} );
+		const errorPromises = this.getItems().map( ( item ) => item.getErrors() );
 
 		return $.when.apply( $, errorPromises ).then( function () {
-			var i, errors;
+			let i, errors;
 			errors = [];
 			// Fold all errors into a single one (they are displayed in the UI for each item, but we still
 			// need to return an error here to prevent form submission).
@@ -214,7 +212,7 @@
 	 * @return {Object} Object where the properties are language codes & values are input
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getValues = function () {
-		var values = {},
+		let values = {},
 			widgets = this.getItems(),
 			language,
 			text,
@@ -238,11 +236,7 @@
 	uw.MultipleLanguageInputWidget.prototype.getWikiText = function () {
 		// Some code here and in mw.UploadWizardDetails relies on this function returning an empty
 		// string when there are some inputs, but all are empty.
-		return this.getItems().map( function ( widget ) {
-			return widget.getWikiText();
-		} ).filter( function ( wikiText ) {
-			return !!wikiText;
-		} ).join( '\n' );
+		return this.getItems().map( ( widget ) => widget.getWikiText() ).filter( ( wikiText ) => !!wikiText ).join( '\n' );
 	};
 
 	/**
@@ -250,9 +244,7 @@
 	 * @return {Object} See #setSerialized
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getSerialized = function () {
-		var inputs = this.getItems().map( function ( widget ) {
-			return widget.getSerialized();
-		} );
+		const inputs = this.getItems().map( ( widget ) => widget.getSerialized() );
 		return {
 			inputs: inputs
 		};
@@ -265,7 +257,7 @@
 	 *   see uw.SingleLanguageInputWidget#setSerialized
 	 */
 	uw.MultipleLanguageInputWidget.prototype.setSerialized = function ( serialized ) {
-		var config = this.config,
+		let config = this.config,
 			i;
 
 		if ( typeof serialized === 'string' ) {
@@ -288,7 +280,7 @@
 	 * @return {string}
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getCaption = function () {
-		var items = this.getItems();
+		const items = this.getItems();
 
 		if ( items.length > 0 ) {
 			return items[ 0 ].getCaption();
diff --git a/resources/details/uw.SingleLanguageInputWidget.js b/resources/details/uw.SingleLanguageInputWidget.js
index 53cf62b..7107d37 100644
--- a/resources/details/uw.SingleLanguageInputWidget.js
+++ b/resources/details/uw.SingleLanguageInputWidget.js
@@ -81,7 +81,7 @@
 	 * @private
 	 */
 	uw.SingleLanguageInputWidget.prototype.onRemoveClick = function () {
-		var element = this.getElementGroup();
+		const element = this.getElementGroup();
 
 		if ( element && typeof element.removeItems === 'function' ) {
 			element.removeItems( [ this ] );
@@ -120,7 +120,7 @@
 	 * @return {string}
 	 */
 	uw.SingleLanguageInputWidget.prototype.getDefaultLanguage = function () {
-		var defaultLanguage;
+		let defaultLanguage;
 
 		if ( this.defaultLanguage !== undefined ) {
 			return this.defaultLanguage;
@@ -153,7 +153,7 @@
 	 * @inheritdoc
 	 */
 	uw.SingleLanguageInputWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.textInput.getValue().trim() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
@@ -163,7 +163,7 @@
 	 * @inheritdoc
 	 */
 	uw.SingleLanguageInputWidget.prototype.getErrors = function () {
-		var
+		const
 			errors = [],
 			text = this.textInput.getValue().trim();
 
@@ -221,7 +221,7 @@
 	 * @inheritdoc
 	 */
 	uw.SingleLanguageInputWidget.prototype.getWikiText = function () {
-		var
+		let
 			language = this.getLanguage(),
 			text = this.getText();
 
diff --git a/resources/details/uw.TextWidget.js b/resources/details/uw.TextWidget.js
index 634e005..4a7f1f3 100644
--- a/resources/details/uw.TextWidget.js
+++ b/resources/details/uw.TextWidget.js
@@ -49,7 +49,7 @@
 	 * @inheritdoc
 	 */
 	uw.TextWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.textInput.getValue().trim() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
@@ -59,7 +59,7 @@
 	 * @inheritdoc
 	 */
 	uw.TextWidget.prototype.getErrors = function () {
-		var
+		const
 			errors = [],
 			text = this.textInput.getValue().trim();
 
diff --git a/resources/details/uw.TitleDetailsWidget.js b/resources/details/uw.TitleDetailsWidget.js
index cce0d4c..8e69895 100644
--- a/resources/details/uw.TitleDetailsWidget.js
+++ b/resources/details/uw.TitleDetailsWidget.js
@@ -1,6 +1,6 @@
 ( function ( uw ) {
 
-	var NS_FILE = mw.config.get( 'wgNamespaceIds' ).file,
+	const NS_FILE = mw.config.get( 'wgNamespaceIds' ).file,
 		byteLength = require( 'mediawiki.String' ).byteLength;
 
 	/**
@@ -44,7 +44,7 @@
 	 * @return {mw.Title|null}
 	 */
 	uw.TitleDetailsWidget.static.makeTitleInFileNS = function ( filename ) {
-		var
+		let
 			mwTitle = mw.Title.newFromText( filename, NS_FILE ),
 			illegalFileChars = new RegExp( '[' + mw.config.get( 'wgIllegalFileChars', '' ) + ']' );
 		if ( mwTitle && mwTitle.getNamespaceId() !== NS_FILE ) {
@@ -78,7 +78,7 @@
 	 * @return {mw.Title|null}
 	 */
 	uw.TitleDetailsWidget.prototype.getTitle = function () {
-		var value, extRegex, cleaned, title;
+		let value, extRegex, cleaned, title;
 		value = this.titleInput.getValue().trim();
 		if ( !value ) {
 			return null;
@@ -99,7 +99,7 @@
 	 * @inheritdoc
 	 */
 	uw.TitleDetailsWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.titleInput.getValue().trim() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
@@ -109,7 +109,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.TitleDetailsWidget.prototype.getErrors = function () {
-		var
+		const
 			errors = [],
 			value = this.titleInput.getValue().trim(),
 			processDestinationCheck = this.processDestinationCheck,
@@ -142,28 +142,24 @@
 		}
 
 		return mw.DestinationChecker.checkTitle( title.getPrefixedText() )
-			.then( function ( result ) {
-				var moreErrors = processDestinationCheck( result );
+			.then( ( result ) => {
+				let moreErrors = processDestinationCheck( result );
 				if ( result.blacklist.unavailable ) {
 					// We don't have a title blacklist, so just check for some likely undesirable patterns.
 					moreErrors = moreErrors.concat(
-						mw.QuickTitleChecker.checkTitle( title.getNameText() ).map( function ( errorCode ) {
+						mw.QuickTitleChecker.checkTitle( title.getNameText() ).map( ( errorCode ) =>
 							// Messages that can be used here:
 							// * mediauploader-error-title-invalid
 							// * mediauploader-error-title-senselessimagename
 							// * mediauploader-error-title-thumbnail
 							// * mediauploader-error-title-extension
-							return mw.message( 'mediauploader-error-title-' + errorCode );
-						} )
+							 mw.message( 'mediauploader-error-title-' + errorCode )
+						 )
 					);
 				}
 				return moreErrors;
 			} )
-			.then( function ( moreErrors ) {
-				return [].concat( errors, moreErrors );
-			}, function () {
-				return $.Deferred().resolve( errors );
-			} );
+			.then( ( moreErrors ) => [].concat( errors, moreErrors ), () => $.Deferred().resolve( errors ) );
 	};
 
 	/**
@@ -175,7 +171,7 @@
 	 * @return {mw.Message[]} Error messages
 	 */
 	uw.TitleDetailsWidget.prototype.processDestinationCheck = function ( result ) {
-		var messageParams, errors, titleString;
+		let messageParams, errors, titleString;
 
 		if ( result.unique.isUnique && result.blacklist.notBlacklisted && !result.unique.isProtected ) {
 			return [];
diff --git a/resources/details/uw.UlsWidget.js b/resources/details/uw.UlsWidget.js
index 826aef6..54813ae 100644
--- a/resources/details/uw.UlsWidget.js
+++ b/resources/details/uw.UlsWidget.js
@@ -9,7 +9,7 @@
 	 * @cfg {Array} [classes] Classes to apply to the ULS container div
 	 */
 	uw.UlsWidget = function UWUlsWidget( config ) {
-		var i;
+		let i;
 
 		uw.UlsWidget.parent.call( this, config );
 
@@ -49,7 +49,7 @@
 	OO.mixinClass( uw.UlsWidget, OO.EventEmitter );
 
 	uw.UlsWidget.prototype.initialiseUls = function ( languages ) {
-		var ulsWidget = this;
+		const ulsWidget = this;
 
 		this.languages = languages;
 
@@ -63,7 +63,7 @@
 			onVisible: function () {
 				// Re-position the ULS *after* the widget has been rendered, so that we can be
 				// sure it's in the right place
-				var offset = ulsWidget.$element.offset();
+				const offset = ulsWidget.$element.offset();
 				if ( this.$menu.css( 'direction' ) === 'rtl' ) {
 					offset.left =
 						offset.left - parseInt( this.$menu.css( 'width' ) ) + ulsWidget.$element.width();
@@ -85,7 +85,7 @@
 	 * @param {string} value
 	 */
 	uw.UlsWidget.prototype.setValue = function ( value ) {
-		var current = this.languageValue;
+		const current = this.languageValue;
 		this.languageValue = value;
 		this.$element.find( '.oo-ui-labelElement-label' ).text( this.languages[ value ] );
 		if ( current !== value ) {
diff --git a/resources/ext.mediaUploader.campaignEditor.js b/resources/ext.mediaUploader.campaignEditor.js
index 3ca08a3..49d3aaf 100644
--- a/resources/ext.mediaUploader.campaignEditor.js
+++ b/resources/ext.mediaUploader.campaignEditor.js
@@ -3,7 +3,7 @@
 	/**
 	 * Sets up indentation settings appropriate for YAML if CodeEditor is loaded.
 	 */
-	mw.hook( 'codeEditor.configure' ).add( function ( session ) {
+	mw.hook( 'codeEditor.configure' ).add( ( session ) => {
 		session.setOptions( {
 			useSoftTabs: true,
 			tabSize: 2
diff --git a/resources/handlers/mw.ApiUploadFormDataHandler.js b/resources/handlers/mw.ApiUploadFormDataHandler.js
index d4ec9b1..e1a571f 100644
--- a/resources/handlers/mw.ApiUploadFormDataHandler.js
+++ b/resources/handlers/mw.ApiUploadFormDataHandler.js
@@ -18,7 +18,7 @@
 		this.transport = new mw.FormDataTransport(
 			this.api,
 			this.formData
-		).on( 'update-stage', function ( stage ) {
+		).on( 'update-stage', ( stage ) => {
 			upload.ui.setStatus( 'mediauploader-' + stage );
 		} );
 	};
@@ -33,15 +33,15 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.ApiUploadFormDataHandler.prototype.submit = function () {
-		var handler = this;
+		const handler = this;
 
-		return this.configureEditToken().then( function () {
+		return this.configureEditToken().then( () => {
 			handler.beginTime = Date.now();
 			handler.upload.ui.setStatus( 'mediauploader-transport-started' );
 			handler.upload.ui.showTransportProgress();
 
 			return handler.transport.upload( handler.upload.file, handler.upload.title.getMainText() )
-				.progress( function ( fraction ) {
+				.progress( ( fraction ) => {
 					if ( handler.upload.state === 'aborted' ) {
 						handler.abort();
 						return;
@@ -61,9 +61,9 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.ApiUploadFormDataHandler.prototype.configureEditToken = function () {
-		var handler = this;
+		const handler = this;
 
-		return this.api.getEditToken().then( function ( token ) {
+		return this.api.getEditToken().then( ( token ) => {
 			handler.formData.token = token;
 		} );
 	};
diff --git a/resources/handlers/mw.ApiUploadHandler.js b/resources/handlers/mw.ApiUploadHandler.js
index e84b50a..93beff8 100644
--- a/resources/handlers/mw.ApiUploadHandler.js
+++ b/resources/handlers/mw.ApiUploadHandler.js
@@ -1,5 +1,5 @@
 ( function () {
-	var NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;
+	const NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;
 
 	/**
 	 * @param {mw.UploadWizardUpload} upload
@@ -51,7 +51,7 @@
 	 * @param {Object} result
 	 */
 	mw.ApiUploadHandler.prototype.setTransported = function ( result ) {
-		var code;
+		let code;
 		if ( result.upload && result.upload.warnings ) {
 			for ( code in result.upload.warnings ) {
 				if ( !this.isIgnoredWarning( code ) ) {
@@ -81,7 +81,7 @@
 	 * @param {Object} result The API result in parsed JSON form
 	 */
 	mw.ApiUploadHandler.prototype.setTransportWarning = function ( code, result ) {
-		var param, duplicates, links;
+		let param, duplicates, links;
 
 		switch ( code ) {
 			case 'duplicate':
@@ -124,7 +124,7 @@
 	 * @param {Object} result The API result in parsed JSON form
 	 */
 	mw.ApiUploadHandler.prototype.setTransportError = function ( code, result ) {
-		var $extra;
+		let $extra;
 
 		if ( code === 'badtoken' ) {
 			this.api.badToken( 'csrf' );
@@ -142,10 +142,10 @@
 				title: mw.message( 'mediauploader-override-upload' ).text(),
 				flags: 'progressive',
 				framed: false
-			} ).on( 'click', function () {
+			} ).on( 'click', () => {
 				// No need to ignore the error, AbuseFilter will only return it once
 				this.start();
-			}.bind( this ) ).$element;
+			} ).$element;
 		}
 
 		this.setError( code, result.errors[ 0 ].html, $extra );
@@ -161,18 +161,18 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.ApiUploadHandler.prototype.processDuplicateError = function ( code, result, duplicates ) {
-		var files = this.getFileLinks( duplicates ),
+		const files = this.getFileLinks( duplicates ),
 			unknownAmount = duplicates.length - Object.keys( files ).length;
 
 		return this.getDuplicateSource( Object.keys( files ) ).then(
-			function ( data ) {
+			( data ) => {
 				this.setDuplicateError( code, result, data.local, data.foreign, unknownAmount );
-			}.bind( this ),
-			function () {
+			},
+			() => {
 				// if anything goes wrong trying to figure out the source of
 				// duplicates, just move on with local duplicate handling
 				this.setDuplicateError( code, result, files, {}, unknownAmount );
-			}.bind( this )
+			}
 		);
 	};
 
@@ -181,8 +181,8 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.ApiUploadHandler.prototype.getDuplicateSource = function ( duplicates ) {
-		return this.getImageInfo( duplicates, 'url' ).then( function ( result ) {
-			var local = [],
+		return this.getImageInfo( duplicates, 'url' ).then( ( result ) => {
+			const local = [],
 				foreign = [],
 				normalized = [];
 
@@ -192,13 +192,13 @@
 
 			// map of normalized titles, so we can find original title
 			if ( result.query.normalized ) {
-				result.query.normalized.forEach( function ( data ) {
+				result.query.normalized.forEach( ( data ) => {
 					normalized[ data.to ] = data.from;
 				} );
 			}
 
-			Object.keys( result.query.pages ).forEach( function ( pageId ) {
-				var page = result.query.pages[ pageId ],
+			Object.keys( result.query.pages ).forEach( ( pageId ) => {
+				const page = result.query.pages[ pageId ],
 					title = page.title in normalized ? normalized[ page.title ] : page.title;
 				if ( page.imagerepository === 'local' ) {
 					local[ title ] = page.imageinfo[ 0 ].descriptionurl;
@@ -221,7 +221,7 @@
 	 * @param {number} unknownAmount Amount of unknown filenames (e.g. revdeleted)
 	 */
 	mw.ApiUploadHandler.prototype.setDuplicateError = function ( code, result, localDuplicates, foreignDuplicates, unknownAmount ) {
-		var allDuplicates = Object.assign( {}, localDuplicates, foreignDuplicates ),
+		let allDuplicates = Object.assign( {}, localDuplicates, foreignDuplicates ),
 			$extra = $( '<div>' ),
 			$ul = $( '<ul>' ).appendTo( $extra ),
 			$a,
@@ -230,8 +230,8 @@
 
 		unknownAmount = unknownAmount || 0;
 
-		Object.keys( allDuplicates ).forEach( function ( filename ) {
-			var href = allDuplicates[ filename ];
+		Object.keys( allDuplicates ).forEach( ( filename ) => {
+			const href = allDuplicates[ filename ];
 			$a = $( '<a>' ).text( filename );
 			$a.attr( { href: href, target: '_blank' } );
 			$ul.append( $( '<li>' ).append( $a ) );
@@ -254,11 +254,11 @@
 				title: mw.message( 'mediauploader-override-upload' ).text(),
 				flags: 'progressive',
 				framed: false
-			} ).on( 'click', function () {
+			} ).on( 'click', () => {
 				// mark this warning as ignored & process the API result again
 				this.ignoreWarning( 'duplicate' );
 				this.setTransported( result );
-			}.bind( this ) );
+			} );
 
 			override.$element.appendTo( $extra );
 		}
@@ -274,17 +274,17 @@
 	 * @param {string} duplicate Duplicate filename
 	 */
 	mw.ApiUploadHandler.prototype.setDuplicateArchiveError = function ( code, result, duplicate ) {
-		var filename = mw.Title.makeTitle( NS_FILE, duplicate ).getPrefixedText(),
+		const filename = mw.Title.makeTitle( NS_FILE, duplicate ).getPrefixedText(),
 			uploadDuplicate = new OO.ui.ButtonWidget( {
 				label: mw.message( 'mediauploader-override' ).text(),
 				title: mw.message( 'mediauploader-override-upload' ).text(),
 				flags: 'progressive',
 				framed: false
-			} ).on( 'click', function () {
+			} ).on( 'click', () => {
 				// mark this warning as ignored & process the API result again
 				this.ignoreWarning( 'duplicate-archive' );
 				this.setTransported( result );
-			}.bind( this ) );
+			} );
 
 		this.setError( code, mw.message( 'file-deleted-duplicate', filename ).parse(), uploadDuplicate.$element );
 	};
@@ -310,10 +310,10 @@
 	 * @return {Object} Map of [prefixed filename => url]
 	 */
 	mw.ApiUploadHandler.prototype.getFileLinks = function ( filenames ) {
-		var files = [];
+		const files = [];
 
-		filenames.forEach( function ( filename ) {
-			var title;
+		filenames.forEach( ( filename ) => {
+			let title;
 			try {
 				title = mw.Title.makeTitle( NS_FILE, filename );
 				files[ title.getPrefixedText() ] = title.getUrl( {} );
@@ -357,6 +357,6 @@
 	 * @return {boolean}
 	 */
 	mw.ApiUploadHandler.prototype.isIgnoredWarning = function ( code ) {
-		return this.ignoreWarnings.indexOf( code ) > -1;
+		return this.ignoreWarnings.includes( code );
 	};
 }( mw.uploadWizard ) );
diff --git a/resources/jquery.arrowSteps/jquery.arrowSteps.js b/resources/jquery.arrowSteps/jquery.arrowSteps.js
index 81115f8..b098721 100644
--- a/resources/jquery.arrowSteps/jquery.arrowSteps.js
+++ b/resources/jquery.arrowSteps/jquery.arrowSteps.js
@@ -35,7 +35,7 @@
 	 * @chainable
 	 */
 	$.fn.arrowSteps = function () {
-		var $steps, width,
+		let $steps, width,
 			$el = this;
 
 		$el.addClass( 'arrowSteps' );
@@ -67,10 +67,10 @@
 	 * @param {string} selector
 	 */
 	$.fn.arrowStepsHighlight = function ( selector ) {
-		var $previous,
+		let $previous,
 			$steps = this.data( 'arrowSteps' );
 		$steps.each( function () {
-			var $step = $( this );
+			const $step = $( this );
 			if ( $step.is( selector ) ) {
 				if ( $previous ) {
 					$previous.addClass( 'tail' );
diff --git a/resources/jquery/jquery.morphCrossfade.js b/resources/jquery/jquery.morphCrossfade.js
index bc159ca..d6f79f3 100644
--- a/resources/jquery/jquery.morphCrossfade.js
+++ b/resources/jquery/jquery.morphCrossfade.js
@@ -47,7 +47,7 @@
 	 * @chainable
 	 */
 	$.fn.morphCrossfader = function () {
-		var $this = $( this );
+		const $this = $( this );
 		// the elements that are immediate children are the crossfadables
 		// they must all be "on top" of each other, so position them relative
 		$this.css( {
@@ -64,7 +64,7 @@
 		// should achieve the same result as crossfade( this.children().first() ) but without
 		// animation etc.
 		$this.each( function () {
-			var $container = $( this );
+			const $container = $( this );
 			$container.morphCrossfade( $container.children().first(), 0 );
 		} );
 
@@ -80,14 +80,14 @@
 	 * @chainable
 	 */
 	$.fn.morphCrossfade = function ( newPanelSelector, speed ) {
-		var $this = $( this );
+		const $this = $( this );
 
 		if ( typeof speed === 'undefined' ) {
 			speed = 400;
 		}
 
 		$this.each( function () {
-			var $container = $( this ),
+			const $container = $( this ),
 				$oldPanel = $( $container.data( 'crossfadeDisplay' ) ),
 				$newPanel = ( typeof newPanelSelector === 'string' ) ?
 					$container.find( newPanelSelector ) : $( newPanelSelector );
@@ -102,7 +102,7 @@
 					$oldPanel.css( { position: 'absolute' } );
 					// fade WITHOUT hiding when opacity = 0
 					// eslint-disable-next-line no-jquery/no-animate
-					$oldPanel.stop().animate( { opacity: 0 }, speed, 'linear', function () {
+					$oldPanel.stop().animate( { opacity: 0 }, speed, 'linear', () => {
 						$oldPanel.css( { visibility: 'hidden' } );
 					} );
 				}
@@ -110,7 +110,7 @@
 
 				$newPanel.css( { visibility: 'visible' } );
 				// eslint-disable-next-line no-jquery/no-animate
-				$container.stop().animate( { height: $newPanel.outerHeight() }, speed, 'linear', function () {
+				$container.stop().animate( { height: $newPanel.outerHeight() }, speed, 'linear', () => {
 					// we place it back into the flow, in case its size changes.
 					$newPanel.css( { position: 'relative' } );
 					// and allow the container to grow with it.
diff --git a/resources/mw.DestinationChecker.js b/resources/mw.DestinationChecker.js
index 6768d22..bcc18f6 100644
--- a/resources/mw.DestinationChecker.js
+++ b/resources/mw.DestinationChecker.js
@@ -22,13 +22,11 @@
 			return $.when(
 				this.checkUnique( title ),
 				this.checkBlacklist( title )
-			).then( function ( unique, blacklist ) {
-				return {
-					unique: unique,
-					blacklist: blacklist,
-					title: title
-				};
-			} );
+			).then( ( unique, blacklist ) => ( {
+				unique: unique,
+				blacklist: blacklist,
+				title: title
+			} ) );
 		},
 
 		/**
@@ -43,7 +41,7 @@
 		 *  {string} [return.done.blacklistLine] See mw.Api#isBlacklisted
 		 */
 		checkBlacklist: function ( title ) {
-			var checker = this;
+			const checker = this;
 
 			/**
 			 * Process result of a TitleBlacklist API call.
@@ -53,7 +51,7 @@
 			 * @return {Object}
 			 */
 			function blacklistResultProcessor( blacklistResult ) {
-				var result;
+				let result;
 
 				if ( blacklistResult === false ) {
 					result = { notBlacklisted: true };
@@ -74,12 +72,10 @@
 				return $.Deferred().resolve( this.cachedBlacklist[ title ] );
 			}
 
-			return mw.loader.using( 'mediawiki.api.titleblacklist' ).then( function () {
-				return checker.api.isBlacklisted( title ).then( blacklistResultProcessor );
-			}, function () {
+			return mw.loader.using( 'mediawiki.api.titleblacklist' ).then( () => checker.api.isBlacklisted( title ).then( blacklistResultProcessor ), () =>
 				// it's not blacklisted, because the API isn't even available
-				return $.Deferred().resolve( { notBlacklisted: true, unavailable: true } );
-			} );
+				 $.Deferred().resolve( { notBlacklisted: true, unavailable: true } )
+			 );
 		},
 
 		/**
@@ -95,7 +91,7 @@
 		 *  {string} [return.done.href] URL to file description page
 		 */
 		checkUnique: function ( title ) {
-			var checker = this,
+			let checker = this,
 				NS_FILE = mw.config.get( 'wgNamespaceIds' ).file,
 				titleObj, prefix, ext;
 
@@ -112,7 +108,7 @@
 			 * @return {Object}
 			 */
 			function checkUniqueProcessor( data ) {
-				var result, protection, pageId, ntitle, ntitleObj, img;
+				let result, protection, pageId, ntitle, ntitleObj, img;
 
 				result = { isUnique: true };
 
@@ -124,8 +120,8 @@
 					if ( data.query.pages[ -1 ] && !data.query.pages[ -1 ].imageinfo ) {
 						protection = data.query.pages[ -1 ].protection;
 						if ( protection && protection.length > 0 ) {
-							protection.forEach( function ( val ) {
-								if ( mw.config.get( 'wgUserGroups' ).indexOf( val.level ) === -1 ) {
+							protection.forEach( ( val ) => {
+								if ( !mw.config.get( 'wgUserGroups' ).includes( val.level ) ) {
 									result = {
 										isUnique: true,
 										isProtected: true
@@ -211,8 +207,8 @@
 					iiprop: 'url|mime|size',
 					iiurlwidth: 150
 				} ).then( checkUniqueProcessor )
-			).then( function ( exact, fuzzy ) {
-				var result;
+			).then( ( exact, fuzzy ) => {
+				let result;
 				if ( !exact.isUnique || exact.isProtected ) {
 					result = exact;
 				} else if ( !fuzzy.isUnique || fuzzy.isProtected ) {
diff --git a/resources/mw.Escaper.js b/resources/mw.Escaper.js
index d34b1d4..b5cfb7e 100644
--- a/resources/mw.Escaper.js
+++ b/resources/mw.Escaper.js
@@ -18,14 +18,12 @@
 		 * @return {string}
 		 */
 		escapePipes: function ( wikitext ) {
-			var extractedTemplates, extractedLinks;
+			let extractedTemplates, extractedLinks;
 
 			// Pipes (`|`) must be escaped because we'll be inserting this
 			// content into a templates & pipes would mess up the syntax.
 			// First, urlencode pipes inside links:
-			wikitext = wikitext.replace( /\bhttps?:\/\/[^\s]+/g, function ( match ) {
-				return match.replace( /\|/g, '%7C' );
-			} );
+			wikitext = wikitext.replace( /\bhttps?:\/\/[^\s]+/g, ( match ) => match.replace( /\|/g, '%7C' ) );
 
 			// Second, pipes can be valid inside other templates or links in
 			// wikitext, so we'll first extract those from the content, then
@@ -51,7 +49,7 @@
 		 * @return {Array} [{string} wikitext, {Object} replacements]
 		 */
 		extractTemplates: function ( wikitext ) {
-			var extracts = {},
+			let extracts = {},
 				previousExtracts = {},
 				extracted = wikitext,
 				// the regex explained:
@@ -62,7 +60,7 @@
 				//   sequence, generated by an earlier run of this regex
 				regex = /\{\{([^{]|\{(?!\{)|\{\{[0-9]+\}\})*?\}\}/g,
 				callback = function ( match ) {
-					var replacement = '{{' + Object.keys( extracts ).length + '}}';
+					const replacement = '{{' + Object.keys( extracts ).length + '}}';
 
 					// safeguard for not replacing already-replaced matches
 					// this makes sure that when real content contains something
@@ -96,10 +94,10 @@
 		 * @return {Array} [{string} wikitext, {Object} replacements]
 		 */
 		extractLinks: function ( wikitext ) {
-			var extracts = {};
+			const extracts = {};
 
-			wikitext = wikitext.replace( /\[\[.*?\]\]/g, function ( match ) {
-				var replacement = '[[' + Object.keys( extracts ).length + ']]';
+			wikitext = wikitext.replace( /\[\[.*?\]\]/g, ( match ) => {
+				const replacement = '[[' + Object.keys( extracts ).length + ']]';
 				extracts[ replacement ] = match;
 				return replacement;
 			} );
@@ -117,10 +115,10 @@
 		restoreExtracts: function ( wikitext, replacements ) {
 			// turn search keys into a regular expression, allowing us to match
 			// all of them at once
-			var searchValues = Object.keys( replacements ).map( mw.util.escapeRegExp ),
+			const searchValues = Object.keys( replacements ).map( mw.util.escapeRegExp ),
 				searchRegex = new RegExp( '(' + searchValues.join( '|' ) + ')', 'g' ),
 				callback = function ( match ) {
-					var replacement = replacements[ match ];
+					const replacement = replacements[ match ];
 
 					// we matched something that has no replacement, must be valid
 					// user input that just happens to look like on of the
diff --git a/resources/mw.GroupProgressBar.js b/resources/mw.GroupProgressBar.js
index 10c2bbe..d9c5fe3 100644
--- a/resources/mw.GroupProgressBar.js
+++ b/resources/mw.GroupProgressBar.js
@@ -56,30 +56,30 @@
 		 * loop around the uploads, summing certain properties for a weighted total fraction
 		 */
 		start: function () {
-			var bar = this,
+			let bar = this,
 				shown = false;
 
 			this.setBeginTime();
 
 			function displayer() {
-				var totalWeight = 0.0,
+				let totalWeight = 0.0,
 					fraction = 0.0,
 					successStateCount = 0,
 					errorStateCount = 0,
 					hasData = false;
 
-				bar.uploads.forEach( function ( upload ) {
+				bar.uploads.forEach( ( upload ) => {
 					totalWeight += upload[ bar.weightProperty ];
 				} );
 
-				bar.uploads.forEach( function ( upload ) {
+				bar.uploads.forEach( ( upload ) => {
 					if ( upload.state === 'aborted' ) {
 						return;
 					}
-					if ( bar.successStates.indexOf( upload.state ) !== -1 ) {
+					if ( bar.successStates.includes( upload.state ) ) {
 						successStateCount++;
 					}
-					if ( bar.errorStates.indexOf( upload.state ) !== -1 ) {
+					if ( bar.errorStates.includes( upload.state ) ) {
 						errorStateCount++;
 					}
 					if ( upload[ bar.progressProperty ] !== undefined ) {
@@ -106,7 +106,7 @@
 				} else {
 					bar.showProgress( 1.0 );
 					bar.finished = true;
-					setTimeout( function () {
+					setTimeout( () => {
 						bar.hideBar();
 					}, 500 );
 				}
@@ -142,7 +142,7 @@
 		 * @param {number} fraction The amount of whatever it is that's done whatever it's done
 		 */
 		showProgress: function ( fraction ) {
-			var t, timeString,
+			let t, timeString,
 				remainingTime = this.getRemainingTime( fraction );
 
 			this.progressBarWidget.setProgress( parseInt( fraction * 100, 10 ) );
@@ -168,7 +168,7 @@
 		 * @return {number} Estimated time remaining (in milliseconds)
 		 */
 		getRemainingTime: function ( fraction ) {
-			var elapsedTime, rate;
+			let elapsedTime, rate;
 			if ( this.beginTime ) {
 				elapsedTime = Date.now() - this.beginTime;
 				if ( fraction > 0.0 && elapsedTime > 0 ) { // or some other minimums for good data
@@ -185,7 +185,7 @@
 		 * @param {number} completed The number of items that have done whatever has been done e.g. in "uploaded 2 of 5", this is the 2
 		 */
 		showCount: function ( completed ) {
-			var total = this.uploads.length - this.countRemoved();
+			const total = this.uploads.length - this.countRemoved();
 			this.$selector
 				.find( '.mediauploader-count' )
 				// Hide if there are no uploads, show otherwise
@@ -194,8 +194,8 @@
 		},
 
 		countRemoved: function () {
-			var count = 0;
-			this.uploads.forEach( function ( upload ) {
+			let count = 0;
+			this.uploads.forEach( ( upload ) => {
 				if ( !upload || upload.state === 'aborted' ) {
 					count += 1;
 				}
diff --git a/resources/mw.QuickTitleChecker.js b/resources/mw.QuickTitleChecker.js
index 589cf37..d6723d5 100644
--- a/resources/mw.QuickTitleChecker.js
+++ b/resources/mw.QuickTitleChecker.js
@@ -70,10 +70,10 @@
 	 *   Possible error codes are 'invalid', 'senselessimagename', 'thumbnail', 'extension'.
 	 */
 	mw.QuickTitleChecker.checkTitle = function ( title ) {
-		var errors = [];
-		Object.keys( mw.QuickTitleChecker.regexSets ).forEach( function ( setName ) {
-			var regexes = mw.QuickTitleChecker.regexSets[ setName ];
-			regexes.forEach( function ( regex ) {
+		const errors = [];
+		Object.keys( mw.QuickTitleChecker.regexSets ).forEach( ( setName ) => {
+			const regexes = mw.QuickTitleChecker.regexSets[ setName ];
+			regexes.forEach( ( regex ) => {
 				if ( title.match( regex ) ) {
 					errors.push( setName );
 				}
diff --git a/resources/mw.UploadWizard.js b/resources/mw.UploadWizard.js
index a96c38e..5f3a29e 100644
--- a/resources/mw.UploadWizard.js
+++ b/resources/mw.UploadWizard.js
@@ -7,7 +7,7 @@
 ( function ( uw ) {
 
 	mw.UploadWizard = function ( config ) {
-		var maxSimPref;
+		let maxSimPref;
 
 		this.api = this.getApi( { ajax: { timeout: 0 } } );
 
@@ -49,7 +49,7 @@
 		createInterface: function ( selector ) {
 			this.ui = new uw.ui.Wizard( selector );
 
-			this.initialiseSteps().then( function ( steps ) {
+			this.initialiseSteps().then( ( steps ) => {
 				// "select" the first step - highlight, make it visible, hide all others
 				steps[ 0 ].load( [] );
 			} );
@@ -61,7 +61,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		initialiseSteps: function () {
-			var self = this,
+			let self = this,
 				steps = [],
 				i,
 				uploadStep;
@@ -98,7 +98,7 @@
 			steps[ steps.length - 1 ].setNextStep( uploadStep );
 
 			return $.Deferred().resolve( steps ).promise()
-				.always( function ( stepsInner ) {
+				.always( ( stepsInner ) => {
 					self.steps = stepsInner;
 					self.ui.initialiseSteps( stepsInner );
 				} );
@@ -119,10 +119,10 @@
 		 * @return {mw.Api}
 		 */
 		getApi: function ( options ) {
-			var api = new mw.Api( options );
+			const api = new mw.Api( options );
 
 			api.ajax = function ( parameters, ajaxOptions ) {
-				var original, override;
+				let original, override;
 
 				Object.assign( parameters, {
 					errorformat: 'html',
@@ -137,8 +137,8 @@
 				// output is always, reliably, in the same format
 				override = original.then(
 					null, // done handler - doesn't need overriding
-					function ( code, result ) { // fail handler
-						var response = { errors: [ {
+					( code, result ) => { // fail handler
+						let response = { errors: [ {
 							code: code,
 							html: result.textStatus || mw.message( 'api-clientside-error-invalidresponse' ).parse()
 						} ] };
@@ -183,10 +183,10 @@
 	 * @return {mw.deed.Abstract[]}
 	 */
 	mw.UploadWizard.getLicensingDeeds = function ( uploads, config ) {
-		var deed, api,
+		let deed, api,
 			deeds = {},
-			doOwnWork = config.licensing.showTypes.indexOf( 'ownWork' ) > -1,
-			doThirdParty = config.licensing.showTypes.indexOf( 'thirdParty' ) > -1;
+			doOwnWork = config.licensing.showTypes.includes( 'ownWork' ),
+			doThirdParty = config.licensing.showTypes.includes( 'thirdParty' );
 
 		if ( !config.licensing.enabled ) {
 			return {
diff --git a/resources/mw.UploadWizardDeedChooser.js b/resources/mw.UploadWizardDeedChooser.js
index 3cf37e3..88a7429 100644
--- a/resources/mw.UploadWizardDeedChooser.js
+++ b/resources/mw.UploadWizardDeedChooser.js
@@ -9,7 +9,7 @@
 	 * @param {mw.UploadWizardUpload[]} uploads Uploads that this applies to (this is just to make deleting and plurals work)
 	 */
 	mw.UploadWizardDeedChooser = function ( config, selector, deeds, uploads ) {
-		var chooser = this;
+		const chooser = this;
 		this.$selector = $( selector );
 		this.uploads = uploads;
 		this.deeds = deeds;
@@ -20,8 +20,8 @@
 
 		this.onLayoutReady = function () {};
 
-		Object.keys( this.deeds ).forEach( function ( name ) {
-			var deed = chooser.deeds[ name ],
+		Object.keys( this.deeds ).forEach( ( name ) => {
+			const deed = chooser.deeds[ name ],
 				radio = new OO.ui.RadioSelectWidget( {
 					items: [ new OO.ui.RadioOptionWidget( {
 						// eslint-disable-next-line mediawiki/msg-doc
@@ -53,7 +53,7 @@
 				if ( config.licensing.defaultType.toLowerCase() === deed.name ) {
 					chooser.onLayoutReady = chooser.selectDeed.bind( chooser, deed );
 				}
-				radio.on( 'choose', function () {
+				radio.on( 'choose', () => {
 					chooser.selectDeed( deed );
 				} );
 			}
@@ -84,7 +84,7 @@
 		uploads: [],
 
 		selectDeed: function ( deed ) {
-			var $deedInterface = this.$selector.find( '.mediauploader-deed.mediauploader-deed-' + deed.name );
+			const $deedInterface = this.$selector.find( '.mediauploader-deed.mediauploader-deed-' + deed.name );
 
 			this.choose( deed );
 			this.selectDeedInterface( $deedInterface );
@@ -92,11 +92,11 @@
 		},
 
 		choose: function ( deed ) {
-			var chooser = this;
+			const chooser = this;
 
 			this.deed = deed;
 
-			this.uploads.forEach( function ( upload ) {
+			this.uploads.forEach( ( upload ) => {
 				upload.deedChooser = chooser;
 			} );
 
@@ -112,7 +112,7 @@
 		deselectDeedInterface: function ( $deedSelector ) {
 			$deedSelector.removeClass( 'selected' );
 			$deedSelector.find( '.mediauploader-deed-form' ).each( function () {
-				var $form = $( this );
+				const $form = $( this );
 				// Prevent validation of deselected deeds by disabling all form inputs
 				// TODO: Use a tag selector
 				// eslint-disable-next-line no-jquery/no-sizzle
@@ -134,13 +134,13 @@
 		 * @param {jQuery} $deedSelector
 		 */
 		selectDeedInterface: function ( $deedSelector ) {
-			var $otherDeeds = $deedSelector.siblings().filter( '.mediauploader-deed' );
+			const $otherDeeds = $deedSelector.siblings().filter( '.mediauploader-deed' );
 			this.deselectDeedInterface( $otherDeeds );
 			// FIXME: Use CSS transition
 			// eslint-disable-next-line no-jquery/no-fade
 			$deedSelector.addClass( 'selected' ).fadeTo( 'fast', 1.0 );
 			$deedSelector.find( '.mediauploader-deed-form' ).each( function () {
-				var $form = $( this );
+				const $form = $( this );
 				// (Re-)enable all form inputs
 				// TODO: Use a tag selector
 				// eslint-disable-next-line no-jquery/no-sizzle
@@ -173,7 +173,7 @@
 		 * @param {Object} serialized
 		 */
 		setSerialized: function ( serialized ) {
-			var deed;
+			let deed;
 
 			if ( serialized.name && serialized.name in this.deeds ) {
 				deed = this.deeds[ serialized.name ];
diff --git a/resources/mw.UploadWizardDetails.js b/resources/mw.UploadWizardDetails.js
index c47e21e..30a63a6 100644
--- a/resources/mw.UploadWizardDetails.js
+++ b/resources/mw.UploadWizardDetails.js
@@ -1,6 +1,6 @@
 ( function ( uw ) {
 
-	var NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;
+	const NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;
 
 	/**
 	 * Object that represents the Details (step 2) portion of the UploadWizard
@@ -42,7 +42,7 @@
 		 * Build the interface and attach all elements - do this on demand.
 		 */
 		buildInterface: function () {
-			var $moreDetailsWrapperDiv, $moreDetailsDiv,
+			let $moreDetailsWrapperDiv, $moreDetailsDiv,
 				fKey, fSpec, fieldWidget, fieldWrapper, fConfigBase,
 				details = this,
 				config = mw.UploadWizard.config;
@@ -135,7 +135,7 @@
 				this.fieldMap[ fKey ] = fieldWidget;
 			}
 
-			this.fieldList.sort( function ( a, b ) {
+			this.fieldList.sort( ( a, b ) => {
 				if ( a.order < b.order ) {
 					return -1;
 				}
@@ -175,7 +175,7 @@
 					$moreDetailsDiv.append( fieldWrapper.$element );
 					// If something changes the input "hidden" in the collapsed section,
 					// expand it.
-					fieldWidget.on( 'change', function () {
+					fieldWidget.on( 'change', () => {
 						$moreDetailsWrapperDiv.data( 'mw-collapsible' ).expand();
 					} );
 				} else {
@@ -194,7 +194,7 @@
 				)
 				.makeCollapsible( { collapsed: true } );
 
-			this.$form.on( 'submit', function ( e ) {
+			this.$form.on( 'submit', ( e ) => {
 				// Prevent actual form submission
 				e.preventDefault();
 			} );
@@ -211,10 +211,10 @@
 				flags: 'destructive',
 				icon: 'trash',
 				framed: false
-			} ).on( 'click', function () {
+			} ).on( 'click', () => {
 				OO.ui.confirm( mw.message( 'mediauploader-license-confirm-remove' ).text(), {
 					title: mw.message( 'mediauploader-license-confirm-remove-title' ).text()
-				} ).done( function ( confirmed ) {
+				} ).done( ( confirmed ) => {
 					if ( confirmed ) {
 						details.upload.emit( 'remove-upload' );
 					}
@@ -272,7 +272,7 @@
 		 * Will only append once.
 		 */
 		attach: function () {
-			var $window = $( window ),
+			const $window = $( window ),
 				details = this;
 
 			function maybeBuild() {
@@ -301,7 +301,7 @@
 		 * @return {mw.Title|null}
 		 */
 		getTitle: function () {
-			var titleField = mw.UploadWizard.config.content.titleField;
+			const titleField = mw.UploadWizard.config.content.titleField;
 
 			// title will not be set until we've actually submitted the file
 			if ( this.title === undefined ) {
@@ -320,7 +320,7 @@
 		 * @chainable
 		 */
 		setDuplicateTitleError: function () {
-			var titleField = mw.UploadWizard.config.content.titleField;
+			const titleField = mw.UploadWizard.config.content.titleField;
 			// TODO This should give immediate response, not only when submitting the form
 			this.fieldWrapperMap[ titleField ].setErrors(
 				[ mw.message( 'mediauploader-error-title-duplicate' ) ]
@@ -357,9 +357,7 @@
 		 *   empty arrays.
 		 */
 		getErrors: function () {
-			return $.when.apply( $, this.getAllFields().map( function ( fieldLayout ) {
-				return fieldLayout.fieldWidget.getErrors();
-			} ) );
+			return $.when.apply( $, this.getAllFields().map( ( fieldLayout ) => fieldLayout.fieldWidget.getErrors() ) );
 		},
 
 		/**
@@ -368,9 +366,7 @@
 		 * @return {jQuery.Promise} Same as #getErrors
 		 */
 		getWarnings: function () {
-			return $.when.apply( $, this.getAllFields().map( function ( fieldLayout ) {
-				return fieldLayout.fieldWidget.getWarnings();
-			} ) );
+			return $.when.apply( $, this.getAllFields().map( ( fieldLayout ) => fieldLayout.fieldWidget.getWarnings() ) );
 		},
 
 		/**
@@ -380,12 +376,12 @@
 		 * @return {jQuery.Promise} Combined promise of all fields' validation results.
 		 */
 		checkValidity: function ( thorough ) {
-			var fields = this.getAllFields();
+			const fields = this.getAllFields();
 
-			return $.when.apply( $, fields.map( function ( fieldLayout ) {
+			return $.when.apply( $, fields.map( ( fieldLayout ) =>
 				// Update any error/warning messages
-				return fieldLayout.checkValidity( thorough );
-			} ) );
+				 fieldLayout.checkValidity( thorough )
+			 ) );
 		},
 
 		/**
@@ -394,7 +390,7 @@
 		 * @return {string}
 		 */
 		getThumbnailCaption: function () {
-			var captionField = mw.UploadWizard.config.content.captionField;
+			const captionField = mw.UploadWizard.config.content.captionField;
 
 			// The caption field should be one of:
 			// TextWidget, SingleLanguageInputWidget, MultipleLanguageInputWidget
@@ -409,7 +405,7 @@
 		 * @param {uw.DetailsWidget} widget
 		 */
 		prefillField: function ( fSpec, widget ) {
-			var dynPrefilled = false;
+			let dynPrefilled = false;
 
 			// Try dynamic prefilling, if requested and available for this type
 			if ( fSpec.autoFill ) {
@@ -447,7 +443,7 @@
 		 * @return {boolean}
 		 */
 		prefillDate: function ( widget ) {
-			var dateObj, metadata, dateStr, saneTime,
+			let dateObj, metadata, dateStr, saneTime,
 				dateMode = 'calendar',
 				yyyyMmDdRegex = /^(\d\d\d\d)[:/-](\d\d)[:/-](\d\d)\D.*/,
 				timeRegex = /\D(\d\d):(\d\d):(\d\d)/;
@@ -458,7 +454,7 @@
 			}
 
 			function getSaneTime( date ) {
-				var str = '';
+				let str = '';
 
 				str += pad( date.getHours() ) + ':';
 				str += pad( date.getMinutes() ) + ':';
@@ -469,8 +465,8 @@
 
 			if ( this.upload.imageinfo.metadata ) {
 				metadata = this.upload.imageinfo.metadata;
-				[ 'datetimeoriginal', 'datetimedigitized', 'datetime', 'date' ].some( function ( propName ) {
-					var matches, timeMatches,
+				[ 'datetimeoriginal', 'datetimedigitized', 'datetime', 'date' ].some( ( propName ) => {
+					let matches, timeMatches,
 						dateInfo = metadata[ propName ];
 					if ( dateInfo ) {
 						matches = dateInfo.trim().match( yyyyMmDdRegex );
@@ -551,7 +547,7 @@
 		 * @return {boolean}
 		 */
 		prefillDescription: function ( type, widget ) {
-			var m, descText;
+			let m, descText;
 
 			if (
 				widget.getWikiText() === '' &&
@@ -601,7 +597,7 @@
 		 * @return {boolean}
 		 */
 		prefillLocation: function ( widget ) {
-			var dir,
+			let dir,
 				m = this.upload.imageinfo.metadata,
 				modified = false,
 				values = {};
@@ -652,7 +648,7 @@
 		 * @return {Object}
 		 */
 		getLanguageOptions: function () {
-			var languages, code;
+			let languages, code;
 
 			languages = {};
 			for ( code in mw.UploadWizard.config.languages ) {
@@ -673,7 +669,7 @@
 		 * @return {Object.<string,Object>}
 		 */
 		getSerialized: function () {
-			var fieldWidget, serialized = {};
+			let fieldWidget, serialized = {};
 
 			if ( !this.interfaceBuilt ) {
 				// We don't have the interface yet, but it'll get filled out as
@@ -734,7 +730,7 @@
 		 * @return {string} wikitext representing all details
 		 */
 		getWikiText: function () {
-			var wikiText = mw.UploadWizard.config.content.wikitext,
+			let wikiText = mw.UploadWizard.config.content.wikitext,
 				substitutions = {}, substList = [],
 				deed = this.upload.deedChooser.deed,
 				fieldWidget, serialized, valueType, re, escapedKey, replaceValue;
@@ -750,7 +746,7 @@
 			}
 
 			function addSubstitution( key, value ) {
-				var v = value;
+				let v = value;
 				if ( key in substitutions ) {
 					return;
 				}
@@ -781,7 +777,7 @@
 					return;
 				}
 				// Also add "subfields" based on the serialized values. Just in case.
-				Object.keys( serialized ).forEach( function ( key ) {
+				Object.keys( serialized ).forEach( ( key ) => {
 					replaceValue = serialized[ key ];
 					valueType = typeof replaceValue;
 					if ( valueType === 'string' || valueType === 'number' || valueType === 'boolean' ) {
@@ -791,11 +787,11 @@
 			}, this );
 
 			// Do the substitutions
-			substList.forEach( function ( substKey ) {
+			substList.forEach( ( substKey ) => {
 				replaceValue = substitutions[ substKey ].trim();
 				escapedKey = substKey.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' );
 				re = new RegExp( '\\{\\{\\{ *' + escapedKey + ' *(\\|(.*?))?\\}\\}\\}', 'giu' );
-				wikiText = wikiText.replace( re, function ( match, _, defaultValue ) {
+				wikiText = wikiText.replace( re, ( match, _, defaultValue ) => {
 					if ( !replaceValue ) {
 						return defaultValue || '';
 					} else {
@@ -814,7 +810,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		submit: function () {
-			var details = this,
+			let details = this,
 				wikitext, promise;
 
 			this.$containerDiv.find( 'form' ).trigger( 'submit' );
@@ -827,7 +823,7 @@
 			wikitext = this.getWikiText();
 			promise = this.submitWikiText( wikitext );
 
-			return promise.then( function () {
+			return promise.then( () => {
 				details.showIndicator( 'success' );
 				details.setStatus( mw.message( 'mediauploader-published' ).text() );
 			} );
@@ -843,7 +839,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		submitWikiText: function ( wikiText ) {
-			var params,
+			let params,
 				tags = [ 'uploadwizard' ],
 				deed = this.upload.deedChooser.deed,
 				comment = '',
@@ -900,7 +896,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		submitWikiTextInternal: function ( params ) {
-			var details = this,
+			const details = this,
 				apiPromise = this.upload.api.postWithEditToken( params );
 
 			return apiPromise
@@ -910,7 +906,7 @@
 				.then( this.validateWikiTextSubmitResult.bind( this, params ) )
 				// making it here means the upload is a success, or it would've been
 				// rejected by now (either by HTTP status code, or in validateWikiTextSubmitResult)
-				.then( function ( result ) {
+				.then( ( result ) => {
 					details.title = mw.Title.makeTitle( 6, result.upload.filename );
 					details.upload.extractImageInfo( result.upload.imageinfo );
 					details.upload.thisProgress = 1.0;
@@ -918,7 +914,7 @@
 					return result;
 				} )
 				// uh-oh - something went wrong!
-				.catch( function ( code, result ) {
+				.catch( ( code, result ) => {
 					details.upload.state = 'error';
 					details.processError( code, result );
 					return $.Deferred().reject( code, result );
@@ -936,7 +932,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		validateWikiTextSubmitResult: function ( params, result ) {
-			var wx, warningsKeys, existingFile, existingFileUrl, existingFileExt, ourFileExt, code, message,
+			let wx, warningsKeys, existingFile, existingFileUrl, existingFileExt, ourFileExt, code, message,
 				details = this,
 				warnings = null,
 				ignoreTheseWarnings = false,
@@ -961,7 +957,7 @@
 						// * mediauploader-publish
 						// * mediauploader-assembling
 						this.setStatus( mw.message( 'mediauploader-' + result.upload.stage ).text() );
-						setTimeout( function () {
+						setTimeout( () => {
 							if ( details.upload.state !== 'aborted' ) {
 								details.submitWikiTextInternal( {
 									action: 'upload',
@@ -1055,7 +1051,7 @@
 		 * @param {string} html Error message to show.
 		 */
 		recoverFromError: function ( code, html ) {
-			var titleField = mw.UploadWizard.config.content.titleField;
+			const titleField = mw.UploadWizard.config.content.titleField;
 
 			this.upload.state = 'recoverable-error';
 			this.$dataDiv.morphCrossfade( '.detailsForm' );
@@ -1080,7 +1076,7 @@
 		 * @param {Object} result Result from ajax call
 		 */
 		processError: function ( code, result ) {
-			var recoverable = [
+			const recoverable = [
 				'abusefilter-disallowed',
 				'abusefilter-warning',
 				'spamblacklist',
@@ -1117,7 +1113,7 @@
 				code = 'ratelimited';
 			}
 
-			if ( recoverable.indexOf( code ) > -1 ) {
+			if ( recoverable.includes( code ) ) {
 				this.recoverFromError( code, result.errors[ 0 ].html );
 				return;
 			}
diff --git a/resources/mw.UploadWizardLicenseInput.js b/resources/mw.UploadWizardLicenseInput.js
index b3696aa..00416ef 100644
--- a/resources/mw.UploadWizardLicenseInput.js
+++ b/resources/mw.UploadWizardLicenseInput.js
@@ -14,7 +14,7 @@
 	 * @param {mw.Api} api API object, used for wikitext previews
 	 */
 	mw.UploadWizardLicenseInput = function ( config, count, api ) {
-		var self = this,
+		let self = this,
 			groups = [],
 			group;
 
@@ -45,7 +45,7 @@
 			group = new uw.LicenseGroup( config, this.type, this.api, this.count );
 			groups.push( group );
 		} else {
-			config.licenseGroups.forEach( function ( groupConfig ) {
+			config.licenseGroups.forEach( ( groupConfig ) => {
 				group = new uw.LicenseGroup( groupConfig, self.type, self.api, self.count );
 				groups.push( group );
 
@@ -54,8 +54,8 @@
 				// upon selecting a new item in any group, iterate the other groups and make
 				// sure they're updated accordingly, deselecting previously selected items
 				if ( self.type === 'radio' ) {
-					group.on( 'change', function ( currentGroup ) {
-						var value = currentGroup.getValue(),
+					group.on( 'change', ( currentGroup ) => {
+						const value = currentGroup.getValue(),
 							group2 = currentGroup.getGroup();
 						self.setValues( value, group2 );
 					} );
@@ -76,7 +76,7 @@
 
 	Object.assign( mw.UploadWizardLicenseInput.prototype, {
 		unload: function () {
-			this.getItems().forEach( function ( group ) {
+			this.getItems().forEach( ( group ) => {
 				group.unload();
 			} );
 		},
@@ -89,10 +89,10 @@
 		 * @param {string} [groupName] Name of group, when values are only relevant to this group
 		 */
 		setValues: function ( values, groupName ) {
-			var self = this,
+			const self = this,
 				selectedGroups = [];
 
-			this.getItems().forEach( function ( group ) {
+			this.getItems().forEach( ( group ) => {
 				if ( groupName === undefined || group.getGroup() === groupName ) {
 					group.setValue( values );
 					if ( Object.keys( group.getValue() ).length > 0 ) {
@@ -115,7 +115,7 @@
 				// 1 group
 				// in that case, we're only going to select the *last* occurrence, which is what
 				// a browser would do when trying to find/select a radio that occurs twice
-				selectedGroups.forEach( function ( group ) {
+				selectedGroups.forEach( ( group ) => {
 					group.setValue( {} );
 				} );
 			}
@@ -125,8 +125,8 @@
 		 * Set the default configured licenses
 		 */
 		setDefaultValues: function () {
-			var values = {};
-			this.defaults.forEach( function ( license ) {
+			const values = {};
+			this.defaults.forEach( ( license ) => {
 				values[ license ] = true;
 			} );
 			this.setValues( values );
@@ -139,11 +139,11 @@
 		 * @return {Object}
 		 */
 		getLicenses: function () {
-			var licenses = {};
+			const licenses = {};
 
-			this.getItems().forEach( function ( group ) {
-				var licenseNames = Object.keys( group.getValue() );
-				licenseNames.forEach( function ( name ) {
+			this.getItems().forEach( ( group ) => {
+				const licenseNames = Object.keys( group.getValue() );
+				licenseNames.forEach( ( name ) => {
 					licenses[ name ] = mw.UploadWizard.config.licenses[ name ] || {};
 				} );
 			} );
@@ -157,9 +157,7 @@
 		 * @return {string} of wikitext (empty string if no inputs set)
 		 */
 		getWikiText: function () {
-			return this.getItems().map( function ( group ) {
-				return group.getWikiText();
-			} ).join( '' ).trim();
+			return this.getItems().map( ( group ) => group.getWikiText() ).join( '' ).trim();
 		},
 
 		/**
@@ -169,7 +167,7 @@
 		 * @return {jQuery.Promise} Promise that resolves with an array of template names
 		 */
 		getUsedTemplates: function ( wikitext ) {
-			var input = this;
+			const input = this;
 
 			if ( wikitext in this.templateCache ) {
 				return $.Deferred().resolve( this.templateCache[ wikitext ] ).promise();
@@ -181,8 +179,8 @@
 				prop: 'templates',
 				title: 'File:UploadWizard license verification.png',
 				text: wikitext
-			} ).then( function ( result ) {
-				var templates = [],
+			} ).then( ( result ) => {
+				let templates = [],
 					template, title, i;
 
 				for ( i = 0; i < result.parse.templates.length; i++ ) {
@@ -207,9 +205,9 @@
 		 * @return {jQuery.Promise}
 		 */
 		getErrors: function () {
-			var errors = $.Deferred().resolve( [] ).promise(),
+			let errors = $.Deferred().resolve( [] ).promise(),
 				addError = function ( message ) {
-					errors = errors.then( function ( errorsCopy ) {
+					errors = errors.then( ( errorsCopy ) => {
 						// eslint-disable-next-line mediawiki/msg-doc
 						errorsCopy.push( mw.message( message ) );
 						return errorsCopy;
@@ -223,8 +221,8 @@
 				// It's pretty hard to screw up a radio button, so if even one of them is selected it's okay.
 				// But also check that associated textareas are filled for if the input is selected, and that
 				// they are the appropriate size.
-				Object.keys( selectedInputs ).forEach( function ( name ) {
-					var wikitext,
+				Object.keys( selectedInputs ).forEach( ( name ) => {
+					let wikitext,
 						data = selectedInputs[ name ];
 
 					if ( typeof data !== 'string' ) {
@@ -259,10 +257,10 @@
 		 * @return {Object}
 		 */
 		getSerialized: function () {
-			var values = {};
+			const values = {};
 
-			this.getItems().forEach( function ( group ) {
-				var groupName = group.getGroup(),
+			this.getItems().forEach( ( group ) => {
+				const groupName = group.getGroup(),
 					value = group.getValue();
 
 				if ( Object.keys( value ).length > 0 ) {
@@ -278,9 +276,9 @@
 		 * @param {Object} serialized
 		 */
 		setSerialized: function ( serialized ) {
-			var self = this;
+			const self = this;
 
-			Object.keys( serialized ).forEach( function ( group ) {
+			Object.keys( serialized ).forEach( ( group ) => {
 				self.setValues( serialized[ group ], group );
 			} );
 		}
diff --git a/resources/mw.UploadWizardPage.js b/resources/mw.UploadWizardPage.js
index c874700..02f8086 100644
--- a/resources/mw.UploadWizardPage.js
+++ b/resources/mw.UploadWizardPage.js
@@ -10,7 +10,7 @@
 ( function () {
 
 	function isCompatible() {
-		var
+		const
 			profile = $.client.profile(),
 			// Firefox < 7.0 sends an empty string as filename for Blobs in FormData.
 			// requests. https://bugzilla.mozilla.org/show_bug.cgi?id=649150
@@ -27,7 +27,7 @@
 
 	mw.UploadWizardPage = function () {
 
-		var uploadWizard,
+		let uploadWizard,
 			config = mw.config.get( 'MediaUploaderConfig' );
 
 		// Default configuration value that cannot be removed
@@ -54,7 +54,7 @@
 		uploadWizard.createInterface( '#upload-wizard' );
 	};
 
-	$( function () {
+	$( () => {
 		// show page.
 		mw.UploadWizardPage();
 	} );
diff --git a/resources/mw.UploadWizardUpload.js b/resources/mw.UploadWizardUpload.js
index a8ce368..b6db80f 100644
--- a/resources/mw.UploadWizardUpload.js
+++ b/resources/mw.UploadWizardUpload.js
@@ -167,7 +167,7 @@
 	 * @return {string} basename
 	 */
 	mw.UploadWizardUpload.prototype.getBasename = function () {
-		var path = this.getFilename();
+		const path = this.getFilename();
 
 		if ( path === undefined || path === null ) {
 			return '';
@@ -200,7 +200,7 @@
 	 * @return {jQuery.Promise} A promise, resolved when we're done
 	 */
 	mw.UploadWizardUpload.prototype.extractMetadataFromJpegMeta = function () {
-		var binReader, jpegmeta,
+		let binReader, jpegmeta,
 			deferred = $.Deferred(),
 			upload = this;
 		if ( this.file && this.file.type === 'image/jpeg' ) {
@@ -209,7 +209,7 @@
 				deferred.resolve();
 			};
 			binReader.onload = function () {
-				var binStr, arr, i, meta;
+				let binStr, arr, i, meta;
 				if ( binReader.result === null ) {
 					// Contrary to documentation, this sometimes fires for unsuccessful loads (T136235)
 					deferred.resolve();
@@ -254,7 +254,7 @@
 	 * @param {Object} meta As returned by jpegmeta
 	 */
 	mw.UploadWizardUpload.prototype.extractMetadataFromJpegMetaCallback = function ( meta ) {
-		var pixelHeightDim, pixelWidthDim, degrees;
+		let pixelHeightDim, pixelWidthDim, degrees;
 
 		if ( meta !== undefined && meta !== null && typeof meta === 'object' ) {
 			if ( this.imageinfo.metadata === undefined ) {
@@ -310,7 +310,7 @@
 	 * @param {Object} imageinfo JSON object obtained from API result.
 	 */
 	mw.UploadWizardUpload.prototype.extractImageInfo = function ( imageinfo ) {
-		var key,
+		let key,
 			upload = this;
 
 		for ( key in imageinfo ) {
@@ -320,7 +320,7 @@
 					this.imageinfo.metadata = {};
 				}
 				if ( imageinfo.metadata && imageinfo.metadata.length ) {
-					imageinfo.metadata.forEach( function ( pair ) {
+					imageinfo.metadata.forEach( ( pair ) => {
 						if ( pair !== undefined ) {
 							upload.imageinfo.metadata[ pair.name.toLowerCase() ] = pair.value;
 						}
@@ -343,7 +343,7 @@
 	 * @param {number} [height] Height of thumbnail. Will force 'url' to be added to props
 	 */
 	mw.UploadWizardUpload.prototype.getStashImageInfo = function ( callback, props, width, height ) {
-		var params = {
+		const params = {
 			prop: 'stashimageinfo',
 			siifilekey: this.fileKey,
 			siiprop: props.join( '|' )
@@ -368,7 +368,7 @@
 		}
 
 		if ( width !== undefined || height !== undefined ) {
-			if ( props.indexOf( 'url' ) === -1 ) {
+			if ( !props.includes( 'url' ) ) {
 				props.push( 'url' );
 			}
 			if ( width !== undefined ) {
@@ -393,15 +393,15 @@
 	 * @param {number} [height] Height of thumbnail. Will force 'url' to be added to props
 	 */
 	mw.UploadWizardUpload.prototype.getImageInfo = function ( callback, props, width, height ) {
-		var requestedTitle, params;
+		let requestedTitle, params;
 
 		function ok( data ) {
-			var found;
+			let found;
 
 			if ( data && data.query && data.query.pages ) {
 				found = false;
-				Object.keys( data.query.pages ).forEach( function ( pageId ) {
-					var page = data.query.pages[ pageId ];
+				Object.keys( data.query.pages ).forEach( ( pageId ) => {
+					const page = data.query.pages[ pageId ];
 					if ( page.title && page.title === requestedTitle && page.imageinfo ) {
 						found = true;
 						callback( page.imageinfo );
@@ -434,7 +434,7 @@
 		};
 
 		if ( width !== undefined || height !== undefined ) {
-			if ( props.indexOf( 'url' ) === -1 ) {
+			if ( !props.includes( 'url' ) ) {
 				props.push( 'url' );
 			}
 			if ( width !== undefined ) {
@@ -454,7 +454,7 @@
 	 * @return {mw.ApiUploadFormDataHandler} upload handler object
 	 */
 	mw.UploadWizardUpload.prototype.getUploadHandler = function () {
-		var constructor; // must be the name of a function in 'mw' namespace
+		let constructor; // must be the name of a function in 'mw' namespace
 
 		if ( !this.uploadHandler ) {
 			constructor = 'ApiUploadFormDataHandler';
@@ -473,7 +473,7 @@
 	 *     couldn't be generated
 	 */
 	mw.UploadWizardUpload.prototype.getApiThumbnail = function ( width, height ) {
-		var deferred = $.Deferred();
+		const deferred = $.Deferred();
 
 		function thumbnailPublisher( thumbnails ) {
 			if ( thumbnails === null ) {
@@ -484,8 +484,8 @@
 				// they are actually there yet. Keep trying to set the source ( which should trigger "error" or "load" event )
 				// on the image. If it loads publish the event with the image. If it errors out too many times, give up and publish
 				// the event with a null.
-				thumbnails.forEach( function ( thumb ) {
-					var timeoutMs, image;
+				thumbnails.forEach( ( thumb ) => {
+					let timeoutMs, image;
 
 					if ( thumb.thumberror || ( !( thumb.thumburl && thumb.thumbwidth && thumb.thumbheight ) ) ) {
 						mw.log.warn( 'mw.UploadWizardUpload::getThumbnail> Thumbnail error or missing information' );
@@ -507,14 +507,14 @@
 					image.width = thumb.thumbwidth;
 					image.height = thumb.thumbheight;
 					$( image )
-						.on( 'load', function () {
+						.on( 'load', () => {
 							// publish the image to anyone who wanted it
 							deferred.resolve( image );
 						} )
-						.on( 'error', function () {
+						.on( 'error', () => {
 							// retry with exponential backoff
 							if ( timeoutMs < 8000 ) {
-								setTimeout( function () {
+								setTimeout( () => {
 									timeoutMs = timeoutMs * 2 + Math.round( Math.random() * ( timeoutMs / 10 ) );
 									setSrc();
 								}, timeoutMs );
@@ -545,7 +545,7 @@
 	 * @return {number} orientation in degrees: 0, 90, 180 or 270
 	 */
 	mw.UploadWizardUpload.prototype.getOrientationDegrees = function () {
-		var orientation = 0;
+		let orientation = 0;
 		if ( this.imageinfo && this.imageinfo.metadata && this.imageinfo.metadata.orientation ) {
 			switch ( this.imageinfo.metadata.orientation ) {
 				case 8:
@@ -579,9 +579,9 @@
 	 * @return {number}
 	 */
 	mw.UploadWizardUpload.prototype.getScalingFromConstraints = function ( image, constraints ) {
-		var scaling = 1;
-		Object.keys( constraints ).forEach( function ( dim ) {
-			var s,
+		let scaling = 1;
+		Object.keys( constraints ).forEach( ( dim ) => {
+			let s,
 				constraint = constraints[ dim ];
 			if ( constraint && image[ dim ] > constraint ) {
 				s = constraint / image[ dim ];
@@ -603,7 +603,7 @@
 	 * @return {HTMLCanvasElement|null}
 	 */
 	mw.UploadWizardUpload.prototype.getTransformedCanvasElement = function ( image, constraints ) {
-		var angle, scaling, width, height,
+		let angle, scaling, width, height,
 			dimensions, dx, dy, x, y, $canvas, ctx,
 			scaleConstraints = constraints,
 			rotation = 0;
@@ -693,7 +693,7 @@
 	 * @return {HTMLImageElement} with same src, but different attrs
 	 */
 	mw.UploadWizardUpload.prototype.getBrowserScaledImageElement = function ( image, constraints ) {
-		var scaling = this.getScalingFromConstraints( image, constraints );
+		const scaling = this.getScalingFromConstraints( image, constraints );
 		return $( '<img>' )
 			.attr( {
 				width: parseInt( image.width * scaling, 10 ),
@@ -712,7 +712,7 @@
 	 * @return {HTMLCanvasElement|HTMLImageElement}
 	 */
 	mw.UploadWizardUpload.prototype.getScaledImageElement = function ( image, width, height ) {
-		var constraints = {},
+		let constraints = {},
 			transform;
 
 		if ( width ) {
@@ -742,7 +742,7 @@
 	 *   containing a thumbnail, or resolved with `null` when one can't be produced
 	 */
 	mw.UploadWizardUpload.prototype.getThumbnail = function ( width, height ) {
-		var upload = this,
+		const upload = this,
 			deferred = $.Deferred();
 
 		if ( this.thumbnailPromise[ width + 'x' + height ] ) {
@@ -767,14 +767,14 @@
 		this.extractMetadataFromJpegMeta()
 			.then( upload.makePreview.bind( upload, width ) )
 			.done( imageCallback )
-			.fail( function () {
+			.fail( () => {
 				// Can't generate the thumbnail locally, get the thumbnail via API after
 				// the file is uploaded. Queries are cached, so if this thumbnail was
 				// already fetched for some reason, we'll get it immediately.
 				if ( upload.state !== 'new' && upload.state !== 'transporting' && upload.state !== 'error' ) {
 					upload.getApiThumbnail( width, height ).done( imageCallback );
 				} else {
-					upload.once( 'success', function () {
+					upload.once( 'success', () => {
 						upload.getApiThumbnail( width, height ).done( imageCallback );
 					} );
 				}
@@ -798,7 +798,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.UploadWizardUpload.prototype.makePreview = function ( width ) {
-		var first, video, url, dataUrlReader,
+		let first, video, url, dataUrlReader,
 			deferred = $.Deferred(),
 			upload = this;
 
@@ -809,12 +809,12 @@
 				first = true;
 				video = document.createElement( 'video' );
 
-				video.addEventListener( 'loadedmetadata', function () {
+				video.addEventListener( 'loadedmetadata', () => {
 					// seek 2 seconds into video or to half if shorter
 					video.currentTime = Math.min( 2, video.duration / 2 );
 					video.volume = 0;
 				} );
-				video.addEventListener( 'seeked', function () {
+				video.addEventListener( 'seeked', () => {
 					// Firefox 16 sometimes does not work on first seek, seek again
 					if ( first ) {
 						first = false;
@@ -823,8 +823,8 @@
 					} else {
 						// Chrome sometimes shows black frames if grabbing right away.
 						// wait 500ms before grabbing frame
-						setTimeout( function () {
-							var context,
+						setTimeout( () => {
+							let context,
 								canvas = document.createElement( 'canvas' );
 							canvas.width = width;
 							canvas.height = Math.round( canvas.width * video.videoHeight / video.videoWidth );
@@ -844,7 +844,7 @@
 				video.src = url;
 				// If we can't get a frame within 10 seconds, something is probably seriously wrong.
 				// This can happen for broken files where we can't actually seek to the time we wanted.
-				setTimeout( function () {
+				setTimeout( () => {
 					deferred.reject();
 					upload.URL().revokeObjectURL( video.url );
 				}, 10000 );
@@ -871,7 +871,7 @@
 	 * @param {jQuery.Deferred} deferred
 	 */
 	mw.UploadWizardUpload.prototype.loadImage = function ( url, deferred ) {
-		var image = document.createElement( 'img' );
+		const image = document.createElement( 'img' );
 		image.onload = function () {
 			deferred.resolve( image );
 		};
diff --git a/resources/mw.UploadWizardUploadInterface.js b/resources/mw.UploadWizardUploadInterface.js
index 263787d..610a2bb 100644
--- a/resources/mw.UploadWizardUploadInterface.js
+++ b/resources/mw.UploadWizardUploadInterface.js
@@ -7,7 +7,7 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	mw.UploadWizardUploadInterface = function MWUploadWizardUploadInterface( upload ) {
-		var ui = this;
+		const ui = this;
 
 		OO.EventEmitter.call( this );
 
@@ -47,7 +47,7 @@
 			flags: 'destructive',
 			icon: 'trash',
 			framed: false
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			ui.emit( 'upload-removed' );
 		} );
 
@@ -63,7 +63,7 @@
 		// this.progressBar = ( no progress bar for individual uploads yet )
 		// we bind to the ui div since .off() doesn't work for non-DOM objects
 		// TODO Convert this to an OO.EventEmitter, and use OOjs events
-		this.$div.on( 'transportProgressEvent', function () {
+		this.$div.on( 'transportProgressEvent', () => {
 			ui.showTransportProgress();
 		} );
 	};
@@ -96,7 +96,7 @@
 	 */
 	mw.UploadWizardUploadInterface.prototype.setStatus = function ( msgKey, args ) {
 		// get the status line for our upload
-		var $status = this.$div.find( '.mediauploader-file-status' );
+		const $status = this.$div.find( '.mediauploader-file-status' );
 		// eslint-disable-next-line mediawiki/msg-doc
 		$status.msg( msgKey, args || [] ).show();
 	};
@@ -176,7 +176,7 @@
 	 * @param {File} file
 	 */
 	mw.UploadWizardUploadInterface.prototype.fileChangedOk = function ( imageinfo, file ) {
-		var statusItems = [];
+		const statusItems = [];
 
 		this.updateFilename();
 
@@ -200,10 +200,10 @@
 	 *     fails
 	 */
 	mw.UploadWizardUploadInterface.prototype.showThumbnail = function () {
-		var $preview = this.$div.find( '.mediauploader-file-preview' ),
+		const $preview = this.$div.find( '.mediauploader-file-preview' ),
 			deferred = $.Deferred();
 		// This must match the CSS dimensions of .mediauploader-file-preview
-		this.upload.getThumbnail( 120, 120 ).done( function ( thumb ) {
+		this.upload.getThumbnail( 120, 120 ).done( ( thumb ) => {
 			mw.UploadWizard.placeThumbnail( $preview, thumb );
 			deferred.resolve();
 		} );
@@ -219,7 +219,7 @@
 	 *       TODO silently fix to have unique filename? unnecessary at this point...
 	 */
 	mw.UploadWizardUploadInterface.prototype.updateFilename = function () {
-		var path = this.upload.getFilename();
+		const path = this.upload.getFilename();
 
 		// visible filename
 		this.$form.find( '.mediauploader-visible-file-filename-text' )
diff --git a/resources/mw.fileApi.js b/resources/mw.fileApi.js
index cb80590..9216c24 100644
--- a/resources/mw.fileApi.js
+++ b/resources/mw.fileApi.js
@@ -15,9 +15,9 @@
 		 * @return {boolean}
 		 */
 		isPreviewableFile: function ( file ) {
-			var known = [ 'image/png', 'image/gif', 'image/jpeg' ],
+			const known = [ 'image/png', 'image/gif', 'image/jpeg' ],
 				tooHuge = 10 * 1024 * 1024;
-			return this.isPreviewableVideo( file ) || ( known.indexOf( file.type ) !== -1 ) && file.size > 0 && file.size < tooHuge;
+			return this.isPreviewableVideo( file ) || ( known.includes( file.type ) ) && file.size > 0 && file.size < tooHuge;
 		},
 
 		/**
@@ -27,7 +27,7 @@
 		 * @return {boolean}
 		 */
 		isPreviewableVideo: function ( file ) {
-			var video = document.createElement( 'video' );
+			const video = document.createElement( 'video' );
 			return video.canPlayType && video.canPlayType( file.type ).replace( 'no', '' ) !== '';
 		}
 
diff --git a/resources/transports/mw.FormDataTransport.js b/resources/transports/mw.FormDataTransport.js
index 95daece..b1c86ec 100644
--- a/resources/transports/mw.FormDataTransport.js
+++ b/resources/transports/mw.FormDataTransport.js
@@ -48,7 +48,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.post = function ( params ) {
-		var deferred = $.Deferred();
+		const deferred = $.Deferred();
 
 		this.request = this.api.post( params, {
 			/*
@@ -66,9 +66,9 @@
 			 * out how much of the upload has already gone out, so let's add it!
 			 */
 			xhr: function () {
-				var xhr = $.ajaxSettings.xhr();
-				xhr.upload.addEventListener( 'progress', function ( evt ) {
-					var fraction = null;
+				const xhr = $.ajaxSettings.xhr();
+				xhr.upload.addEventListener( 'progress', ( evt ) => {
+					let fraction = null;
 					if ( evt.lengthComputable ) {
 						fraction = parseFloat( evt.loaded / evt.total );
 					}
@@ -92,7 +92,7 @@
 	 * @return {Object}
 	 */
 	mw.FormDataTransport.prototype.createParams = function ( filename, offset ) {
-		var params = OO.cloneObject( this.formData );
+		const params = OO.cloneObject( this.formData );
 
 		Object.assign( params, {
 			filename: filename,
@@ -118,7 +118,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.upload = function ( file, tempFileName ) {
-		var params, ext;
+		let params, ext;
 
 		this.tempname = tempFileName;
 		// Limit length to 240 bytes (limit hardcoded in UploadBase.php).
@@ -150,7 +150,7 @@
 	 *   promise from #upload
 	 */
 	mw.FormDataTransport.prototype.chunkedUpload = function ( file ) {
-		var
+		let
 			offset,
 			prevPromise = $.Deferred().resolve(),
 			deferred = $.Deferred(),
@@ -162,15 +162,15 @@
 			// Capture offset in a closure
 			// eslint-disable-next-line no-loop-func
 			( function ( offset2 ) {
-				var
+				const
 					newPromise = $.Deferred(),
 					isLastChunk = offset2 + chunkSize >= fileSize,
 					thisChunkSize = isLastChunk ? ( fileSize % chunkSize ) : chunkSize;
-				prevPromise.done( function () {
+				prevPromise.done( () => {
 					transport.uploadChunk( file, offset2 )
 						.done( isLastChunk ? deferred.resolve : newPromise.resolve )
 						.fail( deferred.reject )
-						.progress( function ( fraction ) {
+						.progress( ( fraction ) => {
 							// The progress notifications give us per-chunk progress.
 							// Calculate progress for the whole file.
 							deferred.notify( ( offset2 + fraction * thisChunkSize ) / fileSize );
@@ -191,7 +191,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.uploadChunk = function ( file, offset ) {
-		var params = this.createParams( this.tempname, offset ),
+		let params = this.createParams( this.tempname, offset ),
 			transport = this,
 			bytesAvailable = file.size,
 			chunk;
@@ -229,7 +229,7 @@
 		params.filesize = bytesAvailable;
 		params.chunk = chunk;
 
-		return this.post( params ).then( function ( response ) {
+		return this.post( params ).then( ( response ) => {
 			if ( response.upload && response.upload.filekey ) {
 				transport.filekey = response.upload.filekey;
 			}
@@ -256,7 +256,7 @@
 					file, offset
 				);
 			}
-		}, function ( code, result ) {
+		}, ( code, result ) => {
 			// Ain't this some great machine readable output eh
 			if (
 				result.errors &&
@@ -323,7 +323,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.retryWithMethod = function ( methodName, file, offset ) {
-		var
+		const
 			transport = this,
 			retryDeferred = $.Deferred(),
 			retry = function () {
@@ -345,7 +345,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.checkStatus = function () {
-		var transport = this,
+		const transport = this,
 			params = OO.cloneObject( this.formData );
 
 		if ( this.aborted ) {
@@ -363,7 +363,7 @@
 		params.checkstatus = true;
 		params.filekey = this.filekey;
 		this.request = this.api.post( params )
-			.then( function ( response ) {
+			.then( ( response ) => {
 				if ( response.upload && response.upload.result === 'Poll' ) {
 					// If concatenation takes longer than 10 minutes give up
 					if ( ( Date.now() - transport.firstPoll ) > 10 * 60 * 1000 ) {
@@ -390,9 +390,7 @@
 				}
 
 				return response;
-			}, function ( code, result ) {
-				return $.Deferred().reject( code, result );
-			} );
+			}, ( code, result ) => $.Deferred().reject( code, result ) );
 
 		return this.request;
 	};
diff --git a/resources/ui/steps/uw.ui.Deed.js b/resources/ui/steps/uw.ui.Deed.js
index 21dcf59..e556430 100644
--- a/resources/ui/steps/uw.ui.Deed.js
+++ b/resources/ui/steps/uw.ui.Deed.js
@@ -36,7 +36,7 @@
 	OO.inheritClass( uw.ui.Deed, uw.ui.Step );
 
 	uw.ui.Deed.prototype.load = function ( uploads ) {
-		var ui = this;
+		const ui = this;
 
 		uw.ui.Step.prototype.load.call( this, uploads );
 
@@ -52,7 +52,7 @@
 				.addClass( 'ui-helper-clearfix' )
 		);
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			// hide "next" button, controller will only show it once license has
 			// been selected
 			ui.nextButton.$element.hide();
diff --git a/resources/ui/steps/uw.ui.Details.js b/resources/ui/steps/uw.ui.Details.js
index e5117db..793da75 100644
--- a/resources/ui/steps/uw.ui.Details.js
+++ b/resources/ui/steps/uw.ui.Details.js
@@ -24,7 +24,7 @@
 	 * @constructor
 	 */
 	uw.ui.Details = function UWUIDetails() {
-		var details = this;
+		const details = this;
 
 		function startDetails() {
 			details.emit( 'start-details' );
@@ -48,7 +48,7 @@
 		this.nextButtonDespiteFailures = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-next-file-despite-failures' ).text(),
 			flags: [ 'progressive' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			details.emit( 'finalize-details-after-removal' );
 		} );
 
@@ -85,9 +85,9 @@
 	};
 
 	uw.ui.Details.prototype.addNextButton = function () {
-		var ui = this;
+		const ui = this;
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			ui.$buttons.append(
 				$( '<div>' )
 					.addClass( 'mediauploader-file-next-all-ok mediauploader-file-endchoice' )
@@ -164,14 +164,14 @@
 	 * This method also opens up "more info" if the form has errors.
 	 */
 	uw.ui.Details.prototype.showErrors = function () {
-		var $errorElements = this.$div
+		const $errorElements = this.$div
 				// TODO Evil
 				.find( '.oo-ui-fieldLayout-messages-error' ),
 			errorCount = $errorElements.length;
 
 		// Open "more info" if that part of the form has errors
 		$errorElements.each( function () {
-			var $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );
+			const $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );
 			if ( $collapsibleWrapper.length ) {
 				$collapsibleWrapper.data( 'mw-collapsible' ).expand();
 			}
@@ -199,14 +199,14 @@
 	 * See #showErrors for details.
 	 */
 	uw.ui.Details.prototype.showWarnings = function () {
-		var $warningElements = this.$div
+		const $warningElements = this.$div
 				// TODO Evil
 				.find( '.oo-ui-fieldLayout-messages-notice' ),
 			warningCount = $warningElements.length;
 
 		// Open "more info" if that part of the form has warnings
 		$warningElements.each( function () {
-			var $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );
+			const $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );
 			if ( $collapsibleWrapper.length ) {
 				$collapsibleWrapper.data( 'mw-collapsible' ).expand();
 			}
diff --git a/resources/ui/steps/uw.ui.Thanks.js b/resources/ui/steps/uw.ui.Thanks.js
index 62290aa..fc56af0 100644
--- a/resources/ui/steps/uw.ui.Thanks.js
+++ b/resources/ui/steps/uw.ui.Thanks.js
@@ -25,7 +25,7 @@
 	 * @param {Object} config
 	 */
 	uw.ui.Thanks = function UWUIThanks( config ) {
-		var $header,
+		let $header,
 			beginButtonTarget,
 			thanks = this;
 
@@ -68,13 +68,13 @@
 		// TODO: make the step order configurable by campaign definitions instead of using these hacks
 		beginButtonTarget = this.getButtonConfig( 'beginButton', 'target' );
 		if ( !beginButtonTarget ) {
-			this.beginButton.on( 'click', function () {
+			this.beginButton.on( 'click', () => {
 				thanks.emit( 'next-step' );
 			} );
 		} else {
 			this.beginButton.setHref( beginButtonTarget );
 		}
-		this.beginButton.on( 'click', function () {
+		this.beginButton.on( 'click', () => {
 			mw.DestinationChecker.clearCache();
 		} );
 
@@ -93,7 +93,7 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.ui.Thanks.prototype.addUpload = function ( upload ) {
-		var thumbWikiText, $thanksDiv, $thumbnailWrapDiv, $thumbnailDiv, $thumbnailCaption, $thumbnailLink;
+		let thumbWikiText, $thanksDiv, $thumbnailWrapDiv, $thumbnailDiv, $thumbnailCaption, $thumbnailLink;
 
 		thumbWikiText = '[[' + [
 			upload.details.getTitle().getPrefixedText(),
@@ -125,7 +125,7 @@
 			);
 
 		// This must match the CSS dimensions of .mediauploader-thumbnail
-		upload.getThumbnail( 120, 120 ).done( function ( thumb ) {
+		upload.getThumbnail( 120, 120 ).done( ( thumb ) => {
 			mw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );
 		} );
 
@@ -148,7 +148,7 @@
 	 * @return {jQuery}
 	 */
 	uw.ui.Thanks.prototype.makeReadOnlyInput = function ( value, label, useEditFont ) {
-		var copyText = new mw.widgets.CopyTextLayout( {
+		const copyText = new mw.widgets.CopyTextLayout( {
 			align: 'top',
 			label: label,
 			copyText: value
diff --git a/resources/ui/steps/uw.ui.Tutorial.js b/resources/ui/steps/uw.ui.Tutorial.js
index 1b8d0d4..fa7fd0f 100644
--- a/resources/ui/steps/uw.ui.Tutorial.js
+++ b/resources/ui/steps/uw.ui.Tutorial.js
@@ -51,7 +51,7 @@
 	 * @constructor
 	 */
 	uw.ui.Tutorial = function UWUITutorial() {
-		var ui = this;
+		const ui = this;
 
 		uw.ui.Step.call(
 			this,
@@ -78,7 +78,7 @@
 			label: mw.message( 'mediauploader-skip-tutorial-future' ).text()
 		} );
 
-		this.skipCheckbox.on( 'change', function () {
+		this.skipCheckbox.on( 'change', () => {
 			ui.emit( 'skip-tutorial-click', ui.skipCheckbox.isSelected() );
 		} );
 
@@ -112,17 +112,17 @@
 	};
 
 	uw.ui.Tutorial.prototype.addNextButton = function () {
-		var ui = this;
+		const ui = this;
 
 		this.nextButton = new OO.ui.ButtonWidget( {
 			classes: [ 'mediauploader-button-next' ],
 			label: mw.message( 'mediauploader-next' ).text(),
 			flags: [ 'progressive', 'primary' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			ui.emit( 'next-step' );
 		} );
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			ui.$buttons.append(
 				new OO.ui.HorizontalLayout( {
 					items: [ ui.skipCheckbox, ui.skipCheckboxLabel, ui.nextButton ]
diff --git a/resources/ui/steps/uw.ui.Upload.js b/resources/ui/steps/uw.ui.Upload.js
index 4ec5509..b7e38bf 100644
--- a/resources/ui/steps/uw.ui.Upload.js
+++ b/resources/ui/steps/uw.ui.Upload.js
@@ -25,7 +25,7 @@
 	 * @param {Object} config UploadWizard config object.
 	 */
 	uw.ui.Upload = function UWUIUpload( config ) {
-		var upload = this;
+		const upload = this;
 
 		this.config = config;
 
@@ -58,14 +58,14 @@
 		this.nextStepButtonAllOk = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-next-file' ).text(),
 			flags: [ 'progressive', 'primary' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			upload.emit( 'next-step' );
 		} );
 
 		this.retryButtonSomeFailed = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-file-retry' ).text(),
 			flags: [ 'progressive' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			upload.hideEndButtons();
 			upload.emit( 'retry' );
 		} );
@@ -73,14 +73,14 @@
 		this.nextStepButtonSomeFailed = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-next-file-despite-failures' ).text(),
 			flags: [ 'progressive', 'primary' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			upload.emit( 'next-step' );
 		} );
 
 		this.retryButtonAllFailed = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-file-retry' ).text(),
 			flags: [ 'progressive' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			upload.hideEndButtons();
 			upload.emit( 'retry' );
 		} );
@@ -145,7 +145,7 @@
 	 * @param {boolean} more
 	 */
 	uw.ui.Upload.prototype.setAddButtonText = function ( more ) {
-		var msg = 'mediauploader-add-file-';
+		let msg = 'mediauploader-add-file-';
 
 		if ( more ) {
 			msg += 'n';
@@ -160,7 +160,7 @@
 	};
 
 	uw.ui.Upload.prototype.load = function ( uploads ) {
-		var ui = this;
+		const ui = this;
 
 		uw.ui.Step.prototype.load.call( this, uploads );
 
@@ -177,17 +177,17 @@
 				)
 		);
 
-		this.addFile.on( 'change', function ( files ) {
+		this.addFile.on( 'change', ( files ) => {
 			ui.emit( 'files-added', files );
 			ui.addFile.setValue( null );
 		} );
 	};
 
 	uw.ui.Upload.prototype.displayUploads = function ( uploads ) {
-		var thumbPromise,
+		let thumbPromise,
 			$uploadInterfaceDivs = $( [] );
 
-		uploads.forEach( function ( upload ) {
+		uploads.forEach( ( upload ) => {
 			// We'll attach all interfaces to the DOM at once rather than one-by-one, for better
 			// performance
 			$uploadInterfaceDivs = $uploadInterfaceDivs.add( upload.ui.$div );
@@ -199,15 +199,15 @@
 		// Display thumbnails, but not all at once because they're somewhat expensive to generate.
 		// This will wait for each thumbnail to be complete before starting the next one.
 		thumbPromise = $.Deferred().resolve();
-		uploads.forEach( function ( upload ) {
-			thumbPromise = thumbPromise.then( function () {
-				var deferred = $.Deferred();
+		uploads.forEach( ( upload ) => {
+			thumbPromise = thumbPromise.then( () => {
+				const deferred = $.Deferred();
 				setTimeout( function () {
 					if ( this.movedFrom ) {
 						// We're no longer displaying any of these thumbnails, stop
 						deferred.reject();
 					}
-					upload.ui.showThumbnail().done( function () {
+					upload.ui.showThumbnail().done( () => {
 						deferred.resolve();
 					} );
 				} );
@@ -217,9 +217,9 @@
 	};
 
 	uw.ui.Upload.prototype.addNextButton = function () {
-		var ui = this;
+		const ui = this;
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			ui.$buttons.append(
 				$( '<div>' )
 					.addClass( 'mediauploader-file-next-all-ok mediauploader-file-endchoice' )
@@ -319,12 +319,12 @@
 	 * @param {string} extension
 	 */
 	uw.ui.Upload.prototype.showBadExtensionError = function ( filename, extension ) {
-		var $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-extension', extension );
+		const $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-extension', extension );
 		this.showFilenameError( $errorMessage );
 	};
 
 	uw.ui.Upload.prototype.showMissingExtensionError = function () {
-		var $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-no-extension' );
+		const $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-no-extension' );
 		this.showFilenameError(
 			$( '<div>' ).append(
 				$errorMessage,
diff --git a/resources/ui/uw.ui.DeedPreview.js b/resources/ui/uw.ui.DeedPreview.js
index a30f6fb..a7b30b5 100644
--- a/resources/ui/uw.ui.DeedPreview.js
+++ b/resources/ui/uw.ui.DeedPreview.js
@@ -24,10 +24,10 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.ui.DeedPreview = function UWUIDeedPreview( upload ) {
-		var $thumbnailDiv = $( '<div>' ).addClass( 'mediauploader-thumbnail' );
+		const $thumbnailDiv = $( '<div>' ).addClass( 'mediauploader-thumbnail' );
 		this.$thumbnailDiv = $thumbnailDiv;
 		// This must match the CSS dimensions of .mediauploader-thumbnail
-		upload.getThumbnail( 120, 120 ).done( function ( thumb ) {
+		upload.getThumbnail( 120, 120 ).done( ( thumb ) => {
 			mw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );
 		} );
 		// eslint-disable-next-line no-jquery/no-global-selector
diff --git a/resources/ui/uw.ui.Step.js b/resources/ui/uw.ui.Step.js
index 6b19ffb..af3d8ae 100644
--- a/resources/ui/uw.ui.Step.js
+++ b/resources/ui/uw.ui.Step.js
@@ -53,7 +53,7 @@
 	 */
 	uw.ui.Step.prototype.load = function ( uploads ) {
 		// eslint-disable-next-line no-jquery/no-global-selector
-		var offset = $( 'h1' ).first().offset();
+		const offset = $( 'h1' ).first().offset();
 
 		this.movedFrom = false;
 
@@ -88,17 +88,17 @@
 	 * Add a 'next' button to the step's button container
 	 */
 	uw.ui.Step.prototype.addNextButton = function () {
-		var ui = this;
+		const ui = this;
 
 		this.nextButton = new OO.ui.ButtonWidget( {
 			classes: [ 'mediauploader-button-next' ],
 			label: mw.message( 'mediauploader-next' ).text(),
 			flags: [ 'progressive', 'primary' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			ui.emit( 'next-step' );
 		} );
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			ui.$buttons.append( ui.nextButton.$element );
 		} );
 	};
@@ -107,16 +107,16 @@
 	 * Add a 'previous' button to the step's button container
 	 */
 	uw.ui.Step.prototype.addPreviousButton = function () {
-		var ui = this;
+		const ui = this;
 
 		this.previousButton = new OO.ui.ButtonWidget( {
 			classes: [ 'mediauploader-button-previous' ],
 			label: mw.message( 'mediauploader-previous' ).text()
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			ui.emit( 'previous-step' );
 		} );
 
-		this.previousButtonPromise.done( function () {
+		this.previousButtonPromise.done( () => {
 			ui.$buttons.append( ui.previousButton.$element );
 		} );
 	};
diff --git a/resources/ui/uw.ui.Wizard.js b/resources/ui/uw.ui.Wizard.js
index 804fbaa..5472285 100644
--- a/resources/ui/uw.ui.Wizard.js
+++ b/resources/ui/uw.ui.Wizard.js
@@ -46,7 +46,7 @@
 	 */
 	uw.ui.Wizard.prototype.initHeader = function ( config ) {
 		// eslint-disable-next-line no-jquery/no-global-selector
-		var $contentSub = $( '#contentSub' );
+		const $contentSub = $( '#contentSub' );
 
 		if ( config.alternativeUploadToolsPage ) {
 			this.$alternativeUploads = $( '<a>' )
@@ -72,7 +72,7 @@
 	 * @param {Object|string} configAltUploadForm A link or map of languages to links, pointing at an alternate form.
 	 */
 	uw.ui.Wizard.prototype.initAltUploadForm = function ( configAltUploadForm ) {
-		var altUploadForm, userLanguage, title;
+		let altUploadForm, userLanguage, title;
 
 		if ( typeof configAltUploadForm === 'object' ) {
 			userLanguage = mw.config.get( 'wgUserLanguage' );
@@ -108,13 +108,13 @@
 	 * @param {uw.controller.Step[]} steps
 	 */
 	uw.ui.Wizard.prototype.initialiseSteps = function ( steps ) {
-		var $steps = $( '<ul>' )
+		const $steps = $( '<ul>' )
 			.attr( 'id', 'mediauploader-steps' )
 			.addClass( 'ui-helper-clearfix' )
 			.insertBefore( '#mediauploader-content' );
 
-		steps.forEach( function ( step ) {
-			var $arrow = $( '<li>' )
+		steps.forEach( ( step ) => {
+			const $arrow = $( '<li>' )
 				.attr( 'id', 'mediauploader-step-' + step.stepName )
 				.append(
 					// Messages that can be used here:
@@ -128,9 +128,9 @@
 			$steps.append( $arrow );
 
 			// once a (new) step loads, highlight it
-			step.on( 'load', function ( $arrow2 ) {
+			step.on( 'load', ( ( $arrow2 ) => {
 				$steps.arrowStepsHighlight( $arrow2 );
-			}.bind( step, $arrow ) );
+			} ).bind( step, $arrow ) );
 		} );
 
 		$steps.arrowSteps();
diff --git a/resources/uw.ConcurrentQueue.js b/resources/uw.ConcurrentQueue.js
index 2ec018f..48383eb 100644
--- a/resources/uw.ConcurrentQueue.js
+++ b/resources/uw.ConcurrentQueue.js
@@ -70,7 +70,7 @@
 	 * @return {boolean} Whether the item was removed
 	 */
 	uw.ConcurrentQueue.prototype.removeItem = function ( item ) {
-		var index, found;
+		let index, found;
 
 		found = false;
 
@@ -113,7 +113,7 @@
 	 * @param {Object} item
 	 */
 	uw.ConcurrentQueue.prototype.promiseComplete = function ( item ) {
-		var index;
+		let index;
 		index = this.running.indexOf( item );
 		// Check that this item wasn't removed while it was being executed
 		if ( index !== -1 ) {
@@ -132,7 +132,7 @@
 	 * @private
 	 */
 	uw.ConcurrentQueue.prototype.executeNext = function () {
-		var item, promise;
+		let item, promise;
 		if ( this.running.length === this.count || !this.executing ) {
 			return;
 		}
@@ -153,7 +153,7 @@
 	 * When the queue finishes executing, a 'complete' event will be emitted.
 	 */
 	uw.ConcurrentQueue.prototype.startExecuting = function () {
-		var i;
+		let i;
 		if ( this.executing ) {
 			return;
 		}
diff --git a/resources/uw.CopyMetadataWidget.js b/resources/uw.CopyMetadataWidget.js
index 784aab0..5fa1180 100644
--- a/resources/uw.CopyMetadataWidget.js
+++ b/resources/uw.CopyMetadataWidget.js
@@ -10,7 +10,7 @@
 	 * @cfg {mw.UploadWizardUpload[]} copyTo Uploads to copy the details to
 	 */
 	uw.CopyMetadataWidget = function UWCopyMetadataWidget( config ) {
-		var metadataType, defaultStatus, copyMetadataMsg,
+		let metadataType, defaultStatus, copyMetadataMsg,
 			checkboxes = [],
 			$copyMetadataWrapperDiv = $( '<div>' ),
 			$copyMetadataDiv = $( '<div>' );
@@ -118,7 +118,7 @@
 	 * @private
 	 */
 	uw.CopyMetadataWidget.prototype.onCopyClick = function () {
-		var metadataTypes = this.checkboxesWidget.findSelectedItemsData();
+		const metadataTypes = this.checkboxesWidget.findSelectedItemsData();
 		this.copyMetadata( metadataTypes );
 
 		this.undoButton.toggle( true );
@@ -153,7 +153,7 @@
 	 * @param {string[]} metadataTypes Types to copy, as defined in the copyMetadataTypes property
 	 */
 	uw.CopyMetadataWidget.prototype.copyMetadata = function ( metadataTypes ) {
-		var titleZero, matches, i,
+		let titleZero, matches, i,
 			uploads = this.copyTo,
 			sourceUpload = this.copyFrom,
 			serialized = sourceUpload.details.getSerialized(),
@@ -164,7 +164,7 @@
 			copyingOther = false;
 
 		// Filter serialized data to only the types we want to copy
-		metadataTypes.forEach( function ( type ) {
+		metadataTypes.forEach( ( type ) => {
 			sourceValue[ type ] = serialized[ type ];
 			copyingTitle = copyingTitle || type === 'title';
 			copyingOther = copyingOther || type === 'other';
@@ -193,8 +193,8 @@
 				// numbers.
 				sourceValue.title.title = titleZero.replace( /(\D+)(\d{1,3})(\D*)$/,
 					// eslint-disable-next-line no-loop-func
-					function ( str, m1, m2, m3 ) {
-						var newstr = String( +m2 + i );
+					( str, m1, m2, m3 ) => {
+						const newstr = String( +m2 + i );
 						return m1 + new Array( m2.length + 1 - newstr.length )
 							.join( '0' ) + newstr + m3;
 					}
@@ -210,7 +210,7 @@
 	 * Restore previously saved metadata that we backed up when copying.
 	 */
 	uw.CopyMetadataWidget.prototype.restoreMetadata = function () {
-		var i,
+		let i,
 			uploads = this.copyTo;
 
 		for ( i = 0; i < uploads.length; i++ ) {
diff --git a/resources/uw.FieldLayout.js b/resources/uw.FieldLayout.js
index 8d52198..7c5f4a5 100644
--- a/resources/uw.FieldLayout.js
+++ b/resources/uw.FieldLayout.js
@@ -16,7 +16,7 @@
 		// FieldLayout will add an icon which, when clicked, reveals more information
 		// about the input. We'll want to display that by default, so we're getting
 		// rid of the "help" property here & will later append that after the header
-		var help = config && config.help ? config.help : '';
+		const help = config && config.help ? config.help : '';
 		config = Object.assign( { align: 'top', required: false }, config, { help: '' } );
 
 		uw.FieldLayout.parent.call( this, fieldWidget, config );
diff --git a/resources/uw.LicenseGroup.js b/resources/uw.LicenseGroup.js
index c5d4f6f..5277ac0 100644
--- a/resources/uw.LicenseGroup.js
+++ b/resources/uw.LicenseGroup.js
@@ -22,7 +22,7 @@
 	 * @param {number} count Number of the things we are licensing (it matters to some texts)
 	 */
 	uw.LicenseGroup = function UWLicenseGroup( config, type, api, count ) {
-		var self = this;
+		const self = this;
 
 		uw.LicenseGroup.parent.call( this, {} );
 
@@ -30,7 +30,7 @@
 			throw new Error( 'improper license config' );
 		}
 
-		if ( [ 'radio', 'checkbox' ].indexOf( type ) < 0 ) {
+		if ( ![ 'radio', 'checkbox' ].includes( type ) ) {
 			throw new Error( 'Invalid type: ' + type );
 		}
 
@@ -58,12 +58,12 @@
 		}
 
 		// when selecting an item that has a custom textarea, we'll immediately focus it
-		this.on( 'change', function ( group, item ) {
+		this.on( 'change', ( group, item ) => {
 			if ( item && item.isSelected && item.isSelected() ) {
 				// wrapped inside setTimeout to ensure it goes at the end of the call stack,
 				// just in case something steals focus in the meantime...
-				setTimeout( function () {
-					var name = item.getData();
+				setTimeout( () => {
+					const name = item.getData();
 					if ( self.textareas[ name ] ) {
 						self.textareas[ name ].focus();
 					}
@@ -86,7 +86,7 @@
 	 */
 	uw.LicenseGroup.prototype.createFieldset = function ( group ) {
 		/* eslint-disable mediawiki/msg-doc */
-		var $head = this.config.head && $( '<a>' )
+		const $head = this.config.head && $( '<a>' )
 				.addClass( 'mediauploader-deed-license-group-head' )
 				.msg( this.config.head, this.count )
 				.prepend( $( '<span>' ).addClass( 'mw-toggle-icon' ) ),
@@ -118,11 +118,11 @@
 	 * @return {OO.ui.RadioSelectWidget}
 	 */
 	uw.LicenseGroup.prototype.createRadioGroup = function ( classes ) {
-		var self = this,
+		const self = this,
 			options = [];
 
-		this.config.licenses.forEach( function ( licenseName ) {
-			var option;
+		this.config.licenses.forEach( ( licenseName ) => {
+			let option;
 
 			if ( mw.UploadWizard.config.licenses[ licenseName ] === undefined ) {
 				// unknown license
@@ -136,7 +136,7 @@
 
 			// when custom text area receives focus, we should make sure this element is selected
 			if ( self.textareas[ licenseName ] ) {
-				self.textareas[ licenseName ].on( 'focus', function () {
+				self.textareas[ licenseName ].on( 'focus', () => {
 					option.setSelected( true );
 				} );
 			}
@@ -153,11 +153,11 @@
 	 * @return {OO.ui.CheckboxMultiselectInputWidget}
 	 */
 	uw.LicenseGroup.prototype.createCheckboxGroup = function ( classes ) {
-		var self = this,
+		const self = this,
 			options = [];
 
-		this.config.licenses.forEach( function ( licenseName ) {
-			var option;
+		this.config.licenses.forEach( ( licenseName ) => {
+			let option;
 
 			if ( mw.UploadWizard.config.licenses[ licenseName ] === undefined ) {
 				// unknown license
@@ -171,7 +171,7 @@
 
 			// when custom text area receives focus, we should make sure this element is selected
 			if ( self.textareas[ licenseName ] ) {
-				self.textareas[ licenseName ].on( 'focus', function () {
+				self.textareas[ licenseName ].on( 'focus', () => {
 					option.setSelected( true );
 				} );
 			}
@@ -187,12 +187,12 @@
 	 * @return {string}
 	 */
 	uw.LicenseGroup.prototype.getWikiText = function () {
-		var wikiTexts,
+		let wikiTexts,
 			self = this,
 			values = this.getValue();
 
-		wikiTexts = Object.keys( values ).map( function ( name ) {
-			var wikiText = self.getLicenseWikiText( name ),
+		wikiTexts = Object.keys( values ).map( ( name ) => {
+			let wikiText = self.getLicenseWikiText( name ),
 				value = values[ name ];
 			if ( typeof value === 'string' ) {
 				// `value` is custom input
@@ -219,7 +219,7 @@
 	 * @return {Object} Map of { licenseName: true }, or { licenseName: "custom input" }
 	 */
 	uw.LicenseGroup.prototype.getValue = function () {
-		var self = this,
+		let self = this,
 			result = {},
 			selected,
 			name;
@@ -232,7 +232,7 @@
 			}
 		} else if ( this.type === 'checkbox' ) {
 			selected = this.group.findSelectedItems();
-			selected.forEach( function ( item ) {
+			selected.forEach( ( item ) => {
 				name = item.getData();
 				result[ name ] = !self.textareas[ name ] || self.textareas[ name ].getValue();
 			} );
@@ -245,12 +245,12 @@
 	 * @param {Object} values Map of { licenseName: true }, or { licenseName: "custom input" }
 	 */
 	uw.LicenseGroup.prototype.setValue = function ( values ) {
-		var self = this,
+		let self = this,
 			selectArray = [],
 			selected;
 
-		Object.keys( values ).forEach( function ( name ) {
-			var value = values[ name ];
+		Object.keys( values ).forEach( ( name ) => {
+			const value = values[ name ];
 			if ( typeof value === 'string' && self.textareas[ name ] ) {
 				self.textareas[ name ].setValue( value );
 				// add to list of items to select
@@ -300,7 +300,7 @@
 	 * @return {string} of wikitext
 	 */
 	uw.LicenseGroup.prototype.getLicenseWikiText = function ( name ) {
-		var licenseInfo = this.getLicenseInfo( name ),
+		let licenseInfo = this.getLicenseInfo( name ),
 			licenseText;
 
 		licenseText = licenseInfo.props.wikitext !== undefined ?
@@ -316,7 +316,7 @@
 	 * @return {jQuery}
 	 */
 	uw.LicenseGroup.prototype.createLabel = function ( name ) {
-		var licenseInfo = this.getLicenseInfo( name ),
+		let licenseInfo = this.getLicenseInfo( name ),
 			messageKey = licenseInfo.props.msg === undefined ?
 				'[missing msg for ' + licenseInfo.name + ']' :
 				licenseInfo.props.msg,
@@ -333,7 +333,7 @@
 		}
 		$licenseLink = $( '<a>' ).attr( { target: '_blank', href: licenseURL } );
 		if ( licenseInfo.props.icons !== undefined ) {
-			licenseInfo.props.icons.forEach( function ( icon ) {
+			licenseInfo.props.icons.forEach( ( icon ) => {
 				// eslint-disable-next-line mediawiki/class-doc
 				$icons.append( $( '<span>' ).addClass( 'mediauploader-license-icon mediauploader-' + icon + '-icon' ) );
 			} );
@@ -358,7 +358,7 @@
 	 * @return {jQuery} Wrapped textarea
 	 */
 	uw.LicenseGroup.prototype.createCustom = function ( name, defaultText ) {
-		var self = this,
+		let self = this,
 			button;
 
 		this.textareas[ name ] = new OO.ui.MultilineTextInputWidget( {
@@ -372,7 +372,7 @@
 		button = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-license-custom-preview' ).text(),
 			flags: [ 'progressive' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			self.showPreview( self.textareas[ name ].getValue() );
 		} );
 
@@ -389,7 +389,7 @@
 	 * @param {string} wikiText
 	 */
 	uw.LicenseGroup.prototype.showPreview = function ( wikiText ) {
-		var input;
+		let input;
 
 		this.previewDialog.setLoading( true );
 		this.windowManager.openWindow( this.previewDialog );
@@ -402,7 +402,7 @@
 		}
 
 		function error( code, result ) {
-			var message = result.errors[ 0 ].html;
+			const message = result.errors[ 0 ].html;
 
 			show( $( '<div>' ).append(
 				$( '<h3>' ).append( code ),
diff --git a/resources/uw.LicensePreviewDialog.js b/resources/uw.LicensePreviewDialog.js
index 133d1b5..08f5231 100644
--- a/resources/uw.LicensePreviewDialog.js
+++ b/resources/uw.LicensePreviewDialog.js
@@ -7,7 +7,7 @@
 	uw.LicensePreviewDialog.static.name = 'licensePreviewDialog';
 
 	uw.LicensePreviewDialog.prototype.initialize = function () {
-		var dialog = this;
+		const dialog = this;
 
 		uw.LicensePreviewDialog.parent.prototype.initialize.call( this );
 
@@ -16,7 +16,7 @@
 		this.$spinner = $.createSpinner( { size: 'large', type: 'block' } )
 			.css( { width: 200, padding: 20, float: 'none', margin: '0 auto' } );
 
-		$( document.body ).on( 'click', function ( e ) {
+		$( document.body ).on( 'click', ( e ) => {
 			if ( !$.contains( dialog.$body.get( 0 ), e.target ) ) {
 				dialog.close();
 			}
@@ -24,12 +24,12 @@
 	};
 
 	uw.LicensePreviewDialog.prototype.addCloseButton = function () {
-		var dialog = this,
+		const dialog = this,
 			closeButton = new OO.ui.ButtonWidget( {
 				label: OO.ui.msg( 'ooui-dialog-process-dismiss' )
 			} );
 
-		closeButton.on( 'click', function () {
+		closeButton.on( 'click', () => {
 			dialog.close();
 		} );
 
diff --git a/resources/uw.ValidationMessageElement.js b/resources/uw.ValidationMessageElement.js
index 1a50d13..72c5e89 100644
--- a/resources/uw.ValidationMessageElement.js
+++ b/resources/uw.ValidationMessageElement.js
@@ -43,7 +43,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.ValidationMessageElement.prototype.checkValidity = function ( thorough ) {
-		var element = this;
+		const element = this;
 		thorough = thorough || false;
 
 		if ( !this.validatedWidget.getWarnings || !this.validatedWidget.getErrors ) {
@@ -57,13 +57,13 @@
 		return $.when(
 			this.validatedWidget.getWarnings( thorough ),
 			this.validatedWidget.getErrors( thorough )
-		).then( function ( warnings, errors ) {
+		).then( ( warnings, errors ) => {
 			// this.notices and this.errors are arrays of mw.Messages and not strings in this subclass
 			element.setNotices( warnings );
 			element.setErrors( errors );
 
 			return $.Deferred().resolve( warnings, errors ).promise();
-		} ).always( function () {
+		} ).always( () => {
 			if ( element.validatedWidget.popPending ) {
 				element.validatedWidget.popPending();
 			}
@@ -77,7 +77,7 @@
 	 * @return {jQuery}
 	 */
 	uw.ValidationMessageElement.prototype.makeMessage = function ( kind, error ) {
-		var code, $content, $listItem;
+		let code, $content, $listItem;
 		if ( error.parseDom ) {
 			// mw.Message object
 			code = error.key;
diff --git a/resources/uw.units.js b/resources/uw.units.js
index 9720982..f36f63c 100644
--- a/resources/uw.units.js
+++ b/resources/uw.units.js
@@ -1,6 +1,6 @@
 ( function ( uw ) {
 
-	var scaleMsgKeys = [ 'size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes' ];
+	const scaleMsgKeys = [ 'size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes' ];
 
 	uw.units = {
 		/**
@@ -13,7 +13,7 @@
 		 * @return {string} formatted size
 		 */
 		bytes: function ( size ) {
-			var i = 0;
+			let i = 0;
 			while ( size >= 1024 && i < scaleMsgKeys.length - 1 ) {
 				size /= 1024.0;
 				i++;
diff --git a/tests/qunit/.eslintrc.json b/tests/qunit/.eslintrc.json
index a4f3832..26a9402 100644
--- a/tests/qunit/.eslintrc.json
+++ b/tests/qunit/.eslintrc.json
@@ -5,5 +5,9 @@
 	],
 	"globals": {
 		"sinon": false
+	},
+	"rules": {
+		"prefer-const": "warn",
+		"no-jquery/no-done-fail": "warn"
 	}
 }
diff --git a/tests/qunit/controller/uw.controller.Deed.test.js b/tests/qunit/controller/uw.controller.Deed.test.js
index fa5b40c..98b5cbb 100644
--- a/tests/qunit/controller/uw.controller.Deed.test.js
+++ b/tests/qunit/controller/uw.controller.Deed.test.js
@@ -18,15 +18,15 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Deed', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Deed();
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Deed();
 		assert.true( !!step );
 		assert.true( step instanceof uw.controller.Step );
 		assert.true( !!step.ui );
 	} );
 
 	QUnit.test( 'load', function ( assert ) {
-		var step = new uw.controller.Deed(
+		const step = new uw.controller.Deed(
 				new mw.Api(),
 				{ licensing: {
 					enabled: true,
diff --git a/tests/qunit/controller/uw.controller.Details.test.js b/tests/qunit/controller/uw.controller.Details.test.js
index 689c5f7..7b6a5d9 100644
--- a/tests/qunit/controller/uw.controller.Details.test.js
+++ b/tests/qunit/controller/uw.controller.Details.test.js
@@ -19,7 +19,7 @@
 	QUnit.module( 'uw.controller.Details', QUnit.newMwEnvironment() );
 
 	function createTestUpload( sandbox, customDeedChooser, aborted ) {
-		var stubs = {
+		const stubs = {
 			ucdc: sandbox.stub(),
 			getSerialized: sandbox.stub(),
 			setSerialized: sandbox.stub(),
@@ -44,8 +44,8 @@
 		};
 	}
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Details( new mw.Api(), {
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Details( new mw.Api(), {
 			maxSimultaneousConnections: 1
 		} );
 		assert.true( !!step );
@@ -54,7 +54,7 @@
 	} );
 
 	QUnit.test( 'load', function ( assert ) {
-		var step = new uw.controller.Details( new mw.Api(), {
+		let step = new uw.controller.Details( new mw.Api(), {
 				maxSimultaneousConnections: 1
 			} ),
 			testUpload = createTestUpload( this.sandbox ),
@@ -92,8 +92,8 @@
 		assert.true( stepUiStub.called );
 	} );
 
-	QUnit.test( 'canTransition', function ( assert ) {
-		var upload = {},
+	QUnit.test( 'canTransition', ( assert ) => {
+		const upload = {},
 			step = new uw.controller.Details( new mw.Api(), {
 				maxSimultaneousConnections: 1
 			} );
@@ -106,7 +106,7 @@
 	} );
 
 	QUnit.test( 'transitionAll', function ( assert ) {
-		var tostub,
+		let tostub,
 			done = assert.async(),
 			donestub = this.sandbox.stub(),
 			ds = [ $.Deferred(), $.Deferred(), $.Deferred() ],
@@ -133,7 +133,7 @@
 		];
 
 		step.transitionAll().done( donestub );
-		setTimeout( function () {
+		setTimeout( () => {
 			calls = [ tostub.getCall( 0 ), tostub.getCall( 1 ), tostub.getCall( 2 ) ];
 
 			assert.strictEqual( calls[ 0 ].args[ 0 ].id, 15 );
@@ -141,11 +141,11 @@
 
 			ds[ 0 ].resolve();
 			ds[ 1 ].resolve();
-			setTimeout( function () {
+			setTimeout( () => {
 				assert.strictEqual( donestub.called, false );
 
 				ds[ 2 ].resolve();
-				setTimeout( function () {
+				setTimeout( () => {
 					assert.true( donestub.called );
 
 					done();
diff --git a/tests/qunit/controller/uw.controller.Step.test.js b/tests/qunit/controller/uw.controller.Step.test.js
index a30f7ae..17a5901 100644
--- a/tests/qunit/controller/uw.controller.Step.test.js
+++ b/tests/qunit/controller/uw.controller.Step.test.js
@@ -18,8 +18,8 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Step', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Step( { on: function () {} }, new mw.Api(), {} );
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Step( { on: function () {} }, new mw.Api(), {} );
 		assert.true( !!step );
 		assert.true( !!step.ui );
 	} );
diff --git a/tests/qunit/controller/uw.controller.Thanks.test.js b/tests/qunit/controller/uw.controller.Thanks.test.js
index c19f4d5..0929619 100644
--- a/tests/qunit/controller/uw.controller.Thanks.test.js
+++ b/tests/qunit/controller/uw.controller.Thanks.test.js
@@ -18,15 +18,15 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Thanks', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Thanks( new mw.Api(), { display: { thanksLabel: 'Thanks!' } } );
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Thanks( new mw.Api(), { display: { thanksLabel: 'Thanks!' } } );
 		assert.true( !!step );
 		assert.true( step instanceof uw.controller.Step );
 		assert.true( !!step.ui );
 	} );
 
 	QUnit.test( 'load', function ( assert ) {
-		var step = new uw.controller.Thanks( new mw.Api(), {} ),
+		const step = new uw.controller.Thanks( new mw.Api(), {} ),
 			auStub = this.sandbox.stub( step.ui, 'addUpload' );
 
 		this.sandbox.stub( step.ui, 'load' );
@@ -39,8 +39,8 @@
 		assert.strictEqual( auStub.callCount, 3 );
 	} );
 
-	QUnit.test( 'Custom button configuration', function ( assert ) {
-		var config = {
+	QUnit.test( 'Custom button configuration', ( assert ) => {
+		const config = {
 				display: {
 					homeButton: {
 						label: 'This is just a test',
diff --git a/tests/qunit/controller/uw.controller.Tutorial.test.js b/tests/qunit/controller/uw.controller.Tutorial.test.js
index 2a780a4..86122c1 100644
--- a/tests/qunit/controller/uw.controller.Tutorial.test.js
+++ b/tests/qunit/controller/uw.controller.Tutorial.test.js
@@ -18,8 +18,8 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Tutorial', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Tutorial( new mw.Api() );
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Tutorial( new mw.Api() );
 		assert.true( !!step );
 		assert.true( step instanceof uw.controller.Step );
 		assert.true( !!step.ui );
@@ -27,7 +27,7 @@
 	} );
 
 	QUnit.test( 'setSkipPreference', function ( assert ) {
-		var mnStub,
+		let mnStub,
 			api = new mw.Api(),
 			step = new uw.controller.Tutorial( api ),
 			acwStub = { release: this.sandbox.stub() },
diff --git a/tests/qunit/controller/uw.controller.Upload.test.js b/tests/qunit/controller/uw.controller.Upload.test.js
index 4cd12dd..09febdd 100644
--- a/tests/qunit/controller/uw.controller.Upload.test.js
+++ b/tests/qunit/controller/uw.controller.Upload.test.js
@@ -18,8 +18,8 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Upload', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Upload( new mw.Api(), {
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Upload( new mw.Api(), {
 			maxUploads: 10,
 			maxSimultaneousConnections: 3
 		} );
@@ -29,7 +29,7 @@
 	} );
 
 	QUnit.test( 'updateFileCounts', function ( assert ) {
-		var step = new uw.controller.Upload( new mw.Api(), {
+		const step = new uw.controller.Upload( new mw.Api(), {
 				maxUploads: 5,
 				maxSimultaneousConnections: 3
 			} ),
@@ -50,8 +50,8 @@
 		assert.true( ufcStub.calledWith( true, false ) );
 	} );
 
-	QUnit.test( 'canTransition', function ( assert ) {
-		var upload = {},
+	QUnit.test( 'canTransition', ( assert ) => {
+		const upload = {},
 			step = new uw.controller.Upload( new mw.Api(), {
 				maxSimultaneousConnections: 1
 			} );
@@ -64,7 +64,7 @@
 	} );
 
 	QUnit.test( 'transitionOne', function ( assert ) {
-		var upload = {
+		const upload = {
 				start: this.sandbox.stub()
 			},
 			step = new uw.controller.Upload( new mw.Api(), {
diff --git a/tests/qunit/mw.UploadWizardLicenseInput.test.js b/tests/qunit/mw.UploadWizardLicenseInput.test.js
index f135b4b..2f84303 100644
--- a/tests/qunit/mw.UploadWizardLicenseInput.test.js
+++ b/tests/qunit/mw.UploadWizardLicenseInput.test.js
@@ -13,8 +13,8 @@ QUnit.module( 'ext.uploadWizardLicenseInput', QUnit.newMwEnvironment( {
 	}
 } ) );
 
-QUnit.test( 'Smoke test', function ( assert ) {
-	var config = { type: 'radio', licenses: [] },
+QUnit.test( 'Smoke test', ( assert ) => {
+	let config = { type: 'radio', licenses: [] },
 		$fixture = $( '<div>' ),
 		uwLicenseInput;
 
@@ -23,8 +23,8 @@ QUnit.test( 'Smoke test', function ( assert ) {
 	assert.true( !!uwLicenseInput, 'LicenseInput object created !' );
 } );
 
-QUnit.test( 'createInputs()', function ( assert ) {
-	var config = { type: 'radio', licenses: [ 'cc-by-sa-3.0' ] },
+QUnit.test( 'createInputs()', ( assert ) => {
+	let config = { type: 'radio', licenses: [ 'cc-by-sa-3.0' ] },
 		$fixture = $( '<div>' ),
 		uwLicenseInput,
 		$input,
@@ -42,8 +42,8 @@ QUnit.test( 'createInputs()', function ( assert ) {
 	assert.strictEqual( $label.length, 1, 'Label created.' );
 } );
 
-QUnit.test( 'createGroupedInputs()', function ( assert ) {
-	var config = {
+QUnit.test( 'createGroupedInputs()', ( assert ) => {
+	let config = {
 			type: 'checkbox',
 			licenseGroups: [
 				{
diff --git a/tests/qunit/mw.UploadWizardUpload.test.js b/tests/qunit/mw.UploadWizardUpload.test.js
index ad76777..0d7673d 100644
--- a/tests/qunit/mw.UploadWizardUpload.test.js
+++ b/tests/qunit/mw.UploadWizardUpload.test.js
@@ -19,7 +19,7 @@
 	QUnit.module( 'mw.UploadWizardUpload', QUnit.newMwEnvironment() );
 
 	function createUpload( filename ) {
-		var upload,
+		let upload,
 			oldconf = mw.UploadWizard.config;
 
 		mw.UploadWizard.config = {};
@@ -39,14 +39,14 @@
 		return upload;
 	}
 
-	QUnit.test( 'constructor sanity test', function ( assert ) {
-		var upload = createUpload();
+	QUnit.test( 'constructor sanity test', ( assert ) => {
+		const upload = createUpload();
 
 		assert.true( !!upload );
 	} );
 
-	QUnit.test( 'getBasename', function ( assert ) {
-		var upload;
+	QUnit.test( 'getBasename', ( assert ) => {
+		let upload;
 
 		upload = createUpload( 'path/to/filename.png' );
 		assert.strictEqual( upload.getBasename(), 'filename.png', 'Path is stripped' );
diff --git a/tests/qunit/mw.fileApi.test.js b/tests/qunit/mw.fileApi.test.js
index 9405e7c..cde0c62 100644
--- a/tests/qunit/mw.fileApi.test.js
+++ b/tests/qunit/mw.fileApi.test.js
@@ -19,7 +19,7 @@
 	QUnit.module( 'mw.fileApi', QUnit.newMwEnvironment() );
 
 	QUnit.test( 'isPreviewableFile', function ( assert ) {
-		var testFile = {};
+		const testFile = {};
 
 		testFile.type = 'image/png';
 		testFile.size = 5 * 1024 * 1024;
@@ -43,7 +43,7 @@
 	} );
 
 	QUnit.test( 'isPreviewableVideo', function ( assert ) {
-		var result, testFile = {},
+		let result, testFile = {},
 			fakeVideo = {
 				canPlayType: this.sandbox.stub().returns( 'yes' )
 			};
diff --git a/tests/qunit/transports/mw.FormDataTransport.test.js b/tests/qunit/transports/mw.FormDataTransport.test.js
index 76b9c4b..f6c3a87 100644
--- a/tests/qunit/transports/mw.FormDataTransport.test.js
+++ b/tests/qunit/transports/mw.FormDataTransport.test.js
@@ -19,7 +19,7 @@
 	QUnit.module( 'mw.FormDataTransport', QUnit.newMwEnvironment() );
 
 	function createTransport( chunkSize, api ) {
-		var config;
+		let config;
 
 		chunkSize = chunkSize || 0;
 		api = api || {};
@@ -33,14 +33,14 @@
 		return new mw.FormDataTransport( api, {}, config );
 	}
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var transport = createTransport();
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const transport = createTransport();
 
 		assert.true( !!transport );
 	} );
 
 	QUnit.test( 'abort', function ( assert ) {
-		var transport = createTransport( 0 ),
+		const transport = createTransport( 0 ),
 			request = $.Deferred().promise( { abort: this.sandbox.stub() } );
 
 		transport.request = request;
@@ -53,8 +53,8 @@
 		assert.true( transport.aborted );
 	} );
 
-	QUnit.test( 'createParams', function ( assert ) {
-		var transport = createTransport( 10 ),
+	QUnit.test( 'createParams', ( assert ) => {
+		const transport = createTransport( 10 ),
 			params = transport.createParams( 'foobar.jpg', 0 );
 
 		assert.true( !!params );
@@ -64,7 +64,7 @@
 	} );
 
 	QUnit.test( 'post', function ( assert ) {
-		var stub = this.sandbox.stub(),
+		const stub = this.sandbox.stub(),
 			// post() works on a promise and binds .then, so we have to make
 			// sure it actually is a promise, but also that it calls our stub
 			transport = createTransport( 10, { post: function () {
@@ -82,7 +82,7 @@
 	} );
 
 	QUnit.test( 'upload', function ( assert ) {
-		var request,
+		let request,
 			transport = createTransport( 10, new mw.Api() ),
 			fakeFile = {
 				name: 'test file for fdt.jpg',
@@ -103,7 +103,7 @@
 	} );
 
 	QUnit.test( 'uploadChunk', function ( assert ) {
-		var request,
+		let request,
 			transport = createTransport( 10, new mw.Api() ),
 			fakeFile = {
 				name: 'test file for fdt.jpg',
@@ -132,7 +132,7 @@
 
 	// test invalid server response (in missing 'stage' param)
 	QUnit.test( 'checkStatus invalid API response', function ( assert ) {
-		var done = assert.async(),
+		const done = assert.async(),
 			transport = createTransport( 10, new mw.Api() ),
 			tstub = this.sandbox.stub(),
 			poststub = this.sandbox.stub( transport.api, 'post' ),
@@ -143,7 +143,7 @@
 		postd.resolve( { upload: { result: 'Poll' } } );
 
 		// call tstub upon checkStatus failure, and verify it got called correctly
-		transport.checkStatus().fail( tstub, function () {
+		transport.checkStatus().fail( tstub, () => {
 			assert.true( tstub.calledWith( 'server-error', { errors: [ {
 				code: 'server-error',
 				html: mw.message( 'api-clientside-error-invalidresponse' ).parse()
@@ -154,7 +154,7 @@
 
 	// test retry after server responds upload is still incomplete
 	QUnit.test( 'checkStatus retry', function ( assert ) {
-		var transport = createTransport( 10, new mw.Api() ),
+		const transport = createTransport( 10, new mw.Api() ),
 			usstub = this.sandbox.stub(),
 			poststub = this.sandbox.stub( transport.api, 'post' ),
 			postd = $.Deferred(),
@@ -176,14 +176,14 @@
 
 		// confirm that, once second API call was successful, status resolves,
 		// 2 API calls have gone out & the failed call updates stage accordingly
-		return transport.checkStatus().done( function () {
+		return transport.checkStatus().done( () => {
 			assert.true( poststub.calledTwice );
 			assert.true( usstub.firstCall.calledWith( 'queued' ) );
 		} );
 	} );
 
 	QUnit.test( 'checkStatus success', function ( assert ) {
-		var transport = createTransport( 10, new mw.Api() ),
+		const transport = createTransport( 10, new mw.Api() ),
 			tstub = this.sandbox.stub(),
 			usstub = this.sandbox.stub(),
 			poststub = this.sandbox.stub( transport.api, 'post' ),
@@ -195,14 +195,14 @@
 		poststub.returns( postd.promise() );
 		postd.resolve( 'testing' );
 
-		return transport.checkStatus().done( tstub, function () {
+		return transport.checkStatus().done( tstub, () => {
 			assert.true( tstub.calledWith( 'testing' ) );
 			assert.false( usstub.called );
 		} );
 	} );
 
 	QUnit.test( 'checkStatus error API response', function ( assert ) {
-		var done = assert.async(),
+		const done = assert.async(),
 			transport = createTransport( 10, new mw.Api() ),
 			tstub = this.sandbox.stub(),
 			usstub = this.sandbox.stub(),
@@ -215,7 +215,7 @@
 		poststub.returns( postd.promise() );
 		postd.reject( 'testing', { error: 'testing' } );
 
-		transport.checkStatus().fail( tstub, function () {
+		transport.checkStatus().fail( tstub, () => {
 			assert.true( tstub.calledWith( 'testing', { error: 'testing' } ) );
 			assert.false( usstub.called );
 			done();
diff --git a/tests/qunit/uw.ConcurrentQueue.test.js b/tests/qunit/uw.ConcurrentQueue.test.js
index 2bf97e4..c288d3e 100644
--- a/tests/qunit/uw.ConcurrentQueue.test.js
+++ b/tests/qunit/uw.ConcurrentQueue.test.js
@@ -25,7 +25,7 @@
 	// trigger the next one to execute, which would terminate immediately,
 	// instead of giving time for a second new thingy to be added)
 	function queueAction() {
-		var deferred = $.Deferred();
+		const deferred = $.Deferred();
 		setTimeout( deferred.resolve, 10 );
 		return deferred.promise();
 	}
@@ -33,9 +33,9 @@
 	// Asserts that the given stub functions were called in the given order.
 	// SinonJS's assert.callOrder doesn't allow to check individual calls.
 	function assertCalledInOrder() {
-		var calls, i, currSpyCall, nextSpyCall;
+		let calls, i, currSpyCall, nextSpyCall;
 		// Map stubs to specific calls
-		calls = Array.prototype.map.call( arguments, function ( spy ) {
+		calls = Array.prototype.map.call( arguments, ( spy ) => {
 			if ( !spy.assertCallsInOrderLastCall ) {
 				spy.assertCallsInOrderLastCall = 0;
 			}
@@ -60,8 +60,8 @@
 		);
 	}
 
-	QUnit.test( 'Basic behavior', function ( assert ) {
-		var done, action, queue;
+	QUnit.test( 'Basic behavior', ( assert ) => {
+		let done, action, queue;
 		done = assert.async();
 		action = sinon.spy( queueAction );
 		queue = new uw.ConcurrentQueue( {
@@ -69,11 +69,11 @@
 			action: action
 		} );
 
-		queue.on( 'progress', function () {
+		queue.on( 'progress', () => {
 			QUnit.assert.true( queue.running.length <= 3, 'No more than 3 items are executing' );
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			// All items executed
 			sinon.assert.callCount( action, 5 );
 			// All items executed in the expected order
@@ -86,15 +86,15 @@
 			done();
 		} );
 
-		[ 'a', 'b', 'c', 'd', 'e' ].forEach( function ( v ) {
+		[ 'a', 'b', 'c', 'd', 'e' ].forEach( ( v ) => {
 			queue.addItem( v );
 		} );
 
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Event emitting', function ( assert ) {
-		var done, changeHandler, progressHandler, completeHandler, queue;
+	QUnit.test( 'Event emitting', ( assert ) => {
+		let done, changeHandler, progressHandler, completeHandler, queue;
 		done = assert.async();
 		changeHandler = sinon.stub();
 		progressHandler = sinon.stub();
@@ -110,7 +110,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			sinon.assert.callCount( changeHandler, 3 );
 			sinon.assert.callCount( progressHandler, 3 );
 			sinon.assert.callCount( completeHandler, 1 );
@@ -134,8 +134,8 @@
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Restarting a completed queue', function ( assert ) {
-		var done, queue;
+	QUnit.test( 'Restarting a completed queue', ( assert ) => {
+		let done, queue;
 		done = assert.async();
 		queue = new uw.ConcurrentQueue( {
 			count: 3,
@@ -146,12 +146,12 @@
 		queue.addItem( 'b' );
 		queue.addItem( 'c' );
 
-		queue.once( 'complete', function () {
+		queue.once( 'complete', () => {
 			QUnit.assert.equal( queue.completed, true );
 			queue.addItem( 'd' );
 			queue.addItem( 'e' );
 
-			queue.once( 'complete', function () {
+			queue.once( 'complete', () => {
 				QUnit.assert.equal( queue.completed, true );
 				done();
 			} );
@@ -162,15 +162,15 @@
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Empty queue completes', function ( assert ) {
-		var done, queue;
+	QUnit.test( 'Empty queue completes', ( assert ) => {
+		let done, queue;
 		done = assert.async();
 		queue = new uw.ConcurrentQueue( {
 			count: 3,
 			action: queueAction
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			QUnit.assert.equal( queue.completed, true );
 
 			done();
@@ -179,8 +179,8 @@
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Adding new items while queue running', function ( assert ) {
-		var done, changeHandler, progressHandler, completeHandler, queue;
+	QUnit.test( 'Adding new items while queue running', ( assert ) => {
+		let done, changeHandler, progressHandler, completeHandler, queue;
 		done = assert.async();
 		changeHandler = sinon.stub();
 		progressHandler = sinon.stub();
@@ -196,7 +196,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			sinon.assert.callCount( changeHandler, 6 );
 			sinon.assert.callCount( progressHandler, 6 );
 			sinon.assert.callCount( completeHandler, 1 );
@@ -223,11 +223,11 @@
 		queue.addItem( 'a' );
 		queue.addItem( 'b' );
 		queue.addItem( 'c' );
-		queue.once( 'progress', function () {
+		queue.once( 'progress', () => {
 			queue.addItem( 'd' );
 			queue.addItem( 'e' );
 		} );
-		queue.on( 'progress', function () {
+		queue.on( 'progress', () => {
 			if ( queue.done.length === 5 ) {
 				queue.addItem( 'f' );
 			}
@@ -235,8 +235,8 @@
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Deleting items while queue running', function ( assert ) {
-		var done, changeHandler, progressHandler, completeHandler, queue;
+	QUnit.test( 'Deleting items while queue running', ( assert ) => {
+		let done, changeHandler, progressHandler, completeHandler, queue;
 		done = assert.async();
 		changeHandler = sinon.stub();
 		progressHandler = sinon.stub();
@@ -252,7 +252,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			sinon.assert.callCount( changeHandler, 8 );
 			sinon.assert.callCount( progressHandler, 4 );
 			sinon.assert.callCount( completeHandler, 1 );
@@ -282,18 +282,18 @@
 		queue.addItem( 'd' );
 		queue.addItem( 'e' );
 		queue.addItem( 'f' );
-		queue.once( 'progress', function () {
+		queue.once( 'progress', () => {
 			queue.removeItem( queue.queued[ 0 ] );
 
-			queue.once( 'progress', function () {
+			queue.once( 'progress', () => {
 				queue.removeItem( queue.queued[ 0 ] );
 			} );
 		} );
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Deleting currently running item', function ( assert ) {
-		var done, action, changeHandler, progressHandler, completeHandler, queue;
+	QUnit.test( 'Deleting currently running item', ( assert ) => {
+		let done, action, changeHandler, progressHandler, completeHandler, queue;
 		done = assert.async();
 		action = sinon.spy( queueAction );
 		changeHandler = sinon.stub();
@@ -310,7 +310,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			// Every item in the queue was executed...
 			sinon.assert.callCount( action, 4 );
 
@@ -342,14 +342,14 @@
 		queue.addItem( 'b' );
 		queue.addItem( 'c' );
 		queue.addItem( 'd' );
-		queue.once( 'progress', function () {
+		queue.once( 'progress', () => {
 			queue.removeItem( queue.running[ 0 ] );
 		} );
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Adding a new item when almost done', function ( assert ) {
-		var done, action, changeHandler, progressHandler, completeHandler, queue, onProgress;
+	QUnit.test( 'Adding a new item when almost done', ( assert ) => {
+		let done, action, changeHandler, progressHandler, completeHandler, queue, onProgress;
 		done = assert.async();
 		// This test seems extra flaky and was occasionally failing, double the delays
 		action = sinon.spy( queueAction );
@@ -367,7 +367,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			sinon.assert.callCount( action, 5 );
 			sinon.assert.callCount( changeHandler, 5 );
 			sinon.assert.callCount( progressHandler, 5 );
diff --git a/tests/qunit/uw.TitleDetailsWidget.test.js b/tests/qunit/uw.TitleDetailsWidget.test.js
index 8992c60..571ab1c 100644
--- a/tests/qunit/uw.TitleDetailsWidget.test.js
+++ b/tests/qunit/uw.TitleDetailsWidget.test.js
@@ -1,7 +1,7 @@
 ( function ( uw ) {
 	'use strict';
 
-	var fileNs, makeTitleInFileNSCases;
+	let fileNs, makeTitleInFileNSCases;
 	fileNs = mw.config.get( 'wgFormattedNamespaces' )[ 6 ];
 	makeTitleInFileNSCases = [ {
 		filename: 'foo.png',
@@ -35,11 +35,11 @@
 
 	QUnit.module( 'uw.TitleDetailsWidget', QUnit.newMwEnvironment() );
 
-	QUnit.test( '.static.makeTitleInFileNS()', function ( assert ) {
-		var makeTitleInFileNS = uw.TitleDetailsWidget.static.makeTitleInFileNS;
+	QUnit.test( '.static.makeTitleInFileNS()', ( assert ) => {
+		const makeTitleInFileNS = uw.TitleDetailsWidget.static.makeTitleInFileNS;
 
-		makeTitleInFileNSCases.forEach( function ( test ) {
-			var title = makeTitleInFileNS( test.filename );
+		makeTitleInFileNSCases.forEach( ( test ) => {
+			const title = makeTitleInFileNS( test.filename );
 			assert.strictEqual(
 				title ? title.getPrefixedText() : title,
 				test.prefixedText,
-- 
2.39.5

$ date
--- stdout ---
Mon Jun  9 02:03:08 UTC 2025

--- end ---
$ git clone file:///srv/git/mediawiki-extensions-MediaUploader.git repo --depth=1 -b master
--- stderr ---
Cloning into 'repo'...
--- stdout ---

--- end ---
$ git config user.name libraryupgrader
--- stdout ---

--- end ---
$ git config user.email tools.libraryupgrader@tools.wmflabs.org
--- stdout ---

--- end ---
$ git submodule update --init
--- stdout ---

--- end ---
$ grr init
--- stdout ---
Installed commit-msg hook.

--- end ---
$ git show-ref refs/heads/master
--- stdout ---
058de7433f7a19034f35f1290ac44867f1318b58 refs/heads/master

--- end ---
$ /usr/bin/npm audit --json
--- stdout ---
{
  "auditReportVersion": 2,
  "vulnerabilities": {
    "cross-spawn": {
      "name": "cross-spawn",
      "severity": "high",
      "isDirect": false,
      "via": [
        {
          "source": 1104664,
          "name": "cross-spawn",
          "dependency": "cross-spawn",
          "title": "Regular Expression Denial of Service (ReDoS) in cross-spawn",
          "url": "https://github.com/advisories/GHSA-3xgq-45jj-v275",
          "severity": "high",
          "cwe": [
            "CWE-1333"
          ],
          "cvss": {
            "score": 7.5,
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
          },
          "range": ">=7.0.0 <7.0.5"
        }
      ],
      "effects": [],
      "range": "7.0.0 - 7.0.4",
      "nodes": [
        "node_modules/cross-spawn"
      ],
      "fixAvailable": true
    },
    "nanoid": {
      "name": "nanoid",
      "severity": "moderate",
      "isDirect": false,
      "via": [
        {
          "source": 1101163,
          "name": "nanoid",
          "dependency": "nanoid",
          "title": "Predictable results in nanoid generation when given non-integer values",
          "url": "https://github.com/advisories/GHSA-mwcw-c2x4-8c55",
          "severity": "moderate",
          "cwe": [
            "CWE-835"
          ],
          "cvss": {
            "score": 4.3,
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N"
          },
          "range": "<3.3.8"
        }
      ],
      "effects": [],
      "range": "<3.3.8",
      "nodes": [
        "node_modules/nanoid"
      ],
      "fixAvailable": true
    }
  },
  "metadata": {
    "vulnerabilities": {
      "info": 0,
      "low": 0,
      "moderate": 1,
      "high": 1,
      "critical": 0,
      "total": 2
    },
    "dependencies": {
      "prod": 1,
      "dev": 449,
      "optional": 0,
      "peer": 1,
      "peerOptional": 0,
      "total": 449
    }
  }
}

--- end ---
$ /usr/bin/composer install
--- stderr ---
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 40 installs, 0 updates, 0 removals
  - Locking composer/pcre (3.3.2)
  - Locking composer/semver (3.4.3)
  - Locking composer/spdx-licenses (1.5.9)
  - Locking composer/xdebug-handler (3.0.5)
  - Locking dealerdirect/phpcodesniffer-composer-installer (v1.0.0)
  - Locking doctrine/deprecations (1.1.5)
  - Locking felixfbecker/advanced-json-rpc (v3.2.1)
  - Locking justinrainbow/json-schema (5.3.0)
  - Locking mediawiki/mediawiki-codesniffer (v45.0.0)
  - Locking mediawiki/mediawiki-phan-config (0.15.1)
  - Locking mediawiki/minus-x (1.1.3)
  - Locking mediawiki/phan-taint-check-plugin (6.1.0)
  - Locking microsoft/tolerant-php-parser (v0.1.2)
  - Locking netresearch/jsonmapper (v4.5.0)
  - Locking phan/phan (5.4.5)
  - Locking php-parallel-lint/php-console-color (v1.0.1)
  - Locking php-parallel-lint/php-console-highlighter (v1.0.0)
  - Locking php-parallel-lint/php-parallel-lint (v1.4.0)
  - Locking phpcsstandards/phpcsextra (1.2.1)
  - Locking phpcsstandards/phpcsutils (1.0.12)
  - Locking phpdocumentor/reflection-common (2.2.0)
  - Locking phpdocumentor/reflection-docblock (5.6.2)
  - Locking phpdocumentor/type-resolver (1.10.0)
  - Locking phpstan/phpdoc-parser (2.1.0)
  - Locking psr/container (2.0.2)
  - Locking psr/log (3.0.2)
  - Locking sabre/event (5.1.7)
  - Locking squizlabs/php_codesniffer (3.10.3)
  - Locking symfony/console (v7.3.0)
  - Locking symfony/deprecation-contracts (v3.6.0)
  - Locking symfony/polyfill-ctype (v1.32.0)
  - Locking symfony/polyfill-intl-grapheme (v1.32.0)
  - Locking symfony/polyfill-intl-normalizer (v1.32.0)
  - Locking symfony/polyfill-mbstring (v1.32.0)
  - Locking symfony/polyfill-php80 (v1.32.0)
  - Locking symfony/service-contracts (v3.6.0)
  - Locking symfony/string (v7.3.0)
  - Locking symfony/yaml (v5.4.45)
  - Locking tysonandre/var_representation_polyfill (0.1.3)
  - Locking webmozart/assert (1.11.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 40 installs, 0 updates, 0 removals
    0 [>---------------------------]    0 [->--------------------------]
  - Installing squizlabs/php_codesniffer (3.10.3): Extracting archive
  - Installing dealerdirect/phpcodesniffer-composer-installer (v1.0.0): Extracting archive
  - Installing composer/pcre (3.3.2): Extracting archive
  - Installing justinrainbow/json-schema (5.3.0): Extracting archive
  - Installing symfony/polyfill-php80 (v1.32.0): Extracting archive
  - Installing phpcsstandards/phpcsutils (1.0.12): Extracting archive
  - Installing phpcsstandards/phpcsextra (1.2.1): Extracting archive
  - Installing symfony/polyfill-mbstring (v1.32.0): Extracting archive
  - Installing composer/spdx-licenses (1.5.9): Extracting archive
  - Installing composer/semver (3.4.3): Extracting archive
  - Installing mediawiki/mediawiki-codesniffer (v45.0.0): Extracting archive
  - Installing tysonandre/var_representation_polyfill (0.1.3): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.32.0): Extracting archive
  - Installing symfony/polyfill-intl-grapheme (v1.32.0): Extracting archive
  - Installing symfony/polyfill-ctype (v1.32.0): Extracting archive
  - Installing symfony/string (v7.3.0): Extracting archive
  - Installing symfony/deprecation-contracts (v3.6.0): Extracting archive
  - Installing psr/container (2.0.2): Extracting archive
  - Installing symfony/service-contracts (v3.6.0): Extracting archive
  - Installing symfony/console (v7.3.0): Extracting archive
  - Installing sabre/event (5.1.7): Extracting archive
  - Installing netresearch/jsonmapper (v4.5.0): Extracting archive
  - Installing microsoft/tolerant-php-parser (v0.1.2): Extracting archive
  - Installing webmozart/assert (1.11.0): Extracting archive
  - Installing phpstan/phpdoc-parser (2.1.0): Extracting archive
  - Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
  - Installing doctrine/deprecations (1.1.5): Extracting archive
  - Installing phpdocumentor/type-resolver (1.10.0): Extracting archive
  - Installing phpdocumentor/reflection-docblock (5.6.2): Extracting archive
  - Installing felixfbecker/advanced-json-rpc (v3.2.1): Extracting archive
  - Installing psr/log (3.0.2): Extracting archive
  - Installing composer/xdebug-handler (3.0.5): Extracting archive
  - Installing phan/phan (5.4.5): Extracting archive
  - Installing mediawiki/phan-taint-check-plugin (6.1.0): Extracting archive
  - Installing mediawiki/mediawiki-phan-config (0.15.1): Extracting archive
  - Installing mediawiki/minus-x (1.1.3): Extracting archive
  - Installing php-parallel-lint/php-console-color (v1.0.1): Extracting archive
  - Installing php-parallel-lint/php-console-highlighter (v1.0.0): Extracting archive
  - Installing php-parallel-lint/php-parallel-lint (v1.4.0): Extracting archive
  - Installing symfony/yaml (v5.4.45): Extracting archive
  0/38 [>---------------------------]   0%
 20/38 [==============>-------------]  52%
 33/38 [========================>---]  86%
 38/38 [============================] 100%
1 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
17 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
--- stdout ---
PHP CodeSniffer Config installed_paths set to ../../mediawiki/mediawiki-codesniffer,../../phpcsstandards/phpcsextra,../../phpcsstandards/phpcsutils

--- end ---
Upgrading n:eslint-config-wikimedia from 0.28.2 -> 0.30.0
Upgrading n:stylelint-config-wikimedia from 0.17.2 -> 0.18.0
$ /usr/bin/npm install
--- stdout ---

added 438 packages, and audited 439 packages in 8s

97 packages are looking for funding
  run `npm fund` for details

1 high severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json

--- end ---
$ /usr/bin/npm install grunt-eslint@24.3.0 --save-exact
--- stdout ---

up to date, audited 439 packages in 1s

97 packages are looking for funding
  run `npm fund` for details

1 high severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json

--- end ---
$ ./node_modules/.bin/eslint . --fix
--- stdout ---

/src/repo/resources/controller/uw.controller.Deed.js
  44:4  error  'deedController' is never reassigned. Use 'const' instead  prefer-const
  52:3  error  'valid' is never reassigned. Use 'const' instead           prefer-const
  57:4  error  Mixed spaces and tabs                                      no-mixed-spaces-and-tabs
  57:6  error  Expected no linebreak before this expression               implicit-arrow-linebreak
  58:3  error  Mixed spaces and tabs                                      no-mixed-spaces-and-tabs

/src/repo/resources/controller/uw.controller.Details.js
   65:4  error  'serialized' is never reassigned. Use 'const' instead     prefer-const
   96:4  error  'invalidStates' is never reassigned. Use 'const' instead  prefer-const
   97:4  error  'invalids' is never reassigned. Use 'const' instead       prefer-const
   98:4  error  'valids' is never reassigned. Use 'const' instead         prefer-const
  153:3  error  Prefer .then to .done                                     no-jquery/no-done-fail
  238:4  error  '$message' is never reassigned. Use 'const' instead       prefer-const
  239:4  error  '$ul' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/controller/uw.controller.Step.js
  223:7  error  'okCount' is never reassigned. Use 'const' instead   prefer-const
  233:3  error  '$buttons' is never reassigned. Use 'const' instead  prefer-const
  324:4  error  'copy' is never reassigned. Use 'const' instead      prefer-const

/src/repo/resources/controller/uw.controller.Tutorial.js
  63:3  error  Prefer .then to .done  no-jquery/no-done-fail
  63:3  error  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/controller/uw.controller.Upload.js
   69:4  error  'max' is never reassigned. Use 'const' instead            prefer-const
   71:3  error  'haveUploads' is never reassigned. Use 'const' instead    prefer-const
   72:3  error  'fewerThanMax' is never reassigned. Use 'const' instead   prefer-const
  223:3  error  'upload' is never reassigned. Use 'const' instead         prefer-const
  251:4  error  'uploadObjs' is never reassigned. Use 'const' instead     prefer-const
  252:4  error  'controller' is never reassigned. Use 'const' instead     prefer-const
  307:4  error  'actualMaxSize' is never reassigned. Use 'const' instead  prefer-const
  311:4  error  'filename' is never reassigned. Use 'const' instead       prefer-const
  312:4  error  'basename' is never reassigned. Use 'const' instead       prefer-const
  335:3  error  'extension' is never reassigned. Use 'const' instead      prefer-const

/src/repo/resources/deed/uw.deed.External.js
  66:10  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/deed/uw.deed.OwnWork.js
   29:7   error    'deed' is never reassigned. Use 'const' instead                 prefer-const
   88:3   error    'deed' is never reassigned. Use 'const' instead                 prefer-const
   89:3   error    'languageCode' is never reassigned. Use 'const' instead         prefer-const
   91:3   error    'defaultLicense' is never reassigned. Use 'const' instead       prefer-const
   92:3   error    'defaultLicConfig' is never reassigned. Use 'const' instead     prefer-const
   99:3   error    '$defaultLicenseLink' is never reassigned. Use 'const' instead  prefer-const
  125:3   error    '$crossfader' is never reassigned. Use 'const' instead          prefer-const
  128:3   error    '$customDiv' is never reassigned. Use 'const' instead           prefer-const
  136:3   error    'crossfaderWidget' is never reassigned. Use 'const' instead     prefer-const
  148:3   error    '$formFields' is never reassigned. Use 'const' instead          prefer-const
  152:3   error    '$toggler' is never reassigned. Use 'const' instead             prefer-const
  192:7   error    'author' is never reassigned. Use 'const' instead               prefer-const
  200:3   error    'userPageTitle' is never reassigned. Use 'const' instead        prefer-const
  215:10  warning  ES2015 'Object.assign' method is forbidden                      es-x/no-object-assign
  255:16  error    'ownWork' is never reassigned. Use 'const' instead              prefer-const
  277:3   error    Prefer .then to .done                                           no-jquery/no-done-fail
  297:3   error    Prefer .then to .done                                           no-jquery/no-done-fail

/src/repo/resources/deed/uw.deed.ThirdParty.js
  178:10  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.CategoriesDetailsWidget.js
   87:3  error  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
   87:5  error  Expected no linebreak before this expression           implicit-arrow-linebreak
   88:2  error  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
   98:3  error  'categories' is never reassigned. Use 'const' instead  prefer-const
  128:3  error  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
  128:5  error  Expected no linebreak before this expression           implicit-arrow-linebreak
  129:2  error  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs

/src/repo/resources/details/uw.DropdownWidget.js
  13:12  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.LocationDetailsWidget.js
   12:17  warning  ES2015 'Object.assign' method is forbidden             es-x/no-object-assign
   71:3   error    Prefer .then to .done                                  no-jquery/no-done-fail
   84:3   error    Prefer .then to .done                                  no-jquery/no-done-fail
  115:7   error    'errors' is never reassigned. Use 'const' instead      prefer-const
  116:4   error    'serialized' is never reassigned. Use 'const' instead  prefer-const
  117:4   error    'parsed' is never reassigned. Use 'const' instead      prefer-const
  165:4   error    'serialized' is never reassigned. Use 'const' instead  prefer-const
  194:4   error    'result' is never reassigned. Use 'const' instead      prefer-const
  210:4   error    'result' is never reassigned. Use 'const' instead      prefer-const
  211:4   error    'serialized' is never reassigned. Use 'const' instead  prefer-const
  258:7   error    'sign' is never reassigned. Use 'const' instead        prefer-const
  268:3   error    'parts' is never reassigned. Use 'const' instead       prefer-const

/src/repo/resources/details/uw.MultipleLanguageInputWidget.js
   16:17  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   50:26  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   60:7   error    'allLanguages' is never reassigned. Use 'const' instead     prefer-const
   61:4   error    'unusedLanguages' is never reassigned. Use 'const' instead  prefer-const
   73:16  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   78:12  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   82:3   error    'item' is never reassigned. Use 'const' instead             prefer-const
  100:7   error    'allLanguages' is never reassigned. Use 'const' instead     prefer-const
  101:4   error    'unusedLanguages' is never reassigned. Use 'const' instead  prefer-const
  102:4   error    'items' is never reassigned. Use 'const' instead            prefer-const
  114:16  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
  192:4   error    'errors' is never reassigned. Use 'const' instead           prefer-const
  215:7   error    'values' is never reassigned. Use 'const' instead           prefer-const
  216:4   error    'widgets' is never reassigned. Use 'const' instead          prefer-const
  272:13  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign

/src/repo/resources/details/uw.SingleLanguageInputWidget.js
   17:17  warning  ES2015 'Object.assign' method is forbidden       es-x/no-object-assign
  226:4   error    'text' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/details/uw.TextWidget.js
  13:17  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.TitleDetailsWidget.js
   49:4  error  'illegalFileChars' is never reassigned. Use 'const' instead  prefer-const
   82:3  error  'value' is never reassigned. Use 'const' instead             prefer-const
   94:3  error  'title' is never reassigned. Use 'const' instead             prefer-const
  156:7  error  Mixed spaces and tabs                                        no-mixed-spaces-and-tabs
  156:9  error  Expected no linebreak before this expression                 implicit-arrow-linebreak
  157:6  error  Mixed spaces and tabs                                        no-mixed-spaces-and-tabs
  181:3  error  'errors' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/handlers/mw.ApiUploadHandler.js
  224:7   error    'allDuplicates' is never reassigned. Use 'const' instead  prefer-const
  224:23  warning  ES2015 'Object.assign' method is forbidden                es-x/no-object-assign
  225:4   error    '$extra' is never reassigned. Use 'const' instead         prefer-const
  226:4   error    '$ul' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/jquery.arrowSteps/jquery.arrowSteps.js
  39:4  error  '$el' is never reassigned. Use 'const' instead     prefer-const
  42:3  error  '$steps' is never reassigned. Use 'const' instead  prefer-const
  44:3  error  'width' is never reassigned. Use 'const' instead   prefer-const
  71:4  error  '$steps' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.DestinationChecker.js
   77:4  error  Mixed spaces and tabs                                no-mixed-spaces-and-tabs
   77:6  error  Expected no linebreak before this expression         implicit-arrow-linebreak
   78:3  error  Mixed spaces and tabs                                no-mixed-spaces-and-tabs
   94:8  error  'checker' is never reassigned. Use 'const' instead   prefer-const
   95:5  error  'NS_FILE' is never reassigned. Use 'const' instead   prefer-const
   98:4  error  'titleObj' is never reassigned. Use 'const' instead  prefer-const
   99:4  error  'ext' is never reassigned. Use 'const' instead       prefer-const
  101:4  error  'prefix' is never reassigned. Use 'const' instead    prefer-const

/src/repo/resources/mw.Escaper.js
  31:4   error    'extractedTemplates' is never reassigned. Use 'const' instead  prefer-const
  32:4   error    'extractedLinks' is never reassigned. Use 'const' instead      prefer-const
  34:43  warning  ES2015 'Object.assign' method is forbidden                     es-x/no-object-assign
  52:8   error    'extracts' is never reassigned. Use 'const' instead            prefer-const
  61:5   error    'regex' is never reassigned. Use 'const' instead               prefer-const
  62:5   error    'callback' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/mw.GroupProgressBar.js
   59:8  error  'bar' is never reassigned. Use 'const' instead            prefer-const
  146:5  error  'remainingTime' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.UploadWizard.js
    4:1  warning  Missing JSDoc @param "uw" type                           jsdoc/require-param-type
   22:3  error    'maxSimPref' is never reassigned. Use 'const' instead    prefer-const
   64:8  error    'self' is never reassigned. Use 'const' instead          prefer-const
   65:5  error    'steps' is never reassigned. Use 'const' instead         prefer-const
   74:4  error    'uploadStep' is never reassigned. Use 'const' instead    prefer-const
  127:5  warning  ES2015 'Object.assign' method is forbidden               es-x/no-object-assign
  134:5  error    'original' is never reassigned. Use 'const' instead      prefer-const
  138:5  error    'override' is never reassigned. Use 'const' instead      prefer-const
  187:4  error    'deeds' is never reassigned. Use 'const' instead         prefer-const
  188:4  error    'doOwnWork' is never reassigned. Use 'const' instead     prefer-const
  189:4  error    'doThirdParty' is never reassigned. Use 'const' instead  prefer-const
  197:3  error    'api' is never reassigned. Use 'const' instead           prefer-const

/src/repo/resources/mw.UploadWizardDetails.js
   45:8   error    '$moreDetailsWrapperDiv' is never reassigned. Use 'const' instead                  prefer-const
   47:5   error    'details' is never reassigned. Use 'const' instead                                 prefer-const
   48:5   error    'config' is never reassigned. Use 'const' instead                                  prefer-const
   56:13  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   73:48  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   83:40  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   90:55  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   98:57  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  105:44  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  113:47  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  118:51  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  123:53  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  151:4   error    '$moreDetailsDiv' is never reassigned. Use 'const' instead                         prefer-const
  215:5   error    Prefer .then to .done                                                              no-jquery/no-done-fail
  255:4   error    Prefer .then to .done                                                              no-jquery/no-done-fail
  383:4   error    Mixed spaces and tabs                                                              no-mixed-spaces-and-tabs
  383:6   error    Expected no linebreak before this expression                                       implicit-arrow-linebreak
  384:3   error    Mixed spaces and tabs                                                              no-mixed-spaces-and-tabs
  448:5   error    'yyyyMmDdRegex' is never reassigned. Use 'const' instead                           prefer-const
  449:5   error    'timeRegex' is never reassigned. Use 'const' instead                               prefer-const
  470:7   error    'dateInfo' is never reassigned. Use 'const' instead                                prefer-const
  508:4   error    'saneTime' is never reassigned. Use 'const' instead                                prefer-const
  601:5   error    'm' is never reassigned. Use 'const' instead                                       prefer-const
  603:5   error    'values' is never reassigned. Use 'const' instead                                  prefer-const
  653:4   error    'languages' is never reassigned. Use 'const' instead                               prefer-const
  662:3   warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  672:21  error    'serialized' is never reassigned. Use 'const' instead                              prefer-const
  734:5   error    'substitutions' is never reassigned. Use 'const' instead                           prefer-const
  734:25  error    'substList' is never reassigned. Use 'const' instead                               prefer-const
  735:5   error    'deed' is never reassigned. Use 'const' instead                                    prefer-const
  793:10  warning  ES2015 RegExp 'u' flag is forbidden                                                es-x/no-regexp-u-flag
  813:8   error    'details' is never reassigned. Use 'const' instead                                 prefer-const
  823:4   error    'wikitext' is never reassigned. Use 'const' instead                                prefer-const
  824:4   error    'promise' is never reassigned. Use 'const' instead                                 prefer-const
  843:5   error    'tags' is never reassigned. Use 'const' instead                                    prefer-const
  844:5   error    'deed' is never reassigned. Use 'const' instead                                    prefer-const
  846:5   error    'config' is never reassigned. Use 'const' instead                                  prefer-const
  869:4   error    'params' is never reassigned. Use 'const' instead                                  prefer-const
  936:5   error    'details' is never reassigned. Use 'const' instead                                 prefer-const
  939:5   error    'deferred' is never reassigned. Use 'const' instead                                prefer-const

/src/repo/resources/mw.UploadWizardLicenseInput.js
   17:7   error    'self' is never reassigned. Use 'const' instead            prefer-const
   18:4   error    'groups' is never reassigned. Use 'const' instead          prefer-const
   77:2   warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign
  183:9   error    'templates' is never reassigned. Use 'const' instead       prefer-const
  209:5   error    'addError' is never reassigned. Use 'const' instead        prefer-const
  216:5   error    'selectedInputs' is never reassigned. Use 'const' instead  prefer-const
  226:7   error    'data' is never reassigned. Use 'const' instead            prefer-const
  232:6   error    'wikitext' is never reassigned. Use 'const' instead        prefer-const
  268:28  warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign

/src/repo/resources/mw.UploadWizardPage.js
  31:4  error  'config' is never reassigned. Use 'const' instead        prefer-const
  53:3  error  'uploadWizard' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.UploadWizardUpload.js
    8:1   warning  Missing JSDoc @param "uw" type                                 jsdoc/require-param-type
   11:14  warning  'uw' is defined but never used                                 no-unused-vars
  204:4   error    'deferred' is never reassigned. Use 'const' instead            prefer-const
  205:4   error    'upload' is never reassigned. Use 'const' instead              prefer-const
  222:16  error    'Uint8Array' is already defined as a built-in global variable  no-redeclare
  223:16  warning  ES2015 'Uint8Array' is forbidden                               es-x/no-typed-arrays
  314:4   error    'upload' is never reassigned. Use 'const' instead              prefer-const
  382:3   error    Prefer .then to .done                                          no-jquery/no-done-fail
  382:3   error    Prefer .then to .fail                                          no-jquery/no-done-fail
  396:7   error    'requestedTitle' is never reassigned. Use 'const' instead      prefer-const
  430:3   error    'params' is never reassigned. Use 'const' instead              prefer-const
  448:3   error    Prefer .then to .done                                          no-jquery/no-done-fail
  448:3   error    Prefer .then to .fail                                          no-jquery/no-done-fail
  488:21  error    'image' is never reassigned. Use 'const' instead               prefer-const
  585:5   error    'constraint' is never reassigned. Use 'const' instead          prefer-const
  629:3   error    'scaling' is never reassigned. Use 'const' instead             prefer-const
  631:3   error    'width' is never reassigned. Use 'const' instead               prefer-const
  632:3   error    'height' is never reassigned. Use 'const' instead              prefer-const
  640:3   error    'dx' is never reassigned. Use 'const' instead                  prefer-const
  641:3   error    'dy' is never reassigned. Use 'const' instead                  prefer-const
  666:3   error    '$canvas' is never reassigned. Use 'const' instead             prefer-const
  667:3   error    'ctx' is never reassigned. Use 'const' instead                 prefer-const
  715:7   error    'constraints' is never reassigned. Use 'const' instead         prefer-const
  767:3   error    Prefer .then to .done                                          no-jquery/no-done-fail
  767:3   error    Prefer .then to .fail                                          no-jquery/no-done-fail
  775:6   error    Prefer .then to .done                                          no-jquery/no-done-fail
  778:7   error    Prefer .then to .done                                          no-jquery/no-done-fail
  802:4   error    'deferred' is never reassigned. Use 'const' instead            prefer-const
  803:4   error    'upload' is never reassigned. Use 'const' instead              prefer-const
  828:9   error    'canvas' is never reassigned. Use 'const' instead              prefer-const
  831:8   error    'context' is never reassigned. Use 'const' instead             prefer-const

/src/repo/resources/mw.UploadWizardUploadInterface.js
  206:3  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/transports/mw.FormDataTransport.js
   97:3  warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign
  156:4  error    'deferred' is never reassigned. Use 'const' instead        prefer-const
  157:4  error    'fileSize' is never reassigned. Use 'const' instead        prefer-const
  158:4  error    'chunkSize' is never reassigned. Use 'const' instead       prefer-const
  159:4  error    'transport' is never reassigned. Use 'const' instead       prefer-const
  169:5  error    Prefer .then to .done                                      no-jquery/no-done-fail
  170:6  error    Prefer .then to .done                                      no-jquery/no-done-fail
  170:6  error    Prefer .then to .fail                                      no-jquery/no-done-fail
  194:7  error    'params' is never reassigned. Use 'const' instead          prefer-const
  195:4  error    'transport' is never reassigned. Use 'const' instead       prefer-const
  196:4  error    'bytesAvailable' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/ui/steps/uw.ui.Deed.js
  55:3  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Details.js
  90:3  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Thanks.js
   30:4  error  'thanks' is never reassigned. Use 'const' instead             prefer-const
   48:3  error  '$header' is never reassigned. Use 'const' instead            prefer-const
   69:3  error  'beginButtonTarget' is never reassigned. Use 'const' instead  prefer-const
   98:3  error  'thumbWikiText' is never reassigned. Use 'const' instead      prefer-const
  104:3  error  '$thanksDiv' is never reassigned. Use 'const' instead         prefer-const
  106:3  error  '$thumbnailWrapDiv' is never reassigned. Use 'const' instead  prefer-const
  109:3  error  '$thumbnailDiv' is never reassigned. Use 'const' instead      prefer-const
  112:3  error  '$thumbnailCaption' is never reassigned. Use 'const' instead  prefer-const
  115:3  error  '$thumbnailLink' is never reassigned. Use 'const' instead     prefer-const
  128:3  error  Prefer .then to .done                                         no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Tutorial.js
  125:3  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Upload.js
  210:6  error  Prefer .then to .done  no-jquery/no-done-fail
  222:3  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/uw.ui.DeedPreview.js
  30:3  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/uw.ui.Step.js
  101:3  error  Prefer .then to .done  no-jquery/no-done-fail
  119:3  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/uw.ConcurrentQueue.js
  117:3  error  'index' is never reassigned. Use 'const' instead    prefer-const
  139:3  error  'item' is never reassigned. Use 'const' instead     prefer-const
  145:3  error  'promise' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/uw.CopyMetadataWidget.js
   14:4  error  'checkboxes' is never reassigned. Use 'const' instead               prefer-const
   15:4  error  '$copyMetadataWrapperDiv' is never reassigned. Use 'const' instead  prefer-const
   16:4  error  '$copyMetadataDiv' is never reassigned. Use 'const' instead         prefer-const
  157:4  error  'uploads' is never reassigned. Use 'const' instead                  prefer-const
  158:4  error  'sourceUpload' is never reassigned. Use 'const' instead             prefer-const
  159:4  error  'serialized' is never reassigned. Use 'const' instead               prefer-const
  161:4  error  'sourceValue' is never reassigned. Use 'const' instead              prefer-const
  214:4  error  'uploads' is never reassigned. Use 'const' instead                  prefer-const

/src/repo/resources/uw.FieldLayout.js
  20:12  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/uw.LicenseGroup.js
   37:17  warning  ES2015 'Object.assign' method is forbidden               es-x/no-object-assign
  132:4   error    'option' is never reassigned. Use 'const' instead        prefer-const
  167:4   error    'option' is never reassigned. Use 'const' instead        prefer-const
  191:4   error    'self' is never reassigned. Use 'const' instead          prefer-const
  192:4   error    'values' is never reassigned. Use 'const' instead        prefer-const
  194:3   error    'wikiTexts' is never reassigned. Use 'const' instead     prefer-const
  196:5   error    'value' is never reassigned. Use 'const' instead         prefer-const
  222:7   error    'self' is never reassigned. Use 'const' instead          prefer-const
  223:4   error    'result' is never reassigned. Use 'const' instead        prefer-const
  248:7   error    'self' is never reassigned. Use 'const' instead          prefer-const
  249:4   error    'selectArray' is never reassigned. Use 'const' instead   prefer-const
  303:7   error    'licenseInfo' is never reassigned. Use 'const' instead   prefer-const
  306:3   error    'licenseText' is never reassigned. Use 'const' instead   prefer-const
  319:7   error    'licenseInfo' is never reassigned. Use 'const' instead   prefer-const
  320:4   error    'messageKey' is never reassigned. Use 'const' instead    prefer-const
  323:4   error    'languageCode' is never reassigned. Use 'const' instead  prefer-const
  328:4   error    '$icons' is never reassigned. Use 'const' instead        prefer-const
  334:3   error    '$licenseLink' is never reassigned. Use 'const' instead  prefer-const
  343:3   error    '$label' is never reassigned. Use 'const' instead        prefer-const
  361:7   error    'self' is never reassigned. Use 'const' instead          prefer-const
  372:3   error    'button' is never reassigned. Use 'const' instead        prefer-const
  397:3   error    'input' is never reassigned. Use 'const' instead         prefer-const
  413:3   error    Prefer .then to .done                                    no-jquery/no-done-fail
  413:3   error    Prefer .then to .fail                                    no-jquery/no-done-fail

/src/repo/resources/uw.ValidationMessageElement.js
  39:2  warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  91:3  error    '$listItem' is never reassigned. Use 'const' instead                               prefer-const

/src/repo/tests/qunit/controller/uw.controller.Details.test.js
   57:7  error  'step' is never reassigned. Use 'const' instead        prefer-const
   61:4  error  'stepUiStub' is never reassigned. Use 'const' instead  prefer-const
  110:4  error  'done' is never reassigned. Use 'const' instead        prefer-const
  111:4  error  'donestub' is never reassigned. Use 'const' instead    prefer-const
  112:4  error  'ds' is never reassigned. Use 'const' instead          prefer-const
  113:4  error  'ps' is never reassigned. Use 'const' instead          prefer-const
  117:3  error  'tostub' is never reassigned. Use 'const' instead      prefer-const
  124:3  error  'step' is never reassigned. Use 'const' instead        prefer-const
  135:3  error  Prefer .then to .done                                  no-jquery/no-done-fail

/src/repo/tests/qunit/controller/uw.controller.Tutorial.test.js
  33:4  error  'acwStub' is never reassigned. Use 'const' instead  prefer-const
  54:3  error  'mnStub' is never reassigned. Use 'const' instead   prefer-const

/src/repo/tests/qunit/mw.UploadWizardLicenseInput.test.js
  17:6  error  'config' is never reassigned. Use 'const' instead          prefer-const
  18:3  error  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  21:2  error  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const
  27:6  error  'config' is never reassigned. Use 'const' instead          prefer-const
  28:3  error  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  33:2  error  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const
  37:2  error  '$input' is never reassigned. Use 'const' instead          prefer-const
  41:2  error  '$label' is never reassigned. Use 'const' instead          prefer-const
  46:6  error  'config' is never reassigned. Use 'const' instead          prefer-const
  56:3  error  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  59:2  error  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const

/src/repo/tests/qunit/mw.UploadWizardUpload.test.js
  23:4  error  'oldconf' is never reassigned. Use 'const' instead  prefer-const
  27:3  error  'upload' is never reassigned. Use 'const' instead   prefer-const

/src/repo/tests/qunit/mw.fileApi.test.js
  46:15  error  'testFile' is never reassigned. Use 'const' instead   prefer-const
  47:4   error  'fakeVideo' is never reassigned. Use 'const' instead  prefer-const

/src/repo/tests/qunit/transports/mw.FormDataTransport.test.js
   27:3   error  'config' is never reassigned. Use 'const' instead     prefer-const
   86:4   error  'transport' is never reassigned. Use 'const' instead  prefer-const
   87:4   error  'fakeFile' is never reassigned. Use 'const' instead   prefer-const
   97:3   error  'request' is never reassigned. Use 'const' instead    prefer-const
  107:4   error  'transport' is never reassigned. Use 'const' instead  prefer-const
  108:4   error  'fakeFile' is never reassigned. Use 'const' instead   prefer-const
  125:3   error  'request' is never reassigned. Use 'const' instead    prefer-const
  146:3   error  Prefer .then to .fail                                 no-jquery/no-done-fail
  179:10  error  Prefer .then to .done                                 no-jquery/no-done-fail
  198:10  error  Prefer .then to .done                                 no-jquery/no-done-fail
  218:3   error  Prefer .then to .fail                                 no-jquery/no-done-fail

/src/repo/tests/qunit/uw.ConcurrentQueue.test.js
   38:3  error  'calls' is never reassigned. Use 'const' instead            prefer-const
   65:3  error  'done' is never reassigned. Use 'const' instead             prefer-const
   66:3  error  'action' is never reassigned. Use 'const' instead           prefer-const
   67:3  error  'queue' is never reassigned. Use 'const' instead            prefer-const
   98:3  error  'done' is never reassigned. Use 'const' instead             prefer-const
   99:3  error  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  100:3  error  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  101:3  error  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  102:3  error  'queue' is never reassigned. Use 'const' instead            prefer-const
  139:3  error  'done' is never reassigned. Use 'const' instead             prefer-const
  140:3  error  'queue' is never reassigned. Use 'const' instead            prefer-const
  167:3  error  'done' is never reassigned. Use 'const' instead             prefer-const
  168:3  error  'queue' is never reassigned. Use 'const' instead            prefer-const
  184:3  error  'done' is never reassigned. Use 'const' instead             prefer-const
  185:3  error  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  186:3  error  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  187:3  error  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  188:3  error  'queue' is never reassigned. Use 'const' instead            prefer-const
  240:3  error  'done' is never reassigned. Use 'const' instead             prefer-const
  241:3  error  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  242:3  error  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  243:3  error  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  244:3  error  'queue' is never reassigned. Use 'const' instead            prefer-const
  297:3  error  'done' is never reassigned. Use 'const' instead             prefer-const
  298:3  error  'action' is never reassigned. Use 'const' instead           prefer-const
  299:3  error  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  300:3  error  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  301:3  error  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  302:3  error  'queue' is never reassigned. Use 'const' instead            prefer-const
  353:3  error  'done' is never reassigned. Use 'const' instead             prefer-const
  355:3  error  'action' is never reassigned. Use 'const' instead           prefer-const
  356:3  error  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  357:3  error  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  358:3  error  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  359:3  error  'queue' is never reassigned. Use 'const' instead            prefer-const
  402:3  error  'onProgress' is never reassigned. Use 'const' instead       prefer-const

/src/repo/tests/qunit/uw.TitleDetailsWidget.test.js
  5:2  error  'fileNs' is never reassigned. Use 'const' instead                  prefer-const
  6:2  error  'makeTitleInFileNSCases' is never reassigned. Use 'const' instead  prefer-const

✖ 352 problems (315 errors, 37 warnings)


--- end ---
$ ./node_modules/.bin/eslint . -f json
--- stdout ---
[{"filePath":"/src/repo/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/.stylelintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/Gruntfile.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/composer.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/docs/external.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/docs/jsduck-config.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/extension.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/ar.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/de.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/eu.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/fr.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/he.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/ia.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/it.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/lt.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/mk.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/nb.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/nl.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/roa-tara.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/skr-arab.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/sl.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/zh-hant.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/ar.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/av.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/bg.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/bug-bugi.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/cs.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/de.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/es.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/eu.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/fa.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/fi.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/fr.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/gu.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/he.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/hi.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/hr.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/hy.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/ia.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/id.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/it.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/ja.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/kaa.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/ko.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/krc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/ky.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/lb.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/ar.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/de.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/es.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/eu.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/fi.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/fr.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/he.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/hy.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/ia.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/it.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/ko.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/lt.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/mk.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/my.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/nl.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/roa-tara.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/ru.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/skr-arab.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/sl.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/sr-ec.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/sr-el.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/license/zh-hant.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/lt.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/mk.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/ms.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/nb.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/ne.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/nl.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/or.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/pa.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/pl.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/pnb.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/pt-br.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/pt.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/ru.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/rw.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sd.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/se.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sh-latn.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/shn.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/si.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/skr-arab.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sl.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/smn.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sms.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sr-ec.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sr-el.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sv.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/th.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/tly.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/tr.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/uk.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/vi.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/zh-hans.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/zh-hant.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/package-lock.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/package.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Deed.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'deedController' is never reassigned. Use 'const' instead.","line":44,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":44,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'valid' is never reassigned. Use 'const' instead.","line":52,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":52,"endColumn":8},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":57,"column":4,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":57,"endColumn":6},{"ruleId":"implicit-arrow-linebreak","severity":2,"message":"Expected no linebreak before this expression.","line":57,"column":6,"nodeType":"Identifier","messageId":"unexpected","endLine":57,"endColumn":17},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":58,"column":3,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":58,"endColumn":5}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Deed step controller.\n\t *\n\t * @class\n\t * @extends uw.controller.Step\n\t * @param {mw.Api} api\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.controller.Deed = function UWControllerDeed( api, config ) {\n\t\tuw.controller.Step.call(\n\t\t\tthis,\n\t\t\tnew uw.ui.Deed(),\n\t\t\tapi,\n\t\t\tconfig\n\t\t);\n\n\t\tthis.stepName = 'deeds';\n\n\t\tthis.deeds = {};\n\t};\n\n\tOO.inheritClass( uw.controller.Deed, uw.controller.Step );\n\n\tuw.controller.Deed.prototype.moveNext = function () {\n\t\tlet\n\t\t\tdeedController = this,\n\t\t\tvalid, fields, validityPromises;\n\n\t\tif ( !this.deedChooser ) {\n\t\t\tuw.controller.Step.prototype.moveNext.call( this );\n\t\t\treturn;\n\t\t}\n\n\t\tvalid = this.deedChooser.valid();\n\t\tif ( valid ) {\n\t\t\tfields = this.deedChooser.deed.getFields();\n\t\t\tvalidityPromises = fields.map( ( fieldLayout ) =>\n\t\t\t\t// Update any error/warning messages\n\t\t\t\t fieldLayout.checkValidity( true )\n\t\t\t );\n\t\t\tif ( validityPromises.length === 1 ) {\n\t\t\t\t// validityPromises will hold all promises for all uploads;\n\t\t\t\t// adding a bogus promise (no warnings & errors) to\n\t\t\t\t// ensure $.when always resolves with an array of multiple\n\t\t\t\t// results (if there's just 1, it would otherwise have just\n\t\t\t\t// that one's arguments, instead of a multi-dimensional array\n\t\t\t\t// of upload warnings & failures)\n\t\t\t\tvalidityPromises.push( $.Deferred().resolve( [], [] ).promise() );\n\t\t\t}\n\n\t\t\t$.when.apply( $, validityPromises ).then( function () {\n\t\t\t\t// `arguments` will be an array of all fields, with their warnings & errors\n\t\t\t\t// e.g. `[[something], []], [[], [something]]` for 2 fields, where the first one has\n\t\t\t\t// a warning and the last one an error\n\n\t\t\t\t// TODO Handle warnings with a confirmation dialog\n\n\t\t\t\tlet i;\n\t\t\t\tfor ( i = 0; i < arguments.length; i++ ) {\n\t\t\t\t\tif ( arguments[ i ][ 1 ].length ) {\n\t\t\t\t\t\t// One of the fields has errors; refuse to proceed!\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tuw.controller.Step.prototype.moveNext.call( deedController );\n\t\t\t} );\n\t\t}\n\t};\n\n\tuw.controller.Deed.prototype.unload = function () {\n\t\tconst deedController = this;\n\t\tuw.controller.Step.prototype.unload.call( this );\n\n\t\tObject.keys( this.deeds ).forEach( ( name ) => {\n\t\t\tdeedController.deeds[ name ].unload();\n\t\t} );\n\t};\n\n\t/**\n\t * Move to this step.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t */\n\tuw.controller.Deed.prototype.load = function ( uploads ) {\n\t\tlet customDeed, previousDeed;\n\n\t\tuw.controller.Step.prototype.load.call( this, uploads );\n\n\t\t// grab a serialized copy of previous deeds' details (if any)\n\t\tif ( this.deedChooser ) {\n\t\t\tpreviousDeed = this.deedChooser.getSerialized();\n\t\t}\n\n\t\tthis.deeds = mw.UploadWizard.getLicensingDeeds( this.uploads, this.config );\n\n\t\t// if we have multiple uploads, also give them the option to set\n\t\t// licenses individually\n\t\tif ( this.uploads.length > 1 ) {\n\t\t\tcustomDeed = new uw.deed.Custom( this.config );\n\t\t\tthis.deeds[ customDeed.name ] = customDeed;\n\t\t}\n\n\t\tthis.deedChooser = new mw.UploadWizardDeedChooser(\n\t\t\tthis.config,\n\t\t\t'#mediauploader-deeds',\n\t\t\tthis.deeds,\n\t\t\tthis.uploads\n\t\t);\n\n\t\t$( '<div>' )\n\t\t\t.insertBefore( this.deedChooser.$selector.find( '.mediauploader-deed-ownwork' ) )\n\t\t\t.msg( 'mediauploader-deeds-macro-prompt', this.uploads.length, mw.user );\n\n\t\tuploads.forEach( ( upload ) => {\n\t\t\t// Add previews and details to the DOM\n\t\t\tupload.deedPreview = new uw.ui.DeedPreview( upload );\n\t\t} );\n\n\t\tthis.deedChooser.onLayoutReady();\n\n\t\t// restore the previous input (if any) for all deeds\n\t\tif ( previousDeed ) {\n\t\t\tthis.deedChooser.setSerialized( previousDeed );\n\t\t}\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Deed.prototype.removeUpload = function ( upload ) {\n\t\tuw.controller.Step.prototype.removeUpload.call( this, upload );\n\n\t\tif ( upload.deedPreview ) {\n\t\t\tupload.deedPreview.remove();\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Details.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'serialized' is never reassigned. Use 'const' instead.","line":65,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":65,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'invalidStates' is never reassigned. Use 'const' instead.","line":96,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":96,"endColumn":17},{"ruleId":"prefer-const","severity":2,"message":"'invalids' is never reassigned. Use 'const' instead.","line":97,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":97,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'valids' is never reassigned. Use 'const' instead.","line":98,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":98,"endColumn":10},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":153,"column":3,"nodeType":"CallExpression","endLine":160,"endColumn":6},{"ruleId":"prefer-const","severity":2,"message":"'$message' is never reassigned. Use 'const' instead.","line":238,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":238,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'$ul' is never reassigned. Use 'const' instead.","line":239,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":239,"endColumn":7}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":143,"column":56,"nodeType":"CallExpression","endLine":143,"endColumn":89,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":7,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the details step in the wizard.\n\t *\n\t * @class\n\t * @extends uw.controller.Step\n\t * @param {mw.Api} api\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.controller.Details = function UWControllerDetails( api, config ) {\n\t\tuw.controller.Step.call(\n\t\t\tthis,\n\t\t\tnew uw.ui.Details()\n\t\t\t\t.on( 'start-details', this.startDetails.bind( this ) )\n\t\t\t\t.on( 'finalize-details-after-removal', this.moveNext.bind( this ) ),\n\t\t\tapi,\n\t\t\tconfig\n\t\t);\n\n\t\tthis.stepName = 'details';\n\t\tthis.finishState = 'complete';\n\n\t\tthis.queue = new uw.ConcurrentQueue( {\n\t\t\tcount: this.config.maxSimultaneousConnections,\n\t\t\taction: this.transitionOne.bind( this )\n\t\t} );\n\t};\n\n\tOO.inheritClass( uw.controller.Details, uw.controller.Step );\n\n\t/**\n\t * Move to this step.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads List of uploads being carried forward.\n\t */\n\tuw.controller.Details.prototype.load = function ( uploads ) {\n\t\tconst controller = this;\n\n\t\tuw.controller.Step.prototype.load.call( this, uploads );\n\n\t\t// make sure queue is empty before starting this step\n\t\tthis.queue.abortExecuting();\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\tlet serialized;\n\n\t\t\t// get existing details\n\t\t\tserialized = upload.details ? upload.details.getSerialized() : null;\n\n\t\t\tcontroller.createDetails( upload );\n\t\t\tif ( upload.deedChooser && upload.deedChooser.deed.name === 'custom' ) {\n\t\t\t\tupload.details.useCustomDeedChooser();\n\t\t\t}\n\t\t\tupload.details.attach();\n\n\t\t\t// restore earlier details (user may have started inputting details,\n\t\t\t// then went back some steps, and now got here again)\n\t\t\tif ( serialized ) {\n\t\t\t\tupload.details.setSerialized( serialized );\n\t\t\t}\n\t\t} );\n\n\t\t// Show the widget allowing to copy selected metadata if there's more than one successful upload\n\t\tif ( this.config.copyMetadataFeature ) {\n\t\t\tthis.addCopyMetadataFeature();\n\t\t}\n\t};\n\n\tuw.controller.Details.prototype.moveNext = function () {\n\t\tthis.removeErrorUploads();\n\n\t\tuw.controller.Step.prototype.moveNext.call( this );\n\t};\n\n\tuw.controller.Details.prototype.addCopyMetadataFeature = function () {\n\t\tlet first,\n\t\t\t// uploads can only be edited when they're in a certain state:\n\t\t\t// a flat out upload failure or a completed upload can not be edited\n\t\t\tinvalidStates = [ 'aborted', 'error', 'complete' ],\n\t\t\tinvalids = this.getUploadStatesCount( invalidStates ),\n\t\t\tvalids = this.uploads.length - invalids;\n\n\t\t// no point in having this feature if there's no target to copy to\n\t\tif ( valids < 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// The first upload is not necessarily the one we want to copy from\n\t\t// E.g. the first upload could've gone through successfully, but the\n\t\t// rest failed because of abusefilter (or another recoverable error), in\n\t\t// which case we'll want the \"copy\" feature to appear below the 2nd\n\t\t// upload (or the first not-yet-completed not flat-out-failed upload)\n\t\tthis.uploads.some( ( upload ) => {\n\t\t\tif ( upload && !invalidStates.includes( upload.state ) ) {\n\t\t\t\tfirst = upload;\n\t\t\t\treturn true; // Break Array.some loop\n\t\t\t}\n\t\t\treturn false;\n\t\t} );\n\n\t\t// could not find a source upload to copy from\n\t\tif ( !first ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.copyMetadataWidget = new uw.CopyMetadataWidget( {\n\t\t\tcopyFrom: first,\n\t\t\t// Include the \"source\" upload in the targets too\n\t\t\tcopyTo: this.uploads\n\t\t} );\n\n\t\tfirst.details.$div.after( this.copyMetadataWidget.$element );\n\t};\n\n\tuw.controller.Details.prototype.removeCopyMetadataFeature = function () {\n\t\tif ( this.copyMetadataWidget ) {\n\t\t\tthis.copyMetadataWidget.$element.remove();\n\t\t}\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Details.prototype.createDetails = function ( upload ) {\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\tupload.details = new mw.UploadWizardDetails( upload, $( '#mediauploader-macro-files' ) );\n\t};\n\n\t/**\n\t * Start details submit.\n\t * TODO move the rest of the logic here from mw.UploadWizard\n\t */\n\tuw.controller.Details.prototype.startDetails = function () {\n\t\tconst details = this;\n\n\t\tthis.valid().done( ( valid ) => {\n\t\t\tif ( valid ) {\n\t\t\t\tdetails.ui.hideEndButtons();\n\t\t\t\tdetails.submit();\n\t\t\t} else {\n\t\t\t\tdetails.showErrors();\n\t\t\t}\n\t\t} );\n\t};\n\n\t/**\n\t * Check details for validity.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tuw.controller.Details.prototype.valid = function () {\n\t\tconst detailsController = this,\n\t\t\t// validityPromises will hold all promises for all uploads;\n\t\t\t// prefilling with a bogus promise (no warnings & errors) to\n\t\t\t// ensure $.when always resolves with an array of multiple\n\t\t\t// results (if there's just 1, it would otherwise have just\n\t\t\t// that one's arguments, instead of a multi-dimensional array\n\t\t\t// of upload warnings & failures)\n\t\t\tvalidityPromises = [ $.Deferred().resolve( [], [] ).promise() ],\n\t\t\ttitles = [];\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\t// Update any error/warning messages about all DetailsWidgets\n\t\t\tconst promise = upload.details.checkValidity( true ).then( function () {\n\t\t\t\tlet warnings = [],\n\t\t\t\t\terrors = [],\n\t\t\t\t\ttitle;\n\n\t\t\t\tArray.prototype.forEach.call( arguments, ( result ) => {\n\t\t\t\t\twarnings = warnings.concat( result[ 0 ] );\n\t\t\t\t\terrors = errors.concat( result[ 1 ] );\n\t\t\t\t} );\n\n\t\t\t\t// Seen this title before?\n\t\t\t\ttitle = upload.details.getTitle();\n\t\t\t\tif ( title ) {\n\t\t\t\t\ttitle = title.getName() + '.' + mw.Title.normalizeExtension( title.getExtension() );\n\t\t\t\t\tif ( titles[ title ] ) {\n\t\t\t\t\t\t// Don't submit. Instead, set an error in details step.\n\t\t\t\t\t\tupload.details.setDuplicateTitleError();\n\t\t\t\t\t\terrors.push( mw.message( 'mediauploader-error-title-duplicate' ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttitles[ title ] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn $.Deferred().resolve( warnings, errors ).promise();\n\t\t\t} );\n\n\t\t\t// Will hold an array of validation promises, one for each upload\n\t\t\tvalidityPromises.push( promise );\n\t\t} );\n\n\t\t// validityPromises is an array of promises that each resolve with [warnings, errors]\n\t\t// for each upload - now iterate them all to figure out if we can proceed\n\t\treturn $.when.apply( $, validityPromises ).then( function () {\n\t\t\tlet warnings = [],\n\t\t\t\terrors = [];\n\n\t\t\tArray.prototype.forEach.call( arguments, ( result ) => {\n\t\t\t\twarnings = warnings.concat( result[ 0 ] );\n\t\t\t\terrors = errors.concat( result[ 1 ] );\n\t\t\t} );\n\n\t\t\tif ( errors.length > 0 ) {\n\t\t\t\treturn $.Deferred().resolve( false );\n\t\t\t}\n\n\t\t\tif ( warnings.length > 0 ) {\n\t\t\t\t// Update warning count before dialog\n\t\t\t\tdetailsController.showErrors();\n\t\t\t\treturn detailsController.confirmationDialog( warnings );\n\t\t\t}\n\n\t\t\treturn $.Deferred().resolve( true );\n\t\t} );\n\t};\n\n\tuw.controller.Details.prototype.confirmationDialog = function ( warnings ) {\n\t\tlet i,\n\t\t\t$message = $( '<p>' ).text( mw.message( 'mediauploader-dialog-warning' ).text() ),\n\t\t\t$ul = $( '<ul>' );\n\n\t\t// parse warning messages\n\t\twarnings = warnings.map( ( warning ) => warning.text() );\n\n\t\t// omit duplicates\n\t\twarnings = warnings.filter( ( warning, j, warningsOld ) => warningsOld.indexOf( warning ) === j );\n\n\t\tfor ( i = 0; i < warnings.length; i++ ) {\n\t\t\t$ul.append( $( '<li>' ).text( warnings[ i ] ) );\n\t\t}\n\n\t\treturn OO.ui.getWindowManager().openWindow( 'message', {\n\t\t\tmessage: $message.append( $ul ),\n\t\t\ttitle: mw.message( 'mediauploader-dialog-title' ).text(),\n\t\t\tactions: [\n\t\t\t\t{\n\t\t\t\t\taction: 'back',\n\t\t\t\t\tlabel: mw.msg( 'mediauploader-dialog-back' )\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\taction: 'continue',\n\t\t\t\t\tlabel: mw.msg( 'mediauploader-dialog-continue' )\n\t\t\t\t}\n\t\t\t]\n\t\t} ).closed.then( ( data ) => !!( data && data.action === 'continue' ) );\n\t};\n\n\tuw.controller.Details.prototype.canTransition = function ( upload ) {\n\t\treturn (\n\t\t\tuw.controller.Step.prototype.canTransition.call( this, upload ) &&\n\t\t\tupload.state === this.stepName\n\t\t);\n\t};\n\n\t/**\n\t * Perform this step's changes on one upload.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {jQuery.Promise}\n\t */\n\tuw.controller.Details.prototype.transitionOne = function ( upload ) {\n\t\treturn upload.details.submit();\n\t};\n\n\t/**\n\t * Perform this step's changes on all uploads.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tuw.controller.Details.prototype.transitionAll = function () {\n\t\tconst\n\t\t\tdeferred = $.Deferred(),\n\t\t\tdetails = this;\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\tif ( details.canTransition( upload ) ) {\n\t\t\t\tdetails.queue.addItem( upload );\n\t\t\t}\n\t\t} );\n\n\t\tthis.queue.on( 'complete', deferred.resolve );\n\t\tthis.queue.startExecuting();\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Submit details to the API.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tuw.controller.Details.prototype.submit = function () {\n\t\tconst details = this;\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\t// Clear error state\n\t\t\tif ( upload.state === 'error' || upload.state === 'recoverable-error' ) {\n\t\t\t\tupload.state = details.stepName;\n\t\t\t}\n\n\t\t\t// Set details view to have correct title\n\t\t\tupload.details.setVisibleTitle( upload.details.getTitle().getMain() );\n\t\t} );\n\n\t\t// Disable edit interface\n\t\tthis.ui.disableEdits();\n\t\tthis.removeCopyMetadataFeature();\n\n\t\treturn this.transitionAll().then( () => {\n\t\t\tdetails.showErrors();\n\n\t\t\tif ( details.showNext() ) {\n\t\t\t\tdetails.moveNext();\n\t\t\t}\n\t\t} );\n\t};\n\n\t/**\n\t * Show warnings and errors in the form.\n\t * See UI class for more.\n\t */\n\tuw.controller.Details.prototype.showErrors = function () {\n\t\tthis.ui.enableEdits();\n\n\t\tthis.removeCopyMetadataFeature();\n\t\tthis.addCopyMetadataFeature();\n\n\t\tthis.ui.showWarnings(); // Scroll to the warning first so that any errors will have precedence\n\t\tthis.ui.showErrors();\n\t};\n\n\t/**\n\t * Handler for when an upload is removed.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Details.prototype.removeUpload = function ( upload ) {\n\t\tuw.controller.Step.prototype.removeUpload.call( this, upload );\n\n\t\tthis.queue.removeItem( upload );\n\n\t\tif ( upload.details && upload.details.$div ) {\n\t\t\tupload.details.$div.remove();\n\t\t}\n\n\t\tif ( this.uploads.length === 0 ) {\n\t\t\t// If we have no more uploads, go to the \"Upload\" step. (This will go to \"Thanks\" step,\n\t\t\t// which will skip itself in load() because there are no uploads left.)\n\t\t\tthis.moveNext();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.removeCopyMetadataFeature();\n\t\t// Make sure we still have more multiple uploads adding the\n\t\t// copy feature again\n\t\tif ( this.config.copyMetadataFeature ) {\n\t\t\tthis.addCopyMetadataFeature();\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Step.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'okCount' is never reassigned. Use 'const' instead.","line":223,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":223,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'$buttons' is never reassigned. Use 'const' instead.","line":233,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":233,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'copy' is never reassigned. Use 'const' instead.","line":324,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":324,"endColumn":8}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents a step in the wizard.\n\t *\n\t * @class\n\t * @abstract\n\t * @param {uw.ui.Step} ui The UI object that controls this step.\n\t * @param {mw.Api} api\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.controller.Step = function UWControllerStep( ui, api, config ) {\n\t\tconst step = this;\n\n\t\tOO.EventEmitter.call( this );\n\n\t\t/**\n\t\t * @property {Object} config\n\t\t */\n\t\tthis.config = config;\n\t\t/**\n\t\t * @property {mw.Api} api\n\t\t */\n\t\tthis.api = api;\n\n\t\tthis.ui = ui;\n\n\t\tthis.uploads = [];\n\n\t\t// children are expected to override this with the actual step name\n\t\tthis.stepName = new Error( 'Undefined stepName' );\n\n\t\t/**\n\t\t * Upload object event handlers to be bound on load & unbound on unload.\n\t\t * This is an object literal where the keys are callback names, and\n\t\t * values all callback. These callbacks will be called with the\n\t\t * controller as content (`this`), and the upload as first argument.\n\t\t * This'll effectively be:\n\t\t * `upload.on( <key>, <value>.bind( this, upload ) );`\n\t\t *\n\t\t * @property {Object}\n\t\t */\n\t\tthis.uploadHandlers = {\n\t\t\t'remove-upload': this.removeUpload\n\t\t};\n\n\t\tthis.ui.on( 'next-step', () => {\n\t\t\tstep.moveNext();\n\t\t} );\n\n\t\tthis.ui.on( 'previous-step', () => {\n\t\t\tstep.movePrevious();\n\t\t} );\n\n\t\t/**\n\t\t * @property {uw.controller.Step} nextStep\n\t\t * The next step in the process.\n\t\t */\n\t\tthis.nextStep = null;\n\n\t\t/**\n\t\t * @property {uw.controller.Step} previousStep\n\t\t * The previous step in the process.\n\t\t */\n\t\tthis.previousStep = null;\n\t};\n\n\tOO.mixinClass( uw.controller.Step, OO.EventEmitter );\n\n\t/**\n\t * Set the next step in the process.\n\t *\n\t * @param {uw.controller.Step} step\n\t */\n\tuw.controller.Step.prototype.setNextStep = function ( step ) {\n\t\tthis.nextStep = step;\n\t\tthis.ui.enableNextButton();\n\t};\n\n\t/**\n\t * Set the previous step in the process.\n\t *\n\t * @param {uw.controller.Step} step\n\t */\n\tuw.controller.Step.prototype.setPreviousStep = function ( step ) {\n\t\tthis.previousStep = step;\n\t\tthis.ui.enablePreviousButton();\n\t};\n\n\t/**\n\t * Initialize this step.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads List of uploads being carried forward.\n\t */\n\tuw.controller.Step.prototype.load = function ( uploads ) {\n\t\tconst step = this;\n\n\t\tthis.emit( 'load' );\n\n\t\tthis.uploads = uploads || [];\n\n\t\t// prevent the window from being closed as long as we have data\n\t\tthis.allowCloseWindow = mw.confirmCloseWindow( {\n\t\t\ttest: step.hasData.bind( this )\n\t\t} );\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\tupload.state = step.stepName;\n\n\t\t\tstep.bindUploadHandlers( upload );\n\t\t} );\n\n\t\tthis.ui.load( uploads );\n\t};\n\n\t/**\n\t * Cleanup this step.\n\t */\n\tuw.controller.Step.prototype.unload = function () {\n\t\tconst step = this;\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\tstep.unbindUploadHandlers( upload );\n\t\t} );\n\n\t\tthis.allowCloseWindow.release();\n\t\tthis.ui.unload();\n\n\t\tthis.emit( 'unload' );\n\t};\n\n\t/**\n\t * Move to the next step.\n\t */\n\tuw.controller.Step.prototype.moveNext = function () {\n\t\tthis.unload();\n\n\t\tif ( this.nextStep ) {\n\t\t\tthis.nextStep.load( this.uploads );\n\t\t}\n\t};\n\n\t/**\n\t * Move to the previous step.\n\t */\n\tuw.controller.Step.prototype.movePrevious = function () {\n\t\tthis.unload();\n\n\t\tif ( this.previousStep ) {\n\t\t\tthis.previousStep.load( this.uploads );\n\t\t}\n\t};\n\n\t/**\n\t * Attaches controller-specific upload event handlers.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Step.prototype.bindUploadHandlers = function ( upload ) {\n\t\tconst controller = this;\n\n\t\tObject.keys( this.uploadHandlers ).forEach( ( event ) => {\n\t\t\tconst callback = controller.uploadHandlers[ event ];\n\t\t\tupload.on( event, callback, [ upload ], controller );\n\t\t} );\n\t};\n\n\t/**\n\t * Removes controller-specific upload event handlers.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Step.prototype.unbindUploadHandlers = function ( upload ) {\n\t\tconst controller = this;\n\n\t\tObject.keys( this.uploadHandlers ).forEach( ( event ) => {\n\t\t\tconst callback = controller.uploadHandlers[ event ];\n\t\t\tupload.off( event, callback, controller );\n\t\t} );\n\t};\n\n\t/**\n\t * Check if upload is able to be put through this step's changes.\n\t *\n\t * @return {boolean}\n\t */\n\tuw.controller.Step.prototype.canTransition = function () {\n\t\treturn true;\n\t};\n\n\t/**\n\t * Figure out what to do and what options to show after the uploads have stopped.\n\t * Uploading has stopped for one of the following reasons:\n\t * 1) The user removed all uploads before they completed, in which case we are at upload.length === 0. We should start over and allow them to add new ones\n\t * 2) All succeeded - show link to next step\n\t * 3) Some failed, some succeeded - offer them the chance to retry the failed ones or go on to the next step\n\t * 4) All failed -- have to retry, no other option\n\t * In principle there could be other configurations, like having the uploads not all in error or stashed state, but\n\t * we trust that this hasn't happened.\n\t *\n\t * For uploads that have succeeded, now is the best time to add the relevant previews and details to the DOM\n\t * in the right order.\n\t *\n\t * @return {boolean} Whether all of the uploads are in a successful state.\n\t */\n\tuw.controller.Step.prototype.showNext = function () {\n\t\tlet okCount = this.getUploadStatesCount( this.finishState ),\n\t\t\t$buttons;\n\n\t\t// abort if all uploads have been removed\n\t\tif ( this.uploads.length === 0 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.updateProgressBarCount( okCount );\n\n\t\t$buttons = this.ui.$div.find( '.mediauploader-buttons' );\n\t\t$buttons.show();\n\n\t\t$buttons.find( '.mediauploader-file-next-all-ok' ).hide();\n\t\t$buttons.find( '.mediauploader-file-next-some-failed' ).hide();\n\t\t$buttons.find( '.mediauploader-file-next-all-failed' ).hide();\n\n\t\tif ( okCount === this.uploads.length ) {\n\t\t\t$buttons.find( '.mediauploader-file-next-all-ok' ).show();\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( this.getUploadStatesCount( [ 'error', 'recoverable-error' ] ) === this.uploads.length ) {\n\t\t\t$buttons.find( '.mediauploader-file-next-all-failed' ).show();\n\t\t} else if ( this.getUploadStatesCount( 'transporting' ) === 0 ) {\n\t\t\t$buttons.find( '.mediauploader-file-next-some-failed' ).show();\n\t\t}\n\n\t\treturn false;\n\t};\n\n\t/**\n\t * @param {string|string[]} states List of upload states we want the count for\n\t * @return {number}\n\t */\n\tuw.controller.Step.prototype.getUploadStatesCount = function ( states ) {\n\t\tlet count = 0;\n\n\t\t// normalize to array of states, even though input can be 1 string\n\t\tstates = Array.isArray( states ) ? states : [ states ];\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\tif ( states.includes( upload.state ) ) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t} );\n\n\t\treturn count;\n\t};\n\n\t/**\n\t * Function used by some steps to update progress bar for the whole\n\t * batch of uploads.\n\t */\n\tuw.controller.Step.prototype.updateProgressBarCount = function () {};\n\n\t/**\n\t * Check if this step has data, to test if the window can be close (i.e. if\n\t * content is going to be lost)\n\t *\n\t * @return {boolean}\n\t */\n\tuw.controller.Step.prototype.hasData = function () {\n\t\treturn this.uploads.length !== 0;\n\t};\n\n\t/**\n\t * Add an upload.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Step.prototype.addUpload = function ( upload ) {\n\t\tthis.uploads.push( upload );\n\t};\n\n\t/**\n\t * Remove an upload.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Step.prototype.removeUpload = function ( upload ) {\n\t\t// remove the upload from the uploads array\n\t\tconst index = this.uploads.indexOf( upload );\n\t\tif ( index !== -1 ) {\n\t\t\tthis.uploads.splice( index, 1 );\n\t\t}\n\n\t\t// let the upload object cleanup itself!\n\t\tupload.remove();\n\t};\n\n\t/**\n\t * Remove multiple uploads.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t */\n\tuw.controller.Step.prototype.removeUploads = function ( uploads ) {\n\t\tlet i,\n\t\t\t// clone the array of uploads, just to be sure it's not a reference\n\t\t\t// to this.uploads, which will be modified (and we can't have that\n\t\t\t// while we're looping it)\n\t\t\tcopy = uploads.slice();\n\n\t\tfor ( i = 0; i < copy.length; i++ ) {\n\t\t\tthis.removeUpload( copy[ i ] );\n\t\t}\n\t};\n\n\t/**\n\t * Clear out uploads that are in error mode, perhaps before proceeding to the next step\n\t */\n\tuw.controller.Step.prototype.removeErrorUploads = function () {\n\t\t// We must not remove items from an array while iterating over it with $.each (it causes the\n\t\t// next item to be skipped). Find and queue them first, then remove them.\n\t\tconst toRemove = [];\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\tif ( upload.state === 'error' || upload.state === 'recoverable-error' ) {\n\t\t\t\ttoRemove.push( upload );\n\t\t\t}\n\t\t} );\n\n\t\tthis.removeUploads( toRemove );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Thanks.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Tutorial.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":63,"column":3,"nodeType":"CallExpression","endLine":69,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":63,"column":3,"nodeType":"CallExpression","endLine":71,"endColumn":6}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\n\t/**\n\t * Tutorial step controller.\n\t *\n\t * @class\n\t * @extends uw.controller.Step\n\t * @param {mw.Api} api\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.controller.Tutorial = function UWControllerTutorial( api, config ) {\n\t\tconst controller = this;\n\n\t\tthis.skipPreference = Boolean( mw.user.options.get( 'upwiz_skiptutorial' ) );\n\t\tthis.newSkipPreference = this.skipPreference;\n\t\tthis.skipped = false;\n\n\t\tuw.controller.Step.call(\n\t\t\tthis,\n\t\t\tnew uw.ui.Tutorial()\n\t\t\t\t.on( 'skip-tutorial-click', ( skipped ) => {\n\t\t\t\t\t// indicate that the skip preference has changed, so we can\n\t\t\t\t\t// alter the preference when we move to another step\n\t\t\t\t\tcontroller.newSkipPreference = skipped;\n\t\t\t\t} ),\n\t\t\tapi,\n\t\t\tconfig\n\t\t);\n\n\t\tthis.stepName = 'tutorial';\n\n\t\tthis.ui.setSelected( this.skipPreference );\n\t};\n\n\tOO.inheritClass( uw.controller.Tutorial, uw.controller.Step );\n\n\t/**\n\t * Set the skip tutorial user preference via the options API\n\t *\n\t * @param {boolean} skip\n\t */\n\tuw.controller.Tutorial.prototype.setSkipPreference = function ( skip ) {\n\t\tconst controller = this,\n\t\t\tallowCloseWindow = mw.confirmCloseWindow();\n\n\t\tthis.api.postWithToken( 'options', {\n\t\t\taction: 'options',\n\t\t\tchange: skip ? 'upwiz_skiptutorial=1' : 'upwiz_skiptutorial'\n\t\t} ).done( () => {\n\t\t\tallowCloseWindow.release();\n\t\t\tcontroller.skipPreference = skip;\n\t\t} ).fail( ( code, err ) => {\n\t\t\tmw.notify( err.textStatus );\n\t\t} );\n\t};\n\n\tuw.controller.Tutorial.prototype.load = function ( uploads ) {\n\t\t// tutorial can be skipped via preference, or config (e.g. campaign config)\n\t\tconst shouldSkipTutorial = this.skipPreference || ( this.config.tutorial && this.config.tutorial.skip );\n\n\t\tuw.controller.Step.prototype.load.call( this, uploads );\n\n\t\t// we only want to skip the tutorial once - if we come back to it, we\n\t\t// don't want it to get auto-skipped again\n\t\tif ( !this.skipped && shouldSkipTutorial ) {\n\t\t\tthis.skipped = true;\n\t\t\tthis.moveNext();\n\t\t}\n\t};\n\n\tuw.controller.Tutorial.prototype.moveNext = function () {\n\t\tuw.controller.Step.prototype.moveNext.call( this );\n\t};\n\n\tuw.controller.Tutorial.prototype.unload = function () {\n\t\tif ( this.skipPreference !== this.newSkipPreference ) {\n\t\t\tthis.setSkipPreference( this.newSkipPreference );\n\t\t}\n\n\t\tuw.controller.Step.prototype.unload.call( this );\n\t};\n\n\tuw.controller.Tutorial.prototype.hasData = function () {\n\t\treturn false;\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Upload.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'max' is never reassigned. Use 'const' instead.","line":69,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":69,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'haveUploads' is never reassigned. Use 'const' instead.","line":71,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":71,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'fewerThanMax' is never reassigned. Use 'const' instead.","line":72,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":72,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'upload' is never reassigned. Use 'const' instead.","line":223,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":223,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'uploadObjs' is never reassigned. Use 'const' instead.","line":251,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":251,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'controller' is never reassigned. Use 'const' instead.","line":252,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":252,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'actualMaxSize' is never reassigned. Use 'const' instead.","line":307,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":307,"endColumn":17},{"ruleId":"prefer-const","severity":2,"message":"'filename' is never reassigned. Use 'const' instead.","line":311,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":311,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'basename' is never reassigned. Use 'const' instead.","line":312,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":312,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'extension' is never reassigned. Use 'const' instead.","line":335,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":335,"endColumn":12}],"suppressedMessages":[],"errorCount":10,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\n\t/**\n\t * Upload step controller.\n\t *\n\t * @class\n\t * @extends uw.controller.Step\n\t * @param {mw.Api} api\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.controller.Upload = function UWControllerUpload( api, config ) {\n\t\tconst step = this;\n\n\t\tuw.controller.Step.call(\n\t\t\tthis,\n\t\t\tnew uw.ui.Upload( config )\n\t\t\t\t.connect( this, {\n\t\t\t\t\tretry: 'retry'\n\t\t\t\t} ),\n\t\t\tapi,\n\t\t\tconfig\n\t\t);\n\n\t\tthis.stepName = 'file';\n\t\tthis.finishState = 'stashed';\n\n\t\tthis.queue = new uw.ConcurrentQueue( {\n\t\t\tcount: this.config.maxSimultaneousConnections,\n\t\t\taction: this.transitionOne.bind( this )\n\t\t} );\n\t\tthis.queue.on( 'complete', this.showNext.bind( this ) );\n\n\t\tthis.ui.on( 'files-added', ( files ) => {\n\t\t\tconst totalFiles = files.length + step.uploads.length,\n\t\t\t\ttooManyFiles = totalFiles > step.config.maxUploads;\n\n\t\t\tif ( tooManyFiles ) {\n\t\t\t\tstep.ui.showTooManyFilesError( totalFiles );\n\t\t\t} else {\n\t\t\t\tstep.addFiles( files );\n\t\t\t}\n\t\t} );\n\t};\n\n\tOO.inheritClass( uw.controller.Upload, uw.controller.Step );\n\n\t/**\n\t * Updates the upload step data when a file is added or removed.\n\t */\n\tuw.controller.Upload.prototype.updateFileCounts = function () {\n\t\tlet fewerThanMax, haveUploads,\n\t\t\tmax = this.config.maxUploads;\n\n\t\thaveUploads = this.uploads.length > 0;\n\t\tfewerThanMax = this.uploads.length < max;\n\n\t\tthis.updateProgressBarCount( this.uploads.length );\n\t\tthis.ui.updateFileCounts( haveUploads, fewerThanMax );\n\t};\n\n\tuw.controller.Upload.prototype.load = function ( uploads ) {\n\t\tconst controller = this;\n\n\t\tuw.controller.Step.prototype.load.call( this, uploads );\n\t\tthis.updateFileCounts();\n\t\tthis.startProgressBar();\n\n\t\t// make sure queue is empty before starting this step\n\t\tthis.queue.abortExecuting();\n\n\t\tif ( uploads.length > 0 ) {\n\t\t\t/*\n\t\t\t * If we have uploads already, we'll want to to update the \"next\"\n\t\t\t * buttons accordingly. showNext() does that, but relies on upload\n\t\t\t * state being set correctly.\n\t\t\t * Since every step overwrites the upload state, we'll need to reset\n\t\t\t * it to reflect the correct upload success state.\n\t\t\t * If other files are to be added, the showNext() callback will deal\n\t\t\t * with new uploads, and still understand the existing files that\n\t\t\t * we've just reset the state for.\n\t\t\t */\n\t\t\tuploads.forEach( ( upload ) => {\n\t\t\t\tupload.state = upload.fileKey === undefined ? 'error' : controller.finishState;\n\t\t\t} );\n\n\t\t\tthis.showNext();\n\t\t}\n\t};\n\n\tuw.controller.Upload.prototype.moveNext = function () {\n\t\tthis.removeErrorUploads();\n\n\t\tuw.controller.Step.prototype.moveNext.call( this );\n\t};\n\n\t/**\n\t * Starts the upload progress bar.\n\t */\n\tuw.controller.Upload.prototype.startProgressBar = function () {\n\t\tthis.ui.showProgressBar();\n\t\tthis.progressBar = new mw.GroupProgressBar( this.ui.$progress,\n\t\t\tthis.uploads,\n\t\t\t[ 'stashed' ],\n\t\t\t[ 'error' ],\n\t\t\t'transportProgress',\n\t\t\t'transportWeight' );\n\t\tthis.progressBar.start();\n\t};\n\n\t/**\n\t * Starts progress bar if there's not an existing one.\n\t */\n\tuw.controller.Upload.prototype.maybeStartProgressBar = function () {\n\t\tif ( this.progressBarEmptyOrFinished() ) {\n\t\t\tthis.startProgressBar();\n\t\t}\n\t};\n\n\t/**\n\t * Check if there is a vacancy for a new progress bar.\n\t *\n\t * @return {boolean}\n\t */\n\tuw.controller.Upload.prototype.progressBarEmptyOrFinished = function () {\n\t\treturn !this.progressBar || this.progressBar.finished === true;\n\t};\n\n\t/**\n\t * Update success count on the progress bar.\n\t *\n\t * @param {number} okCount\n\t */\n\tuw.controller.Upload.prototype.updateProgressBarCount = function ( okCount ) {\n\t\tif ( this.progressBar ) {\n\t\t\tthis.progressBar.showCount( okCount );\n\t\t}\n\t};\n\n\tuw.controller.Upload.prototype.canTransition = function ( upload ) {\n\t\treturn (\n\t\t\tuw.controller.Step.prototype.canTransition.call( this, upload ) &&\n\t\t\tupload.state === 'new'\n\t\t);\n\t};\n\n\t/**\n\t * Perform this step's changes on one upload.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {jQuery.Promise}\n\t */\n\tuw.controller.Upload.prototype.transitionOne = function ( upload ) {\n\t\tconst promise = upload.start();\n\t\tthis.maybeStartProgressBar();\n\t\treturn promise;\n\t};\n\n\t/**\n\t * Queue an upload object to be uploaded.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Upload.prototype.queueUpload = function ( upload ) {\n\t\tif ( this.canTransition( upload ) ) {\n\t\t\tthis.queue.addItem( upload );\n\t\t}\n\t};\n\n\t/**\n\t * Kick off the upload processes.\n\t */\n\tuw.controller.Upload.prototype.startQueuedUploads = function () {\n\t\tthis.queue.startExecuting();\n\t};\n\n\tuw.controller.Upload.prototype.retry = function () {\n\t\tconst controller = this;\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\tif ( upload.state === 'error' ) {\n\t\t\t\t// reset any uploads in error state back to be shiny & new\n\t\t\t\tupload.state = 'new';\n\t\t\t\tupload.ui.clearStatus();\n\t\t\t\t// and queue them\n\t\t\t\tcontroller.queueUpload( upload );\n\t\t\t}\n\t\t} );\n\n\t\tthis.startQueuedUploads();\n\t};\n\n\t/**\n\t * Create the upload interface, a handler to transport it to the server, and UI for the upload\n\t * itself; and immediately fill it with a file and add it to the list of uploads.\n\t *\n\t * @param {File} file\n\t * @return {mw.UploadWizardUpload|boolean} The new upload, or false if it can't be added\n\t */\n\tuw.controller.Upload.prototype.addFile = function ( file ) {\n\t\tlet upload;\n\n\t\tif ( this.uploads.length >= this.config.maxUploads ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tupload = new mw.UploadWizardUpload( this, file );\n\n\t\tif ( !this.validateFile( upload ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tupload.fileChangedOk();\n\n\t\t// attach controller-specific event handlers (they're automatically\n\t\t// bound on load already, but we've only just added these files...)\n\t\tthis.bindUploadHandlers( upload );\n\n\t\tthis.setUploadFilled( upload );\n\n\t\treturn upload;\n\t};\n\n\t/**\n\t * Do everything that needs to be done to start uploading a file. Calls #addFile, then appends\n\t * each mw.UploadWizardUploadInterface to the DOM and queues thumbnails to be generated.\n\t *\n\t * @param {FileList} files\n\t */\n\tuw.controller.Upload.prototype.addFiles = function ( files ) {\n\t\tlet\n\t\t\tuploadObj,\n\t\t\ti,\n\t\t\tfile,\n\t\t\tuploadObjs = [],\n\t\t\tcontroller = this;\n\n\t\tfor ( i = 0; i < files.length; i++ ) {\n\t\t\tfile = files[ i ];\n\t\t\tuploadObj = controller.addFile( file );\n\t\t\tif ( uploadObj ) {\n\t\t\t\tuploadObjs.push( uploadObj );\n\t\t\t}\n\t\t}\n\n\t\tthis.ui.displayUploads( uploadObjs );\n\t\tthis.updateFileCounts();\n\t};\n\n\t/**\n\t * Remove an upload from our array of uploads, and the HTML UI\n\t * We can remove the HTML UI directly, as jquery will just get the parent.\n\t * We need to grep through the array of uploads, since we don't know the current index.\n\t * We need to update file counts for obvious reasons.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Upload.prototype.removeUpload = function ( upload ) {\n\t\tuw.controller.Step.prototype.removeUpload.call( this, upload );\n\n\t\tthis.queue.removeItem( upload );\n\n\t\tthis.updateFileCounts();\n\n\t\t// check all uploads, if they're complete, show the next button\n\t\tthis.showNext();\n\t};\n\n\t/**\n\t * When an upload is filled with a real file, accept it in the list of uploads\n\t * and set up some other interfaces\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Upload.prototype.setUploadFilled = function ( upload ) {\n\t\tthis.addUpload( upload );\n\t\t// Start uploads now, no reason to wait--leave the remove button alone\n\t\tthis.queueUpload( upload );\n\t\tthis.startQueuedUploads();\n\t};\n\n\t/**\n\t * Checks for file validity.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {boolean} Error in [code, info] format, or empty [] for no errors\n\t */\n\tuw.controller.Upload.prototype.validateFile = function ( upload ) {\n\t\tlet extension,\n\t\t\ti,\n\t\t\tactualMaxSize = mw.UploadWizard.config.maxMwUploadSize,\n\n\t\t\t// Check if filename is acceptable\n\t\t\t// TODO sanitize filename\n\t\t\tfilename = upload.getFilename(),\n\t\t\tbasename = upload.getBasename();\n\n\t\t// check to see if this file has already been selected for upload\n\t\tfor ( i = 0; i < this.uploads.length; i++ ) {\n\t\t\tif ( upload !== this.uploads[ i ] && filename === this.uploads[ i ].getFilename() ) {\n\t\t\t\tthis.ui.showDuplicateError( filename, basename );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// check if the filename is valid\n\t\tupload.setTitle( basename );\n\t\tif ( !upload.title ) {\n\t\t\tif ( !basename.includes( '.' ) ) {\n\t\t\t\tthis.ui.showMissingExtensionError( filename );\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\tthis.ui.showUnparseableFilenameError( filename );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// check if extension is acceptable\n\t\textension = upload.title.getExtension();\n\t\tif ( !extension ) {\n\t\t\tthis.ui.showMissingExtensionError( filename );\n\t\t\treturn false;\n\t\t}\n\n\t\tif (\n\t\t\tmw.UploadWizard.config.fileExtensions !== null &&\n\t\t\t!mw.UploadWizard.config.fileExtensions.includes( extension.toLowerCase() )\n\t\t) {\n\t\t\tthis.ui.showBadExtensionError( filename, extension );\n\t\t\treturn false;\n\t\t}\n\n\t\t// make sure the file isn't too large\n\t\tif ( upload.file.size ) {\n\t\t\tupload.transportWeight = upload.file.size;\n\t\t\tif ( upload.transportWeight > actualMaxSize ) {\n\t\t\t\tthis.ui.showFileTooLargeError( actualMaxSize, upload.transportWeight );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.Abstract.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.Custom.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.External.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":66,"column":10,"nodeType":"MemberExpression","messageId":"forbidden","endLine":66,"endColumn":23}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * @param {Object} config The UW config\n\t * @param {mw.UploadWizardUpload} upload Uploads that this deed refers to\n\t * @class uw.deed.External\n\t * @constructor\n\t */\n\tuw.deed.External = function UWDeedExternal( config, upload ) {\n\t\tuw.deed.Custom.call( this, config, upload );\n\n\t\tthis.licenseInput = new mw.UploadWizardLicenseInput(\n\t\t\tconfig.licensing.thirdParty,\n\t\t\t1,\n\t\t\tupload.api\n\t\t);\n\t\tthis.licenseInput.$element.addClass( 'mediauploader-External-deed' );\n\t\tthis.licenseInputField = new uw.FieldLayout( this.licenseInput );\n\t\tthis.licenseInput.setDefaultValues();\n\t};\n\n\tOO.inheritClass( uw.deed.External, uw.deed.Custom );\n\n\tuw.deed.External.prototype.unload = function () {\n\t\tthis.licenseInput.unload();\n\t};\n\n\t/**\n\t * @return {uw.FieldLayout[]} Fields that need validation\n\t */\n\tuw.deed.External.prototype.getFields = function () {\n\t\treturn [ this.licenseInputField ];\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.External.prototype.getLicenseWikiText = function () {\n\t\tif ( this.upload.file.licenseValue ) {\n\t\t\treturn this.upload.file.licenseValue + this.licenseInput.getWikiText();\n\t\t} else {\n\t\t\treturn this.licenseInput.getWikiText();\n\t\t}\n\t};\n\n\t/**\n\t * @return {Object}\n\t */\n\tuw.deed.External.prototype.getSerialized = function () {\n\t\treturn Object.assign( uw.deed.Custom.prototype.getSerialized.call( this ), {\n\t\t\tlicense: this.licenseInput.getSerialized()\n\t\t} );\n\t};\n\n\t/**\n\t * @param {Object} serialized\n\t */\n\tuw.deed.External.prototype.setSerialized = function ( serialized ) {\n\t\tuw.deed.Custom.prototype.setSerialized.call( this, serialized );\n\n\t\tif ( serialized.license ) {\n\t\t\tthis.licenseInput.setSerialized( serialized.license );\n\t\t}\n\t};\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.None.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.OwnWork.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'deed' is never reassigned. Use 'const' instead.","line":29,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":29,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'deed' is never reassigned. Use 'const' instead.","line":88,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":88,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'languageCode' is never reassigned. Use 'const' instead.","line":89,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":89,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'defaultLicense' is never reassigned. Use 'const' instead.","line":91,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":91,"endColumn":17},{"ruleId":"prefer-const","severity":2,"message":"'defaultLicConfig' is never reassigned. Use 'const' instead.","line":92,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":92,"endColumn":19},{"ruleId":"prefer-const","severity":2,"message":"'$defaultLicenseLink' is never reassigned. Use 'const' instead.","line":99,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":99,"endColumn":22},{"ruleId":"prefer-const","severity":2,"message":"'$crossfader' is never reassigned. Use 'const' instead.","line":125,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":125,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'$customDiv' is never reassigned. Use 'const' instead.","line":128,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":128,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'crossfaderWidget' is never reassigned. Use 'const' instead.","line":136,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":136,"endColumn":19},{"ruleId":"prefer-const","severity":2,"message":"'$formFields' is never reassigned. Use 'const' instead.","line":148,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":148,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'$toggler' is never reassigned. Use 'const' instead.","line":152,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":152,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'author' is never reassigned. Use 'const' instead.","line":192,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":192,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'userPageTitle' is never reassigned. Use 'const' instead.","line":200,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":200,"endColumn":16},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":215,"column":10,"nodeType":"MemberExpression","messageId":"forbidden","endLine":215,"endColumn":23},{"ruleId":"prefer-const","severity":2,"message":"'ownWork' is never reassigned. Use 'const' instead.","line":255,"column":16,"nodeType":"Identifier","messageId":"useConst","endLine":255,"endColumn":23},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":277,"column":3,"nodeType":"CallExpression","endLine":280,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":297,"column":3,"nodeType":"CallExpression","endLine":300,"endColumn":7}],"suppressedMessages":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":111,"column":28,"nodeType":"CallExpression","endLine":113,"endColumn":5,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":118,"column":5,"nodeType":"CallExpression","endLine":121,"endColumn":6,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-slide","severity":2,"message":"Prefer CSS transitions to .slideUp","line":284,"column":3,"nodeType":"CallExpression","endLine":285,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-animate","severity":2,"message":"Prefer CSS transitions to .animate","line":284,"column":3,"nodeType":"CallExpression","endLine":286,"endColumn":66,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-slide","severity":2,"message":"Prefer CSS transitions to .slideDown","line":304,"column":3,"nodeType":"CallExpression","endLine":305,"endColumn":16,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-animate","severity":2,"message":"Prefer CSS transitions to .animate","line":304,"column":3,"nodeType":"CallExpression","endLine":306,"endColumn":88,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":16,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Set up the form and deed object for the deed option that says these uploads are all the user's own work.\n\t *\n\t * @class uw.deed.OwnWork\n\t * @constructor\n\t * @param {Object} config The UW config\n\t * @param {mw.UploadWizardUpload[]} uploads Array of uploads that this deed refers to\n\t * @param {mw.Api} api API object - useful for doing previews\n\t */\n\tuw.deed.OwnWork = function UWDeedOwnWork( config, uploads, api ) {\n\t\tlet deed = this,\n\t\t\tprefAuthName = mw.user.options.get( 'upwiz_licensename' );\n\n\t\tuw.deed.Abstract.call( this, 'ownwork', config );\n\n\t\tthis.uploadCount = uploads.length;\n\n\t\tif ( !prefAuthName ) {\n\t\t\tprefAuthName = mw.config.get( 'wgUserName' );\n\t\t}\n\n\t\t// copyright holder\n\t\tthis.authorInput = new OO.ui.TextInputWidget( {\n\t\t\tname: 'author',\n\t\t\ttitle: mw.message( 'mediauploader-tooltip-sign' ).text(),\n\t\t\tvalue: prefAuthName,\n\t\t\tclasses: [ 'mediauploader-sign' ]\n\t\t} );\n\t\tthis.fakeAuthorInput = new OO.ui.TextInputWidget( {\n\t\t\treadOnly: true,\n\t\t\tvalue: prefAuthName,\n\t\t\tclasses: [ 'mediauploader-sign' ]\n\t\t} );\n\t\tthis.authorInput.on( 'change', () => {\n\t\t\tdeed.fakeAuthorInput.setValue( deed.authorInput.getValue() );\n\t\t} );\n\n\t\t// \"use a different license\"\n\t\tthis.licenseInput = new mw.UploadWizardLicenseInput(\n\t\t\tthis.config.licensing.ownWork,\n\t\t\tthis.uploadCount,\n\t\t\tapi\n\t\t);\n\t\tthis.licenseInput.$element.addClass( 'mediauploader-deed-license' );\n\t\tthis.licenseInputField = new uw.FieldLayout( this.licenseInput );\n\t};\n\n\tOO.inheritClass( uw.deed.OwnWork, uw.deed.Abstract );\n\n\tuw.deed.OwnWork.prototype.unload = function () {\n\t\t// No licenseInput is present if there's no custom licenses allowed (e.g. campaigns)\n\t\tif ( this.licenseInput !== undefined ) {\n\t\t\tthis.licenseInput.unload();\n\t\t}\n\t};\n\n\t/**\n\t * @return {uw.FieldLayout[]} Fields that need validation\n\t */\n\tuw.deed.OwnWork.prototype.getFields = function () {\n\t\treturn [ this.authorInputField, this.licenseInputField ];\n\t};\n\n\tuw.deed.OwnWork.prototype.setFormFields = function ( $selector ) {\n\t\tlet $customDiv, $formFields, $toggler, crossfaderWidget, defaultLicense,\n\t\t\tdefaultLicenseURL, $defaultLicenseLink, $standardDiv, $crossfader,\n\t\t\tdeed, languageCode, defaultLicConfig;\n\n\t\tthis.$selector = $selector;\n\t\tdeed = this;\n\t\tlanguageCode = mw.config.get( 'wgUserLanguage' );\n\n\t\tdefaultLicense = this.getDefaultLicenses()[ 0 ];\n\t\tdefaultLicConfig = this.config.licenses[ defaultLicense ];\n\n\t\tdefaultLicenseURL = defaultLicConfig.url === undefined ?\n\t\t\t'#missing license URL' : defaultLicConfig.url;\n\t\tif ( defaultLicConfig.languageCodePrefix !== undefined ) {\n\t\t\tdefaultLicenseURL += defaultLicConfig.languageCodePrefix + languageCode;\n\t\t}\n\t\t$defaultLicenseLink = $( '<a>' ).attr( { target: '_blank', href: defaultLicenseURL } );\n\n\t\tthis.$form = $( '<form>' );\n\n\t\t/* eslint-disable mediawiki/msg-doc */\n\t\t$standardDiv = $( '<div>' ).addClass( 'mediauploader-standard' ).append(\n\t\t\t$( '<p>' ).msg(\n\t\t\t\t'mediauploader-source-ownwork-assert',\n\t\t\t\tthis.uploadCount,\n\t\t\t\tthis.authorInput.$element,\n\t\t\t\t$defaultLicenseLink,\n\t\t\t\tmw.user\n\t\t\t).append( ' ' ).append( mw.message(\n\t\t\t\tdefaultLicConfig.msg, '', defaultLicenseURL\n\t\t\t).parse() )\n\t\t);\n\n\t\tif ( defaultLicConfig.explainMsg !== undefined ) {\n\t\t\t$standardDiv = $standardDiv.append(\n\t\t\t\t$( '<p>' ).addClass( 'mwe-small-print' ).msg(\n\t\t\t\t\tdefaultLicConfig.explainMsg,\n\t\t\t\t\tthis.uploadCount\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\t$crossfader = $( '<div>' ).addClass( 'mediauploader-crossfader' ).append( $standardDiv );\n\t\t/* eslint-enable mediawiki/msg-doc */\n\n\t\t$customDiv = $( '<div>' ).addClass( 'mediauploader-custom' ).append(\n\t\t\t$( '<p>' ).msg( 'mediauploader-source-ownwork-assert',\n\t\t\t\tthis.uploadCount,\n\t\t\t\tthis.fakeAuthorInput.$element )\n\t\t);\n\n\t\t$crossfader.append( $customDiv );\n\n\t\tcrossfaderWidget = new OO.ui.Widget();\n\t\tcrossfaderWidget.$element.append( $crossfader );\n\t\t// See uw.DetailsWidget\n\t\tcrossfaderWidget.getErrors = this.getAuthorErrors.bind( this, this.authorInput );\n\t\tcrossfaderWidget.getWarnings = this.getAuthorWarnings.bind( this, this.authorInput );\n\n\t\tthis.authorInputField = new uw.FieldLayout( crossfaderWidget );\n\t\t// Aggregate 'change' event\n\t\tthis.authorInput.on( 'change', OO.ui.debounce( () => {\n\t\t\tcrossfaderWidget.emit( 'change' );\n\t\t}, 500 ) );\n\n\t\t$formFields = $( '<div>' ).addClass( 'mediauploader-deed-form-internal' )\n\t\t\t.append( this.authorInputField.$element );\n\n\t\t// FIXME: Move CSS rule to CSS file\n\t\t$toggler = $( '<p>' ).addClass( 'mwe-more-options' ).css( 'text-align', 'right' )\n\t\t\t.append( $( '<a>' )\n\t\t\t\t.msg( 'mediauploader-license-show-all' )\n\t\t\t\t.on( 'click', () => {\n\t\t\t\t\tif ( $crossfader.data( 'crossfadeDisplay' ).get( 0 ) === $customDiv.get( 0 ) ) {\n\t\t\t\t\t\tdeed.standardLicense();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdeed.customLicense();\n\t\t\t\t\t}\n\t\t\t\t} ) );\n\n\t\t$formFields.append( this.licenseInputField.$element.hide(), $toggler );\n\n\t\tthis.$form.append( $formFields ).appendTo( $selector );\n\n\t\t// done after added to the DOM, so there are true heights\n\t\t$crossfader.morphCrossfader();\n\n\t\tthis.setDefaultLicenses();\n\t};\n\n\tuw.deed.OwnWork.prototype.setDefaultLicenses = function () {\n\t\tconst defaultLicenses = {};\n\t\tthis.getDefaultLicenses().forEach( ( licName ) => {\n\t\t\tdefaultLicenses[ licName ] = true;\n\t\t} );\n\t\tthis.licenseInput.setValues( defaultLicenses );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.OwnWork.prototype.getSourceWikiText = function () {\n\t\treturn mw.message( 'mediauploader-content-source-ownwork' ).plain();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.OwnWork.prototype.getAuthorWikiText = function () {\n\t\tlet author = this.authorInput.getValue(),\n\t\t\tuserPageTitle;\n\n\t\tif ( author.includes( '[' ) || author.includes( '{' ) ) {\n\t\t\treturn author;\n\t\t}\n\n\t\t// Construct a Title for the user page to get the localized NS prefix\n\t\tuserPageTitle = new mw.Title( 'User:' + mw.config.get( 'wgUserName' ) );\n\t\treturn '[[' + userPageTitle.getPrefixedText() + '|' + author + ']]';\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.OwnWork.prototype.getLicenseWikiText = function () {\n\t\treturn this.licenseInput.getWikiText();\n\t};\n\n\t/**\n\t * @return {Object}\n\t */\n\tuw.deed.OwnWork.prototype.getSerialized = function () {\n\t\treturn Object.assign( uw.deed.Abstract.prototype.getSerialized.call( this ), {\n\t\t\tauthor: this.authorInput.getValue(),\n\t\t\tlicense: this.licenseInput.getSerialized()\n\t\t} );\n\t};\n\n\t/**\n\t * @param {Object} serialized\n\t */\n\tuw.deed.OwnWork.prototype.setSerialized = function ( serialized ) {\n\t\tuw.deed.Abstract.prototype.setSerialized.call( this, serialized );\n\n\t\tif ( serialized.author ) {\n\t\t\tthis.authorInput.setValue( serialized.author );\n\t\t}\n\n\t\tif ( serialized.license ) {\n\t\t\t// expand licenses container\n\t\t\tthis.customLicense();\n\t\t\tthis.licenseInput.setSerialized( serialized.license );\n\t\t}\n\t};\n\n\tuw.deed.OwnWork.prototype.swapNodes = function ( a, b ) {\n\t\tconst\n\t\t\tparentA = a.parentNode,\n\t\t\tparentB = b.parentNode,\n\t\t\tnextA = a.nextSibling,\n\t\t\tnextB = b.nextSibling;\n\n\t\t// This is not correct if a and b are siblings, or if one is a child of the\n\t\t// other, or if they're detached, or maybe in other cases, but we don't care\n\t\tparentA[ nextA ? 'insertBefore' : 'appendChild' ]( b, nextA );\n\t\tparentB[ nextB ? 'insertBefore' : 'appendChild' ]( a, nextB );\n\t};\n\n\t/**\n\t * @return {string[]}\n\t */\n\tuw.deed.OwnWork.prototype.getDefaultLicenses = function () {\n\t\tlet license, ownWork = this.config.licensing.ownWork;\n\n\t\tif ( this.config.licensing.defaultType === 'ownWork' ) {\n\t\t\tlicense = ownWork.defaults;\n\t\t\treturn license instanceof Array ? license : [ license ];\n\t\t} else {\n\t\t\tif ( ownWork.licenses ) {\n\t\t\t\treturn [ ownWork.licenses[ 0 ] ];\n\t\t\t} else {\n\t\t\t\treturn [ ownWork.licenseGroups[ 0 ].licenses[ 0 ] ];\n\t\t\t}\n\t\t}\n\t};\n\n\tuw.deed.OwnWork.prototype.standardLicense = function () {\n\t\tconst deed = this,\n\t\t\t$crossfader = this.$selector.find( '.mediauploader-crossfader' ),\n\t\t\t$standardDiv = this.$selector.find( '.mediauploader-standard' ),\n\t\t\t$toggler = this.$selector.find( '.mwe-more-options a' );\n\n\t\tthis.setDefaultLicenses();\n\n\t\t$crossfader.morphCrossfade( $standardDiv )\n\t\t\t.promise().done( () => {\n\t\t\t\tdeed.swapNodes( deed.authorInput.$element[ 0 ], deed.fakeAuthorInput.$element[ 0 ] );\n\t\t\t} );\n\n\t\t// FIXME: Use CSS transition\n\t\t// eslint-disable-next-line no-jquery/no-slide, no-jquery/no-animate\n\t\tthis.licenseInputField.$element\n\t\t\t.slideUp()\n\t\t\t.animate( { opacity: 0 }, { queue: false, easing: 'linear' } );\n\n\t\t$toggler.msg( 'mediauploader-license-show-all' );\n\t};\n\n\tuw.deed.OwnWork.prototype.customLicense = function () {\n\t\tconst deed = this,\n\t\t\t$crossfader = this.$selector.find( '.mediauploader-crossfader' ),\n\t\t\t$customDiv = this.$selector.find( '.mediauploader-custom' ),\n\t\t\t$toggler = this.$selector.find( '.mwe-more-options a' );\n\n\t\t$crossfader.morphCrossfade( $customDiv )\n\t\t\t.promise().done( () => {\n\t\t\t\tdeed.swapNodes( deed.authorInput.$element[ 0 ], deed.fakeAuthorInput.$element[ 0 ] );\n\t\t\t} );\n\n\t\t// FIXME: Use CSS transition\n\t\t// eslint-disable-next-line no-jquery/no-slide, no-jquery/no-animate\n\t\tthis.licenseInputField.$element\n\t\t\t.slideDown()\n\t\t\t.css( { opacity: 0 } ).animate( { opacity: 1 }, { queue: false, easing: 'linear' } );\n\n\t\t$toggler.msg( 'mediauploader-license-show-recommended' );\n\t};\n\n\t/**\n\t * @param {OO.ui.InputWidget} input\n\t * @return {jQuery.Promise}\n\t */\n\tuw.deed.OwnWork.prototype.getAuthorErrors = function ( input ) {\n\t\tconst\n\t\t\terrors = [],\n\t\t\tminLength = this.config.minAuthorLength,\n\t\t\tmaxLength = this.config.maxAuthorLength,\n\t\t\ttext = input.getValue().trim();\n\n\t\tif ( text === '' ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-signature-blank' ) );\n\t\t} else if ( text.length < minLength ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-signature-too-short', minLength ) );\n\t\t} else if ( text.length > maxLength ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-signature-too-long', maxLength ) );\n\t\t}\n\n\t\treturn $.Deferred().resolve( errors ).promise();\n\t};\n\n\t/**\n\t * @return {jQuery.Promise}\n\t */\n\tuw.deed.OwnWork.prototype.getAuthorWarnings = function () {\n\t\treturn $.Deferred().resolve( [] ).promise();\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.ThirdParty.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":178,"column":10,"nodeType":"MemberExpression","messageId":"forbidden","endLine":178,"endColumn":23}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Set up the form and deed object for the deed option that says these uploads are the work of a third party.\n\t *\n\t * @class uw.deed.ThirdParty\n\t * @constructor\n\t * @param {Object} config The UW config\n\t * @param {mw.UploadWizardUpload[]} uploads Array of uploads that this deed refers to\n\t * @param {mw.Api} api API object - useful for doing previews\n\t */\n\tuw.deed.ThirdParty = function UWDeedThirdParty( config, uploads, api ) {\n\t\tconst deed = this;\n\n\t\tuw.deed.Abstract.call( this, 'thirdparty', config );\n\n\t\tthis.uploadCount = uploads.length;\n\n\t\tthis.sourceInput = new OO.ui.MultilineTextInputWidget( {\n\t\t\tautosize: true,\n\t\t\tclasses: [ 'mwe-source' ],\n\t\t\tname: 'source'\n\t\t} );\n\t\tthis.sourceInput.$input.attr( 'id', 'mwe-source-' + this.getInstanceCount() );\n\t\t// See uw.DetailsWidget\n\t\tthis.sourceInput.getErrors = function () {\n\t\t\tconst\n\t\t\t\terrors = [],\n\t\t\t\tminLength = deed.config.minSourceLength,\n\t\t\t\tmaxLength = deed.config.maxSourceLength,\n\t\t\t\ttext = this.getValue().trim();\n\n\t\t\tif ( text === '' ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t\t} else if ( text.length < minLength ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-too-short', minLength ) );\n\t\t\t} else if ( text.length > maxLength ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-too-long', maxLength ) );\n\t\t\t}\n\n\t\t\treturn $.Deferred().resolve( errors ).promise();\n\t\t};\n\t\t// See uw.DetailsWidget\n\t\tthis.sourceInput.getWarnings = function () {\n\t\t\treturn $.Deferred().resolve( [] ).promise();\n\t\t};\n\t\tthis.sourceInputField = new uw.FieldLayout( this.sourceInput, {\n\t\t\tlabel: mw.message( 'mediauploader-source' ).text(),\n\t\t\thelp: mw.message( 'mediauploader-tooltip-source' ).text(),\n\t\t\trequired: true\n\t\t} );\n\n\t\tthis.authorInput = new OO.ui.MultilineTextInputWidget( {\n\t\t\tautosize: true,\n\t\t\tclasses: [ 'mwe-author' ],\n\t\t\tname: 'author'\n\t\t} );\n\t\tthis.authorInput.$input.attr( 'id', 'mwe-author-' + this.getInstanceCount() );\n\t\t// See uw.DetailsWidget\n\t\tthis.authorInput.getErrors = function () {\n\t\t\tconst\n\t\t\t\terrors = [],\n\t\t\t\tminLength = deed.config.minAuthorLength,\n\t\t\t\tmaxLength = deed.config.maxAuthorLength,\n\t\t\t\ttext = this.getValue().trim();\n\n\t\t\tif ( text === '' ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t\t} else if ( text.length < minLength ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-too-short', minLength ) );\n\t\t\t} else if ( text.length > maxLength ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-too-long', maxLength ) );\n\t\t\t}\n\n\t\t\treturn $.Deferred().resolve( errors ).promise();\n\t\t};\n\t\t// See uw.DetailsWidget\n\t\tthis.authorInput.getWarnings = function () {\n\t\t\treturn $.Deferred().resolve( [] ).promise();\n\t\t};\n\t\tthis.authorInputField = new uw.FieldLayout( this.authorInput, {\n\t\t\tlabel: mw.message( 'mediauploader-author' ).text(),\n\t\t\thelp: mw.message( 'mediauploader-tooltip-author' ).text(),\n\t\t\trequired: true\n\t\t} );\n\n\t\tthis.licenseInput = new mw.UploadWizardLicenseInput(\n\t\t\tthis.config.licensing.thirdParty,\n\t\t\tthis.uploadCount,\n\t\t\tapi\n\t\t);\n\t\tthis.licenseInput.$element.addClass( 'mediauploader-deed-license-groups' );\n\t\tthis.licenseInput.setDefaultValues();\n\t\tthis.licenseInputField = new uw.FieldLayout( this.licenseInput, {\n\t\t\tlabel: mw.message( 'mediauploader-source-thirdparty-cases', this.uploadCount ).text(),\n\t\t\trequired: true\n\t\t} );\n\t};\n\n\tOO.inheritClass( uw.deed.ThirdParty, uw.deed.Abstract );\n\n\tuw.deed.ThirdParty.prototype.unload = function () {\n\t\tthis.licenseInput.unload();\n\t};\n\n\t/**\n\t * @return {uw.FieldLayout[]} Fields that need validation\n\t */\n\tuw.deed.ThirdParty.prototype.getFields = function () {\n\t\treturn [ this.authorInputField, this.sourceInputField, this.licenseInputField ];\n\t};\n\n\tuw.deed.ThirdParty.prototype.setFormFields = function ( $selector ) {\n\t\tconst $formFields = $( '<div>' ).addClass( 'mediauploader-deed-form-internal' );\n\n\t\tthis.$form = $( '<form>' );\n\n\t\tif ( this.uploadCount > 1 ) {\n\t\t\t$formFields.append( $( '<div>' ).msg( 'mediauploader-source-thirdparty-custom-multiple-intro' ) );\n\t\t}\n\n\t\t$formFields.append(\n\t\t\t$( '<div>' ).addClass( 'mediauploader-source-thirdparty-custom-multiple-intro' ),\n\t\t\t$( '<div>' ).addClass( 'mediauploader-thirdparty-fields' )\n\t\t\t\t.append( this.sourceInputField.$element ),\n\t\t\t$( '<div>' ).addClass( 'mediauploader-thirdparty-fields' )\n\t\t\t\t.append( this.authorInputField.$element ),\n\t\t\t$( '<div>' ).addClass( 'mediauploader-thirdparty-license' )\n\t\t\t\t.append( this.licenseInputField.$element )\n\t\t);\n\n\t\tthis.$form.append( $formFields );\n\n\t\t$selector.append( this.$form );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.ThirdParty.prototype.getSourceWikiText = function () {\n\t\treturn this.sourceInput.getValue();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.ThirdParty.prototype.getAuthorWikiText = function () {\n\t\treturn this.authorInput.getValue();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.ThirdParty.prototype.getLicenseWikiText = function () {\n\t\treturn this.licenseInput.getWikiText();\n\t};\n\n\t/**\n\t * @return {Object}\n\t */\n\tuw.deed.ThirdParty.prototype.getSerialized = function () {\n\t\treturn Object.assign( uw.deed.Abstract.prototype.getSerialized.call( this ), {\n\t\t\tsource: this.sourceInput.getValue(),\n\t\t\tauthor: this.authorInput.getValue(),\n\t\t\tlicense: this.licenseInput.getSerialized()\n\t\t} );\n\t};\n\n\t/**\n\t * @param {Object} serialized\n\t */\n\tuw.deed.ThirdParty.prototype.setSerialized = function ( serialized ) {\n\t\tuw.deed.Abstract.prototype.setSerialized.call( this, serialized );\n\n\t\tif ( serialized.source ) {\n\t\t\tthis.sourceInput.setValue( serialized.source );\n\t\t}\n\t\tif ( serialized.author ) {\n\t\t\tthis.authorInput.setValue( serialized.author );\n\t\t}\n\t\tif ( serialized.license ) {\n\t\t\tthis.licenseInput.setSerialized( serialized.license );\n\t\t}\n\t};\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.CategoriesDetailsWidget.js","messages":[{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":87,"column":3,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":87,"endColumn":5},{"ruleId":"implicit-arrow-linebreak","severity":2,"message":"Expected no linebreak before this expression.","line":87,"column":5,"nodeType":"Punctuator","messageId":"unexpected","endLine":87,"endColumn":6},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":88,"column":2,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":88,"endColumn":4},{"ruleId":"prefer-const","severity":2,"message":"'categories' is never reassigned. Use 'const' instead.","line":98,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":98,"endColumn":13},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":128,"column":3,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":128,"endColumn":5},{"ruleId":"implicit-arrow-linebreak","severity":2,"message":"Expected no linebreak before this expression.","line":128,"column":5,"nodeType":"Punctuator","messageId":"unexpected","endLine":128,"endColumn":6},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":129,"column":2,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":129,"endColumn":4}],"suppressedMessages":[],"errorCount":7,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tconst NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;\n\n\t/**\n\t * A categories field in UploadWizard's \"Details\" step form.\n\t *\n\t * @extends uw.DetailsWidget\n\t * @param {Object} config\n\t */\n\tuw.CategoriesDetailsWidget = function UWCategoriesDetailsWidget( config ) {\n\t\tconst catDetails = this;\n\t\tthis.config = config;\n\n\t\tuw.CategoriesDetailsWidget.parent.call( this, this.config );\n\n\t\tthis.categoriesWidget = new mw.widgets.CategoryMultiselectWidget( {\n\t\t\tdisabled: this.config.disabled\n\t\t} );\n\n\t\tthis.categoriesWidget.createTagItemWidget = function ( data ) {\n\t\t\tconst widget = this.constructor.prototype.createTagItemWidget.call( this, data );\n\t\t\tif ( !widget ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\twidget.setMissing = function ( missing ) {\n\t\t\t\tthis.constructor.prototype.setMissing.call( this, missing );\n\t\t\t\t// Aggregate 'change' event\n\t\t\t\tcatDetails.emit( 'change' );\n\t\t\t};\n\t\t\treturn widget;\n\t\t};\n\n\t\tthis.$element.addClass( 'mediauploader-categoriesDetailsWidget' );\n\t\tthis.$element.append( this.categoriesWidget.$element );\n\n\t\t// Aggregate 'change' event\n\t\tthis.categoriesWidget.connect( this, { change: [ 'emit', 'change' ] } );\n\t};\n\tOO.inheritClass( uw.CategoriesDetailsWidget, uw.DetailsWidget );\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.CategoriesDetailsWidget.prototype.getErrors = function () {\n\t\tconst errors = [];\n\n\t\tif ( this.config.required && this.categoriesWidget.getItems().length === 0 ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t}\n\n\t\treturn $.Deferred().resolve( errors ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.CategoriesDetailsWidget.prototype.getWarnings = function () {\n\t\tconst warnings = [];\n\t\tthis.getEmptyWarning( this.categoriesWidget.getItems().length === 0, warnings );\n\n\t\tif ( this.categoriesWidget.getItems().some( ( item ) => item.missing ) ) {\n\t\t\twarnings.push( mw.message( 'mediauploader-categories-missing' ) );\n\t\t}\n\t\treturn $.Deferred().resolve( warnings ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.CategoriesDetailsWidget.prototype.getWikiText = function () {\n\t\tlet hiddenCats, missingCatsWikiText, categories, wikiText;\n\n\t\thiddenCats = [];\n\t\tif ( this.config.hiddenDefault ) {\n\t\t\thiddenCats = hiddenCats.concat( this.config.hiddenDefault );\n\t\t}\n\t\tif ( mw.UploadWizard.config.trackingCategory ) {\n\t\t\tif ( mw.UploadWizard.config.trackingCategory.campaign &&\n\t\t\t\tmw.UploadWizard.config.trackingCategory.autoAdd\n\t\t\t) {\n\t\t\t\thiddenCats.push( mw.UploadWizard.config.trackingCategory.campaign );\n\t\t\t}\n\t\t}\n\t\thiddenCats = hiddenCats.filter( ( cat ) =>\n\t\t\t// Keep only valid titles\n\t\t\t !!mw.Title.makeTitle( NS_CATEGORY, cat )\n\t\t );\n\n\t\tmissingCatsWikiText = null;\n\t\tif (\n\t\t\ttypeof this.config.missingWikitext === 'string' &&\n\t\t\tthis.config.missingWikitext.length > 0\n\t\t) {\n\t\t\tmissingCatsWikiText = this.config.missingWikitext;\n\t\t}\n\n\t\tcategories = this.categoriesWidget.getItems().map( ( item ) => item.data );\n\n\t\t// add all categories\n\t\twikiText = categories.concat( hiddenCats )\n\t\t\t.map( ( cat ) => '[[' + mw.Title.makeTitle( NS_CATEGORY, cat ).getPrefixedText() + ']]' )\n\t\t\t.join( '\\n' );\n\n\t\t// if so configured, and there are no user-visible categories, add warning\n\t\tif ( missingCatsWikiText !== null && categories.length === 0 ) {\n\t\t\twikiText += '\\n\\n' + missingCatsWikiText;\n\t\t}\n\n\t\treturn wikiText;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.CategoriesDetailsWidget.prototype.getSerialized = function () {\n\t\treturn this.categoriesWidget.getItems().map( ( item ) => item.data );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {string[]} serialized List of categories\n\t */\n\tuw.CategoriesDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\tconst categories = ( serialized || [] ).filter( ( cat ) =>\n\t\t\t// Keep only valid titles\n\t\t\t !!mw.Title.makeTitle( NS_CATEGORY, cat )\n\t\t );\n\t\tthis.categoriesWidget.setValue( categories );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.DateDetailsWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.DeedChooserDetailsWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.DropdownWidget.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":13,"column":12,"nodeType":"MemberExpression","messageId":"forbidden","endLine":13,"endColumn":25}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A field with a dropdown.\n\t *\n\t * @extends uw.DetailsWidget\n\t * @constructor\n\t * @param {Object} [config] Configuration options\n\t * @cfg {boolean} [required=false] Whether to mark this field as required\n\t * @cfg {Object} [options] Map of select dropdown options\n\t */\n\tuw.DropdownWidget = function MUDropdownWidget( config ) {\n\t\tconfig = Object.assign( { type: 'text' }, config );\n\t\tuw.DropdownWidget.parent.call( this, config );\n\n\t\tthis.required = !!config.required;\n\t\tthis.wikitext = config.wikitext;\n\t\tthis.input = new OO.ui.DropdownInputWidget( {\n\t\t\tclasses: [ 'mwe-idfield', 'mediauploader-dropdownWidget-input' ],\n\t\t\toptions: Object.keys( config.options ).map( ( key ) => ( { data: key, label: config.options[ key ] } ) )\n\t\t} );\n\n\t\t// Aggregate 'change' event\n\t\t// (but do not flash warnings in the user's face while they're typing)\n\t\tthis.input.on( 'change', OO.ui.debounce( this.emit.bind( this, 'change' ), 500 ) );\n\n\t\tthis.$element.addClass( 'mwe-id-field mediauploader-dropdownWidget' );\n\t\tthis.$element.append(\n\t\t\tthis.input.$element\n\t\t);\n\t};\n\tOO.inheritClass( uw.DropdownWidget, uw.DetailsWidget );\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.DropdownWidget.prototype.getErrors = function () {\n\t\tconst errors = [];\n\t\tif ( this.required && this.input.getValue().trim() === '' ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t}\n\t\treturn $.Deferred().resolve( errors ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.DropdownWidget.prototype.getWarnings = function () {\n\t\tconst warnings = [];\n\t\tthis.getEmptyWarning( this.input.getValue().trim() === '', warnings );\n\n\t\treturn $.Deferred().resolve( warnings ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.DropdownWidget.prototype.getWikiText = function () {\n\t\treturn this.input.getValue().trim();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.DropdownWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\tvalue: this.input.getValue()\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {string} serialized.value Campaign informations text\n\t */\n\tuw.DropdownWidget.prototype.setSerialized = function ( serialized ) {\n\t\tthis.input.setValue( serialized.value );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.LanguageDropdownWidget.js","messages":[],"suppressedMessages":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":17,"column":53,"nodeType":"ObjectExpression","endLine":21,"endColumn":4,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.LocationDetailsWidget.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":12,"column":17,"nodeType":"MemberExpression","messageId":"forbidden","endLine":12,"endColumn":30},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":71,"column":3,"nodeType":"CallExpression","endLine":74,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":84,"column":3,"nodeType":"CallExpression","endLine":86,"endColumn":6},{"ruleId":"prefer-const","severity":2,"message":"'errors' is never reassigned. Use 'const' instead.","line":115,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":115,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'serialized' is never reassigned. Use 'const' instead.","line":116,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":116,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'parsed' is never reassigned. Use 'const' instead.","line":117,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":117,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'serialized' is never reassigned. Use 'const' instead.","line":165,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":165,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'result' is never reassigned. Use 'const' instead.","line":194,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":194,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'result' is never reassigned. Use 'const' instead.","line":210,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":210,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'serialized' is never reassigned. Use 'const' instead.","line":211,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":211,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'sign' is never reassigned. Use 'const' instead.","line":258,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":258,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'parts' is never reassigned. Use 'const' instead.","line":268,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":268,"endColumn":8}],"suppressedMessages":[],"errorCount":11,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A set of location fields in UploadWizard's \"Details\" step form.\n\t *\n\t * @extends uw.DetailsWidget\n\t * @constructor\n\t * @param {Object} [config] Configuration options\n\t * @cfg {string[]} [fields] List of fields to show in the widget\n\t */\n\tuw.LocationDetailsWidget = function UWLocationDetailsWidget( config ) {\n\t\tthis.config = Object.assign( {\n\t\t\tfields: [ 'latitude', 'longitude' ]\n\t\t}, config );\n\n\t\tuw.LocationDetailsWidget.parent.call( this, this.config );\n\n\t\tthis.$element.addClass( 'mediauploader-locationDetailsWidget' );\n\n\t\tthis.config.showField = {};\n\t\tthis.inputs = {};\n\t\tthis.allFields = [ 'latitude', 'longitude', 'altitude', 'heading' ];\n\n\t\tthis.config.fields.forEach( function ( field ) {\n\t\t\tthis.config.showField[ field ] = true;\n\t\t}, this );\n\n\t\t// Go over all available fields in order\n\t\tthis.allFields.forEach( function ( field ) {\n\t\t\tif ( !this.config.showField[ field ] ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.inputs[ field ] = new OO.ui.TextInputWidget( { disabled: this.config.disabled } );\n\n\t\t\t// Messages that can be used here:\n\t\t\t// * mediauploader-location-latitude\n\t\t\t// * mediauploader-location-longitude\n\t\t\t// * mediauploader-location-altitude\n\t\t\t// * mediauploader-location-heading\n\t\t\tthis.$element.append(\n\t\t\t\tnew OO.ui.FieldLayout( this.inputs[ field ], {\n\t\t\t\t\talign: 'top',\n\t\t\t\t\tlabel: mw.message( 'mediauploader-location-' + field ).text(),\n\t\t\t\t\tdisabled: this.config.disabled\n\t\t\t\t} ).$element\n\t\t\t);\n\n\t\t\t// Aggregate 'change' events\n\t\t\tthis.inputs[ field ].connect( this, { change: [ 'emit', 'change' ] } );\n\t\t}, this );\n\n\t\tthis.$map = $( '<div>' ).css( { width: 500, height: 300 } );\n\t\tthis.mapButton = new OO.ui.PopupButtonWidget( {\n\t\t\ticon: 'mapPin',\n\t\t\ttitle: mw.message( 'mediauploader-location-button' ).text(),\n\t\t\tpopup: {\n\t\t\t\t$content: this.$map,\n\t\t\t\twidth: 500,\n\t\t\t\theight: 300\n\t\t\t},\n\t\t\tdisabled: this.config.disabled\n\t\t} );\n\n\t\tthis.mapButton.setDisabled( true );\n\t\tthis.$element.append( this.mapButton.$element );\n\n\t\tthis.mapButton.connect( this, { click: 'onMapButtonClick' } );\n\t\tthis.connect( this, { change: 'onChange' } );\n\n\t\tthis.mapButton.toggle( false );\n\t\tmw.loader.using( [ 'ext.kartographer.box', 'ext.kartographer.editing' ] ).done( () => {\n\t\t\t// Kartographer is installed and we'll be able to show the map. Display the button.\n\t\t\tthis.mapButton.toggle( true );\n\t\t} );\n\t};\n\n\tOO.inheritClass( uw.LocationDetailsWidget, uw.DetailsWidget );\n\n\t/**\n\t * @private\n\t */\n\tuw.LocationDetailsWidget.prototype.onChange = function () {\n\t\tconst widget = this;\n\t\tthis.getErrors().done( ( errors ) => {\n\t\t\twidget.mapButton.setDisabled( !( errors.length === 0 && widget.getWikiText() !== '' ) );\n\t\t} );\n\t};\n\n\t/**\n\t * @private\n\t */\n\tuw.LocationDetailsWidget.prototype.onMapButtonClick = function () {\n\t\tconst coords = this.getSerializedParsed();\n\n\t\t// Disable clipping because it doesn't play nicely with the map\n\t\tthis.mapButton.getPopup().toggleClipping( false );\n\n\t\tif ( !this.map ) {\n\t\t\tthis.map = require( 'ext.kartographer.box' ).map( {\n\t\t\t\tcontainer: this.$map[ 0 ]\n\t\t\t} );\n\t\t}\n\t\trequire( 'ext.kartographer.editing' ).getKartographerLayer( this.map ).setGeoJSON( {\n\t\t\ttype: 'Feature',\n\t\t\tproperties: {},\n\t\t\tgeometry: { type: 'Point', coordinates: [ coords.longitude, coords.latitude ] }\n\t\t} );\n\t\tthis.map.setView( [ coords.latitude, coords.longitude ], 9 );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.LocationDetailsWidget.prototype.getErrors = function () {\n\t\tlet errors = [],\n\t\t\tserialized = this.getSerialized(),\n\t\t\tparsed = this.getSerializedParsed(),\n\t\t\tfield;\n\n\t\t// If the field is required and any of the subfields is empty\n\t\t// -> throw an error\n\t\tif ( this.config.required ) {\n\t\t\tfor ( field in this.config.showField ) {\n\t\t\t\tif ( !serialized[ field ] ) {\n\t\t\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// input is invalid if the coordinates are out of bounds, or if the\n\t\t// coordinates that were derived from the input are 0, without a 0 even\n\t\t// being present in the input\n\t\tif ( this.config.showField.latitude && serialized.latitude ) {\n\t\t\tif ( isNaN( parsed.latitude ) || parsed.latitude > 90 || parsed.latitude < -90 || ( parsed.latitude === 0 && !serialized.latitude.includes( '0' ) ) ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-latitude' ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( this.config.showField.longitude && serialized.longitude ) {\n\t\t\tif ( isNaN( parsed.longitude ) || parsed.longitude > 180 || parsed.longitude < -180 || ( parsed.longitude === 0 && !serialized.longitude.includes( '0' ) ) ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-longitude' ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( this.config.showField.heading && serialized.heading !== '' ) {\n\t\t\tif ( isNaN( parsed.heading ) || parsed.heading > 360 || parsed.heading < 0 ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-heading' ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( this.config.showField.altitude && serialized.altitude !== '' && isNaN( parsed.altitude ) ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-altitude' ) );\n\t\t}\n\n\t\treturn $.Deferred().resolve( errors );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.LocationDetailsWidget.prototype.getWikiText = function () {\n\t\tlet field,\n\t\t\tresult = '',\n\t\t\tserialized = this.getSerializedParsed();\n\n\t\tif ( 'latitude' in this.config.showField &&\n\t\t\t( !isNaN( serialized.latitude ) || !isNaN( serialized.longitude ) )\n\t\t) {\n\t\t\tresult = ( isNaN( serialized.latitude ) ? '?' : serialized.latitude ).toString() +\n\t\t\t\t'; ' + ( isNaN( serialized.longitude ) ? '?' : serialized.longitude ).toString();\n\t\t}\n\n\t\tfor ( field in [ 'heading', 'altitude' ] ) {\n\t\t\tif ( field in this.config.showField && serialized[ field ] && !isNaN( serialized[ field ] )\n\t\t\t) {\n\t\t\t\t// Messages that can be used here:\n\t\t\t\t// * mediauploader-location-heading\n\t\t\t\t// * mediauploader-location-altitude\n\t\t\t\tresult += ' ' + mw.msg( 'mediauploader-location-' + field ) + ': ' +\n\t\t\t\t\tserialized[ field ].toString();\n\t\t\t}\n\t\t}\n\n\t\treturn result.trim();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.LocationDetailsWidget.prototype.getSerialized = function () {\n\t\tlet field,\n\t\t\tresult = {};\n\n\t\tfor ( field in this.config.showField ) {\n\t\t\tresult[ field ] = this.inputs[ field ].getValue();\n\t\t}\n\n\t\treturn result;\n\t};\n\n\t/**\n\t * Returns a serialized representation of the subfields' values that were parsed to a number.\n\t *\n\t * @return {Object} Serialized, parsed values of the subfields (numbers)\n\t */\n\tuw.LocationDetailsWidget.prototype.getSerializedParsed = function () {\n\t\tlet field,\n\t\t\tresult = {},\n\t\t\tserialized = this.getSerialized();\n\n\t\tfor ( field in this.config.showField ) {\n\t\t\tif ( serialized[ field ] === '' || serialized[ field ] === undefined ) {\n\t\t\t\tresult[ field ] = NaN;\n\t\t\t} else if ( field === 'latitude' || field === 'longitude' ) {\n\t\t\t\tresult[ field ] = this.normalizeCoordinate( serialized[ field ] );\n\t\t\t} else {\n\t\t\t\tresult[ field ] = parseFloat( serialized[ field ] );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {number} serialized.latitude Latitude value\n\t * @param {number} serialized.longitude Longitude value\n\t * @param {string} serialized.altitude Altitude value\n\t * @param {string} serialized.heading Heading value\n\t */\n\tuw.LocationDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\tlet field;\n\n\t\tfor ( field in this.config.showField ) {\n\t\t\tif ( serialized[ field ] !== undefined ) {\n\t\t\t\tthis.inputs[ field ].setValue( serialized[ field ] );\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Interprets a wide variety of coordinate input formats, it'll return the\n\t * coordinate in decimal degrees.\n\t *\n\t * Formats understood include:\n\t * * degrees minutes seconds: 40° 26' 46\" S\n\t * * degrees decimal minutes: 40° 26.767' S\n\t * * decimal degrees: 40.446° S\n\t * * decimal degrees exact value: -40.446\n\t *\n\t * @param {string} coordinate\n\t * @return {number}\n\t */\n\tuw.LocationDetailsWidget.prototype.normalizeCoordinate = function ( coordinate ) {\n\t\tlet sign = coordinate.match( /[sw]/i ) ? -1 : 1,\n\t\t\tparts, value;\n\n\t\t// fix commonly used character alternatives\n\t\tcoordinate = coordinate.replace( /\\s*[,.]\\s*/, '.' );\n\n\t\t// convert degrees, minutes, seconds (or degrees & decimal minutes) to\n\t\t// decimal degrees\n\t\t// there can be a lot of variation in the notation, so let's only\n\t\t// focus on \"groups of digits\" (and not whether e.g. ″ or \" is used)\n\t\tparts = coordinate.match( /(-?[0-9.]+)[^0-9.]+([0-9.]+)(?:[^0-9.]+([0-9.]+))?/ );\n\t\tif ( parts ) {\n\t\t\tvalue = this.dmsToDecimal( parts[ 1 ], parts[ 2 ], parts[ 3 ] || 0 );\n\t\t} else {\n\t\t\tvalue = coordinate.replace( /[^\\-0-9.]/g, '' ) * 1;\n\t\t}\n\n\t\t// round to 6 decimal places\n\t\treturn Math.round( sign * value * 1000000 ) / 1000000;\n\t};\n\n\t/**\n\t * Convert degrees, minutes & seconds to decimal.\n\t *\n\t * @param {number} degrees\n\t * @param {number} minutes\n\t * @param {number} seconds\n\t * @return {number}\n\t */\n\tuw.LocationDetailsWidget.prototype.dmsToDecimal = function ( degrees, minutes, seconds ) {\n\t\treturn ( degrees * 1 ) + ( minutes / 60.0 ) + ( seconds / 3600.0 );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.MultipleLanguageInputWidget.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":16,"column":17,"nodeType":"MemberExpression","messageId":"forbidden","endLine":16,"endColumn":30},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":50,"column":26,"nodeType":"MemberExpression","messageId":"forbidden","endLine":50,"endColumn":39},{"ruleId":"prefer-const","severity":2,"message":"'allLanguages' is never reassigned. Use 'const' instead.","line":60,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":60,"endColumn":19},{"ruleId":"prefer-const","severity":2,"message":"'unusedLanguages' is never reassigned. Use 'const' instead.","line":61,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":61,"endColumn":19},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":73,"column":16,"nodeType":"MemberExpression","messageId":"forbidden","endLine":73,"endColumn":29},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":78,"column":12,"nodeType":"MemberExpression","messageId":"forbidden","endLine":78,"endColumn":25},{"ruleId":"prefer-const","severity":2,"message":"'item' is never reassigned. Use 'const' instead.","line":82,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":82,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'allLanguages' is never reassigned. Use 'const' instead.","line":100,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":100,"endColumn":19},{"ruleId":"prefer-const","severity":2,"message":"'unusedLanguages' is never reassigned. Use 'const' instead.","line":101,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":101,"endColumn":19},{"ruleId":"prefer-const","severity":2,"message":"'items' is never reassigned. Use 'const' instead.","line":102,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":102,"endColumn":9},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":114,"column":16,"nodeType":"MemberExpression","messageId":"forbidden","endLine":114,"endColumn":29},{"ruleId":"prefer-const","severity":2,"message":"'errors' is never reassigned. Use 'const' instead.","line":192,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":192,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'values' is never reassigned. Use 'const' instead.","line":215,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":215,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'widgets' is never reassigned. Use 'const' instead.","line":216,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":216,"endColumn":11},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":272,"column":13,"nodeType":"MemberExpression","messageId":"forbidden","endLine":272,"endColumn":26}],"suppressedMessages":[],"errorCount":9,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A multi-language input field in UploadWizard's \"Details\" step form.\n\t *\n\t * @class uw.MultipleLanguageInputWidget\n\t * @extends uw.DetailsWidget\n\t * @constructor\n\t * @param {Object} [config]\n\t * @cfg {boolean} [required=false]\n\t * @cfg {number} [minLength=0] Minimum input length\n\t * @cfg {number} [maxLength=99999] Maximum input length\n\t * @cfg {Object} [languages] { langcode: text } map of languages\n\t */\n\tuw.MultipleLanguageInputWidget = function UWMultipleLanguageInputWidget( config ) {\n\t\tthis.config = Object.assign( {}, config );\n\t\tuw.MultipleLanguageInputWidget.parent.call( this, this.config );\n\t\tOO.ui.mixin.GroupElement.call( this );\n\n\t\tthis.required = !!this.config.required;\n\t\tthis.addButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mediauploader-multipleLanguageInputWidget-addItem' ],\n\t\t\tframed: true,\n\t\t\ticon: 'add',\n\t\t\tflags: [ 'progressive' ],\n\t\t\tlabel: this.getLabelText()\n\t\t} );\n\t\tthis.addButton.connect( this, { click: [ 'addLanguageInput', this.config ] } );\n\n\t\t// if a language becomes available because the input gets removed,\n\t\t// or unavailable because it gets added, we'll need to update other\n\t\t// language dropdowns to reflect the change\n\t\tthis.connect( this, { add: 'onChangeLanguages' } );\n\t\tthis.connect( this, { remove: 'onChangeLanguages' } );\n\n\t\t// update the 'add language' button accordingly\n\t\tthis.connect( this, { add: 'recount' } );\n\t\tthis.connect( this, { remove: 'recount' } );\n\n\t\t// Aggregate 'change' event\n\t\tthis.aggregate( { change: 'change' } );\n\n\t\tthis.$element.addClass( 'mediauploader-multipleLanguageInputsWidget' );\n\t\tthis.$element.append(\n\t\t\tthis.$group,\n\t\t\tthis.addButton.$element\n\t\t);\n\n\t\t// Add empty input (non-removable if this field is required)\n\t\tthis.addLanguageInput( Object.assign( {}, this.config, { canBeRemoved: !this.required } ) );\n\t};\n\tOO.inheritClass( uw.MultipleLanguageInputWidget, uw.DetailsWidget );\n\tOO.mixinClass( uw.MultipleLanguageInputWidget, OO.ui.mixin.GroupElement );\n\n\t/**\n\t * @param {Object} config\n\t * @param {string} [text]\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.addLanguageInput = function ( config, text ) {\n\t\tlet allLanguages = this.config.languages,\n\t\t\tunusedLanguages = this.getUnusedLanguages(),\n\t\t\tlanguages = {},\n\t\t\titem;\n\n\t\tif ( unusedLanguages.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// only add given language + unused/remaining languages - we don't want\n\t\t// languages that have already been selected to show up in the next dropdown...\n\t\tif ( config.defaultLanguage ) {\n\t\t\tlanguages[ config.defaultLanguage ] = allLanguages[ config.defaultLanguage ];\n\t\t\tlanguages = Object.assign( {}, languages, unusedLanguages );\n\t\t} else {\n\t\t\tlanguages = unusedLanguages;\n\t\t}\n\n\t\tconfig = Object.assign( {}, config, {\n\t\t\tlanguages: languages,\n\t\t\trequired: false\n\t\t} );\n\t\titem = new uw.SingleLanguageInputWidget( config );\n\t\titem.setText( text || '' );\n\n\t\t// if a language is changed, we'll need to update other language dropdowns\n\t\t// to reflect the change\n\t\titem.connect( this, { select: 'onChangeLanguages' } );\n\n\t\tthis.addItems( [ item ] );\n\t};\n\n\t/**\n\t * When a language changes (or an input is removed), the old language\n\t * becomes available again in other language dropdowns, and the new\n\t * language should no longer be selected.\n\t * This will iterate all inputs, destroy then, and construct new ones\n\t * with the updated language selections.\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.onChangeLanguages = function () {\n\t\tlet allLanguages = this.config.languages,\n\t\t\tunusedLanguages = this.getUnusedLanguages(),\n\t\t\titems = this.getItems(),\n\t\t\tlanguages,\n\t\t\titem,\n\t\t\ti;\n\n\t\tfor ( i = 0; i < items.length; i++ ) {\n\t\t\titem = items[ i ];\n\n\t\t\t// only add existing language + unused/remaining languages - we don't want\n\t\t\t// languages that have already been selected to show up in the next dropdown...\n\t\t\tlanguages = {};\n\t\t\tlanguages[ item.getLanguage() ] = allLanguages[ item.getLanguage() ];\n\t\t\tlanguages = Object.assign( {}, languages, unusedLanguages );\n\t\t\titem.updateLanguages( languages );\n\t\t}\n\t};\n\n\t/**\n\t * Returns an object of `langcode: text` pairs with the languages\n\t * already used in dropdowns.\n\t *\n\t * @return {Object}\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getUsedLanguages = function () {\n\t\tconst allLanguages = this.config.languages,\n\t\t\titems = this.getItems();\n\n\t\treturn items.reduce( ( obj, item ) => {\n\t\t\tconst languageCode = item.getLanguage();\n\t\t\tobj[ languageCode ] = allLanguages[ languageCode ];\n\t\t\treturn obj;\n\t\t}, {} );\n\t};\n\n\t/**\n\t * Returns an object of `langcode: text` pairs with remaining languages\n\t * not yet used in dropdowns.\n\t *\n\t * @return {Object}\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getUnusedLanguages = function () {\n\t\tconst allLanguages = this.config.languages,\n\t\t\tusedLanguageCodes = Object.keys( this.getUsedLanguages() );\n\n\t\treturn Object.keys( allLanguages ).reduce( ( remaining, language ) => {\n\t\t\tif ( !usedLanguageCodes.includes( language ) ) {\n\t\t\t\tremaining[ language ] = allLanguages[ language ];\n\t\t\t}\n\t\t\treturn remaining;\n\t\t}, {} );\n\t};\n\n\t/**\n\t * Update the button label after adding or removing inputs.\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.recount = function () {\n\t\tconst text = this.getLabelText(),\n\t\t\tunusedLanguages = this.getUnusedLanguages();\n\n\t\tthis.addButton.setLabel( text );\n\t\t// hide the button if there are no remaining languages...\n\t\tthis.addButton.toggle( Object.keys( unusedLanguages ).length > 0 );\n\t};\n\n\t/**\n\t * @return {string}\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getLabelText = function () {\n\t\treturn mw.message( 'mediauploader-multilang-add' ).params( [ this.items.length ] ).text();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getWarnings = function () {\n\t\tconst warnings = [];\n\t\tthis.getEmptyWarning( this.getWikiText() === '', warnings );\n\n\t\treturn $.Deferred().resolve( warnings ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getErrors = function () {\n\t\t// Gather errors from each item\n\t\tconst errorPromises = this.getItems().map( ( item ) => item.getErrors() );\n\n\t\treturn $.when.apply( $, errorPromises ).then( function () {\n\t\t\tlet i, errors;\n\t\t\terrors = [];\n\t\t\t// Fold all errors into a single one (they are displayed in the UI for each item, but we still\n\t\t\t// need to return an error here to prevent form submission).\n\t\t\tfor ( i = 0; i < arguments.length; i++ ) {\n\t\t\t\tif ( arguments[ i ].length ) {\n\t\t\t\t\t// One of the items has errors\n\t\t\t\t\terrors.push( mw.message( 'mediauploader-error-bad-multilang' ) );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// And add some more:\n\t\t\tif ( this.required && this.getWikiText() === '' ) {\n\t\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t\t}\n\t\t\t// TODO Check for duplicate languages\n\t\t\treturn errors;\n\t\t}.bind( this ) );\n\t};\n\n\t/**\n\t * @return {Object} Object where the properties are language codes & values are input\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getValues = function () {\n\t\tlet values = {},\n\t\t\twidgets = this.getItems(),\n\t\t\tlanguage,\n\t\t\ttext,\n\t\t\ti;\n\n\t\tfor ( i = 0; i < widgets.length; i++ ) {\n\t\t\tlanguage = widgets[ i ].getLanguage();\n\t\t\ttext = widgets[ i ].getText();\n\n\t\t\tif ( text !== '' ) {\n\t\t\t\tvalues[ language ] = text;\n\t\t\t}\n\t\t}\n\n\t\treturn values;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getWikiText = function () {\n\t\t// Some code here and in mw.UploadWizardDetails relies on this function returning an empty\n\t\t// string when there are some inputs, but all are empty.\n\t\treturn this.getItems().map( ( widget ) => widget.getWikiText() ).filter( ( wikiText ) => !!wikiText ).join( '\\n' );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getSerialized = function () {\n\t\tconst inputs = this.getItems().map( ( widget ) => widget.getSerialized() );\n\t\treturn {\n\t\t\tinputs: inputs\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object|string} serialized\n\t * @param {Object[]} serialized.inputs Array of serialized inputs,\n\t *   see uw.SingleLanguageInputWidget#setSerialized\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.setSerialized = function ( serialized ) {\n\t\tlet config = this.config,\n\t\t\ti;\n\n\t\tif ( typeof serialized === 'string' ) {\n\t\t\tthis.setSerialized( { inputs: [ { text: serialized } ] } );\n\t\t\treturn;\n\t\t}\n\n\t\t// remove all existing\n\t\tthis.removeItems( this.getItems() );\n\n\t\tfor ( i = 0; i < serialized.inputs.length; i++ ) {\n\t\t\tconfig = Object.assign( {}, config, { defaultLanguage: serialized.inputs[ i ].language } );\n\t\t\tthis.addLanguageInput( config, serialized.inputs[ i ].text );\n\t\t}\n\t};\n\n\t/**\n\t * Returns the value of the field which can be used as a caption.\n\t *\n\t * @return {string}\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getCaption = function () {\n\t\tconst items = this.getItems();\n\n\t\tif ( items.length > 0 ) {\n\t\t\treturn items[ 0 ].getCaption();\n\t\t}\n\n\t\treturn '';\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.SingleLanguageInputWidget.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":17,"column":17,"nodeType":"MemberExpression","messageId":"forbidden","endLine":17,"endColumn":30},{"ruleId":"prefer-const","severity":2,"message":"'text' is never reassigned. Use 'const' instead.","line":226,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":226,"endColumn":8}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A single language input field in UploadWizard's \"Details\" step form.\n\t *\n\t * @extends uw.DetailsWidget\n\t * @constructor\n\t * @param {Object} config\n\t * @param {Object} config.languages { langcode: text } map of languages\n\t * @param {Object} [config.defaultLanguage]\n\t * @param {Object} [config.required]\n\t * @param {boolean} [config.canBeRemoved=true]\n\t * @param {number} [config.minLength=0] Minimum input length\n\t * @param {number} [config.maxLength=99999] Maximum input length\n\t */\n\tuw.SingleLanguageInputWidget = function UWSingleLanguageInputWidget( config ) {\n\t\tthis.config = Object.assign( {\n\t\t\tminLength: 0,\n\t\t\tmaxLength: 99999\n\t\t}, config );\n\n\t\tuw.SingleLanguageInputWidget.parent.call( this, this.config );\n\t\tuw.ValidationMessageElement.call( this );\n\n\t\tif ( mw.loader.getState( 'ext.uls.mediawiki' ) === 'ready' ) {\n\t\t\tthis.languageSelector = new uw.UlsWidget( {\n\t\t\t\tlanguages: config.languages,\n\t\t\t\tclasses: [ 'mediauploader-singleLanguageInputWidget-language' ],\n\t\t\t\tdisabled: this.config.disabled\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.languageSelector = new uw.LanguageDropdownWidget( {\n\t\t\t\tlanguages: config.languages,\n\t\t\t\tclasses: [ 'mediauploader-singleLanguageInputWidget-language' ],\n\t\t\t\tdisabled: this.config.disabled\n\t\t\t} );\n\t\t}\n\t\tthis.languageSelector.setValue( config.defaultLanguage || this.getDefaultLanguage() );\n\n\t\tthis.textInput = new OO.ui.MultilineTextInputWidget( {\n\t\t\tclasses: [ 'mediauploader-singleLanguageInputWidget-text' ],\n\t\t\tautosize: true,\n\t\t\trows: 2,\n\t\t\tdisabled: this.config.disabled\n\t\t} );\n\t\tthis.removeButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mediauploader-singleLanguageInputWidget-removeItem' ],\n\t\t\ticon: 'trash',\n\t\t\tframed: false,\n\t\t\tflags: [ 'destructive' ],\n\t\t\ttitle: mw.message( 'mediauploader-multilang-remove' ).text(),\n\t\t\tdisabled: this.config.disabled\n\t\t} );\n\n\t\tthis.removeButton.connect( this, {\n\t\t\tclick: 'onRemoveClick'\n\t\t} );\n\n\t\tthis.languageSelector.connect( this, { select: [ 'emit', 'select' ] } );\n\t\t// Aggregate 'change' event\n\t\t// (but do not flash warnings in the user's face while they're typing)\n\t\tthis.textInput.on( 'change', OO.ui.debounce( this.emit.bind( this, 'change' ), 500 ) );\n\n\t\tthis.$element.addClass( 'mediauploader-singleLanguageInputWidget' );\n\t\tthis.$element.append( this.languageSelector.getElement() );\n\t\t// HACK: ValidationMessageElement will append messages after this.$body\n\t\tthis.$body = this.textInput.$element;\n\t\tif ( this.config.canBeRemoved !== false ) {\n\t\t\tthis.$element.append( this.removeButton.$element );\n\t\t\tthis.$body = this.removeButton.$element; // HACK\n\t\t}\n\t\tthis.$element.append( this.textInput.$element );\n\n\t};\n\tOO.inheritClass( uw.SingleLanguageInputWidget, uw.DetailsWidget );\n\tOO.mixinClass( uw.SingleLanguageInputWidget, uw.ValidationMessageElement );\n\n\t/**\n\t * Handle remove button click events.\n\t *\n\t * @private\n\t */\n\tuw.SingleLanguageInputWidget.prototype.onRemoveClick = function () {\n\t\tconst element = this.getElementGroup();\n\n\t\tif ( element && typeof element.removeItems === 'function' ) {\n\t\t\telement.removeItems( [ this ] );\n\t\t}\n\t};\n\n\t/**\n\t * Check if the given language code can be used for inputs.\n\t * If not, try finding a similar language code that can be.\n\t *\n\t * @public\n\t * @param {string} code Language code\n\t * @param {string} [fallback] Language code to use when there's nothing close,\n\t *   defaults to result of #getDefaultLanguage\n\t * @return {string|null}\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getClosestAllowedLanguage = function ( code, fallback ) {\n\t\t// Is this still needed?\n\t\tif ( code === 'nan' || code === 'minnan' ) {\n\t\t\tcode = 'zh-min-nan';\n\t\t}\n\t\tif ( this.config.languages[ code ] ) {\n\t\t\treturn code;\n\t\t}\n\t\tif ( code.lastIndexOf( '-' ) !== -1 ) {\n\t\t\treturn this.getClosestAllowedLanguage( code.slice( 0, Math.max( 0, code.lastIndexOf( '-' ) ) ) );\n\t\t}\n\t\treturn arguments.length > 1 ? fallback : this.getDefaultLanguage();\n\t};\n\n\t/**\n\t * Get the default language to use for inputs.\n\t * Choose a sane default based on user preferences and wiki config.\n\t *\n\t * @public\n\t * @return {string}\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getDefaultLanguage = function () {\n\t\tlet defaultLanguage;\n\n\t\tif ( this.defaultLanguage !== undefined ) {\n\t\t\treturn this.defaultLanguage;\n\t\t}\n\n\t\tif ( this.getClosestAllowedLanguage( mw.config.get( 'wgUserLanguage' ), null ) ) {\n\t\t\tdefaultLanguage = this.getClosestAllowedLanguage( mw.config.get( 'wgUserLanguage' ) );\n\t\t} else if ( this.getClosestAllowedLanguage( mw.config.get( 'wgContentLanguage' ), null ) ) {\n\t\t\tdefaultLanguage = this.getClosestAllowedLanguage( mw.config.get( 'wgContentLanguage' ) );\n\t\t} else if ( this.getClosestAllowedLanguage( 'en', null ) ) {\n\t\t\tdefaultLanguage = this.getClosestAllowedLanguage( 'en' );\n\t\t} else {\n\t\t\tdefaultLanguage = Object.keys( this.config.languages )[ 0 ];\n\t\t}\n\n\t\t// Logic copied from MediaWiki:UploadForm.js\n\t\t// Per request from Portuguese and Brazilian users, treat Brazilian Portuguese as Portuguese.\n\t\tif ( defaultLanguage === 'pt-br' ) {\n\t\t\tdefaultLanguage = 'pt';\n\t\t// this was also in UploadForm.js, but without the heartwarming justification\n\t\t} else if ( defaultLanguage === 'en-gb' ) {\n\t\t\tdefaultLanguage = 'en';\n\t\t}\n\n\t\tthis.defaultLanguage = defaultLanguage;\n\t\treturn defaultLanguage;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getWarnings = function () {\n\t\tconst warnings = [];\n\t\tthis.getEmptyWarning( this.textInput.getValue().trim() === '', warnings );\n\n\t\treturn $.Deferred().resolve( warnings ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getErrors = function () {\n\t\tconst\n\t\t\terrors = [],\n\t\t\ttext = this.textInput.getValue().trim();\n\n\t\tif ( this.config.required && text.length === 0 ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t}\n\n\t\tif ( text.length !== 0 && text.length < this.config.minLength ) {\n\t\t\t// Empty input is allowed\n\t\t\terrors.push( mw.message( 'mediauploader-error-too-short', this.config.minLength ) );\n\t\t}\n\t\tif ( text.length > this.config.maxLength ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-too-long', this.config.maxLength ) );\n\t\t}\n\n\t\treturn $.Deferred().resolve( errors ).promise();\n\t};\n\n\t/**\n\t * @param {Object} languages\n\t */\n\tuw.SingleLanguageInputWidget.prototype.updateLanguages = function ( languages ) {\n\t\tthis.languageSelector.updateLanguages( languages );\n\t};\n\n\t/**\n\t * @return {string} language code\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getLanguage = function () {\n\t\treturn this.languageSelector.getValue();\n\t};\n\n\t/**\n\t * @param {string} value language code\n\t */\n\tuw.SingleLanguageInputWidget.prototype.setLanguage = function ( value ) {\n\t\tthis.languageSelector.setValue( value );\n\t};\n\n\t/**\n\t * @return {string} text input\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getText = function () {\n\t\treturn this.textInput.getValue().trim();\n\t};\n\n\t/**\n\t * @param {string} value text input\n\t */\n\tuw.SingleLanguageInputWidget.prototype.setText = function ( value ) {\n\t\tthis.textInput.setValue( value );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getWikiText = function () {\n\t\tlet\n\t\t\tlanguage = this.getLanguage(),\n\t\t\ttext = this.getText();\n\n\t\tif ( !text ) {\n\t\t\treturn '';\n\t\t}\n\n\t\tif ( mw.UploadWizard.config.languageTemplateFixups[ language ] ) {\n\t\t\tlanguage = mw.UploadWizard.config.languageTemplateFixups[ language ];\n\t\t}\n\n\t\treturn '{{' + language + '|1=' + mw.Escaper.escapeForTemplate( text ) + '}}';\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\tlanguage: this.languageSelector.getValue(),\n\t\t\ttext: this.textInput.getValue()\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object|string} serialized\n\t * @param {string} [serialized.language] Language code\n\t * @param {string} serialized.text Text\n\t */\n\tuw.SingleLanguageInputWidget.prototype.setSerialized = function ( serialized ) {\n\t\tif ( typeof serialized === 'string' ) {\n\t\t\tthis.setSerialized( { text: serialized } );\n\t\t\treturn;\n\t\t}\n\t\tthis.setLanguage( serialized.language );\n\t\tthis.setText( serialized.text );\n\t};\n\n\t/**\n\t * Returns the value of the field which can be used as a caption.\n\t *\n\t * @return {string}\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getCaption = function () {\n\t\treturn this.textInput.getValue().trim();\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.TextWidget.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":13,"column":17,"nodeType":"MemberExpression","messageId":"forbidden","endLine":13,"endColumn":30}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A generic text input field.\n\t *\n\t * @extends uw.DetailsWidget\n\t * @param {Object} config\n\t * @param {string} [config.mode] Mode, either 'text' or 'textarea'\n\t * @param {number} [config.minLength=0] Minimum input length\n\t * @param {number} [config.maxLength=99999] Maximum input length\n\t */\n\tuw.TextWidget = function UWTextWidget( config ) {\n\t\tthis.config = Object.assign( {\n\t\t\tminLength: 0,\n\t\t\tmaxLength: 99999,\n\t\t\tmode: 'text'\n\t\t}, config );\n\n\t\tuw.TextWidget.parent.call( this, this.config );\n\n\t\tif ( this.config.mode === 'text' ) {\n\t\t\tthis.textInput = new OO.ui.TextInputWidget( {\n\t\t\t\tclasses: [ 'mediauploader-other-text', 'mediauploader-textWidget-other' ],\n\t\t\t\tmaxLength: this.config.maxLength,\n\t\t\t\tdisabled: this.config.disabled\n\t\t\t} );\n\t\t\tthis.$element.addClass( 'mediauploader-textWidget' );\n\t\t} else {\n\t\t\tthis.textInput = new OO.ui.MultilineTextInputWidget( {\n\t\t\t\tclasses: [ 'mediauploader-other-textarea', 'mediauploader-textAreaWidget-other' ],\n\t\t\t\tautosize: true,\n\t\t\t\trows: 2,\n\t\t\t\tdisabled: this.config.disabled\n\t\t\t} );\n\t\t\tthis.$element.addClass( 'mediauploader-textAreaWidget' );\n\t\t}\n\n\t\t// Aggregate 'change' event\n\t\t// (but do not flash warnings in the user's face while they're typing)\n\t\tthis.textInput.on( 'change', OO.ui.debounce( this.emit.bind( this, 'change' ), 500 ) );\n\n\t\tthis.$element.append(\n\t\t\tthis.textInput.$element\n\t\t);\n\t};\n\tOO.inheritClass( uw.TextWidget, uw.DetailsWidget );\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TextWidget.prototype.getWarnings = function () {\n\t\tconst warnings = [];\n\t\tthis.getEmptyWarning( this.textInput.getValue().trim() === '', warnings );\n\n\t\treturn $.Deferred().resolve( warnings ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TextWidget.prototype.getErrors = function () {\n\t\tconst\n\t\t\terrors = [],\n\t\t\ttext = this.textInput.getValue().trim();\n\n\t\tif ( this.config.required && text.length === 0 ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t}\n\n\t\tif ( text.length !== 0 && text.length < this.config.minLength ) {\n\t\t\t// Empty input is allowed\n\t\t\terrors.push( mw.message( 'mediauploader-error-too-short', this.config.minLength ) );\n\t\t}\n\t\tif ( text.length > this.config.maxLength ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-too-long', this.config.maxLength ) );\n\t\t}\n\n\t\treturn $.Deferred().resolve( errors ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TextWidget.prototype.getWikiText = function () {\n\t\treturn this.textInput.getValue().trim();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.TextWidget.prototype.getSerialized = function () {\n\t\treturn this.textInput.getValue();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {string} serialized\n\t */\n\tuw.TextWidget.prototype.setSerialized = function ( serialized ) {\n\t\tthis.textInput.setValue( serialized );\n\t};\n\n\t/**\n\t * Returns the value of the field which can be used as a caption.\n\t *\n\t * @return {string}\n\t */\n\tuw.TextWidget.prototype.getCaption = function () {\n\t\treturn this.getWikiText();\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.TitleDetailsWidget.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'illegalFileChars' is never reassigned. Use 'const' instead.","line":49,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":49,"endColumn":20},{"ruleId":"prefer-const","severity":2,"message":"'value' is never reassigned. Use 'const' instead.","line":82,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":82,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'title' is never reassigned. Use 'const' instead.","line":94,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":94,"endColumn":8},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":156,"column":7,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":156,"endColumn":9},{"ruleId":"implicit-arrow-linebreak","severity":2,"message":"Expected no linebreak before this expression.","line":156,"column":9,"nodeType":"Identifier","messageId":"unexpected","endLine":156,"endColumn":11},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":157,"column":6,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":157,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'errors' is never reassigned. Use 'const' instead.","line":181,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":181,"endColumn":9}],"suppressedMessages":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":212,"column":22,"nodeType":"CallExpression","endLine":212,"endColumn":75,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":7,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tconst NS_FILE = mw.config.get( 'wgNamespaceIds' ).file,\n\t\tbyteLength = require( 'mediawiki.String' ).byteLength;\n\n\t/**\n\t * A title field in UploadWizard's \"Details\" step form.\n\t *\n\t * @class uw.TitleDetailsWidget\n\t * @extends uw.DetailsWidget\n\t * @constructor\n\t * @param {Object} [config]\n\t */\n\tuw.TitleDetailsWidget = function UWTitleDetailsWidget( config ) {\n\t\tconfig = config || {};\n\t\tuw.TitleDetailsWidget.parent.call( this, config );\n\n\t\tthis.config = config;\n\t\t// We wouldn't want or use any of mw.widgets.TitleInputWidget functionality.\n\t\tthis.titleInput = new OO.ui.TextInputWidget( {\n\t\t\tclasses: [ 'mwe-title', 'mediauploader-titleDetailsWidget-title' ],\n\t\t\tmaxLength: config.maxLength,\n\t\t\tdisabled: this.config.disabled\n\t\t} );\n\n\t\t// Aggregate 'change' event (with delay)\n\t\tthis.titleInput.on( 'change', OO.ui.debounce( this.emit.bind( this, 'change' ), 500 ) );\n\n\t\tthis.$element.addClass( 'mediauploader-titleDetailsWidget' );\n\t\tthis.$element.append(\n\t\t\tthis.titleInput.$element\n\t\t);\n\t};\n\tOO.inheritClass( uw.TitleDetailsWidget, uw.DetailsWidget );\n\n\t/**\n\t * Reliably turn input into a MediaWiki title that is located in the 'File:' namespace.\n\t * Also applies file-specific checks ($wgIllegalFileChars).\n\t *\n\t *     var title = uw.TitleDetailsWidget.static.makeTitleInFileNS( 'filename.ext' );\n\t *\n\t * @static\n\t * @param {string} filename Desired file name; optionally with 'File:' namespace prefixed\n\t * @return {mw.Title|null}\n\t */\n\tuw.TitleDetailsWidget.static.makeTitleInFileNS = function ( filename ) {\n\t\tlet\n\t\t\tmwTitle = mw.Title.newFromText( filename, NS_FILE ),\n\t\t\tillegalFileChars = new RegExp( '[' + mw.config.get( 'wgIllegalFileChars', '' ) + ']' );\n\t\tif ( mwTitle && mwTitle.getNamespaceId() !== NS_FILE ) {\n\t\t\t// Force file namespace\n\t\t\tmwTitle = mw.Title.makeTitle( NS_FILE, filename );\n\t\t}\n\t\tif ( mwTitle && ( illegalFileChars.test( mwTitle.getMainText() ) || mwTitle.fragment !== null ) ) {\n\t\t\t// Consider the title invalid if it contains characters disallowed in file names\n\t\t\tmwTitle = null;\n\t\t}\n\t\treturn mwTitle;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TitleDetailsWidget.prototype.pushPending = function () {\n\t\tthis.titleInput.pushPending();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TitleDetailsWidget.prototype.popPending = function () {\n\t\tthis.titleInput.popPending();\n\t};\n\n\t/**\n\t * Get a mw.Title object for current value.\n\t *\n\t * @return {mw.Title|null}\n\t */\n\tuw.TitleDetailsWidget.prototype.getTitle = function () {\n\t\tlet value, extRegex, cleaned, title;\n\t\tvalue = this.titleInput.getValue().trim();\n\t\tif ( !value ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( this.config.extension ) {\n\t\t\textRegex = new RegExp( '\\\\.' + this.extension + '$', 'i' );\n\t\t\tcleaned = value.replace( extRegex, '' ).replace( /\\.+$/g, '' ).trim();\n\t\t\tcleaned = cleaned + '.' + this.config.extension;\n\t\t} else {\n\t\t\tcleaned = value;\n\t\t}\n\t\ttitle = uw.TitleDetailsWidget.static.makeTitleInFileNS( cleaned );\n\t\treturn title;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TitleDetailsWidget.prototype.getWarnings = function () {\n\t\tconst warnings = [];\n\t\tthis.getEmptyWarning( this.titleInput.getValue().trim() === '', warnings );\n\n\t\treturn $.Deferred().resolve( warnings ).promise();\n\t};\n\n\t/**\n\t * @return {jQuery.Promise}\n\t */\n\tuw.TitleDetailsWidget.prototype.getErrors = function () {\n\t\tconst\n\t\t\terrors = [],\n\t\t\tvalue = this.titleInput.getValue().trim(),\n\t\t\tprocessDestinationCheck = this.processDestinationCheck,\n\t\t\ttitle = this.getTitle(),\n\t\t\t// title length is dependent on DB column size and is bytes rather than characters\n\t\t\tlength = byteLength( value );\n\n\t\tif ( this.config.required && value === '' ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-blank' ) );\n\t\t\treturn $.Deferred().resolve( errors ).promise();\n\t\t}\n\n\t\tif ( !this.config.required && value === '' ) {\n\t\t\treturn $.Deferred().resolve( [] ).promise();\n\t\t}\n\n\t\tif ( length !== 0 && this.config.minLength && length < this.config.minLength ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-title-too-short', this.config.minLength ) );\n\t\t\treturn $.Deferred().resolve( errors ).promise();\n\t\t}\n\n\t\tif ( this.config.maxLength && length > this.config.maxLength ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-title-too-long', this.config.maxLength ) );\n\t\t\treturn $.Deferred().resolve( errors ).promise();\n\t\t}\n\n\t\tif ( !title ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-title-invalid' ) );\n\t\t\treturn $.Deferred().resolve( errors ).promise();\n\t\t}\n\n\t\treturn mw.DestinationChecker.checkTitle( title.getPrefixedText() )\n\t\t\t.then( ( result ) => {\n\t\t\t\tlet moreErrors = processDestinationCheck( result );\n\t\t\t\tif ( result.blacklist.unavailable ) {\n\t\t\t\t\t// We don't have a title blacklist, so just check for some likely undesirable patterns.\n\t\t\t\t\tmoreErrors = moreErrors.concat(\n\t\t\t\t\t\tmw.QuickTitleChecker.checkTitle( title.getNameText() ).map( ( errorCode ) =>\n\t\t\t\t\t\t\t// Messages that can be used here:\n\t\t\t\t\t\t\t// * mediauploader-error-title-invalid\n\t\t\t\t\t\t\t// * mediauploader-error-title-senselessimagename\n\t\t\t\t\t\t\t// * mediauploader-error-title-thumbnail\n\t\t\t\t\t\t\t// * mediauploader-error-title-extension\n\t\t\t\t\t\t\t mw.message( 'mediauploader-error-title-' + errorCode )\n\t\t\t\t\t\t )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn moreErrors;\n\t\t\t} )\n\t\t\t.then( ( moreErrors ) => [].concat( errors, moreErrors ), () => $.Deferred().resolve( errors ) );\n\t};\n\n\t/**\n\t * Process the result of a destination filename check, return array of mw.Messages objects\n\t * representing errors.\n\t *\n\t * @private\n\t * @param {Object} result Result to process, output from mw.DestinationChecker\n\t * @return {mw.Message[]} Error messages\n\t */\n\tuw.TitleDetailsWidget.prototype.processDestinationCheck = function ( result ) {\n\t\tlet messageParams, errors, titleString;\n\n\t\tif ( result.unique.isUnique && result.blacklist.notBlacklisted && !result.unique.isProtected ) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Something is wrong with this title.\n\t\terrors = [];\n\n\t\ttry {\n\t\t\ttitleString = result.unique.title || result.title;\n\t\t\ttitleString = uw.TitleDetailsWidget.static.makeTitleInFileNS( titleString ).getPrefixedText();\n\t\t} catch ( e ) {\n\t\t\t// Unparseable result? This shouldn't happen, we checked for that earlier...\n\t\t\terrors.push( mw.message( 'mediauploader-error-title-invalid' ) );\n\t\t\treturn errors;\n\t\t}\n\n\t\tif ( !result.unique.isUnique ) {\n\t\t\t// result is NOT unique\n\t\t\tif ( result.unique.href ) {\n\t\t\t\terrors.push( mw.message(\n\t\t\t\t\t'mediauploader-fileexists-replace-on-page',\n\t\t\t\t\ttitleString,\n\t\t\t\t\t$( '<a>' ).attr( { href: result.unique.href, target: '_blank' } )\n\t\t\t\t) );\n\t\t\t} else {\n\t\t\t\terrors.push( mw.message( 'mediauploader-fileexists-replace-no-link', titleString ) );\n\t\t\t}\n\t\t} else if ( result.unique.isProtected ) {\n\t\t\terrors.push( mw.message( 'mediauploader-error-title-protected' ) );\n\t\t} else {\n\t\t\tmw.messages.set( result.blacklist.blacklistMessage, result.blacklist.blacklistReason );\n\t\t\tmessageParams = [\n\t\t\t\t'mediauploader-blacklisted-details',\n\t\t\t\ttitleString,\n\t\t\t\tfunction () {\n\t\t\t\t\t// eslint-disable-next-line mediawiki/msg-doc\n\t\t\t\t\tmw.errorDialog( $( '<div>' ).msg( result.blacklist.blacklistMessage ) );\n\t\t\t\t}\n\t\t\t];\n\n\t\t\terrors.push( mw.message.apply( mw, messageParams ) );\n\t\t}\n\n\t\treturn errors;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TitleDetailsWidget.prototype.getWikiText = function () {\n\t\treturn this.titleInput.getValue().trim();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.TitleDetailsWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\ttitle: this.titleInput.getValue()\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {string} serialized.language Title language code\n\t * @param {string} serialized.title Title text\n\t */\n\tuw.TitleDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\tthis.titleInput.setValue( serialized.title );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.UlsWidget.js","messages":[],"suppressedMessages":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":34,"column":4,"nodeType":"CallExpression","endLine":34,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ext.mediaUploader.campaignEditor.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/handlers/mw.ApiUploadFormDataHandler.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/handlers/mw.ApiUploadHandler.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'allDuplicates' is never reassigned. Use 'const' instead.","line":224,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":224,"endColumn":20},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":224,"column":23,"nodeType":"MemberExpression","messageId":"forbidden","endLine":224,"endColumn":36},{"ruleId":"prefer-const","severity":2,"message":"'$extra' is never reassigned. Use 'const' instead.","line":225,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":225,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'$ul' is never reassigned. Use 'const' instead.","line":226,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":226,"endColumn":7}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\tconst NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;\n\n\t/**\n\t * @param {mw.UploadWizardUpload} upload\n\t * @param {mw.Api} api\n\t */\n\tmw.ApiUploadHandler = function ( upload, api ) {\n\t\tthis.upload = upload;\n\t\tthis.api = api;\n\n\t\tthis.ignoreWarnings = [\n\t\t\t// we ignore these warnings, because the title is not our final title.\n\t\t\t'page-exists',\n\t\t\t'exists',\n\t\t\t'exists-normalized',\n\t\t\t'was-deleted',\n\t\t\t'badfilename',\n\t\t\t'bad-prefix'\n\t\t];\n\n\t\tthis.upload.on( 'remove-upload', this.abort.bind( this ) );\n\t};\n\n\t/**\n\t * @method\n\t * @abstract\n\t */\n\tmw.ApiUploadHandler.prototype.abort = null;\n\n\t/**\n\t * @method\n\t * @abstract\n\t * @return {jQuery.Promise}\n\t */\n\tmw.ApiUploadHandler.prototype.submit = null;\n\n\t/**\n\t * @return {jQuery.Promise}\n\t */\n\tmw.ApiUploadHandler.prototype.start = function () {\n\t\treturn this.submit().then(\n\t\t\tthis.setTransported.bind( this ),\n\t\t\tthis.setTransportError.bind( this )\n\t\t);\n\t};\n\n\t/**\n\t * Process a successful upload.\n\t *\n\t * @param {Object} result\n\t */\n\tmw.ApiUploadHandler.prototype.setTransported = function ( result ) {\n\t\tlet code;\n\t\tif ( result.upload && result.upload.warnings ) {\n\t\t\tfor ( code in result.upload.warnings ) {\n\t\t\t\tif ( !this.isIgnoredWarning( code ) ) {\n\t\t\t\t\tthis.setTransportWarning( code, result );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( !result.upload || result.upload.result !== 'Success' ) {\n\t\t\tthis.setError( 'unknown', mw.message( 'unknown-error' ).parse() );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !result.upload.imageinfo ) {\n\t\t\tthis.setError( 'noimageinfo', mw.message( 'mediauploader-api-error-noimageinfo' ).parse() );\n\t\t\treturn;\n\t\t}\n\n\t\tthis.upload.setSuccess( result );\n\t};\n\n\t/**\n\t * Process an upload with a warning.\n\t *\n\t * @param {string} code The API warning code\n\t * @param {Object} result The API result in parsed JSON form\n\t */\n\tmw.ApiUploadHandler.prototype.setTransportWarning = function ( code, result ) {\n\t\tlet param, duplicates, links;\n\n\t\tswitch ( code ) {\n\t\t\tcase 'duplicate':\n\t\t\t\tduplicates = result.upload.warnings.duplicate;\n\t\t\t\tif ( result.upload.warnings.exists && result.upload.warnings.nochange ) {\n\t\t\t\t\t// An existing same (nochange) file will not show up as\n\t\t\t\t\t// duplicate, but it should also be present in order to\n\t\t\t\t\t// figure out how to process the attempted upload)\n\t\t\t\t\tduplicates.push( result.upload.warnings.exists );\n\t\t\t\t}\n\t\t\t\tthis.processDuplicateError( code, result, result.upload.warnings.duplicate );\n\t\t\t\treturn;\n\t\t\tcase 'nochange':\n\t\t\t\t// This is like 'duplicate', but also the filename is the same, which doesn't matter\n\t\t\t\tif ( result.upload.warnings.exists ) {\n\t\t\t\t\tlinks = this.getFileLinks( [ result.upload.warnings.exists ] );\n\t\t\t\t\tthis.setDuplicateError( code, result, links, {}, 1 - links.length );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tcase 'duplicate-archive':\n\t\t\t\tthis.setDuplicateArchiveError( code, result, result.upload.warnings[ 'duplicate-archive' ] );\n\t\t\t\treturn;\n\t\t\tdefault:\n\t\t\t\tparam = code;\n\t\t\t\tif ( typeof result.upload.warnings[ code ] === 'string' ) {\n\t\t\t\t\t// tack the original error code onto the warning message\n\t\t\t\t\tparam += mw.message( 'colon-separator' ).text() + result.upload.warnings[ code ];\n\t\t\t\t}\n\n\t\t\t\t// we have an unknown warning, so let's say what we know\n\t\t\t\tthis.setError( code, mw.message( 'mediauploader-api-error-unknown-warning', param ).parse() );\n\t\t\t\treturn;\n\t\t}\n\t};\n\n\t/**\n\t * Process an erroneous upload.\n\t *\n\t * @param {string} code The API error code\n\t * @param {Object} result The API result in parsed JSON form\n\t */\n\tmw.ApiUploadHandler.prototype.setTransportError = function ( code, result ) {\n\t\tlet $extra;\n\n\t\tif ( code === 'badtoken' ) {\n\t\t\tthis.api.badToken( 'csrf' );\n\n\t\t\t// Try again once\n\t\t\tif ( this.ignoreWarning( code ) ) {\n\t\t\t\tthis.start();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif ( code === 'abusefilter-warning' ) {\n\t\t\t$extra = new OO.ui.ButtonWidget( {\n\t\t\t\tlabel: mw.message( 'mediauploader-override' ).text(),\n\t\t\t\ttitle: mw.message( 'mediauploader-override-upload' ).text(),\n\t\t\t\tflags: 'progressive',\n\t\t\t\tframed: false\n\t\t\t} ).on( 'click', () => {\n\t\t\t\t// No need to ignore the error, AbuseFilter will only return it once\n\t\t\t\tthis.start();\n\t\t\t} ).$element;\n\t\t}\n\n\t\tthis.setError( code, result.errors[ 0 ].html, $extra );\n\t};\n\n\t/**\n\t * Figure out the source of duplicates (local or foreign) and distribute\n\t * them to the correct function to display the accurate error messages.\n\t *\n\t * @param {string} code\n\t * @param {Object} result\n\t * @param {string[] }duplicates\n\t * @return {jQuery.Promise}\n\t */\n\tmw.ApiUploadHandler.prototype.processDuplicateError = function ( code, result, duplicates ) {\n\t\tconst files = this.getFileLinks( duplicates ),\n\t\t\tunknownAmount = duplicates.length - Object.keys( files ).length;\n\n\t\treturn this.getDuplicateSource( Object.keys( files ) ).then(\n\t\t\t( data ) => {\n\t\t\t\tthis.setDuplicateError( code, result, data.local, data.foreign, unknownAmount );\n\t\t\t},\n\t\t\t() => {\n\t\t\t\t// if anything goes wrong trying to figure out the source of\n\t\t\t\t// duplicates, just move on with local duplicate handling\n\t\t\t\tthis.setDuplicateError( code, result, files, {}, unknownAmount );\n\t\t\t}\n\t\t);\n\t};\n\n\t/**\n\t * @param {string[]} duplicates Array of duplicate filenames\n\t * @return {jQuery.Promise}\n\t */\n\tmw.ApiUploadHandler.prototype.getDuplicateSource = function ( duplicates ) {\n\t\treturn this.getImageInfo( duplicates, 'url' ).then( ( result ) => {\n\t\t\tconst local = [],\n\t\t\t\tforeign = [],\n\t\t\t\tnormalized = [];\n\n\t\t\tif ( !result.query || !result.query.pages ) {\n\t\t\t\treturn $.Deferred().reject();\n\t\t\t}\n\n\t\t\t// map of normalized titles, so we can find original title\n\t\t\tif ( result.query.normalized ) {\n\t\t\t\tresult.query.normalized.forEach( ( data ) => {\n\t\t\t\t\tnormalized[ data.to ] = data.from;\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tObject.keys( result.query.pages ).forEach( ( pageId ) => {\n\t\t\t\tconst page = result.query.pages[ pageId ],\n\t\t\t\t\ttitle = page.title in normalized ? normalized[ page.title ] : page.title;\n\t\t\t\tif ( page.imagerepository === 'local' ) {\n\t\t\t\t\tlocal[ title ] = page.imageinfo[ 0 ].descriptionurl;\n\t\t\t\t} else if ( page.imagerepository !== '' ) {\n\t\t\t\t\tforeign[ title ] = page.imageinfo[ 0 ].descriptionurl;\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn $.Deferred().resolve( { local: local, foreign: foreign } );\n\t\t} );\n\t};\n\n\t/**\n\t * Helper function to generate existing duplicate errors in a possibly collapsible list.\n\t *\n\t * @param {string} code Warning code, should have matching strings in .i18n.php\n\t * @param {Object} result The API result in parsed JSON form\n\t * @param {Object} localDuplicates Array of [duplicate filenames => local url]\n\t * @param {Object} foreignDuplicates Array of [duplicate filenames => foreign url]\n\t * @param {number} unknownAmount Amount of unknown filenames (e.g. revdeleted)\n\t */\n\tmw.ApiUploadHandler.prototype.setDuplicateError = function ( code, result, localDuplicates, foreignDuplicates, unknownAmount ) {\n\t\tlet allDuplicates = Object.assign( {}, localDuplicates, foreignDuplicates ),\n\t\t\t$extra = $( '<div>' ),\n\t\t\t$ul = $( '<ul>' ).appendTo( $extra ),\n\t\t\t$a,\n\t\t\toverride,\n\t\t\ti;\n\n\t\tunknownAmount = unknownAmount || 0;\n\n\t\tObject.keys( allDuplicates ).forEach( ( filename ) => {\n\t\t\tconst href = allDuplicates[ filename ];\n\t\t\t$a = $( '<a>' ).text( filename );\n\t\t\t$a.attr( { href: href, target: '_blank' } );\n\t\t\t$ul.append( $( '<li>' ).append( $a ) );\n\t\t} );\n\n\t\tfor ( i = 0; i < unknownAmount; i++ ) {\n\t\t\t$a = $( '<em>' ).text( mw.msg( 'mediauploader-deleted-duplicate-unknown-filename' ) );\n\t\t\t$ul.append( $( '<li>' ).append( $a ) );\n\t\t}\n\n\t\tif ( allDuplicates.length > 1 ) {\n\t\t\t$ul.makeCollapsible( { collapsed: true } );\n\t\t}\n\n\t\t// allow upload to continue if it's only a duplicate of files in a\n\t\t// foreign repo, not when it's a local dupe\n\t\tif ( Object.keys( localDuplicates ).length === 0 ) {\n\t\t\toverride = new OO.ui.ButtonWidget( {\n\t\t\t\tlabel: mw.message( 'mediauploader-override' ).text(),\n\t\t\t\ttitle: mw.message( 'mediauploader-override-upload' ).text(),\n\t\t\t\tflags: 'progressive',\n\t\t\t\tframed: false\n\t\t\t} ).on( 'click', () => {\n\t\t\t\t// mark this warning as ignored & process the API result again\n\t\t\t\tthis.ignoreWarning( 'duplicate' );\n\t\t\t\tthis.setTransported( result );\n\t\t\t} );\n\n\t\t\toverride.$element.appendTo( $extra );\n\t\t}\n\n\t\tthis.setError( code, mw.message( 'file-exists-duplicate', allDuplicates.length ).parse(), $extra );\n\t};\n\n\t/**\n\t * Helper function to generate deleted duplicate errors in a possibly collapsible list.\n\t *\n\t * @param {string} code Warning code, should have matching strings in .i18n.php\n\t * @param {Object} result The API result in parsed JSON form\n\t * @param {string} duplicate Duplicate filename\n\t */\n\tmw.ApiUploadHandler.prototype.setDuplicateArchiveError = function ( code, result, duplicate ) {\n\t\tconst filename = mw.Title.makeTitle( NS_FILE, duplicate ).getPrefixedText(),\n\t\t\tuploadDuplicate = new OO.ui.ButtonWidget( {\n\t\t\t\tlabel: mw.message( 'mediauploader-override' ).text(),\n\t\t\t\ttitle: mw.message( 'mediauploader-override-upload' ).text(),\n\t\t\t\tflags: 'progressive',\n\t\t\t\tframed: false\n\t\t\t} ).on( 'click', () => {\n\t\t\t\t// mark this warning as ignored & process the API result again\n\t\t\t\tthis.ignoreWarning( 'duplicate-archive' );\n\t\t\t\tthis.setTransported( result );\n\t\t\t} );\n\n\t\tthis.setError( code, mw.message( 'file-deleted-duplicate', filename ).parse(), uploadDuplicate.$element );\n\t};\n\n\t/**\n\t * @param {string|string[]} titles File title or array of titles\n\t * @param {string|string[]} prop Image props\n\t * @return {jQuery.Promise}\n\t */\n\tmw.ApiUploadHandler.prototype.getImageInfo = function ( titles, prop ) {\n\t\treturn this.api.get( {\n\t\t\taction: 'query',\n\t\t\ttitles: titles,\n\t\t\tprop: 'imageinfo',\n\t\t\tiiprop: prop\n\t\t} );\n\t};\n\n\t/**\n\t * Convert an array of non-prefixed filenames into a [filename => url] map.\n\t *\n\t * @param {string[]} filenames Array of non-prefixed filenames\n\t * @return {Object} Map of [prefixed filename => url]\n\t */\n\tmw.ApiUploadHandler.prototype.getFileLinks = function ( filenames ) {\n\t\tconst files = [];\n\n\t\tfilenames.forEach( ( filename ) => {\n\t\t\tlet title;\n\t\t\ttry {\n\t\t\t\ttitle = mw.Title.makeTitle( NS_FILE, filename );\n\t\t\t\tfiles[ title.getPrefixedText() ] = title.getUrl( {} );\n\t\t\t} catch ( e ) {\n\t\t\t\t// invalid filename (e.g. file was revdeleted)\n\t\t\t}\n\t\t} );\n\n\t\treturn files;\n\t};\n\n\t/**\n\t * @param {string} code Error code from API\n\t * @param {string} html Error message\n\t * @param {jQuery} [$extra]\n\t */\n\tmw.ApiUploadHandler.prototype.setError = function ( code, html, $extra ) {\n\t\tthis.upload.setError( code, html, $extra );\n\t};\n\n\t/**\n\t * Marks a warning to be ignored.\n\t *\n\t * @param {string} code\n\t * @return {boolean}\n\t */\n\tmw.ApiUploadHandler.prototype.ignoreWarning = function ( code ) {\n\t\tif ( this.isIgnoredWarning( code ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// mark the warning as being ignored, then restart the request\n\t\tthis.ignoreWarnings.push( code );\n\t\treturn true;\n\t};\n\n\t/**\n\t * Returns whether or not the warning is being ignored.\n\t *\n\t * @param {string} code\n\t * @return {boolean}\n\t */\n\tmw.ApiUploadHandler.prototype.isIgnoredWarning = function ( code ) {\n\t\treturn this.ignoreWarnings.includes( code );\n\t};\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/jquery.arrowSteps/jquery.arrowSteps.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'$el' is never reassigned. Use 'const' instead.","line":39,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":39,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'$steps' is never reassigned. Use 'const' instead.","line":42,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":42,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'width' is never reassigned. Use 'const' instead.","line":44,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":44,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'$steps' is never reassigned. Use 'const' instead.","line":71,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":71,"endColumn":10}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * jQuery arrowSteps plugin\n * Copyright Neil Kandalgaonkar, 2010\n *\n * This work is licensed under the terms of the GNU General Public License,\n * version 2 or later.\n * (see http://www.fsf.org/licensing/licenses/gpl.html).\n * Derivative works and later versions of the code must be free software\n * licensed under the same or a compatible license.\n */\n\n/**\n * @class jQuery.plugin.arrowSteps\n */\n( function () {\n\t/**\n\t * Show users their progress through a series of steps, via a row of items that fit\n\t * together like arrows. One item can be highlighted at a time.\n\t *\n\t *     <ul id=\"robin-hood-daffy\">\n\t *       <li id=\"guard\"><div>Guard!</div></li>\n\t *       <li id=\"turn\"><div>Turn!</div></li>\n\t *       <li id=\"parry\"><div>Parry!</div></li>\n\t *       <li id=\"dodge\"><div>Dodge!</div></li>\n\t *       <li id=\"spin\"><div>Spin!</div></li>\n\t *       <li id=\"ha\"><div>Ha!</div></li>\n\t *       <li id=\"thrust\"><div>Thrust!</div></li>\n\t *     </ul>\n\t *\n\t *     <script>\n\t *       $( '#robin-hood-daffy' ).arrowSteps();\n\t *     </script>\n\t *\n\t * @return {jQuery}\n\t * @chainable\n\t */\n\t$.fn.arrowSteps = function () {\n\t\tlet $steps, width,\n\t\t\t$el = this;\n\n\t\t$el.addClass( 'arrowSteps' );\n\t\t$steps = $el.find( 'li' );\n\n\t\twidth = Math.floor( 100 / $steps.length * 100 ) / 100;\n\t\t$steps.css( 'width', width + '%' );\n\n\t\t// Every step except the last one has an arrow pointing forward:\n\t\t// at the right hand side in LTR languages, and at the left hand side in RTL.\n\t\t$steps.filter( ':not(:last-child)' ).addClass( 'arrow' );\n\n\t\t$el.data( 'arrowSteps', $steps );\n\n\t\treturn this;\n\t};\n\n\t/**\n\t * Highlights the element selected by the selector.\n\t *\n\t *       $( '#robin-hood-daffy' ).arrowStepsHighlight( '#guard' );\n\t *       // 'Guard!' is highlighted.\n\t *\n\t *       // ... user completes the 'guard' step ...\n\t *\n\t *       $( '#robin-hood-daffy' ).arrowStepsHighlight( '#turn' );\n\t *       // 'Turn!' is highlighted.\n\t *\n\t * @param {string} selector\n\t */\n\t$.fn.arrowStepsHighlight = function ( selector ) {\n\t\tlet $previous,\n\t\t\t$steps = this.data( 'arrowSteps' );\n\t\t$steps.each( function () {\n\t\t\tconst $step = $( this );\n\t\t\tif ( $step.is( selector ) ) {\n\t\t\t\tif ( $previous ) {\n\t\t\t\t\t$previous.addClass( 'tail' );\n\t\t\t\t}\n\t\t\t\t$step.addClass( 'head' );\n\t\t\t} else {\n\t\t\t\t$step.removeClass( 'head tail lasthead' );\n\t\t\t}\n\t\t\t$previous = $step;\n\t\t} );\n\t};\n\n\t/**\n\t * @class jQuery\n\t */\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/jquery/jquery.morphCrossfade.js","messages":[],"suppressedMessages":[{"ruleId":"no-jquery/no-animate","severity":2,"message":"Prefer CSS transitions to .animate","line":105,"column":6,"nodeType":"CallExpression","endLine":107,"endColumn":9,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-animate","severity":2,"message":"Prefer CSS transitions to .animate","line":113,"column":5,"nodeType":"CallExpression","endLine":118,"endColumn":8,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-animate","severity":2,"message":"Prefer CSS transitions to .animate","line":120,"column":5,"nodeType":"CallExpression","endLine":120,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.DestinationChecker.js","messages":[{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":77,"column":4,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":77,"endColumn":6},{"ruleId":"implicit-arrow-linebreak","severity":2,"message":"Expected no linebreak before this expression.","line":77,"column":6,"nodeType":"Identifier","messageId":"unexpected","endLine":77,"endColumn":7},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":78,"column":3,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":78,"endColumn":5},{"ruleId":"prefer-const","severity":2,"message":"'checker' is never reassigned. Use 'const' instead.","line":94,"column":8,"nodeType":"Identifier","messageId":"useConst","endLine":94,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'NS_FILE' is never reassigned. Use 'const' instead.","line":95,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":95,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'titleObj' is never reassigned. Use 'const' instead.","line":98,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":98,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'ext' is never reassigned. Use 'const' instead.","line":99,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":99,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'prefix' is never reassigned. Use 'const' instead.","line":101,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":101,"endColumn":10}],"suppressedMessages":[],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\n\tmw.DestinationChecker = {\n\n\t\tapi: new mw.Api(),\n\n\t\t// cached results from uniqueness api calls\n\t\tcachedResult: {},\n\t\tcachedBlacklist: {},\n\n\t\t/**\n\t\t * Check title for validity.\n\t\t *\n\t\t * @param {string} title Title to check\n\t\t * @return {jQuery.Promise}\n\t\t *  {Function} return.done\n\t\t *  {string} return.done.title The title that was passed in\n\t\t *  {Object|boolean} return.done.blacklist See #checkBlacklist\n\t\t *  {Object|boolean} return.done.unique See #checkUnique\n\t\t */\n\t\tcheckTitle: function ( title ) {\n\t\t\treturn $.when(\n\t\t\t\tthis.checkUnique( title ),\n\t\t\t\tthis.checkBlacklist( title )\n\t\t\t).then( ( unique, blacklist ) => ( {\n\t\t\t\tunique: unique,\n\t\t\t\tblacklist: blacklist,\n\t\t\t\ttitle: title\n\t\t\t} ) );\n\t\t},\n\n\t\t/**\n\t\t * Async check if a title is in the titleblacklist.\n\t\t *\n\t\t * @param {string} title Title to check against the blacklist\n\t\t * @return {jQuery.Promise}\n\t\t *  {Function} return.done\n\t\t *  {boolean} return.done.notBlacklisted\n\t\t *  {string} [return.done.blacklistReason] See mw.Api#isBlacklisted\n\t\t *  {string} [return.done.blacklistMessage] See mw.Api#isBlacklisted\n\t\t *  {string} [return.done.blacklistLine] See mw.Api#isBlacklisted\n\t\t */\n\t\tcheckBlacklist: function ( title ) {\n\t\t\tconst checker = this;\n\n\t\t\t/**\n\t\t\t * Process result of a TitleBlacklist API call.\n\t\t\t *\n\t\t\t * @private\n\t\t\t * @param {Object|boolean} blacklistResult `false` if not blacklisted, object if blacklisted\n\t\t\t * @return {Object}\n\t\t\t */\n\t\t\tfunction blacklistResultProcessor( blacklistResult ) {\n\t\t\t\tlet result;\n\n\t\t\t\tif ( blacklistResult === false ) {\n\t\t\t\t\tresult = { notBlacklisted: true };\n\t\t\t\t} else {\n\t\t\t\t\tresult = {\n\t\t\t\t\t\tnotBlacklisted: false,\n\t\t\t\t\t\tblacklistReason: blacklistResult.reason,\n\t\t\t\t\t\tblacklistMessage: blacklistResult.message,\n\t\t\t\t\t\tblacklistLine: blacklistResult.line\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tchecker.cachedBlacklist[ title ] = result;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tif ( this.cachedBlacklist[ title ] !== undefined ) {\n\t\t\t\treturn $.Deferred().resolve( this.cachedBlacklist[ title ] );\n\t\t\t}\n\n\t\t\treturn mw.loader.using( 'mediawiki.api.titleblacklist' ).then( () => checker.api.isBlacklisted( title ).then( blacklistResultProcessor ), () =>\n\t\t\t\t// it's not blacklisted, because the API isn't even available\n\t\t\t\t $.Deferred().resolve( { notBlacklisted: true, unavailable: true } )\n\t\t\t );\n\t\t},\n\n\t\t/**\n\t\t * Async check if a filename is unique. Can be attached to a field's change() event\n\t\t * This is a more abstract version of AddMedia/UploadHandler.js::doDestCheck\n\t\t *\n\t\t * @param {string} title Title to check for uniqueness\n\t\t * @return {jQuery.Promise}\n\t\t *  {Function} return.done\n\t\t *  {boolean} return.done.isUnique\n\t\t *  {boolean} [return.done.isProtected]\n\t\t *  {Object} [return.done.img] Image info\n\t\t *  {string} [return.done.href] URL to file description page\n\t\t */\n\t\tcheckUnique: function ( title ) {\n\t\t\tlet checker = this,\n\t\t\t\tNS_FILE = mw.config.get( 'wgNamespaceIds' ).file,\n\t\t\t\ttitleObj, prefix, ext;\n\n\t\t\ttitleObj = mw.Title.newFromText( title );\n\t\t\text = mw.Title.normalizeExtension( titleObj.getExtension() || '' );\n\t\t\t// Strip namespace and file extension\n\t\t\tprefix = titleObj.getNameText();\n\n\t\t\t/**\n\t\t\t * Process result of a an imageinfo API call.\n\t\t\t *\n\t\t\t * @private\n\t\t\t * @param {Object} data API result\n\t\t\t * @return {Object}\n\t\t\t */\n\t\t\tfunction checkUniqueProcessor( data ) {\n\t\t\t\tlet result, protection, pageId, ntitle, ntitleObj, img;\n\n\t\t\t\tresult = { isUnique: true };\n\n\t\t\t\tif ( data.query && data.query.pages ) {\n\t\t\t\t\t// The API will check for files with that filename.\n\t\t\t\t\t// If no file found: a page with a key of -1 and no imageinfo\n\t\t\t\t\t// If file found on another repository, such as when the wiki is using InstantCommons: page with a key of -1, plus imageinfo\n\t\t\t\t\t// If file found on this repository: page with some positive numeric key\n\t\t\t\t\tif ( data.query.pages[ -1 ] && !data.query.pages[ -1 ].imageinfo ) {\n\t\t\t\t\t\tprotection = data.query.pages[ -1 ].protection;\n\t\t\t\t\t\tif ( protection && protection.length > 0 ) {\n\t\t\t\t\t\t\tprotection.forEach( ( val ) => {\n\t\t\t\t\t\t\t\tif ( !mw.config.get( 'wgUserGroups' ).includes( val.level ) ) {\n\t\t\t\t\t\t\t\t\tresult = {\n\t\t\t\t\t\t\t\t\t\tisUnique: true,\n\t\t\t\t\t\t\t\t\t\tisProtected: true\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// No conflict found on any repository this wiki uses\n\t\t\t\t\t\t\tresult = { isUnique: true };\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor ( pageId in data.query.pages ) {\n\t\t\t\t\t\t\tif ( !Object.prototype.hasOwnProperty.call( data.query.pages, pageId ) ) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tntitle = data.query.pages[ pageId ].title;\n\t\t\t\t\t\t\tntitleObj = mw.Title.newFromText( ntitle );\n\t\t\t\t\t\t\tif ( ntitleObj.getNameText() !== prefix ) {\n\t\t\t\t\t\t\t\t// It's a different file name entirely\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ( ext !== mw.Title.normalizeExtension( ntitleObj.getExtension() || '' ) ) {\n\t\t\t\t\t\t\t\t// It's a different extension, that's fine (e.g. to upload a SVG version of a PNG file)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Conflict found, this filename is NOT unique\n\n\t\t\t\t\t\t\tif ( !data.query.pages[ pageId ].imageinfo ) {\n\t\t\t\t\t\t\t\t// This means that there's a page, but it's not a file. Well,\n\t\t\t\t\t\t\t\t// we should really report that anyway, but we shouldn't process\n\t\t\t\t\t\t\t\t// it like a file, and we should defer to other entries that may be files.\n\t\t\t\t\t\t\t\tresult = {\n\t\t\t\t\t\t\t\t\tisUnique: false,\n\t\t\t\t\t\t\t\t\ttitle: ntitle,\n\t\t\t\t\t\t\t\t\timg: null,\n\t\t\t\t\t\t\t\t\thref: null\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\timg = data.query.pages[ pageId ].imageinfo[ 0 ];\n\n\t\t\t\t\t\t\tresult = {\n\t\t\t\t\t\t\t\tisUnique: false,\n\t\t\t\t\t\t\t\timg: img,\n\t\t\t\t\t\t\t\ttitle: ntitle,\n\t\t\t\t\t\t\t\thref: img.descriptionurl\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tif ( this.cachedResult[ title ] !== undefined ) {\n\t\t\t\treturn $.Deferred().resolve( this.cachedResult[ title ] );\n\t\t\t}\n\n\t\t\t// Setup the request -- will return thumbnail data if it finds one\n\t\t\t// XXX do not use iiurlwidth as it will create a thumbnail\n\t\t\treturn $.when(\n\t\t\t\t// Checks for exact matches on this wiki and foreign file repos\n\t\t\t\tthis.api.get( {\n\t\t\t\t\taction: 'query',\n\t\t\t\t\ttitles: title,\n\t\t\t\t\tprop: 'info|imageinfo',\n\t\t\t\t\tinprop: 'protection',\n\t\t\t\t\tiiprop: 'url|mime|size',\n\t\t\t\t\tiiurlwidth: 150\n\t\t\t\t} ).then( checkUniqueProcessor ),\n\t\t\t\t// Checks for matches with different versions of the file extension on this wiki only\n\t\t\t\tthis.api.get( {\n\t\t\t\t\taction: 'query',\n\t\t\t\t\tgenerator: 'allpages',\n\t\t\t\t\tgapnamespace: NS_FILE,\n\t\t\t\t\tgapprefix: prefix,\n\t\t\t\t\tprop: 'info|imageinfo',\n\t\t\t\t\tinprop: 'protection',\n\t\t\t\t\tiiprop: 'url|mime|size',\n\t\t\t\t\tiiurlwidth: 150\n\t\t\t\t} ).then( checkUniqueProcessor )\n\t\t\t).then( ( exact, fuzzy ) => {\n\t\t\t\tlet result;\n\t\t\t\tif ( !exact.isUnique || exact.isProtected ) {\n\t\t\t\t\tresult = exact;\n\t\t\t\t} else if ( !fuzzy.isUnique || fuzzy.isProtected ) {\n\t\t\t\t\tresult = fuzzy;\n\t\t\t\t} else {\n\t\t\t\t\tresult = { isUnique: true };\n\t\t\t\t}\n\n\t\t\t\tchecker.cachedResult[ title ] = result;\n\t\t\t\treturn result;\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Clears the result cache\n\t\t */\n\t\tclearCache: function () {\n\t\t\tthis.cachedResult = {};\n\t\t}\n\n\t};\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.Escaper.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'extractedTemplates' is never reassigned. Use 'const' instead.","line":31,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":31,"endColumn":22},{"ruleId":"prefer-const","severity":2,"message":"'extractedLinks' is never reassigned. Use 'const' instead.","line":32,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":32,"endColumn":18},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":34,"column":43,"nodeType":"MemberExpression","messageId":"forbidden","endLine":34,"endColumn":56},{"ruleId":"prefer-const","severity":2,"message":"'extracts' is never reassigned. Use 'const' instead.","line":52,"column":8,"nodeType":"Identifier","messageId":"useConst","endLine":52,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'regex' is never reassigned. Use 'const' instead.","line":61,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":61,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'callback' is never reassigned. Use 'const' instead.","line":62,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":62,"endColumn":13}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\tmw.Escaper = {\n\t\t/**\n\t\t * Escapes wikitext for use inside {{templates}}.\n\t\t *\n\t\t * @param {string} wikitext\n\t\t * @return {string}\n\t\t */\n\t\tescapeForTemplate: function ( wikitext ) {\n\t\t\treturn this.escapePipes( wikitext );\n\t\t},\n\n\t\t/**\n\t\t * Escapes pipe characters, which could be problematic when the content is\n\t\t * inserted in a template.\n\t\t *\n\t\t * @param {string} wikitext\n\t\t * @return {string}\n\t\t */\n\t\tescapePipes: function ( wikitext ) {\n\t\t\tlet extractedTemplates, extractedLinks;\n\n\t\t\t// Pipes (`|`) must be escaped because we'll be inserting this\n\t\t\t// content into a templates & pipes would mess up the syntax.\n\t\t\t// First, urlencode pipes inside links:\n\t\t\twikitext = wikitext.replace( /\\bhttps?:\\/\\/[^\\s]+/g, ( match ) => match.replace( /\\|/g, '%7C' ) );\n\n\t\t\t// Second, pipes can be valid inside other templates or links in\n\t\t\t// wikitext, so we'll first extract those from the content, then\n\t\t\t// replace the pipes, then restore the original (extracted) content:\n\t\t\textractedTemplates = this.extractTemplates( wikitext );\n\t\t\textractedLinks = this.extractLinks( extractedTemplates[ 0 ] );\n\t\t\twikitext = extractedLinks[ 0 ].replace( /\\|/g, '{{!}}' );\n\t\t\treturn this.restoreExtracts( wikitext, Object.assign( extractedTemplates[ 1 ], extractedLinks[ 1 ] ) );\n\t\t},\n\n\t\t/**\n\t\t * Extract all {{templates}} from wikitext, replacing them with\n\t\t * placeholder content in the form of {{1}}, {{2}}.\n\t\t *\n\t\t * Nested templates will safely be extracted by first replacing inner\n\t\t * templates, then moving outwards, ensuring we don't get closing\n\t\t * bracket mismatches.\n\t\t *\n\t\t * Restoring the content is as simple as feeding the returned content &\n\t\t * replacements back into this.restoreExtracts.\n\t\t *\n\t\t * @param {string} wikitext\n\t\t * @return {Array} [{string} wikitext, {Object} replacements]\n\t\t */\n\t\textractTemplates: function ( wikitext ) {\n\t\t\tlet extracts = {},\n\t\t\t\tpreviousExtracts = {},\n\t\t\t\textracted = wikitext,\n\t\t\t\t// the regex explained:\n\t\t\t\t// * `[^\\{]`: character can not be {\n\t\t\t\t// * `\\{(?!\\{)`: or if it is, it can't be followed by another {\n\t\t\t\t// this excludes template opening brackets: {{\n\t\t\t\t// * `\\{\\{[0-9]+\\}\\}`: unless it's a complete {{[0-9]+}}\n\t\t\t\t//   sequence, generated by an earlier run of this regex\n\t\t\t\tregex = /\\{\\{([^{]|\\{(?!\\{)|\\{\\{[0-9]+\\}\\})*?\\}\\}/g,\n\t\t\t\tcallback = function ( match ) {\n\t\t\t\t\tconst replacement = '{{' + Object.keys( extracts ).length + '}}';\n\n\t\t\t\t\t// safeguard for not replacing already-replaced matches\n\t\t\t\t\t// this makes sure that when real content contains something\n\t\t\t\t\t// like {{1}}, it will still be replaced, while {{1}}\n\t\t\t\t\t// generated by this code can be recognized & ignored\n\t\t\t\t\tif ( match in previousExtracts ) {\n\t\t\t\t\t\treturn match;\n\t\t\t\t\t}\n\n\t\t\t\t\textracts[ replacement ] = match;\n\t\t\t\t\treturn replacement;\n\t\t\t\t};\n\n\t\t\tdo {\n\t\t\t\twikitext = extracted;\n\t\t\t\tpreviousExtracts = OO.copy( extracts );\n\t\t\t\textracted = wikitext.replace( regex, callback );\n\t\t\t} while ( wikitext !== extracted );\n\n\t\t\treturn [ wikitext, extracts ];\n\t\t},\n\n\t\t/**\n\t\t * Extract all [[links]] from wikitext, replacing them with placeholder\n\t\t * content in the form of [[1]], [[2]].\n\t\t *\n\t\t * Restoring the content is as simple as feeding the returned content &\n\t\t * replacements back into this.restoreExtracts.\n\t\t *\n\t\t * @param {string} wikitext\n\t\t * @return {Array} [{string} wikitext, {Object} replacements]\n\t\t */\n\t\textractLinks: function ( wikitext ) {\n\t\t\tconst extracts = {};\n\n\t\t\twikitext = wikitext.replace( /\\[\\[.*?\\]\\]/g, ( match ) => {\n\t\t\t\tconst replacement = '[[' + Object.keys( extracts ).length + ']]';\n\t\t\t\textracts[ replacement ] = match;\n\t\t\t\treturn replacement;\n\t\t\t} );\n\n\t\t\treturn [ wikitext, extracts ];\n\t\t},\n\n\t\t/**\n\t\t * Restores content that was extracted from wikitext.\n\t\t *\n\t\t * @param {string} wikitext\n\t\t * @param {Object} replacements\n\t\t * @return {string}\n\t\t */\n\t\trestoreExtracts: function ( wikitext, replacements ) {\n\t\t\t// turn search keys into a regular expression, allowing us to match\n\t\t\t// all of them at once\n\t\t\tconst searchValues = Object.keys( replacements ).map( mw.util.escapeRegExp ),\n\t\t\t\tsearchRegex = new RegExp( '(' + searchValues.join( '|' ) + ')', 'g' ),\n\t\t\t\tcallback = function ( match ) {\n\t\t\t\t\tconst replacement = replacements[ match ];\n\n\t\t\t\t\t// we matched something that has no replacement, must be valid\n\t\t\t\t\t// user input that just happens to look like on of the\n\t\t\t\t\t// replacement values\n\t\t\t\t\tif ( replacement === undefined ) {\n\t\t\t\t\t\treturn match;\n\t\t\t\t\t}\n\n\t\t\t\t\t// if we find the replacement itself matches a search value, we\n\t\t\t\t\t// also don't want to go recursive: nesting doesn't work like\n\t\t\t\t\t// that, it's just a coincidence where user input happens to\n\t\t\t\t\t// look just like a replacement value (e.g. `{{1}}`)\n\t\t\t\t\tif ( replacement in replacements ) {\n\t\t\t\t\t\treturn replacement;\n\t\t\t\t\t}\n\n\t\t\t\t\t// we must not replace this one again, to avoid getting stuck in\n\t\t\t\t\t// endless recursion\n\t\t\t\t\tdelete replacements[ match ];\n\n\t\t\t\t\t// go recursive, there may be more replacements nested down there\n\t\t\t\t\treturn this.restoreExtracts( replacement, replacements );\n\t\t\t\t}.bind( this );\n\n\t\t\treturn wikitext.replace( searchRegex, callback );\n\t\t}\n\t};\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.GroupProgressBar.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'bar' is never reassigned. Use 'const' instead.","line":59,"column":8,"nodeType":"Identifier","messageId":"useConst","endLine":59,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'remainingTime' is never reassigned. Use 'const' instead.","line":146,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":146,"endColumn":18}],"suppressedMessages":[{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeIn","line":52,"column":4,"nodeType":"CallExpression","endLine":52,"endColumn":74,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeOut","line":123,"column":4,"nodeType":"CallExpression","endLine":123,"endColumn":75,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/* global moment */\n( function () {\n\t/**\n\t * This is a progress bar for monitoring multiple objects, giving summary view\n\t *\n\t * @class mw.GroupProgressbar\n\t * @constructor\n\t * @param {string} selector\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @param {string[]} successStates\n\t * @param {string[]} errorStates\n\t * @param {string} progressProperty\n\t * @param {string} weightProperty\n\t */\n\tmw.GroupProgressBar = function ( selector, uploads, successStates, errorStates, progressProperty, weightProperty ) {\n\t\tthis.$selector = $( selector );\n\t\tthis.$selector.empty().append(\n\t\t\t$( '<div>' ).addClass( 'mediauploader-progress-inner' ).append(\n\t\t\t\t$( '<div>' ).addClass( 'mediauploader-progress-bar-etr-container' ).append(\n\t\t\t\t\t$( '<div>' ).addClass( 'mediauploader-progress-bar-etr' ).hide().append(\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mediauploader-etr' )\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\t$( '<div>' ).addClass( 'mediauploader-count' )\n\t\t\t)\n\t\t);\n\n\t\tthis.progressBarWidget = new OO.ui.ProgressBarWidget( {\n\t\t\tclasses: [ 'mediauploader-progress-bar' ],\n\t\t\tprogress: 0\n\t\t} );\n\n\t\tthis.$selector.find( '.mediauploader-progress-bar-etr' )\n\t\t\t.prepend( this.progressBarWidget.$element );\n\n\t\tthis.uploads = uploads;\n\t\tthis.successStates = successStates;\n\t\tthis.errorStates = errorStates;\n\t\tthis.progressProperty = progressProperty;\n\t\tthis.weightProperty = weightProperty;\n\t\tthis.beginTime = undefined;\n\t};\n\n\tmw.GroupProgressBar.prototype = {\n\n\t\t/**\n\t\t * Show the progress bar\n\t\t */\n\t\tshowBar: function () {\n\t\t\t// FIXME: Use CSS transition\n\t\t\t// eslint-disable-next-line no-jquery/no-fade\n\t\t\tthis.$selector.find( '.mediauploader-progress-bar-etr' ).fadeIn( 200 );\n\t\t},\n\n\t\t/**\n\t\t * loop around the uploads, summing certain properties for a weighted total fraction\n\t\t */\n\t\tstart: function () {\n\t\t\tlet bar = this,\n\t\t\t\tshown = false;\n\n\t\t\tthis.setBeginTime();\n\n\t\t\tfunction displayer() {\n\t\t\t\tlet totalWeight = 0.0,\n\t\t\t\t\tfraction = 0.0,\n\t\t\t\t\tsuccessStateCount = 0,\n\t\t\t\t\terrorStateCount = 0,\n\t\t\t\t\thasData = false;\n\n\t\t\t\tbar.uploads.forEach( ( upload ) => {\n\t\t\t\t\ttotalWeight += upload[ bar.weightProperty ];\n\t\t\t\t} );\n\n\t\t\t\tbar.uploads.forEach( ( upload ) => {\n\t\t\t\t\tif ( upload.state === 'aborted' ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif ( bar.successStates.includes( upload.state ) ) {\n\t\t\t\t\t\tsuccessStateCount++;\n\t\t\t\t\t}\n\t\t\t\t\tif ( bar.errorStates.includes( upload.state ) ) {\n\t\t\t\t\t\terrorStateCount++;\n\t\t\t\t\t}\n\t\t\t\t\tif ( upload[ bar.progressProperty ] !== undefined ) {\n\t\t\t\t\t\tfraction += upload[ bar.progressProperty ] * ( upload[ bar.weightProperty ] / totalWeight );\n\t\t\t\t\t\tif ( upload[ bar.progressProperty ] > 0 ) {\n\t\t\t\t\t\t\thasData = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\t// sometimes, the first data we have just tells us that it's over. So only show the bar\n\t\t\t\t// if we have good data AND the fraction is less than 1.\n\t\t\t\tif ( hasData && fraction < 1.0 ) {\n\t\t\t\t\tif ( !shown ) {\n\t\t\t\t\t\tbar.showBar();\n\t\t\t\t\t\tshown = true;\n\t\t\t\t\t}\n\t\t\t\t\tbar.showProgress( fraction );\n\t\t\t\t}\n\t\t\t\tbar.showCount( successStateCount );\n\n\t\t\t\tif ( successStateCount + errorStateCount < bar.uploads.length - bar.countRemoved() ) {\n\t\t\t\t\tsetTimeout( displayer, 200 );\n\t\t\t\t} else {\n\t\t\t\t\tbar.showProgress( 1.0 );\n\t\t\t\t\tbar.finished = true;\n\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\tbar.hideBar();\n\t\t\t\t\t}, 500 );\n\t\t\t\t}\n\t\t\t}\n\t\t\tdisplayer();\n\t\t},\n\n\t\t/**\n\t\t * Hide the progress bar with a slideup motion\n\t\t */\n\t\thideBar: function () {\n\t\t\t// FIXME: Use CSS transition\n\t\t\t// eslint-disable-next-line no-jquery/no-fade\n\t\t\tthis.$selector.find( '.mediauploader-progress-bar-etr' ).fadeOut( 200 );\n\t\t},\n\n\t\t/**\n\t\t * sets the beginning time (useful for figuring out estimated time remaining)\n\t\t * if time parameter omitted, will set beginning time to now\n\t\t *\n\t\t * @param {number} [time] The time this bar is presumed to have started (epoch milliseconds)\n\t\t */\n\t\tsetBeginTime: function ( time ) {\n\t\t\tthis.beginTime = time || Date.now();\n\t\t},\n\n\t\t/**\n\t\t * Show overall progress for the entire UploadWizard\n\t\t * The current design doesn't have individual progress bars, just one giant one.\n\t\t * We did some tricky calculations in startUploads to try to weight each individual file's progress against\n\t\t * the overall progress.\n\t\t *\n\t\t * @param {number} fraction The amount of whatever it is that's done whatever it's done\n\t\t */\n\t\tshowProgress: function ( fraction ) {\n\t\t\tlet t, timeString,\n\t\t\t\tremainingTime = this.getRemainingTime( fraction );\n\n\t\t\tthis.progressBarWidget.setProgress( parseInt( fraction * 100, 10 ) );\n\n\t\t\tif ( remainingTime !== null ) {\n\t\t\t\tif ( remainingTime === 0 ) {\n\t\t\t\t\ttimeString = mw.message( 'mediauploader-finished' ).text();\n\t\t\t\t} else if ( remainingTime < 1000 ) {\n\t\t\t\t\ttimeString = mw.message( 'mediauploader-almost-finished' ).text();\n\t\t\t\t} else {\n\t\t\t\t\tt = moment.duration( remainingTime );\n\t\t\t\t\ttimeString = t.humanize();\n\t\t\t\t}\n\n\t\t\t\tthis.$selector.find( '.mediauploader-etr' ).text( timeString );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Calculate remaining time for all uploads to complete.\n\t\t *\n\t\t * @param {number} fraction Fraction of progress to show\n\t\t * @return {number} Estimated time remaining (in milliseconds)\n\t\t */\n\t\tgetRemainingTime: function ( fraction ) {\n\t\t\tlet elapsedTime, rate;\n\t\t\tif ( this.beginTime ) {\n\t\t\t\telapsedTime = Date.now() - this.beginTime;\n\t\t\t\tif ( fraction > 0.0 && elapsedTime > 0 ) { // or some other minimums for good data\n\t\t\t\t\trate = fraction / elapsedTime;\n\t\t\t\t\treturn ( ( 1.0 - fraction ) / rate );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\n\t\t/**\n\t\t * Show the overall count as we upload\n\t\t *\n\t\t * @param {number} completed The number of items that have done whatever has been done e.g. in \"uploaded 2 of 5\", this is the 2\n\t\t */\n\t\tshowCount: function ( completed ) {\n\t\t\tconst total = this.uploads.length - this.countRemoved();\n\t\t\tthis.$selector\n\t\t\t\t.find( '.mediauploader-count' )\n\t\t\t\t// Hide if there are no uploads, show otherwise\n\t\t\t\t.toggle( total !== 0 )\n\t\t\t\t.html( mw.message( 'mediauploader-upload-count', completed, total ).escaped() );\n\t\t},\n\n\t\tcountRemoved: function () {\n\t\t\tlet count = 0;\n\t\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\t\tif ( !upload || upload.state === 'aborted' ) {\n\t\t\t\t\tcount += 1;\n\t\t\t\t}\n\t\t\t} );\n\t\t\treturn count;\n\t\t}\n\t};\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.QuickTitleChecker.js","messages":[],"suppressedMessages":[{"ruleId":"no-control-regex","severity":2,"message":"Unexpected control character(s) in regular expression: \\x00, \\x1f.","line":27,"column":4,"nodeType":"Literal","messageId":"unexpected","endLine":27,"endColumn":17,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizard.js","messages":[{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"uw\" type.","line":4,"column":1,"nodeType":"Block","endLine":4,"endColumn":1},{"ruleId":"prefer-const","severity":2,"message":"'maxSimPref' is never reassigned. Use 'const' instead.","line":22,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":22,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'self' is never reassigned. Use 'const' instead.","line":64,"column":8,"nodeType":"Identifier","messageId":"useConst","endLine":64,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'steps' is never reassigned. Use 'const' instead.","line":65,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":65,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'uploadStep' is never reassigned. Use 'const' instead.","line":74,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":74,"endColumn":14},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":127,"column":5,"nodeType":"MemberExpression","messageId":"forbidden","endLine":127,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'original' is never reassigned. Use 'const' instead.","line":134,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":134,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'override' is never reassigned. Use 'const' instead.","line":138,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":138,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'deeds' is never reassigned. Use 'const' instead.","line":187,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":187,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'doOwnWork' is never reassigned. Use 'const' instead.","line":188,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":188,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'doThirdParty' is never reassigned. Use 'const' instead.","line":189,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":189,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'api' is never reassigned. Use 'const' instead.","line":197,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":197,"endColumn":6}],"suppressedMessages":[],"errorCount":10,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Object that represents the entire multi-step Upload Wizard\n *\n * @param uw\n */\n\n( function ( uw ) {\n\n\tmw.UploadWizard = function ( config ) {\n\t\tlet maxSimPref;\n\n\t\tthis.api = this.getApi( { ajax: { timeout: 0 } } );\n\n\t\t// making a sort of global for now, should be done by passing in config or fragments of config\n\t\t// when needed elsewhere\n\t\tmw.UploadWizard.config = config;\n\t\t// Shortcut for local references\n\t\tthis.config = config;\n\n\t\tthis.steps = {};\n\n\t\tmaxSimPref = mw.user.options.get( 'upwiz_maxsimultaneous' );\n\n\t\tif ( maxSimPref !== 'default' ) {\n\t\t\tif ( maxSimPref > 0 ) {\n\t\t\t\tconfig.maxSimultaneousConnections = maxSimPref;\n\t\t\t} else {\n\t\t\t\tconfig.maxSimultaneousConnections = 1;\n\t\t\t}\n\t\t}\n\n\t\tthis.maxSimultaneousConnections = config.maxSimultaneousConnections;\n\n\t\tif ( mw.loader.getState( 'ext.uls.mediawiki' ) !== null ) {\n\t\t\tmw.loader.load( 'ext.uls.mediawiki' );\n\t\t}\n\t};\n\n\tmw.UploadWizard.DEBUG = true;\n\n\tmw.UploadWizard.userAgent = 'UploadWizard';\n\n\tmw.UploadWizard.prototype = {\n\t\t/**\n\t\t * Create the basic interface to make an upload in this div\n\t\t *\n\t\t * @param {string} selector\n\t\t */\n\t\tcreateInterface: function ( selector ) {\n\t\t\tthis.ui = new uw.ui.Wizard( selector );\n\n\t\t\tthis.initialiseSteps().then( ( steps ) => {\n\t\t\t\t// \"select\" the first step - highlight, make it visible, hide all others\n\t\t\t\tsteps[ 0 ].load( [] );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Initialise the steps in the wizard\n\t\t *\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tinitialiseSteps: function () {\n\t\t\tlet self = this,\n\t\t\t\tsteps = [],\n\t\t\t\ti,\n\t\t\t\tuploadStep;\n\n\t\t\t// Add the tutorial step if it's enabled\n\t\t\tif ( this.config.tutorial.enabled ) {\n\t\t\t\tsteps.push( new uw.controller.Tutorial( this.api, this.config ) );\n\t\t\t}\n\n\t\t\tuploadStep = new uw.controller.Upload( this.api, this.config );\n\t\t\tsteps.push( uploadStep );\n\n\t\t\t// Add the licensing step if it's enabled\n\t\t\tif ( this.config.licensing.enabled ) {\n\t\t\t\tsteps.push( new uw.controller.Deed( this.api, this.config ) );\n\t\t\t}\n\n\t\t\tsteps.push(\n\t\t\t\tnew uw.controller.Details( this.api, this.config ),\n\t\t\t\tnew uw.controller.Thanks( this.api, this.config )\n\t\t\t);\n\n\t\t\t// The first step obviously does not have a previous step\n\t\t\tsteps[ 0 ].setNextStep( steps[ 1 ] );\n\n\t\t\t// The \"intermediate\" steps can navigate in both directions\n\t\t\tfor ( i = 1; i < steps.length - 1; i++ ) {\n\t\t\t\tsteps[ i ].setPreviousStep( steps[ i - 1 ] );\n\t\t\t\tsteps[ i ].setNextStep( steps[ i + 1 ] );\n\t\t\t}\n\n\t\t\t// The last step does not have a \"previous\" step, there's no undoing uploads!\n\t\t\t// The \"next\" one is always looping back to the upload step\n\t\t\tsteps[ steps.length - 1 ].setNextStep( uploadStep );\n\n\t\t\treturn $.Deferred().resolve( steps ).promise()\n\t\t\t\t.always( ( stepsInner ) => {\n\t\t\t\t\tself.steps = stepsInner;\n\t\t\t\t\tself.ui.initialiseSteps( stepsInner );\n\t\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * mw.Api's ajax calls are not very consistent in their error handling.\n\t\t * As long as the response comes back, the response will be fine: it'll\n\t\t * get rejected with the error details there. However, if no response\n\t\t * comes back for whatever reason, things can get confusing.\n\t\t * I'll monkeypatch around such cases so that we can always rely on the\n\t\t * error response the way we want it to be.\n\t\t *\n\t\t * TODO: Instead of this monkeypatching, we could call api.getErrorMessage()\n\t\t * in the error handlers to get nice messages.\n\t\t *\n\t\t * @param {Object} options\n\t\t * @return {mw.Api}\n\t\t */\n\t\tgetApi: function ( options ) {\n\t\t\tconst api = new mw.Api( options );\n\n\t\t\tapi.ajax = function ( parameters, ajaxOptions ) {\n\t\t\t\tlet original, override;\n\n\t\t\t\tObject.assign( parameters, {\n\t\t\t\t\terrorformat: 'html',\n\t\t\t\t\terrorlang: mw.config.get( 'wgUserLanguage' ),\n\t\t\t\t\terrorsuselocal: 1,\n\t\t\t\t\tformatversion: 2\n\t\t\t\t} );\n\n\t\t\t\toriginal = mw.Api.prototype.ajax.apply( this, [ parameters, ajaxOptions ] );\n\n\t\t\t\t// we'll attach a default error handler that makes sure error\n\t\t\t\t// output is always, reliably, in the same format\n\t\t\t\toverride = original.then(\n\t\t\t\t\tnull, // done handler - doesn't need overriding\n\t\t\t\t\t( code, result ) => { // fail handler\n\t\t\t\t\t\tlet response = { errors: [ {\n\t\t\t\t\t\t\tcode: code,\n\t\t\t\t\t\t\thtml: result.textStatus || mw.message( 'api-clientside-error-invalidresponse' ).parse()\n\t\t\t\t\t\t} ] };\n\n\t\t\t\t\t\tif ( result.errors && result.errors[ 0 ] ) {\n\t\t\t\t\t\t\t// in case of success-but-has-errors, we have a valid result\n\t\t\t\t\t\t\tresponse = result;\n\t\t\t\t\t\t} else if ( result && result.textStatus === 'timeout' ) {\n\t\t\t\t\t\t\t// in case of $.ajax.fail(), there is no response json\n\t\t\t\t\t\t\tresponse.errors[ 0 ].html = mw.message( 'api-clientside-error-timeout' ).parse();\n\t\t\t\t\t\t} else if ( result && result.textStatus === 'parsererror' ) {\n\t\t\t\t\t\t\tresponse.errors[ 0 ].html = mw.message( 'mediauploader-api-error-parsererror' ).parse();\n\t\t\t\t\t\t} else if ( code === 'http' && result && result.xhr && result.xhr.status === 0 ) {\n\t\t\t\t\t\t\t// failed to even connect to server\n\t\t\t\t\t\t\tresponse.errors[ 0 ].html = mw.message( 'api-clientside-error-noconnect' ).parse();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn $.Deferred().reject( code, response, response );\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\t/*\n\t\t\t\t * After attaching (.then) our error handler, a new promise is\n\t\t\t\t * returned. The original promise had an 'abort' method, which\n\t\t\t\t * we'll also want to make use of...\n\t\t\t\t */\n\t\t\t\treturn override.promise( { abort: original.abort } );\n\t\t\t};\n\n\t\t\treturn api;\n\t\t}\n\t};\n\n\t/**\n\t * Get the own work and third party licensing deeds if they are needed.\n\t *\n\t * @static\n\t * @since 1.2\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @param {Object} config The UW config object.\n\t * @param {string[]} [config.licensing.showTypes]\n\t * @return {mw.deed.Abstract[]}\n\t */\n\tmw.UploadWizard.getLicensingDeeds = function ( uploads, config ) {\n\t\tlet deed, api,\n\t\t\tdeeds = {},\n\t\t\tdoOwnWork = config.licensing.showTypes.includes( 'ownWork' ),\n\t\t\tdoThirdParty = config.licensing.showTypes.includes( 'thirdParty' );\n\n\t\tif ( !config.licensing.enabled ) {\n\t\t\treturn {\n\t\t\t\tnone: new uw.deed.None( config )\n\t\t\t};\n\t\t}\n\n\t\tapi = this.prototype.getApi( { ajax: { timeout: 0 } } );\n\n\t\tif ( doOwnWork ) {\n\t\t\tdeed = new uw.deed.OwnWork( config, uploads, api );\n\t\t\tdeeds[ deed.name ] = deed;\n\t\t}\n\t\tif ( doThirdParty ) {\n\t\t\tdeed = new uw.deed.ThirdParty( config, uploads, api );\n\t\t\tdeeds[ deed.name ] = deed;\n\t\t}\n\n\t\treturn deeds;\n\t};\n\n\t/**\n\t * Helper method to put a thumbnail somewhere.\n\t *\n\t * @param {string|jQuery} selector String representing a jQuery selector, or a jQuery object\n\t * @param {HTMLCanvasElement|HTMLImageElement|null} image\n\t */\n\tmw.UploadWizard.placeThumbnail = function ( selector, image ) {\n\t\tif ( image === null ) {\n\t\t\t$( selector ).addClass( 'mediauploader-file-preview-broken' );\n\t\t\treturn;\n\t\t}\n\n\t\t$( selector )\n\t\t\t.css( { background: 'none' } )\n\t\t\t.prepend(\n\t\t\t\t$( '<a>' )\n\t\t\t\t\t.addClass( 'mediauploader-thumbnail-link' )\n\t\t\t\t\t.append( image )\n\t\t\t);\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardDeedChooser.js","messages":[],"suppressedMessages":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":28,"column":14,"nodeType":"CallExpression","endLine":28,"endColumn":87,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":32,"column":22,"nodeType":"CallExpression","endLine":32,"endColumn":99,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":104,"column":4,"nodeType":"CallExpression","endLine":104,"endColumn":66,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":119,"column":5,"nodeType":"CallExpression","endLine":119,"endColumn":27,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":121,"column":10,"nodeType":"CallExpression","endLine":121,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-slide","severity":2,"message":"Prefer CSS transitions to .slideUp","line":126,"column":6,"nodeType":"CallExpression","endLine":126,"endColumn":26,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeTo","line":141,"column":4,"nodeType":"CallExpression","endLine":141,"endColumn":62,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":147,"column":5,"nodeType":"CallExpression","endLine":147,"endColumn":27,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":149,"column":10,"nodeType":"CallExpression","endLine":149,"endColumn":31,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-slide","severity":2,"message":"Prefer CSS transitions to .slideUp","line":153,"column":6,"nodeType":"CallExpression","endLine":153,"endColumn":31,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-slide","severity":2,"message":"Prefer CSS transitions to .slideDown","line":157,"column":5,"nodeType":"CallExpression","endLine":157,"endColumn":27,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardDetails.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'$moreDetailsWrapperDiv' is never reassigned. Use 'const' instead.","line":45,"column":8,"nodeType":"Identifier","messageId":"useConst","endLine":45,"endColumn":30},{"ruleId":"prefer-const","severity":2,"message":"'details' is never reassigned. Use 'const' instead.","line":47,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":47,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'config' is never reassigned. Use 'const' instead.","line":48,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":48,"endColumn":11},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":56,"column":13,"nodeType":"MemberExpression","messageId":"forbidden","endLine":56,"endColumn":26},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":73,"column":48,"nodeType":"MemberExpression","messageId":"forbidden","endLine":73,"endColumn":61},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":83,"column":40,"nodeType":"MemberExpression","messageId":"forbidden","endLine":83,"endColumn":53},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":90,"column":55,"nodeType":"MemberExpression","messageId":"forbidden","endLine":90,"endColumn":68},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":98,"column":57,"nodeType":"MemberExpression","messageId":"forbidden","endLine":98,"endColumn":70},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":105,"column":44,"nodeType":"MemberExpression","messageId":"forbidden","endLine":105,"endColumn":57},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":113,"column":47,"nodeType":"MemberExpression","messageId":"forbidden","endLine":113,"endColumn":60},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":118,"column":51,"nodeType":"MemberExpression","messageId":"forbidden","endLine":118,"endColumn":64},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":123,"column":53,"nodeType":"MemberExpression","messageId":"forbidden","endLine":123,"endColumn":66},{"ruleId":"prefer-const","severity":2,"message":"'$moreDetailsDiv' is never reassigned. Use 'const' instead.","line":151,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":151,"endColumn":19},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":215,"column":5,"nodeType":"CallExpression","endLine":221,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":255,"column":4,"nodeType":"CallExpression","endLine":257,"endColumn":13},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":383,"column":4,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":383,"endColumn":6},{"ruleId":"implicit-arrow-linebreak","severity":2,"message":"Expected no linebreak before this expression.","line":383,"column":6,"nodeType":"Identifier","messageId":"unexpected","endLine":383,"endColumn":17},{"ruleId":"no-mixed-spaces-and-tabs","severity":2,"message":"Mixed spaces and tabs.","line":384,"column":3,"nodeType":"Program","messageId":"mixedSpacesAndTabs","endLine":384,"endColumn":5},{"ruleId":"prefer-const","severity":2,"message":"'yyyyMmDdRegex' is never reassigned. Use 'const' instead.","line":448,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":448,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'timeRegex' is never reassigned. Use 'const' instead.","line":449,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":449,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'dateInfo' is never reassigned. Use 'const' instead.","line":470,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":470,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'saneTime' is never reassigned. Use 'const' instead.","line":508,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":508,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'m' is never reassigned. Use 'const' instead.","line":601,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":601,"endColumn":6},{"ruleId":"prefer-const","severity":2,"message":"'values' is never reassigned. Use 'const' instead.","line":603,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":603,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'languages' is never reassigned. Use 'const' instead.","line":653,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":653,"endColumn":13},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"JSDoc @return declaration present but return expression not available in function.","line":662,"column":3,"nodeType":"Block","endLine":670,"endColumn":6},{"ruleId":"prefer-const","severity":2,"message":"'serialized' is never reassigned. Use 'const' instead.","line":672,"column":21,"nodeType":"Identifier","messageId":"useConst","endLine":672,"endColumn":31},{"ruleId":"prefer-const","severity":2,"message":"'substitutions' is never reassigned. Use 'const' instead.","line":734,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":734,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'substList' is never reassigned. Use 'const' instead.","line":734,"column":25,"nodeType":"Identifier","messageId":"useConst","endLine":734,"endColumn":34},{"ruleId":"prefer-const","severity":2,"message":"'deed' is never reassigned. Use 'const' instead.","line":735,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":735,"endColumn":9},{"ruleId":"es-x/no-regexp-u-flag","severity":1,"message":"ES2015 RegExp 'u' flag is forbidden.","line":793,"column":10,"nodeType":"NewExpression","messageId":"forbidden","endLine":793,"endColumn":84},{"ruleId":"prefer-const","severity":2,"message":"'details' is never reassigned. Use 'const' instead.","line":813,"column":8,"nodeType":"Identifier","messageId":"useConst","endLine":813,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'wikitext' is never reassigned. Use 'const' instead.","line":823,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":823,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'promise' is never reassigned. Use 'const' instead.","line":824,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":824,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'tags' is never reassigned. Use 'const' instead.","line":843,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":843,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'deed' is never reassigned. Use 'const' instead.","line":844,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":844,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'config' is never reassigned. Use 'const' instead.","line":846,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":846,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'params' is never reassigned. Use 'const' instead.","line":869,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":869,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'details' is never reassigned. Use 'const' instead.","line":936,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":936,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'deferred' is never reassigned. Use 'const' instead.","line":939,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":939,"endColumn":13}],"suppressedMessages":[],"errorCount":29,"fatalErrorCount":0,"warningCount":11,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tconst NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;\n\n\t/**\n\t * Object that represents the Details (step 2) portion of the UploadWizard\n\t * n.b. each upload gets its own details.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t * @param {jQuery} $containerDiv The `div` to put the interface into\n\t */\n\tmw.UploadWizardDetails = function ( upload, $containerDiv ) {\n\t\tthis.upload = upload;\n\t\tthis.$containerDiv = $containerDiv;\n\t\tthis.api = upload.api;\n\n\t\tthis.fieldList = [];\n\t\tthis.fieldMap = {};\n\t\tthis.fieldWrapperList = [];\n\t\tthis.fieldWrapperMap = {};\n\n\t\t// This widget has to be initialized early for\n\t\t// useCustomDeedChooser() to work.\n\t\tthis.deedChooserDetails = new uw.DeedChooserDetailsWidget();\n\t\tthis.customDeedChooser = false;\n\n\t\tif ( !mw.UploadWizard.config.licensing.enabled ) {\n\t\t\t// Create a pseudo-deed chooser if licensing is disabled\n\t\t\tthis.upload.deedChooser = {\n\t\t\t\tdeed: new uw.deed.None( mw.UploadWizard.config )\n\t\t\t};\n\t\t}\n\n\t\tthis.$div = $( '<div>' ).addClass( 'mediauploader-info-file ui-helper-clearfix filled' );\n\t};\n\n\tmw.UploadWizardDetails.prototype = {\n\t\t// Has this details object been attached to the DOM already?\n\t\tisAttached: false,\n\n\t\t/**\n\t\t * Build the interface and attach all elements - do this on demand.\n\t\t */\n\t\tbuildInterface: function () {\n\t\t\tlet $moreDetailsWrapperDiv, $moreDetailsDiv,\n\t\t\t\tfKey, fSpec, fieldWidget, fieldWrapper, fConfigBase,\n\t\t\t\tdetails = this,\n\t\t\t\tconfig = mw.UploadWizard.config;\n\n\t\t\tthis.$thumbnailDiv = $( '<div>' ).addClass( 'mediauploader-thumbnail mediauploader-thumbnail-side' );\n\n\t\t\tthis.$dataDiv = $( '<div>' ).addClass( 'mediauploader-data' );\n\n\t\t\tfor ( fKey in config.fields ) {\n\t\t\t\t// Make a deep copy\n\t\t\t\tfSpec = Object.assign( {}, config.fields[ fKey ] );\n\t\t\t\tfSpec.key = fKey;\n\t\t\t\tfSpec.enabled = fSpec.enabled === undefined ? true : fSpec.enabled;\n\t\t\t\t// Override the label in case it wasn't set\n\t\t\t\tfSpec.label = fSpec.label ? $( $.parseHTML( fSpec.label ) ) : fSpec.key;\n\n\t\t\t\t// Common settings for all fields\n\t\t\t\tfConfigBase = {\n\t\t\t\t\trequired: fSpec.required === 'required',\n\t\t\t\t\trecommended: fSpec.required === 'recommended',\n\t\t\t\t\tfieldName: fSpec.label,\n\t\t\t\t\tdisabled: !fSpec.enabled\n\t\t\t\t};\n\n\t\t\t\tfieldWidget = null;\n\t\t\t\tswitch ( fSpec.type ) {\n\t\t\t\t\tcase 'title':\n\t\t\t\t\t\tfieldWidget = new uw.TitleDetailsWidget( Object.assign( {}, fConfigBase, {\n\t\t\t\t\t\t\t// Normalize file extension, e.g. 'JPEG' to 'jpg'\n\t\t\t\t\t\t\textension: mw.UploadWizard.config.content.titleField === fKey ?\n\t\t\t\t\t\t\t\tmw.Title.normalizeExtension( this.upload.title.getExtension() ) : '',\n\t\t\t\t\t\t\tminLength: fSpec.minLength || 5,\n\t\t\t\t\t\t\tmaxLength: fSpec.maxLength || 240\n\t\t\t\t\t\t} ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'text':\n\t\t\t\t\tcase 'textarea':\n\t\t\t\t\t\tfieldWidget = new uw.TextWidget( Object.assign( {}, fConfigBase, {\n\t\t\t\t\t\t\tdisabled: !fSpec.enabled,\n\t\t\t\t\t\t\tminLength: fSpec.minLength,\n\t\t\t\t\t\t\tmaxLength: fSpec.maxLength\n\t\t\t\t\t\t} ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'singlelang':\n\t\t\t\t\t\tfieldWidget = new uw.SingleLanguageInputWidget( Object.assign( {}, fConfigBase, {\n\t\t\t\t\t\t\tcanBeRemoved: false,\n\t\t\t\t\t\t\tlanguages: this.getLanguageOptions(),\n\t\t\t\t\t\t\tminLength: fSpec.minLength,\n\t\t\t\t\t\t\tmaxLength: fSpec.maxLength\n\t\t\t\t\t\t} ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'multilang':\n\t\t\t\t\t\tfieldWidget = new uw.MultipleLanguageInputWidget( Object.assign( {}, fConfigBase, {\n\t\t\t\t\t\t\tlanguages: this.getLanguageOptions(),\n\t\t\t\t\t\t\tminLength: fSpec.minLength,\n\t\t\t\t\t\t\tmaxLength: fSpec.maxLength\n\t\t\t\t\t\t} ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'select':\n\t\t\t\t\t\tfieldWidget = new uw.DropdownWidget( Object.assign( {}, fConfigBase, {\n\t\t\t\t\t\t\toptions: fSpec.options\n\t\t\t\t\t\t} ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'license':\n\t\t\t\t\t\tfieldWidget = this.deedChooserDetails;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'date':\n\t\t\t\t\t\tfieldWidget = new uw.DateDetailsWidget( Object.assign( {}, fConfigBase, {\n\t\t\t\t\t\t\tupload: this.upload\n\t\t\t\t\t\t} ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'location':\n\t\t\t\t\t\tfieldWidget = new uw.LocationDetailsWidget( Object.assign( {}, fConfigBase, {\n\t\t\t\t\t\t\tfields: fSpec.fields\n\t\t\t\t\t\t} ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'categories':\n\t\t\t\t\t\tfieldWidget = new uw.CategoriesDetailsWidget( Object.assign( {}, fConfigBase, {\n\t\t\t\t\t\t\thiddenDefault: fSpec.hiddenDefault,\n\t\t\t\t\t\t\tmissingWikitext: fSpec.missingWikitext\n\t\t\t\t\t\t} ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t// Can't build the widget, ignore it\n\t\t\t\t\t\tmw.error( \"Can't build details widget\", fSpec );\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthis.fieldList.push( fSpec );\n\t\t\t\tthis.fieldMap[ fKey ] = fieldWidget;\n\t\t\t}\n\n\t\t\tthis.fieldList.sort( ( a, b ) => {\n\t\t\t\tif ( a.order < b.order ) {\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\tif ( a.order > b.order ) {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t} );\n\n\t\t\t// Build the form for the file upload\n\t\t\tthis.$form = $( '<form id=\"mediauploader-detailsform' + this.upload.index + '\"></form>' )\n\t\t\t\t.addClass( 'detailsForm' );\n\t\t\t$moreDetailsDiv = $( '<div>' );\n\n\t\t\tthis.fieldList.forEach( function ( spec ) {\n\t\t\t\tfieldWidget = this.fieldMap[ spec.key ];\n\t\t\t\tfieldWrapper = new uw.FieldLayout( fieldWidget, {\n\t\t\t\t\trequired: spec.type === 'license' || spec.required === 'required',\n\t\t\t\t\tlabel: spec.label,\n\t\t\t\t\thelp: spec.help ? $( $.parseHTML( spec.help ) ) : null\n\t\t\t\t} );\n\t\t\t\tif ( spec.type === 'license' ) {\n\t\t\t\t\tfieldWrapper.toggle( this.customDeedChooser ); // See useCustomDeedChooser()\n\t\t\t\t} else if ( spec.hidden ) {\n\t\t\t\t\tfieldWrapper.toggle( false );\n\t\t\t\t}\n\n\t\t\t\t// Apply field defaults\n\t\t\t\tthis.prefillField( spec, fieldWidget );\n\n\t\t\t\t// List of fields for validation etc.\n\t\t\t\tthis.fieldWrapperList.push( fieldWrapper );\n\t\t\t\tthis.fieldWrapperMap[ spec.key ] = fieldWrapper;\n\n\t\t\t\t// Add the field wrapper to HTML of the form\n\t\t\t\tif ( spec.auxiliary ) {\n\t\t\t\t\t$moreDetailsDiv.append( fieldWrapper.$element );\n\t\t\t\t\t// If something changes the input \"hidden\" in the collapsed section,\n\t\t\t\t\t// expand it.\n\t\t\t\t\tfieldWidget.on( 'change', () => {\n\t\t\t\t\t\t$moreDetailsWrapperDiv.data( 'mw-collapsible' ).expand();\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\tthis.$form.append( fieldWrapper.$element );\n\t\t\t\t}\n\t\t\t}, this );\n\n\t\t\t// Wrap the auxiliary fields in a dropdown\n\t\t\t$moreDetailsWrapperDiv = $( '<div>' ).addClass( 'mwe-more-details' );\n\t\t\t$moreDetailsWrapperDiv\n\t\t\t\t.append(\n\t\t\t\t\t$( '<a>' ).text( mw.msg( 'mediauploader-more-options' ) )\n\t\t\t\t\t\t.prepend( $( '<span>' ).addClass( 'mw-toggle-icon' ) )\n\t\t\t\t\t\t.addClass( 'mediauploader-details-more-options mw-collapsible-toggle mw-collapsible-arrow' ),\n\t\t\t\t\t$moreDetailsDiv.addClass( 'mw-collapsible-content' )\n\t\t\t\t)\n\t\t\t\t.makeCollapsible( { collapsed: true } );\n\n\t\t\tthis.$form.on( 'submit', ( e ) => {\n\t\t\t\t// Prevent actual form submission\n\t\t\t\te.preventDefault();\n\t\t\t} );\n\n\t\t\tthis.$form.append(\n\t\t\t\t$moreDetailsWrapperDiv\n\t\t\t);\n\n\t\t\t// Add in remove control to form\n\t\t\tthis.removeCtrl = new OO.ui.ButtonWidget( {\n\t\t\t\tlabel: mw.message( 'mediauploader-remove' ).text(),\n\t\t\t\ttitle: mw.message( 'mediauploader-remove-upload' ).text(),\n\t\t\t\tclasses: [ 'mediauploader-remove-upload' ],\n\t\t\t\tflags: 'destructive',\n\t\t\t\ticon: 'trash',\n\t\t\t\tframed: false\n\t\t\t} ).on( 'click', () => {\n\t\t\t\tOO.ui.confirm( mw.message( 'mediauploader-license-confirm-remove' ).text(), {\n\t\t\t\t\ttitle: mw.message( 'mediauploader-license-confirm-remove-title' ).text()\n\t\t\t\t} ).done( ( confirmed ) => {\n\t\t\t\t\tif ( confirmed ) {\n\t\t\t\t\t\tdetails.upload.emit( 'remove-upload' );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\tthis.$thumbnailDiv.append( this.removeCtrl.$element );\n\n\t\t\tthis.statusMessage = new OO.ui.MessageWidget( { inline: true } );\n\t\t\tthis.statusMessage.toggle( false );\n\t\t\tthis.$spinner = $.createSpinner( { size: 'small', type: 'inline' } );\n\t\t\tthis.$spinner.hide();\n\t\t\tthis.$indicator = $( '<div>' ).addClass( 'mediauploader-file-indicator' ).append(\n\t\t\t\tthis.$spinner,\n\t\t\t\tthis.statusMessage.$element\n\t\t\t);\n\n\t\t\tthis.$submittingDiv = $( '<div>' ).addClass( 'mediauploader-submitting' )\n\t\t\t\t.append(\n\t\t\t\t\tthis.$indicator,\n\t\t\t\t\t$( '<div>' ).addClass( 'mediauploader-details-texts' ).append(\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mediauploader-visible-file-filename-text' ),\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mediauploader-file-status-line' )\n\t\t\t\t\t)\n\t\t\t\t);\n\n\t\t\tthis.$dataDiv.append(\n\t\t\t\tthis.$form,\n\t\t\t\tthis.$submittingDiv\n\t\t\t).morphCrossfader();\n\n\t\t\tthis.$div.append(\n\t\t\t\tthis.$thumbnailDiv,\n\t\t\t\tthis.$dataDiv\n\t\t\t);\n\n\t\t\t// This must match the CSS dimensions of .mediauploader-thumbnail\n\t\t\tthis.upload.getThumbnail( 230 ).done( function ( thumb ) {\n\t\t\t\tmw.UploadWizard.placeThumbnail( this.$thumbnailDiv, thumb );\n\t\t\t}, this );\n\n\t\t\tthis.interfaceBuilt = true;\n\n\t\t\tif ( this.savedSerialData ) {\n\t\t\t\tthis.setSerialized( this.savedSerialData );\n\t\t\t\tthis.savedSerialData = undefined;\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t * Append the div for this details object to the DOM.\n\t\t * We need to ensure that we add divs in the right order\n\t\t * (the order in which the user selected files).\n\t\t *\n\t\t * Will only append once.\n\t\t */\n\t\tattach: function () {\n\t\t\tconst $window = $( window ),\n\t\t\t\tdetails = this;\n\n\t\t\tfunction maybeBuild() {\n\t\t\t\tif ( !this.interfaceBuilt && $window.scrollTop() + $window.height() + 1000 >= details.$div.offset().top ) {\n\t\t\t\t\tdetails.buildInterface();\n\t\t\t\t\t$window.off( 'scroll', maybeBuild );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !this.isAttached ) {\n\t\t\t\tthis.$containerDiv.append( this.$div );\n\n\t\t\t\tif ( $window.scrollTop() + $window.height() + 1000 >= this.$div.offset().top ) {\n\t\t\t\t\tthis.buildInterface();\n\t\t\t\t} else {\n\t\t\t\t\t$window.on( 'scroll', maybeBuild );\n\t\t\t\t}\n\n\t\t\t\tthis.isAttached = true;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Get file page title for this upload.\n\t\t *\n\t\t * @return {mw.Title|null}\n\t\t */\n\t\tgetTitle: function () {\n\t\t\tconst titleField = mw.UploadWizard.config.content.titleField;\n\n\t\t\t// title will not be set until we've actually submitted the file\n\t\t\tif ( this.title === undefined ) {\n\t\t\t\treturn this.fieldMap[ titleField ].getTitle();\n\t\t\t}\n\n\t\t\t// once the file has been submitted, we'll have confirmation on\n\t\t\t// the filename and trust the authoritative source over own input\n\t\t\treturn this.title;\n\t\t},\n\n\t\t/**\n\t\t * Display error message about multiple uploaded files with the same title specified\n\t\t *\n\t\t * @return {mw.UploadWizardDetails}\n\t\t * @chainable\n\t\t */\n\t\tsetDuplicateTitleError: function () {\n\t\t\tconst titleField = mw.UploadWizard.config.content.titleField;\n\t\t\t// TODO This should give immediate response, not only when submitting the form\n\t\t\tthis.fieldWrapperMap[ titleField ].setErrors(\n\t\t\t\t[ mw.message( 'mediauploader-error-title-duplicate' ) ]\n\t\t\t);\n\t\t\treturn this;\n\t\t},\n\n\t\t/**\n\t\t * Toggles whether we use the 'macro' deed or our own.\n\t\t */\n\t\tuseCustomDeedChooser: function () {\n\t\t\tthis.customDeedChooser = true;\n\t\t\tthis.deedChooserDetails.useCustomDeedChooser( this.upload );\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t *\n\t\t * @return {uw.FieldLayout[]}\n\t\t */\n\t\tgetAllFields: function () {\n\t\t\treturn [].concat(\n\t\t\t\tthis.fieldWrapperList,\n\t\t\t\tthis.upload.deedChooser.deed ? this.upload.deedChooser.deed.getFields() : []\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Check all the fields for validity.\n\t\t *\n\t\t * @return {jQuery.Promise} Promise resolved with multiple array arguments, each containing a\n\t\t *   list of error messages for a single field. If API requests necessary to check validity\n\t\t *   fail, the promise may be rejected. The form is valid if the promise is resolved with all\n\t\t *   empty arrays.\n\t\t */\n\t\tgetErrors: function () {\n\t\t\treturn $.when.apply( $, this.getAllFields().map( ( fieldLayout ) => fieldLayout.fieldWidget.getErrors() ) );\n\t\t},\n\n\t\t/**\n\t\t * Check all the fields for warnings.\n\t\t *\n\t\t * @return {jQuery.Promise} Same as #getErrors\n\t\t */\n\t\tgetWarnings: function () {\n\t\t\treturn $.when.apply( $, this.getAllFields().map( ( fieldLayout ) => fieldLayout.fieldWidget.getWarnings() ) );\n\t\t},\n\n\t\t/**\n\t\t * Check all the fields for errors and warnings and display them in the UI.\n\t\t *\n\t\t * @param {boolean} thorough True to perform a thorough validity check. Defaults to false for a fast on-change check.\n\t\t * @return {jQuery.Promise} Combined promise of all fields' validation results.\n\t\t */\n\t\tcheckValidity: function ( thorough ) {\n\t\t\tconst fields = this.getAllFields();\n\n\t\t\treturn $.when.apply( $, fields.map( ( fieldLayout ) =>\n\t\t\t\t// Update any error/warning messages\n\t\t\t\t fieldLayout.checkValidity( thorough )\n\t\t\t ) );\n\t\t},\n\n\t\t/**\n\t\t * Get a thumbnail caption for this upload (basically, the first caption).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tgetThumbnailCaption: function () {\n\t\t\tconst captionField = mw.UploadWizard.config.content.captionField;\n\n\t\t\t// The caption field should be one of:\n\t\t\t// TextWidget, SingleLanguageInputWidget, MultipleLanguageInputWidget\n\t\t\treturn this.fieldMap[ captionField ].getCaption();\n\t\t},\n\n\t\t/**\n\t\t * Prefills the statically (defaults) and dynamically available info\n\t\t * for the file (from EXIF etc.), for the given field.\n\t\t *\n\t\t * @param {Object} fSpec\n\t\t * @param {uw.DetailsWidget} widget\n\t\t */\n\t\tprefillField: function ( fSpec, widget ) {\n\t\t\tlet dynPrefilled = false;\n\n\t\t\t// Try dynamic prefilling, if requested and available for this type\n\t\t\tif ( fSpec.autoFill ) {\n\t\t\t\tswitch ( fSpec.type ) {\n\t\t\t\t\tcase 'title':\n\t\t\t\t\t\tdynPrefilled = this.prefillTitle( widget );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'text':\n\t\t\t\t\tcase 'textarea':\n\t\t\t\t\tcase 'singlelang':\n\t\t\t\t\tcase 'multilang':\n\t\t\t\t\t\tdynPrefilled = this.prefillDescription( fSpec.type, widget );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'date':\n\t\t\t\t\t\tdynPrefilled = this.prefillDate( widget );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'location':\n\t\t\t\t\t\tdynPrefilled = this.prefillLocation( widget );\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !dynPrefilled && fSpec.default !== undefined ) {\n\t\t\t\twidget.setSerialized( fSpec.default );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Check if we got an EXIF date back and enter it into the details\n\t\t * XXX We ought to be using date + time here...\n\t\t * EXIF examples tend to be in ISO 8601, but the separators are sometimes things like colons, and they have lots of trailing info\n\t\t * (which we should actually be using, such as time and timezone)\n\t\t *\n\t\t * @param {uw.DateDetailsWidget} widget\n\t\t * @return {boolean}\n\t\t */\n\t\tprefillDate: function ( widget ) {\n\t\t\tlet dateObj, metadata, dateStr, saneTime,\n\t\t\t\tdateMode = 'calendar',\n\t\t\t\tyyyyMmDdRegex = /^(\\d\\d\\d\\d)[:/-](\\d\\d)[:/-](\\d\\d)\\D.*/,\n\t\t\t\ttimeRegex = /\\D(\\d\\d):(\\d\\d):(\\d\\d)/;\n\n\t\t\t// XXX surely we have this function somewhere already\n\t\t\tfunction pad( n ) {\n\t\t\t\treturn ( n < 10 ? '0' : '' ) + String( n );\n\t\t\t}\n\n\t\t\tfunction getSaneTime( date ) {\n\t\t\t\tlet str = '';\n\n\t\t\t\tstr += pad( date.getHours() ) + ':';\n\t\t\t\tstr += pad( date.getMinutes() ) + ':';\n\t\t\t\tstr += pad( date.getSeconds() );\n\n\t\t\t\treturn str;\n\t\t\t}\n\n\t\t\tif ( this.upload.imageinfo.metadata ) {\n\t\t\t\tmetadata = this.upload.imageinfo.metadata;\n\t\t\t\t[ 'datetimeoriginal', 'datetimedigitized', 'datetime', 'date' ].some( ( propName ) => {\n\t\t\t\t\tlet matches, timeMatches,\n\t\t\t\t\t\tdateInfo = metadata[ propName ];\n\t\t\t\t\tif ( dateInfo ) {\n\t\t\t\t\t\tmatches = dateInfo.trim().match( yyyyMmDdRegex );\n\t\t\t\t\t\tif ( matches ) {\n\t\t\t\t\t\t\ttimeMatches = dateInfo.trim().match( timeRegex );\n\t\t\t\t\t\t\tif ( timeMatches ) {\n\t\t\t\t\t\t\t\tdateObj = new Date( parseInt( matches[ 1 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( matches[ 2 ], 10 ) - 1,\n\t\t\t\t\t\t\t\t\tparseInt( matches[ 3 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( timeMatches[ 1 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( timeMatches[ 2 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( timeMatches[ 3 ], 10 ) );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdateObj = new Date( parseInt( matches[ 1 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( matches[ 2 ], 10 ) - 1,\n\t\t\t\t\t\t\t\t\tparseInt( matches[ 3 ], 10 ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true; // break from Array.some\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// if we don't have EXIF or other metadata, just don't put a date in.\n\t\t\t// XXX if we have FileAPI, it might be clever to look at file attrs, saved\n\t\t\t// in the upload object for use here later, perhaps\n\t\t\tif ( dateObj === undefined ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tdateStr = dateObj.getFullYear() + '-' + pad( dateObj.getMonth() + 1 ) + '-' + pad( dateObj.getDate() );\n\n\t\t\t// Add the time\n\t\t\t// If the date but not the time is set in EXIF data, we'll get a bogus\n\t\t\t// time value of '00:00:00'.\n\t\t\t// FIXME: Check for missing time value earlier rather than blacklisting\n\t\t\t// a potentially legitimate time value.\n\t\t\tsaneTime = getSaneTime( dateObj );\n\t\t\tif ( saneTime !== '00:00:00' ) {\n\t\t\t\tdateStr += ' ' + saneTime;\n\n\t\t\t\t// Switch to freeform date field. DateInputWidget (with calendar) handles dates only, not times.\n\t\t\t\tdateMode = 'arbitrary';\n\t\t\t}\n\n\t\t\t// ok by now we should definitely have a dateObj and a date string\n\t\t\twidget.setSerialized( {\n\t\t\t\tmode: dateMode,\n\t\t\t\tvalue: dateStr\n\t\t\t} );\n\n\t\t\treturn true;\n\t\t},\n\n\t\t/**\n\t\t * Set the title of the thing we just uploaded, visibly\n\t\t *\n\t\t * @param {uw.TitleDetailsWidget} widget\n\t\t * @return {boolean}\n\t\t */\n\t\tprefillTitle: function ( widget ) {\n\t\t\twidget.setSerialized( {\n\t\t\t\ttitle: this.upload.title.getNameText()\n\t\t\t} );\n\t\t\treturn true;\n\t\t},\n\n\t\t/**\n\t\t * Prefill the image description if we have a description\n\t\t *\n\t\t * Note that this is not related to specifying the description from the query\n\t\t * string (that happens earlier). This is for when we have retrieved a\n\t\t * description from an upload_by_url upload or from the metadata.\n\t\t *\n\t\t * @param {string} type\n\t\t * @param {uw.TextWidget} widget\n\t\t * @return {boolean}\n\t\t */\n\t\tprefillDescription: function ( type, widget ) {\n\t\t\tlet m, descText;\n\n\t\t\tif (\n\t\t\t\twidget.getWikiText() === '' &&\n\t\t\t\tthis.upload.file !== undefined\n\t\t\t) {\n\t\t\t\tm = this.upload.imageinfo.metadata;\n\t\t\t\tdescText = this.upload.file.description ||\n\t\t\t\t\t( m && m.imagedescription && m.imagedescription[ 0 ] && m.imagedescription[ 0 ].value );\n\n\t\t\t\tif ( !descText ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t// strip out any HTML tags\n\t\t\t\tdescText = descText.replace( /<[^>]+>/g, '' );\n\n\t\t\t\t// Set the text – both singlelang and multilang can fall back to\n\t\t\t\t// a simple string serialization.\n\t\t\t\twidget.setSerialized( descText.trim() );\n\n\t\t\t\t// Set the language – probably wrong in many cases...\n\t\t\t\tif ( type === 'singlelang' ) {\n\t\t\t\t\twidget.setLanguage(\n\t\t\t\t\t\twidget.getClosestAllowedLanguage( mw.config.get( 'wgContentLanguage' ) )\n\t\t\t\t\t);\n\t\t\t\t} else if ( type === 'multilang' ) {\n\t\t\t\t\twidget.getItems()[ 0 ].setLanguage(\n\t\t\t\t\t\twidget.getItems()[ 0 ].getClosestAllowedLanguage(\n\t\t\t\t\t\t\tmw.config.get( 'wgContentLanguage' )\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\t/**\n\t\t * Prefill location input from image info and metadata\n\t\t *\n\t\t * As of MediaWiki 1.18, the exif parser translates the rational GPS data tagged by the camera\n\t\t * to decimal format. Let's just use that.\n\t\t *\n\t\t * @param {uw.LocationDetailsWidget} widget\n\t\t * @return {boolean}\n\t\t */\n\t\tprefillLocation: function ( widget ) {\n\t\t\tlet dir,\n\t\t\t\tm = this.upload.imageinfo.metadata,\n\t\t\t\tmodified = false,\n\t\t\t\tvalues = {};\n\n\t\t\tif ( m ) {\n\t\t\t\tdir = m.gpsimgdirection || m.gpsdestbearing;\n\n\t\t\t\tif ( dir ) {\n\t\t\t\t\tif ( dir.match( /^\\d+\\/\\d+$/ ) !== null ) {\n\t\t\t\t\t\t// Apparently it can take the form \"x/y\" instead of\n\t\t\t\t\t\t// a decimal value. Mighty silly, but let's save it.\n\t\t\t\t\t\tdir = dir.split( '/' );\n\t\t\t\t\t\tdir = parseInt( dir[ 0 ], 10 ) / parseInt( dir[ 1 ], 10 );\n\t\t\t\t\t}\n\n\t\t\t\t\tvalues.heading = dir;\n\n\t\t\t\t\tmodified = true;\n\t\t\t\t}\n\n\t\t\t\t// Prefill useful stuff only\n\t\t\t\tif ( Number( m.gpslatitude ) && Number( m.gpslongitude ) ) {\n\t\t\t\t\tvalues.latitude = m.gpslatitude;\n\t\t\t\t\tvalues.longitude = m.gpslongitude;\n\t\t\t\t\tmodified = true;\n\t\t\t\t} else if (\n\t\t\t\t\tthis.upload.file &&\n\t\t\t\t\tthis.upload.file.location &&\n\t\t\t\t\tthis.upload.file.location.latitude &&\n\t\t\t\t\tthis.upload.file.location.longitude\n\t\t\t\t) {\n\t\t\t\t\tvalues.latitude = this.upload.file.location.latitude;\n\t\t\t\t\tvalues.longitude = this.upload.file.location.longitude;\n\t\t\t\t\tmodified = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( modified ) {\n\t\t\t\twidget.setSerialized( values );\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\n\t\t/**\n\t\t * Returns the language list to use in (Single|Multiple)LanguageInputWidget\n\t\t *\n\t\t * @return {Object}\n\t\t */\n\t\tgetLanguageOptions: function () {\n\t\t\tlet languages, code;\n\n\t\t\tlanguages = {};\n\t\t\tfor ( code in mw.UploadWizard.config.languages ) {\n\t\t\t\tif ( Object.prototype.hasOwnProperty.call( mw.UploadWizard.config.languages, code ) ) {\n\t\t\t\t\tlanguages[ code ] = mw.UploadWizard.config.languages[ code ];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn languages;\n\t\t},\n\n\t\t/**\n\t\t * Get a machine-readable representation of the current state of the upload details. It can be\n\t\t * passed to #setSerialized to restore this state (or to set it for another instance of the same\n\t\t * class).\n\t\t *\n\t\t * Note that this doesn't include custom deed's state.\n\t\t *\n\t\t * @return {Object.<string,Object>}\n\t\t */\n\t\tgetSerialized: function () {\n\t\t\tlet fieldWidget, serialized = {};\n\n\t\t\tif ( !this.interfaceBuilt ) {\n\t\t\t\t// We don't have the interface yet, but it'll get filled out as\n\t\t\t\t// needed.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.fieldList.forEach( function ( fSpec ) {\n\t\t\t\tfieldWidget = this.fieldMap[ fSpec.key ];\n\t\t\t\tserialized[ fSpec.key ] = fieldWidget.getSerialized();\n\t\t\t}, this );\n\n\t\t\treturn serialized;\n\t\t},\n\n\t\t/**\n\t\t * Set the state of this widget from machine-readable representation, as returned by\n\t\t * #getSerialized.\n\t\t *\n\t\t * Fields from the representation can be omitted to keep the current value.\n\t\t *\n\t\t * @param {Object.<string,Object>} [serialized]\n\t\t */\n\t\tsetSerialized: function ( serialized ) {\n\t\t\tif ( !this.interfaceBuilt ) {\n\t\t\t\t// There's no interface yet! Don't load the data, just keep it\n\t\t\t\t// around.\n\t\t\t\tif ( serialized === undefined ) {\n\t\t\t\t\t// Note: This will happen if we \"undo\" a copy operation while\n\t\t\t\t\t// some of the details interfaces aren't loaded.\n\t\t\t\t\tthis.savedSerialData = undefined;\n\t\t\t\t} else {\n\t\t\t\t\tthis.savedSerialData = $.extend( true,\n\t\t\t\t\t\tthis.savedSerialData || {},\n\t\t\t\t\t\tserialized\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( serialized === undefined ) {\n\t\t\t\t// This is meaningless if the interface is already built.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.fieldList.forEach( function ( fSpec ) {\n\t\t\t\tif ( serialized[ fSpec.key ] ) {\n\t\t\t\t\tthis.fieldMap[ fSpec.key ].setSerialized( serialized[ fSpec.key ] );\n\t\t\t\t}\n\t\t\t}, this );\n\t\t},\n\n\t\t/**\n\t\t * Convert entire details for this file into wikiText, which will then be posted to the file\n\t\t *\n\t\t * This function assumes that all input is valid.\n\t\t *\n\t\t * @return {string} wikitext representing all details\n\t\t */\n\t\tgetWikiText: function () {\n\t\t\tlet wikiText = mw.UploadWizard.config.content.wikitext,\n\t\t\t\tsubstitutions = {}, substList = [],\n\t\t\t\tdeed = this.upload.deedChooser.deed,\n\t\t\t\tfieldWidget, serialized, valueType, re, escapedKey, replaceValue;\n\n\t\t\tif ( !wikiText ) {\n\t\t\t\twikiText = mw.message( 'mediauploader-default-content-wikitext' ).plain();\n\t\t\t}\n\t\t\tif ( mw.UploadWizard.config.content.prepend ) {\n\t\t\t\twikiText = mw.UploadWizard.config.content.prepend + '\\n' + wikiText;\n\t\t\t}\n\t\t\tif ( mw.UploadWizard.config.content.append ) {\n\t\t\t\twikiText += '\\n' + mw.UploadWizard.config.content.append;\n\t\t\t}\n\n\t\t\tfunction addSubstitution( key, value ) {\n\t\t\t\tlet v = value;\n\t\t\t\tif ( key in substitutions ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Discard funny values that toString poorly\n\t\t\t\tif ( v === undefined || v === null || ( typeof v === 'number' && isNaN( v ) ) ) {\n\t\t\t\t\tv = '';\n\t\t\t\t}\n\t\t\t\tsubstList.push( key );\n\t\t\t\tsubstitutions[ key ] = v.toString();\n\t\t\t}\n\n\t\t\t// Add hardcoded substitutions\n\t\t\taddSubstitution( 'source', deed.getSourceWikiText( this.upload ) );\n\t\t\taddSubstitution( 'author', deed.getAuthorWikiText( this.upload ) );\n\t\t\taddSubstitution( 'license', deed.getLicenseWikiText() );\n\n\t\t\t// Add substitutions for all the defined details fields\n\t\t\tthis.fieldList.forEach( function ( spec ) {\n\t\t\t\tif ( spec.type === 'license' ) {\n\t\t\t\t\t// Skip the license input... it is handled separately above.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tfieldWidget = this.fieldMap[ spec.key ];\n\t\t\t\taddSubstitution( spec.key, fieldWidget.getWikiText() );\n\t\t\t\tserialized = fieldWidget.getSerializedParsed();\n\t\t\t\tif ( typeof serialized !== 'object' ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Also add \"subfields\" based on the serialized values. Just in case.\n\t\t\t\tObject.keys( serialized ).forEach( ( key ) => {\n\t\t\t\t\treplaceValue = serialized[ key ];\n\t\t\t\t\tvalueType = typeof replaceValue;\n\t\t\t\t\tif ( valueType === 'string' || valueType === 'number' || valueType === 'boolean' ) {\n\t\t\t\t\t\taddSubstitution( spec.key + '.' + key, replaceValue );\n\t\t\t\t\t}\n\t\t\t\t}, this );\n\t\t\t}, this );\n\n\t\t\t// Do the substitutions\n\t\t\tsubstList.forEach( ( substKey ) => {\n\t\t\t\treplaceValue = substitutions[ substKey ].trim();\n\t\t\t\tescapedKey = substKey.replace( /[.*+?^${}()|[\\]\\\\]/g, '\\\\$&' );\n\t\t\t\tre = new RegExp( '\\\\{\\\\{\\\\{ *' + escapedKey + ' *(\\\\|(.*?))?\\\\}\\\\}\\\\}', 'giu' );\n\t\t\t\twikiText = wikiText.replace( re, ( match, _, defaultValue ) => {\n\t\t\t\t\tif ( !replaceValue ) {\n\t\t\t\t\t\treturn defaultValue || '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn replaceValue;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}, this );\n\n\t\t\t// remove too many newlines in a row\n\t\t\twikiText = wikiText.replace( /\\n{3,}/g, '\\n\\n' );\n\n\t\t\treturn wikiText;\n\t\t},\n\n\t\t/**\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmit: function () {\n\t\t\tlet details = this,\n\t\t\t\twikitext, promise;\n\n\t\t\tthis.$containerDiv.find( 'form' ).trigger( 'submit' );\n\n\t\t\tthis.upload.title = this.getTitle();\n\t\t\tthis.upload.state = 'submitting-details';\n\t\t\tthis.setStatus( mw.message( 'mediauploader-submitting-details' ).text() );\n\t\t\tthis.showIndicator( 'progress' );\n\n\t\t\twikitext = this.getWikiText();\n\t\t\tpromise = this.submitWikiText( wikitext );\n\n\t\t\treturn promise.then( () => {\n\t\t\t\tdetails.showIndicator( 'success' );\n\t\t\t\tdetails.setStatus( mw.message( 'mediauploader-published' ).text() );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Post wikitext as edited here, to the file\n\t\t *\n\t\t * This function is only called if all input seems valid (which doesn't mean that we can't get\n\t\t * an error, see #processError).\n\t\t *\n\t\t * @param {string} wikiText\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmitWikiText: function ( wikiText ) {\n\t\t\tlet params,\n\t\t\t\ttags = [ 'uploadwizard' ],\n\t\t\t\tdeed = this.upload.deedChooser.deed,\n\t\t\t\tcomment = '',\n\t\t\t\tconfig = mw.UploadWizard.config;\n\n\t\t\tthis.firstPoll = Date.now();\n\n\t\t\tif ( this.upload.file.source ) {\n\t\t\t\ttags.push( 'uploadwizard-' + this.upload.file.source );\n\t\t\t}\n\n\t\t\tif ( deed.name === 'ownwork' ) {\n\t\t\t\t// This message does not have any parameters, so there's nothing to substitute\n\t\t\t\tcomment = config.uploadComment.ownWork;\n\t\t\t} else {\n\t\t\t\tmw.messages.set(\n\t\t\t\t\t'mediauploader-upload-comment-third-party',\n\t\t\t\t\tconfig.uploadComment.thirdParty\n\t\t\t\t);\n\t\t\t\tcomment = mw.message(\n\t\t\t\t\t'mediauploader-upload-comment-third-party',\n\t\t\t\t\tdeed.getAuthorWikiText(),\n\t\t\t\t\tdeed.getSourceWikiText()\n\t\t\t\t).plain();\n\t\t\t}\n\n\t\t\tparams = {\n\t\t\t\taction: 'upload',\n\t\t\t\tfilekey: this.upload.fileKey,\n\t\t\t\tfilename: this.getTitle().getMain(),\n\t\t\t\tcomment: comment,\n\t\t\t\ttags: config.CanAddTags ? tags : [],\n\t\t\t\t// we can ignore upload warnings here, we've already checked\n\t\t\t\t// when stashing the file\n\t\t\t\t// not ignoring warnings would prevent us from uploading a file\n\t\t\t\t// that is a duplicate of something in a foreign repo\n\t\t\t\tignorewarnings: true,\n\t\t\t\ttext: wikiText\n\t\t\t};\n\n\t\t\t// Only enable async publishing if file is larger than 10MiB\n\t\t\tif ( this.upload.transportWeight > 10 * 1024 * 1024 ) {\n\t\t\t\tparams.async = true;\n\t\t\t}\n\n\t\t\treturn this.submitWikiTextInternal( params );\n\t\t},\n\n\t\t/**\n\t\t * Perform the API call with given parameters (which is expected to publish this file) and\n\t\t * handle the result.\n\t\t *\n\t\t * @param {Object} params API call parameters\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmitWikiTextInternal: function ( params ) {\n\t\t\tconst details = this,\n\t\t\t\tapiPromise = this.upload.api.postWithEditToken( params );\n\n\t\t\treturn apiPromise\n\t\t\t\t// process the successful (in terms of HTTP status...) API call first:\n\t\t\t\t// there may be warnings or other issues with the upload that need\n\t\t\t\t// to be dealt with\n\t\t\t\t.then( this.validateWikiTextSubmitResult.bind( this, params ) )\n\t\t\t\t// making it here means the upload is a success, or it would've been\n\t\t\t\t// rejected by now (either by HTTP status code, or in validateWikiTextSubmitResult)\n\t\t\t\t.then( ( result ) => {\n\t\t\t\t\tdetails.title = mw.Title.makeTitle( 6, result.upload.filename );\n\t\t\t\t\tdetails.upload.extractImageInfo( result.upload.imageinfo );\n\t\t\t\t\tdetails.upload.thisProgress = 1.0;\n\t\t\t\t\tdetails.upload.state = 'complete';\n\t\t\t\t\treturn result;\n\t\t\t\t} )\n\t\t\t\t// uh-oh - something went wrong!\n\t\t\t\t.catch( ( code, result ) => {\n\t\t\t\t\tdetails.upload.state = 'error';\n\t\t\t\t\tdetails.processError( code, result );\n\t\t\t\t\treturn $.Deferred().reject( code, result );\n\t\t\t\t} )\n\t\t\t\t.promise( { abort: apiPromise.abort } );\n\t\t},\n\n\t\t/**\n\t\t * Validates the result of a submission & returns a resolved promise with\n\t\t * the API response if all went well, or rejects with error code & error\n\t\t * message as you would expect from failed mediawiki API calls.\n\t\t *\n\t\t * @param {Object} params What we passed to the API that caused this response.\n\t\t * @param {Object} result API result of an upload or status check.\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tvalidateWikiTextSubmitResult: function ( params, result ) {\n\t\t\tlet wx, warningsKeys, existingFile, existingFileUrl, existingFileExt, ourFileExt, code, message,\n\t\t\t\tdetails = this,\n\t\t\t\twarnings = null,\n\t\t\t\tignoreTheseWarnings = false,\n\t\t\t\tdeferred = $.Deferred();\n\n\t\t\tif ( result && result.upload && result.upload.result === 'Poll' ) {\n\t\t\t\t// if async publishing takes longer than 10 minutes give up\n\t\t\t\tif ( ( Date.now() - this.firstPoll ) > 10 * 60 * 1000 ) {\n\t\t\t\t\treturn deferred.reject( 'server-error', { errors: [ {\n\t\t\t\t\t\tcode: 'server-error',\n\t\t\t\t\t\thtml: 'Unknown server error'\n\t\t\t\t\t} ] } );\n\t\t\t\t} else {\n\t\t\t\t\tif ( result.upload.stage === undefined ) {\n\t\t\t\t\t\treturn deferred.reject( 'no-stage', { errors: [ {\n\t\t\t\t\t\t\tcode: 'no-stage',\n\t\t\t\t\t\t\thtml: 'Unable to check file\\'s status'\n\t\t\t\t\t\t} ] } );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Messages that can be returned:\n\t\t\t\t\t\t// * mediauploader-queued\n\t\t\t\t\t\t// * mediauploader-publish\n\t\t\t\t\t\t// * mediauploader-assembling\n\t\t\t\t\t\tthis.setStatus( mw.message( 'mediauploader-' + result.upload.stage ).text() );\n\t\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\t\tif ( details.upload.state !== 'aborted' ) {\n\t\t\t\t\t\t\t\tdetails.submitWikiTextInternal( {\n\t\t\t\t\t\t\t\t\taction: 'upload',\n\t\t\t\t\t\t\t\t\tcheckstatus: true,\n\t\t\t\t\t\t\t\t\tfilekey: details.upload.fileKey\n\t\t\t\t\t\t\t\t} ).then( deferred.resolve, deferred.reject );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdeferred.resolve( 'aborted' );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 3000 );\n\n\t\t\t\t\t\treturn deferred.promise();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( result && result.upload && result.upload.warnings ) {\n\t\t\t\twarnings = result.upload.warnings;\n\t\t\t}\n\t\t\tif ( warnings && warnings.exists ) {\n\t\t\t\texistingFile = warnings.exists;\n\t\t\t} else if ( warnings && warnings[ 'exists-normalized' ] ) {\n\t\t\t\texistingFile = warnings[ 'exists-normalized' ];\n\t\t\t\texistingFileExt = mw.Title.normalizeExtension( existingFile.split( '.' ).pop() );\n\t\t\t\tourFileExt = mw.Title.normalizeExtension( this.getTitle().getExtension() );\n\n\t\t\t\tif ( existingFileExt !== ourFileExt ) {\n\t\t\t\t\tdelete warnings[ 'exists-normalized' ];\n\t\t\t\t\tignoreTheseWarnings = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( warnings && warnings[ 'was-deleted' ] ) {\n\t\t\t\tdelete warnings[ 'was-deleted' ];\n\t\t\t\tignoreTheseWarnings = true;\n\t\t\t}\n\t\t\tfor ( wx in warnings ) {\n\t\t\t\tif ( Object.prototype.hasOwnProperty.call( warnings, wx ) ) {\n\t\t\t\t\t// if there are other warnings, deal with those first\n\t\t\t\t\tignoreTheseWarnings = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( result && result.upload && result.upload.imageinfo ) {\n\t\t\t\treturn $.Deferred().resolve( result );\n\t\t\t} else if ( ignoreTheseWarnings ) {\n\t\t\t\tparams.ignorewarnings = 1;\n\t\t\t\treturn this.submitWikiTextInternal( params );\n\t\t\t} else if ( result && result.upload && result.upload.warnings ) {\n\t\t\t\tif ( warnings.thumb || warnings[ 'thumb-name' ] ) {\n\t\t\t\t\tcode = 'error-title-thumbnail';\n\t\t\t\t\tmessage = mw.message( 'mediauploader-error-title-thumbnail' ).parse();\n\t\t\t\t} else if ( warnings.badfilename ) {\n\t\t\t\t\tcode = 'title-invalid';\n\t\t\t\t\tmessage = mw.message( 'mediauploader-error-title-invalid' ).parse();\n\t\t\t\t} else if ( warnings[ 'bad-prefix' ] ) {\n\t\t\t\t\tcode = 'title-senselessimagename';\n\t\t\t\t\tmessage = mw.message( 'mediauploader-error-title-senselessimagename' ).parse();\n\t\t\t\t} else if ( existingFile ) {\n\t\t\t\t\texistingFileUrl = mw.config.get( 'wgServer' ) + mw.Title.makeTitle( NS_FILE, existingFile ).getUrl();\n\t\t\t\t\tcode = 'api-warning-exists';\n\t\t\t\t\tmessage = mw.message( 'mediauploader-api-warning-exists', existingFileUrl ).parse();\n\t\t\t\t} else if ( warnings.duplicate ) {\n\t\t\t\t\tcode = 'upload-error-duplicate';\n\t\t\t\t\tmessage = mw.message( 'mediauploader-upload-error-duplicate' ).parse();\n\t\t\t\t} else if ( warnings[ 'duplicate-archive' ] !== undefined ) {\n\t\t\t\t\t// warnings[ 'duplicate-archive' ] may be '' (empty string) for revdeleted files\n\t\t\t\t\tif ( this.upload.handler.isIgnoredWarning( 'duplicate-archive' ) ) {\n\t\t\t\t\t\t// We already told the interface to ignore this warning, so\n\t\t\t\t\t\t// let's steamroll over it and re-call this handler.\n\t\t\t\t\t\tparams.ignorewarnings = true;\n\t\t\t\t\t\treturn this.submitWikiTextInternal( params );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// This should _never_ happen, but just in case....\n\t\t\t\t\t\tcode = 'upload-error-duplicate-archive';\n\t\t\t\t\t\tmessage = mw.message( 'mediauploader-upload-error-duplicate-archive' ).parse();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\twarningsKeys = Object.keys( warnings );\n\t\t\t\t\tcode = 'unknown-warning';\n\t\t\t\t\tmessage = mw.message( 'mediauploader-api-error-unknown-warning', warningsKeys.join( ', ' ) ).parse();\n\t\t\t\t}\n\n\t\t\t\treturn $.Deferred().reject( code, { errors: [ { html: message } ] } );\n\t\t\t} else {\n\t\t\t\treturn $.Deferred().reject( 'this-info-missing', result );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Create a recoverable error -- show the form again, and highlight the problematic field.\n\t\t *\n\t\t * @param {string} code\n\t\t * @param {string} html Error message to show.\n\t\t */\n\t\trecoverFromError: function ( code, html ) {\n\t\t\tconst titleField = mw.UploadWizard.config.content.titleField;\n\n\t\t\tthis.upload.state = 'recoverable-error';\n\t\t\tthis.$dataDiv.morphCrossfade( '.detailsForm' );\n\t\t\tthis.fieldWrapperMap[ titleField ].setErrors( [ { code: code, html: html } ] );\n\t\t},\n\n\t\t/**\n\t\t * Show error state, possibly using a recoverable error form\n\t\t *\n\t\t * @param {string} code Error code\n\t\t * @param {string} html Error message\n\t\t */\n\t\tshowError: function ( code, html ) {\n\t\t\tthis.showIndicator( 'error' );\n\t\t\tthis.setStatus( html );\n\t\t},\n\n\t\t/**\n\t\t * Decide how to treat various errors\n\t\t *\n\t\t * @param {string} code Error code\n\t\t * @param {Object} result Result from ajax call\n\t\t */\n\t\tprocessError: function ( code, result ) {\n\t\t\tconst recoverable = [\n\t\t\t\t'abusefilter-disallowed',\n\t\t\t\t'abusefilter-warning',\n\t\t\t\t'spamblacklist',\n\t\t\t\t'fileexists-shared-forbidden',\n\t\t\t\t'protectedpage',\n\t\t\t\t'titleblacklist-forbidden',\n\n\t\t\t\t// below are not actual API errors, but recoverable warnings that have\n\t\t\t\t// been discovered in validateWikiTextSubmitResult and fabricated to resemble\n\t\t\t\t// API errors and end up here to be dealt with\n\t\t\t\t'error-title-thumbnail',\n\t\t\t\t'title-invalid',\n\t\t\t\t'title-senselessimagename',\n\t\t\t\t'api-warning-exists',\n\t\t\t\t'upload-error-duplicate',\n\t\t\t\t'upload-error-duplicate',\n\t\t\t\t'upload-error-duplicate-archive',\n\t\t\t\t'unknown-warning'\n\t\t\t];\n\n\t\t\tif ( code === 'badtoken' ) {\n\t\t\t\tthis.api.badToken( 'csrf' );\n\t\t\t\t// TODO Automatically try again instead of requiring the user to bonk the button\n\t\t\t}\n\n\t\t\tif ( code === 'ratelimited' ) {\n\t\t\t\t// None of the remaining uploads is going to succeed, and every failed one is going to\n\t\t\t\t// ping the rate limiter again.\n\t\t\t\tthis.upload.wizard.steps.details.queue.abortExecuting();\n\t\t\t} else if ( code === 'http' && result && result.exception === 'abort' ) {\n\t\t\t\t// This upload has just been aborted because an earlier one got the 'ratelimited' error.\n\t\t\t\t// This could potentially also come up when an upload is removed by the user, but in that\n\t\t\t\t// case the UI is invisible anyway, so whatever.\n\t\t\t\tcode = 'ratelimited';\n\t\t\t}\n\n\t\t\tif ( recoverable.includes( code ) ) {\n\t\t\t\tthis.recoverFromError( code, result.errors[ 0 ].html );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.showError( code, result.errors[ 0 ].html );\n\t\t},\n\n\t\tsetStatus: function ( s ) {\n\t\t\tthis.$div.find( '.mediauploader-file-status-line' ).html( s ).show();\n\t\t},\n\n\t\t// TODO: De-duplicate with code form mw.UploadWizardUploadInterface.js\n\t\tshowIndicator: function ( status ) {\n\t\t\tthis.$spinner.hide();\n\t\t\tthis.statusMessage.toggle( false );\n\n\t\t\tif ( status === 'progress' ) {\n\t\t\t\tthis.$spinner.show();\n\t\t\t} else if ( status ) {\n\t\t\t\tthis.statusMessage.toggle( true ).setType( status );\n\t\t\t}\n\t\t\tthis.$indicator.toggleClass( 'mediauploader-file-indicator-visible', !!status );\n\t\t},\n\n\t\tsetVisibleTitle: function ( s ) {\n\t\t\t$( this.$submittingDiv )\n\t\t\t\t.find( '.mediauploader-visible-file-filename-text' )\n\t\t\t\t.text( s );\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardLicenseInput.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'self' is never reassigned. Use 'const' instead.","line":17,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":17,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'groups' is never reassigned. Use 'const' instead.","line":18,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":18,"endColumn":10},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":77,"column":2,"nodeType":"MemberExpression","messageId":"forbidden","endLine":77,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'templates' is never reassigned. Use 'const' instead.","line":183,"column":9,"nodeType":"Identifier","messageId":"useConst","endLine":183,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'addError' is never reassigned. Use 'const' instead.","line":209,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":209,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'selectedInputs' is never reassigned. Use 'const' instead.","line":216,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":216,"endColumn":19},{"ruleId":"prefer-const","severity":2,"message":"'data' is never reassigned. Use 'const' instead.","line":226,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":226,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'wikitext' is never reassigned. Use 'const' instead.","line":232,"column":6,"nodeType":"Identifier","messageId":"useConst","endLine":232,"endColumn":14},{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":268,"column":28,"nodeType":"MemberExpression","messageId":"forbidden","endLine":268,"endColumn":41}],"suppressedMessages":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":212,"column":24,"nodeType":"CallExpression","endLine":212,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":7,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * Create a group of radio buttons for licenses. N.B. the licenses are named after the templates they invoke.\n\t * Note that this is very anti-MVC. The values are held only in the actual form elements themselves.\n\t *\n\t * @extends OO.ui.Widget\n\t * @param {Object} config Configuration. Must have following properties:\n\t * @param {string} config.type Whether inclusive or exclusive license allowed (\"and\"|\"or\")\n\t * @param {string[]} config.licenses Template string names (matching keys in mw.UploadWizard.config.licenses)\n\t * @param {string[]} [config.licenseGroups] Groups of licenses, with more explanation\n\t * @param {string} [config.special] Indicates, don't put licenses here, instead use a special widget\n\t * @param {number} count Number of the things we are licensing (it matters to some texts)\n\t * @param {mw.Api} api API object, used for wikitext previews\n\t */\n\tmw.UploadWizardLicenseInput = function ( config, count, api ) {\n\t\tlet self = this,\n\t\t\tgroups = [],\n\t\t\tgroup;\n\n\t\tmw.UploadWizardLicenseInput.parent.call( this );\n\t\tOO.ui.mixin.GroupElement.call( this );\n\n\t\tthis.count = count;\n\n\t\tthis.api = api;\n\n\t\tif (\n\t\t\tconfig.type === undefined ||\n\t\t\t( config.licenses === undefined && config.licenseGroups === undefined )\n\t\t) {\n\t\t\tthrow new Error( 'improper initialization' );\n\t\t}\n\n\t\tthis.type = config.type;\n\t\tthis.defaults = [];\n\t\tif ( config.defaults ) {\n\t\t\tthis.defaults = config.defaults instanceof Array ? config.defaults : [ config.defaults ];\n\t\t} else if ( config.licenses && config.licenses[ 0 ] ) {\n\t\t\tthis.defaults = [ config.licenses[ 0 ] ];\n\t\t}\n\n\t\t// create inputs and licenses from config\n\t\tif ( config.licenseGroups === undefined ) {\n\t\t\tgroup = new uw.LicenseGroup( config, this.type, this.api, this.count );\n\t\t\tgroups.push( group );\n\t\t} else {\n\t\t\tconfig.licenseGroups.forEach( ( groupConfig ) => {\n\t\t\t\tgroup = new uw.LicenseGroup( groupConfig, self.type, self.api, self.count );\n\t\t\t\tgroups.push( group );\n\n\t\t\t\t// if we have multiple radio groups, it would be possible to select a radio\n\t\t\t\t// from each group; we obviously don't want that to happen!\n\t\t\t\t// upon selecting a new item in any group, iterate the other groups and make\n\t\t\t\t// sure they're updated accordingly, deselecting previously selected items\n\t\t\t\tif ( self.type === 'radio' ) {\n\t\t\t\t\tgroup.on( 'change', ( currentGroup ) => {\n\t\t\t\t\t\tconst value = currentGroup.getValue(),\n\t\t\t\t\t\t\tgroup2 = currentGroup.getGroup();\n\t\t\t\t\t\tself.setValues( value, group2 );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tthis.addItems( groups );\n\t\tthis.aggregate( { change: 'change' } );\n\t\tthis.$element.append( this.$group );\n\n\t\t// [wikitext => list of templates used in wikitext] map, used in\n\t\t// getUsedTemplates to reduce amount of API calls\n\t\tthis.templateCache = {};\n\t};\n\tOO.inheritClass( mw.UploadWizardLicenseInput, OO.ui.Widget );\n\tOO.mixinClass( mw.UploadWizardLicenseInput, OO.ui.mixin.GroupElement );\n\n\tObject.assign( mw.UploadWizardLicenseInput.prototype, {\n\t\tunload: function () {\n\t\t\tthis.getItems().forEach( ( group ) => {\n\t\t\t\tgroup.unload();\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Sets the value(s) of a license input. This is a little bit klugey because it relies on an inverted dict, and in some\n\t\t * cases we are now letting license inputs create multiple templates.\n\t\t *\n\t\t * @param {Object} values License-key to boolean values, e.g. { 'cc_by_sa_30': true, gfdl: false }\n\t\t * @param {string} [groupName] Name of group, when values are only relevant to this group\n\t\t */\n\t\tsetValues: function ( values, groupName ) {\n\t\t\tconst self = this,\n\t\t\t\tselectedGroups = [];\n\n\t\t\tthis.getItems().forEach( ( group ) => {\n\t\t\t\tif ( groupName === undefined || group.getGroup() === groupName ) {\n\t\t\t\t\tgroup.setValue( values );\n\t\t\t\t\tif ( Object.keys( group.getValue() ).length > 0 ) {\n\t\t\t\t\t\tselectedGroups.push( group );\n\t\t\t\t\t}\n\t\t\t\t} else if ( self.type === 'radio' ) {\n\t\t\t\t\t// when we're dealing with radio buttons and there are changes in another\n\t\t\t\t\t// group, then we'll need to clear out this group...\n\t\t\t\t\tgroup.setValue( {} );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif ( selectedGroups.length > 1 && this.type === 'radio' ) {\n\t\t\t\t// leave the last one alone - that one can remain selected\n\t\t\t\tselectedGroups.pop();\n\n\t\t\t\t// if we've selected things in multiple groups (= when the group was not defined,\n\t\t\t\t// which is basically only when dealing with defaults, from config or user\n\t\t\t\t// preferences), we need to make sure we're left with only 1 selected radio in\n\t\t\t\t// 1 group\n\t\t\t\t// in that case, we're only going to select the *last* occurrence, which is what\n\t\t\t\t// a browser would do when trying to find/select a radio that occurs twice\n\t\t\t\tselectedGroups.forEach( ( group ) => {\n\t\t\t\t\tgroup.setValue( {} );\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Set the default configured licenses\n\t\t */\n\t\tsetDefaultValues: function () {\n\t\t\tconst values = {};\n\t\t\tthis.defaults.forEach( ( license ) => {\n\t\t\t\tvalues[ license ] = true;\n\t\t\t} );\n\t\t\tthis.setValues( values );\n\t\t},\n\n\t\t/**\n\t\t * Gets the selected license(s). The returned value will be a license\n\t\t * key => license props map, as defined in MediaUploader.config.php.\n\t\t *\n\t\t * @return {Object}\n\t\t */\n\t\tgetLicenses: function () {\n\t\t\tconst licenses = {};\n\n\t\t\tthis.getItems().forEach( ( group ) => {\n\t\t\t\tconst licenseNames = Object.keys( group.getValue() );\n\t\t\t\tlicenseNames.forEach( ( name ) => {\n\t\t\t\t\tlicenses[ name ] = mw.UploadWizard.config.licenses[ name ] || {};\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\treturn licenses;\n\t\t},\n\n\t\t/**\n\t\t * Gets the wikitext associated with all selected inputs.\n\t\t *\n\t\t * @return {string} of wikitext (empty string if no inputs set)\n\t\t */\n\t\tgetWikiText: function () {\n\t\t\treturn this.getItems().map( ( group ) => group.getWikiText() ).join( '' ).trim();\n\t\t},\n\n\t\t/**\n\t\t * Returns a list of templates used & transcluded in given wikitext\n\t\t *\n\t\t * @param {string} wikitext\n\t\t * @return {jQuery.Promise} Promise that resolves with an array of template names\n\t\t */\n\t\tgetUsedTemplates: function ( wikitext ) {\n\t\t\tconst input = this;\n\n\t\t\tif ( wikitext in this.templateCache ) {\n\t\t\t\treturn $.Deferred().resolve( this.templateCache[ wikitext ] ).promise();\n\t\t\t}\n\n\t\t\treturn this.api.get( {\n\t\t\t\taction: 'parse',\n\t\t\t\tpst: true,\n\t\t\t\tprop: 'templates',\n\t\t\t\ttitle: 'File:UploadWizard license verification.png',\n\t\t\t\ttext: wikitext\n\t\t\t} ).then( ( result ) => {\n\t\t\t\tlet templates = [],\n\t\t\t\t\ttemplate, title, i;\n\n\t\t\t\tfor ( i = 0; i < result.parse.templates.length; i++ ) {\n\t\t\t\t\ttemplate = result.parse.templates[ i ];\n\n\t\t\t\t\t// normalize templates to mw.Title.getPrefixedDb() format\n\t\t\t\t\ttitle = new mw.Title( template.title, template.ns );\n\t\t\t\t\ttemplates.push( title.getPrefixedDb() );\n\t\t\t\t}\n\n\t\t\t\t// cache result so we won't have to fire another API request\n\t\t\t\t// for the same content\n\t\t\t\tinput.templateCache[ wikitext ] = templates;\n\n\t\t\t\treturn templates;\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * See uw.DetailsWidget\n\t\t *\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tgetErrors: function () {\n\t\t\tlet errors = $.Deferred().resolve( [] ).promise(),\n\t\t\t\taddError = function ( message ) {\n\t\t\t\t\terrors = errors.then( ( errorsCopy ) => {\n\t\t\t\t\t\t// eslint-disable-next-line mediawiki/msg-doc\n\t\t\t\t\t\terrorsCopy.push( mw.message( message ) );\n\t\t\t\t\t\treturn errorsCopy;\n\t\t\t\t\t} );\n\t\t\t\t},\n\t\t\t\tselectedInputs = this.getSerialized();\n\n\t\t\tif ( Object.keys( selectedInputs ).length === 0 ) {\n\t\t\t\taddError( 'mediauploader-deeds-need-license' );\n\t\t\t} else {\n\t\t\t\t// It's pretty hard to screw up a radio button, so if even one of them is selected it's okay.\n\t\t\t\t// But also check that associated textareas are filled for if the input is selected, and that\n\t\t\t\t// they are the appropriate size.\n\t\t\t\tObject.keys( selectedInputs ).forEach( ( name ) => {\n\t\t\t\t\tlet wikitext,\n\t\t\t\t\t\tdata = selectedInputs[ name ];\n\n\t\t\t\t\tif ( typeof data !== 'string' ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\twikitext = data.trim();\n\n\t\t\t\t\tif ( wikitext === '' ) {\n\t\t\t\t\t\taddError( 'mediauploader-error-license-wikitext-missing' );\n\t\t\t\t\t} else if ( wikitext.length < mw.UploadWizard.config.minCustomLicenseLength ) {\n\t\t\t\t\t\taddError( 'mediauploader-error-license-wikitext-too-short' );\n\t\t\t\t\t} else if ( wikitext.length > mw.UploadWizard.config.maxCustomLicenseLength ) {\n\t\t\t\t\t\taddError( 'mediauploader-error-license-wikitext-too-long' );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn errors;\n\t\t},\n\n\t\t/**\n\t\t * See uw.DetailsWidget\n\t\t *\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tgetWarnings: function () {\n\t\t\treturn $.Deferred().resolve( [] ).promise();\n\t\t},\n\n\t\t/**\n\t\t * @return {Object}\n\t\t */\n\t\tgetSerialized: function () {\n\t\t\tconst values = {};\n\n\t\t\tthis.getItems().forEach( ( group ) => {\n\t\t\t\tconst groupName = group.getGroup(),\n\t\t\t\t\tvalue = group.getValue();\n\n\t\t\t\tif ( Object.keys( value ).length > 0 ) {\n\t\t\t\t\t// $.extend just in case there are multiple groups with the same name...\n\t\t\t\t\tvalues[ groupName ] = Object.assign( {}, values[ groupName ] || {}, value );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn values;\n\t\t},\n\n\t\t/**\n\t\t * @param {Object} serialized\n\t\t */\n\t\tsetSerialized: function ( serialized ) {\n\t\t\tconst self = this;\n\n\t\t\tObject.keys( serialized ).forEach( ( group ) => {\n\t\t\t\tself.setValues( serialized[ group ], group );\n\t\t\t} );\n\t\t}\n\n\t} );\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardPage.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'config' is never reassigned. Use 'const' instead.","line":31,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":31,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'uploadWizard' is never reassigned. Use 'const' instead.","line":53,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":53,"endColumn":15}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":38,"column":3,"nodeType":"CallExpression","endLine":38,"endColumn":28,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":41,"column":8,"nodeType":"CallExpression","endLine":41,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":49,"column":4,"nodeType":"CallExpression","endLine":49,"endColumn":37,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This script is run on [[Special:MediaUploader]].\n * Configures and creates an interface for uploading files in multiple steps, hence \"wizard\".\n *\n * Tries to transform Javascript globals dumped on us by the PHP code into a more\n * compact configuration, owned by the MediaUploader created.\n */\n\n// Create UploadWizard\n( function () {\n\n\tfunction isCompatible() {\n\t\tconst\n\t\t\tprofile = $.client.profile(),\n\t\t\t// Firefox < 7.0 sends an empty string as filename for Blobs in FormData.\n\t\t\t// requests. https://bugzilla.mozilla.org/show_bug.cgi?id=649150\n\t\t\tbadFormDataBlobs = profile.name === 'firefox' && profile.versionNumber < 7;\n\n\t\treturn !!(\n\t\t\twindow.FileReader &&\n\t\t\twindow.FormData &&\n\t\t\twindow.File &&\n\t\t\twindow.File.prototype.slice &&\n\t\t\t!badFormDataBlobs\n\t\t);\n\t}\n\n\tmw.UploadWizardPage = function () {\n\n\t\tlet uploadWizard,\n\t\t\tconfig = mw.config.get( 'MediaUploaderConfig' );\n\n\t\t// Default configuration value that cannot be removed\n\t\tconfig.maxUploads = config.maxUploads || 10;\n\n\t\t// Remove the initial spinner\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( '.mwe-first-spinner' ).remove();\n\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\tif ( $( '#upload-wizard' ).length === 0 ) {\n\t\t\tmw.log( 'MediaUploader is disabled, nothing to do.' );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !isCompatible() ) {\n\t\t\t// Display the same error message as for grade-C browsers\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( '.mediauploader-unavailable' ).show();\n\t\t\treturn;\n\t\t}\n\n\t\tuploadWizard = new mw.UploadWizard( config );\n\t\tuploadWizard.createInterface( '#upload-wizard' );\n\t};\n\n\t$( () => {\n\t\t// show page.\n\t\tmw.UploadWizardPage();\n\t} );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardUpload.js","messages":[{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"uw\" type.","line":8,"column":1,"nodeType":"Block","endLine":8,"endColumn":1},{"ruleId":"no-unused-vars","severity":1,"message":"'uw' is defined but never used.","line":11,"column":14,"nodeType":"Identifier","messageId":"unusedVar","endLine":11,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'deferred' is never reassigned. Use 'const' instead.","line":204,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":204,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'upload' is never reassigned. Use 'const' instead.","line":205,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":205,"endColumn":10},{"ruleId":"no-redeclare","severity":2,"message":"'Uint8Array' is already defined as a built-in global variable.","line":222,"column":16,"nodeType":"Block","messageId":"redeclaredAsBuiltin","endLine":222,"endColumn":26},{"ruleId":"es-x/no-typed-arrays","severity":1,"message":"ES2015 'Uint8Array' is forbidden.","line":223,"column":16,"nodeType":"Identifier","messageId":"forbidden","endLine":223,"endColumn":26},{"ruleId":"prefer-const","severity":2,"message":"'upload' is never reassigned. Use 'const' instead.","line":314,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":314,"endColumn":10},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":382,"column":3,"nodeType":"CallExpression","endLine":382,"endColumn":36},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":382,"column":3,"nodeType":"CallExpression","endLine":382,"endColumn":48},{"ruleId":"prefer-const","severity":2,"message":"'requestedTitle' is never reassigned. Use 'const' instead.","line":396,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":396,"endColumn":21},{"ruleId":"prefer-const","severity":2,"message":"'params' is never reassigned. Use 'const' instead.","line":430,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":430,"endColumn":9},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":448,"column":3,"nodeType":"CallExpression","endLine":448,"endColumn":36},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":448,"column":3,"nodeType":"CallExpression","endLine":448,"endColumn":48},{"ruleId":"prefer-const","severity":2,"message":"'image' is never reassigned. Use 'const' instead.","line":488,"column":21,"nodeType":"Identifier","messageId":"useConst","endLine":488,"endColumn":26},{"ruleId":"prefer-const","severity":2,"message":"'constraint' is never reassigned. Use 'const' instead.","line":585,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":585,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'scaling' is never reassigned. Use 'const' instead.","line":629,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":629,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'width' is never reassigned. Use 'const' instead.","line":631,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":631,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'height' is never reassigned. Use 'const' instead.","line":632,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":632,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'dx' is never reassigned. Use 'const' instead.","line":640,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":640,"endColumn":5},{"ruleId":"prefer-const","severity":2,"message":"'dy' is never reassigned. Use 'const' instead.","line":641,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":641,"endColumn":5},{"ruleId":"prefer-const","severity":2,"message":"'$canvas' is never reassigned. Use 'const' instead.","line":666,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":666,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'ctx' is never reassigned. Use 'const' instead.","line":667,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":667,"endColumn":6},{"ruleId":"prefer-const","severity":2,"message":"'constraints' is never reassigned. Use 'const' instead.","line":715,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":715,"endColumn":18},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":767,"column":3,"nodeType":"CallExpression","endLine":769,"endColumn":26},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":767,"column":3,"nodeType":"CallExpression","endLine":781,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":775,"column":6,"nodeType":"CallExpression","endLine":775,"endColumn":67},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":778,"column":7,"nodeType":"CallExpression","endLine":778,"endColumn":68},{"ruleId":"prefer-const","severity":2,"message":"'deferred' is never reassigned. Use 'const' instead.","line":802,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":802,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'upload' is never reassigned. Use 'const' instead.","line":803,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":803,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'canvas' is never reassigned. Use 'const' instead.","line":828,"column":9,"nodeType":"Identifier","messageId":"useConst","endLine":828,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'context' is never reassigned. Use 'const' instead.","line":831,"column":8,"nodeType":"Identifier","messageId":"useConst","endLine":831,"endColumn":15}],"suppressedMessages":[{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_binary_data'.","line":233,"column":6,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":233,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier '_binary_data' is not in camel case.","line":233,"column":11,"nodeType":"Identifier","messageId":"notCamelCase","endLine":233,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":28,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Represents the upload -- in its local and remote state. (Possibly those could be separate objects too...)\n * This is our 'model' object if we are thinking MVC. Needs to be better factored, lots of feature envy with the UploadWizard\n * states:\n * 'new' 'transporting' 'transported' 'metadata' 'stashed' 'details' 'submitting-details' 'complete' 'error'\n * should fork this into two -- local and remote, e.g. filename\n *\n * @param uw\n */\n\n( function ( uw ) {\n\t/**\n\t * Constructor for objects representing uploads. The workhorse of this entire extension.\n\t *\n\t * The upload knows nothing of other uploads. It manages its own interface, and transporting its own data, to\n\t * the server.\n\t *\n\t * Upload objects are usually created without a file, they are just associated with a form.\n\t * There is an \"empty\" fileInput which is invisibly floating above certain buttons in the interface, like \"Add a file\". When\n\t * this fileInput gets a file, this upload becomes 'filled'.\n\t *\n\t * @class mw.UploadWizardUpload\n\t * @constructor\n\t * @param {uw.controller.Step} controller\n\t * @param {File} file\n\t */\n\tmw.UploadWizardUpload = function MWUploadWizardUpload( controller, file ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.index = mw.UploadWizardUpload.prototype.count;\n\t\tmw.UploadWizardUpload.prototype.count++;\n\n\t\tthis.controller = controller;\n\t\tthis.api = controller.api;\n\t\tthis.file = file;\n\t\tthis.state = 'new';\n\t\tthis.imageinfo = {};\n\t\tthis.title = undefined;\n\t\tthis.thumbnailPromise = {};\n\n\t\tthis.fileKey = undefined;\n\n\t\t// this should be moved to the interface, if we even keep this\n\t\tthis.transportWeight = 1; // default all same\n\n\t\t// details\n\t\tthis.ui = new mw.UploadWizardUploadInterface( this )\n\t\t\t.connect( this, {\n\t\t\t\t/*\n\t\t\t\t * This may be confusing!\n\t\t\t\t * This object also has a `remove` method, which will also be\n\t\t\t\t * called when an upload is removed. But an upload can be\n\t\t\t\t * removed for multiple reasons (one being clicking the \"remove\"\n\t\t\t\t * button, which triggers this event - but another could be\n\t\t\t\t * removing faulty uploads).\n\t\t\t\t * To simplify things, we'll always initiate the remove from the\n\t\t\t\t * controllers, so we'll relay this event to the controllers,\n\t\t\t\t * which will then eventually come back to call `remove` on this\n\t\t\t\t * object.\n\t\t\t\t */\n\t\t\t\t'upload-removed': [ 'emit', 'remove-upload' ]\n\t\t\t} );\n\t};\n\n\tOO.mixinClass( mw.UploadWizardUpload, OO.EventEmitter );\n\n\t// Upload handler\n\tmw.UploadWizardUpload.prototype.uploadHandler = null;\n\n\t// increments with each upload\n\tmw.UploadWizardUpload.prototype.count = 0;\n\n\t/**\n\t * start\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tmw.UploadWizardUpload.prototype.start = function () {\n\t\tthis.setTransportProgress( 0.0 );\n\n\t\t// handler -- usually ApiUploadFormDataHandler\n\t\tthis.handler = this.getUploadHandler();\n\t\treturn this.handler.start();\n\t};\n\n\t/**\n\t * Remove this upload. n.b. we trigger a removeUpload this is usually triggered from\n\t */\n\tmw.UploadWizardUpload.prototype.remove = function () {\n\t\t// remove the div that passed along the trigger\n\t\tthis.ui.$div.remove();\n\n\t\tthis.state = 'aborted';\n\t};\n\n\t/**\n\t * Wear our current progress, for observing processes to see\n\t *\n\t * @param {number} fraction\n\t */\n\tmw.UploadWizardUpload.prototype.setTransportProgress = function ( fraction ) {\n\t\tif ( this.state === 'aborted' ) {\n\t\t\t// We shouldn't be transporting anything anymore.\n\t\t\treturn;\n\t\t}\n\t\tthis.state = 'transporting';\n\t\tthis.transportProgress = fraction;\n\t\tthis.ui.$div.trigger( 'transportProgressEvent' );\n\t};\n\n\t/**\n\t * Stop the upload -- we have failed for some reason\n\t *\n\t * @param {string} code Error code from API\n\t * @param {string} html Error message\n\t * @param {jQuery} [$additionalStatus]\n\t */\n\tmw.UploadWizardUpload.prototype.setError = function ( code, html, $additionalStatus ) {\n\t\tif ( this.state === 'aborted' ) {\n\t\t\t// There's no point in reporting an error anymore.\n\t\t\treturn;\n\t\t}\n\t\tthis.state = 'error';\n\t\tthis.transportProgress = 0;\n\t\tthis.ui.showError( code, html, $additionalStatus );\n\t};\n\n\t/**\n\t * Called from any upload success condition\n\t *\n\t * @param {Object} result -- result of AJAX call\n\t */\n\tmw.UploadWizardUpload.prototype.setSuccess = function ( result ) {\n\t\tthis.state = 'transported';\n\t\tthis.transportProgress = 1;\n\n\t\tthis.ui.setStatus( 'mediauploader-getting-metadata' );\n\n\t\tthis.extractUploadInfo( result.upload );\n\t\tthis.state = 'stashed';\n\t\tthis.ui.showStashed();\n\n\t\tthis.emit( 'success' );\n\t\t// check all uploads, if they're complete, show the next button\n\t\t// TODO Make wizard connect to 'success' event\n\t\tthis.controller.showNext();\n\t};\n\n\t/**\n\t * Get just the filename.\n\t *\n\t * @return {string}\n\t */\n\tmw.UploadWizardUpload.prototype.getFilename = function () {\n\t\tif ( this.file.fileName ) {\n\t\t\treturn this.file.fileName;\n\t\t} else {\n\t\t\t// this property has a different name in FF vs Chrome.\n\t\t\treturn this.file.name;\n\t\t}\n\t};\n\n\t/**\n\t * Get the basename of a path.\n\t * For error conditions, returns the empty string.\n\t *\n\t * @return {string} basename\n\t */\n\tmw.UploadWizardUpload.prototype.getBasename = function () {\n\t\tconst path = this.getFilename();\n\n\t\tif ( path === undefined || path === null ) {\n\t\t\treturn '';\n\t\t}\n\n\t\t// find index of last path separator in the path, add 1. (If no separator found, yields 0)\n\t\t// then take the entire string after that.\n\t\treturn path.slice( Math.max( path.lastIndexOf( '/' ), path.lastIndexOf( '\\\\' ) ) + 1 );\n\t};\n\n\t/**\n\t * Sanitize and set the title of the upload.\n\t *\n\t * @param {string} title Unsanitized title.\n\t */\n\tmw.UploadWizardUpload.prototype.setTitle = function ( title ) {\n\t\tthis.title = mw.Title.newFromFileName( title );\n\t};\n\n\t/**\n\t * Extract some JPEG metadata that we need to render thumbnails (EXIF rotation mostly).\n\t *\n\t * For JPEGs, we use the JsJpegMeta library in core to extract metadata,\n\t * including EXIF tags. This is done asynchronously once each file has been\n\t * read.\n\t *\n\t * For all other file types, we don't need or want to run this, and this function does nothing.\n\t *\n\t * @private\n\t * @return {jQuery.Promise} A promise, resolved when we're done\n\t */\n\tmw.UploadWizardUpload.prototype.extractMetadataFromJpegMeta = function () {\n\t\tlet binReader, jpegmeta,\n\t\t\tdeferred = $.Deferred(),\n\t\t\tupload = this;\n\t\tif ( this.file && this.file.type === 'image/jpeg' ) {\n\t\t\tbinReader = new FileReader();\n\t\t\tbinReader.onerror = function () {\n\t\t\t\tdeferred.resolve();\n\t\t\t};\n\t\t\tbinReader.onload = function () {\n\t\t\t\tlet binStr, arr, i, meta;\n\t\t\t\tif ( binReader.result === null ) {\n\t\t\t\t\t// Contrary to documentation, this sometimes fires for unsuccessful loads (T136235)\n\t\t\t\t\tdeferred.resolve();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif ( typeof binReader.result === 'string' ) {\n\t\t\t\t\tbinStr = binReader.result;\n\t\t\t\t} else {\n\t\t\t\t\t// Array buffer; convert to binary string for the library.\n\t\t\t\t\t/* global Uint8Array */\n\t\t\t\t\tarr = new Uint8Array( binReader.result );\n\t\t\t\t\tbinStr = '';\n\t\t\t\t\tfor ( i = 0; i < arr.byteLength; i++ ) {\n\t\t\t\t\t\tbinStr += String.fromCharCode( arr[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tjpegmeta = require( 'mediawiki.libs.jpegmeta' );\n\t\t\t\t\tmeta = jpegmeta( binStr, upload.file.fileName );\n\t\t\t\t\t// eslint-disable-next-line camelcase, no-underscore-dangle\n\t\t\t\t\tmeta._binary_data = null;\n\t\t\t\t} catch ( e ) {\n\t\t\t\t\tmeta = null;\n\t\t\t\t}\n\t\t\t\tupload.extractMetadataFromJpegMetaCallback( meta );\n\t\t\t\tdeferred.resolve();\n\t\t\t};\n\t\t\tif ( 'readAsBinaryString' in binReader ) {\n\t\t\t\tbinReader.readAsBinaryString( upload.file );\n\t\t\t} else if ( 'readAsArrayBuffer' in binReader ) {\n\t\t\t\tbinReader.readAsArrayBuffer( upload.file );\n\t\t\t}\n\t\t} else {\n\t\t\tdeferred.resolve();\n\t\t}\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Map fields from jpegmeta's metadata return into our format (which is more like the imageinfo returned from the API\n\t *\n\t * @param {Object} meta As returned by jpegmeta\n\t */\n\tmw.UploadWizardUpload.prototype.extractMetadataFromJpegMetaCallback = function ( meta ) {\n\t\tlet pixelHeightDim, pixelWidthDim, degrees;\n\n\t\tif ( meta !== undefined && meta !== null && typeof meta === 'object' ) {\n\t\t\tif ( this.imageinfo.metadata === undefined ) {\n\t\t\t\tthis.imageinfo.metadata = {};\n\t\t\t}\n\t\t\tif ( meta.tiff && meta.tiff.Orientation ) {\n\t\t\t\tthis.imageinfo.metadata.orientation = meta.tiff.Orientation.value;\n\t\t\t}\n\t\t\tif ( meta.general ) {\n\t\t\t\tpixelHeightDim = 'height';\n\t\t\t\tpixelWidthDim = 'width';\n\t\t\t\t// this must be called after orientation is set above. If no orientation set, defaults to 0\n\t\t\t\tdegrees = this.getOrientationDegrees();\n\n\t\t\t\t// jpegmeta reports pixelHeight & width\n\t\t\t\tif ( degrees === 90 || degrees === 270 ) {\n\t\t\t\t\tpixelHeightDim = 'width';\n\t\t\t\t\tpixelWidthDim = 'height';\n\t\t\t\t}\n\t\t\t\tif ( meta.general.pixelHeight ) {\n\t\t\t\t\tthis.imageinfo[ pixelHeightDim ] = meta.general.pixelHeight.value;\n\t\t\t\t}\n\t\t\t\tif ( meta.general.pixelWidth ) {\n\t\t\t\t\tthis.imageinfo[ pixelWidthDim ] = meta.general.pixelWidth.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Accept the result from a successful API upload transport, and fill our own info\n\t *\n\t * @param {Object} resultUpload The JSON object from a successful API upload result.\n\t */\n\tmw.UploadWizardUpload.prototype.extractUploadInfo = function ( resultUpload ) {\n\t\tif ( resultUpload.filekey ) {\n\t\t\tthis.fileKey = resultUpload.filekey;\n\t\t}\n\n\t\tif ( resultUpload.imageinfo ) {\n\t\t\tthis.extractImageInfo( resultUpload.imageinfo );\n\t\t} else if ( resultUpload.stashimageinfo ) {\n\t\t\tthis.extractImageInfo( resultUpload.stashimageinfo );\n\t\t}\n\n\t};\n\n\t/**\n\t * Extract image info into our upload object\n\t * Image info is obtained from various different API methods\n\t * This may overwrite metadata obtained from FileReader.\n\t *\n\t * @param {Object} imageinfo JSON object obtained from API result.\n\t */\n\tmw.UploadWizardUpload.prototype.extractImageInfo = function ( imageinfo ) {\n\t\tlet key,\n\t\t\tupload = this;\n\n\t\tfor ( key in imageinfo ) {\n\t\t\t// we get metadata as list of key-val pairs; convert to object for easier lookup. Assuming that EXIF fields are unique.\n\t\t\tif ( key === 'metadata' ) {\n\t\t\t\tif ( this.imageinfo.metadata === undefined ) {\n\t\t\t\t\tthis.imageinfo.metadata = {};\n\t\t\t\t}\n\t\t\t\tif ( imageinfo.metadata && imageinfo.metadata.length ) {\n\t\t\t\t\timageinfo.metadata.forEach( ( pair ) => {\n\t\t\t\t\t\tif ( pair !== undefined ) {\n\t\t\t\t\t\t\tupload.imageinfo.metadata[ pair.name.toLowerCase() ] = pair.value;\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.imageinfo[ key ] = imageinfo[ key ];\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Get information about stashed images\n\t *\n\t * See API documentation for prop=stashimageinfo for what 'props' can contain\n\t *\n\t * @param {Function} callback Called with null if failure, with imageinfo data structure if success\n\t * @param {Array} props Properties to extract\n\t * @param {number} [width] Width of thumbnail. Will force 'url' to be added to props\n\t * @param {number} [height] Height of thumbnail. Will force 'url' to be added to props\n\t */\n\tmw.UploadWizardUpload.prototype.getStashImageInfo = function ( callback, props, width, height ) {\n\t\tconst params = {\n\t\t\tprop: 'stashimageinfo',\n\t\t\tsiifilekey: this.fileKey,\n\t\t\tsiiprop: props.join( '|' )\n\t\t};\n\n\t\tfunction ok( data ) {\n\t\t\tif ( !data || !data.query || !data.query.stashimageinfo ) {\n\t\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getStashImageInfo> No data?' );\n\t\t\t\tcallback( null );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcallback( data.query.stashimageinfo );\n\t\t}\n\n\t\tfunction err( code ) {\n\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getStashImageInfo> ' + code );\n\t\t\tcallback( null );\n\t\t}\n\n\t\tif ( props === undefined ) {\n\t\t\tprops = [];\n\t\t}\n\n\t\tif ( width !== undefined || height !== undefined ) {\n\t\t\tif ( !props.includes( 'url' ) ) {\n\t\t\t\tprops.push( 'url' );\n\t\t\t}\n\t\t\tif ( width !== undefined ) {\n\t\t\t\tparams.siiurlwidth = width;\n\t\t\t}\n\t\t\tif ( height !== undefined ) {\n\t\t\t\tparams.siiurlheight = height;\n\t\t\t}\n\t\t}\n\n\t\tthis.api.get( params ).done( ok ).fail( err );\n\t};\n\n\t/**\n\t * Get information about published images\n\t * (There is some overlap with getStashedImageInfo, but it's different at every stage so it's clearer to have separate functions)\n\t * See API documentation for prop=imageinfo for what 'props' can contain\n\t *\n\t * @param {Function} callback Called with null if failure, with imageinfo data structure if success\n\t * @param {Array} props Properties to extract\n\t * @param {number} [width] Width of thumbnail. Will force 'url' to be added to props\n\t * @param {number} [height] Height of thumbnail. Will force 'url' to be added to props\n\t */\n\tmw.UploadWizardUpload.prototype.getImageInfo = function ( callback, props, width, height ) {\n\t\tlet requestedTitle, params;\n\n\t\tfunction ok( data ) {\n\t\t\tlet found;\n\n\t\t\tif ( data && data.query && data.query.pages ) {\n\t\t\t\tfound = false;\n\t\t\t\tObject.keys( data.query.pages ).forEach( ( pageId ) => {\n\t\t\t\t\tconst page = data.query.pages[ pageId ];\n\t\t\t\t\tif ( page.title && page.title === requestedTitle && page.imageinfo ) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tcallback( page.imageinfo );\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tif ( found ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getImageInfo> No data matching ' + requestedTitle + ' ?' );\n\t\t\tcallback( null );\n\t\t}\n\n\t\tfunction err( code ) {\n\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getImageInfo> ' + code );\n\t\t\tcallback( null );\n\t\t}\n\n\t\tif ( props === undefined ) {\n\t\t\tprops = [];\n\t\t}\n\n\t\trequestedTitle = this.title.getPrefixedText();\n\t\tparams = {\n\t\t\tprop: 'imageinfo',\n\t\t\ttitles: requestedTitle,\n\t\t\tiiprop: props.join( '|' )\n\t\t};\n\n\t\tif ( width !== undefined || height !== undefined ) {\n\t\t\tif ( !props.includes( 'url' ) ) {\n\t\t\t\tprops.push( 'url' );\n\t\t\t}\n\t\t\tif ( width !== undefined ) {\n\t\t\t\tparams.iiurlwidth = width;\n\t\t\t}\n\t\t\tif ( height !== undefined ) {\n\t\t\t\tparams.iiurlheight = height;\n\t\t\t}\n\t\t}\n\n\t\tthis.api.get( params ).done( ok ).fail( err );\n\t};\n\n\t/**\n\t * Get the upload handler per browser capabilities\n\t *\n\t * @return {mw.ApiUploadFormDataHandler} upload handler object\n\t */\n\tmw.UploadWizardUpload.prototype.getUploadHandler = function () {\n\t\tlet constructor; // must be the name of a function in 'mw' namespace\n\n\t\tif ( !this.uploadHandler ) {\n\t\t\tconstructor = 'ApiUploadFormDataHandler';\n\t\t\tthis.uploadHandler = new mw[ constructor ]( this, this.api );\n\t\t}\n\t\treturn this.uploadHandler;\n\t};\n\n\t/**\n\t * Explicitly fetch a thumbnail for a stashed upload of the desired width.\n\t *\n\t * @private\n\t * @param {number} width Desired width of thumbnail\n\t * @param {number} height Maximum height of thumbnail\n\t * @return {jQuery.Promise} Promise resolved with a HTMLImageElement, or null if thumbnail\n\t *     couldn't be generated\n\t */\n\tmw.UploadWizardUpload.prototype.getApiThumbnail = function ( width, height ) {\n\t\tconst deferred = $.Deferred();\n\n\t\tfunction thumbnailPublisher( thumbnails ) {\n\t\t\tif ( thumbnails === null ) {\n\t\t\t\t// the api call failed somehow, no thumbnail data.\n\t\t\t\tdeferred.resolve( null );\n\t\t\t} else {\n\t\t\t\t// ok, the api callback has returned us information on where the thumbnail(s) ARE, but that doesn't mean\n\t\t\t\t// they are actually there yet. Keep trying to set the source ( which should trigger \"error\" or \"load\" event )\n\t\t\t\t// on the image. If it loads publish the event with the image. If it errors out too many times, give up and publish\n\t\t\t\t// the event with a null.\n\t\t\t\tthumbnails.forEach( ( thumb ) => {\n\t\t\t\t\tlet timeoutMs, image;\n\n\t\t\t\t\tif ( thumb.thumberror || ( !( thumb.thumburl && thumb.thumbwidth && thumb.thumbheight ) ) ) {\n\t\t\t\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getThumbnail> Thumbnail error or missing information' );\n\t\t\t\t\t\tdeferred.resolve( null );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// executing this should cause a .load() or .error() event on the image\n\t\t\t\t\tfunction setSrc() {\n\t\t\t\t\t\t// IE 11 and Opera 12 will not, ever, re-request an image that they have already loaded\n\t\t\t\t\t\t// once, regardless of caching headers. Append bogus stuff to the URL to make it work.\n\t\t\t\t\t\timage.src = thumb.thumburl + '?' + Math.random();\n\t\t\t\t\t}\n\n\t\t\t\t\t// try to load this image with exponential backoff\n\t\t\t\t\t// if the delay goes past 8 seconds, it gives up and publishes the event with null\n\t\t\t\t\ttimeoutMs = 100;\n\t\t\t\t\timage = document.createElement( 'img' );\n\t\t\t\t\timage.width = thumb.thumbwidth;\n\t\t\t\t\timage.height = thumb.thumbheight;\n\t\t\t\t\t$( image )\n\t\t\t\t\t\t.on( 'load', () => {\n\t\t\t\t\t\t\t// publish the image to anyone who wanted it\n\t\t\t\t\t\t\tdeferred.resolve( image );\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.on( 'error', () => {\n\t\t\t\t\t\t\t// retry with exponential backoff\n\t\t\t\t\t\t\tif ( timeoutMs < 8000 ) {\n\t\t\t\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\t\t\t\ttimeoutMs = timeoutMs * 2 + Math.round( Math.random() * ( timeoutMs / 10 ) );\n\t\t\t\t\t\t\t\t\tsetSrc();\n\t\t\t\t\t\t\t\t}, timeoutMs );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdeferred.resolve( null );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t// and, go!\n\t\t\t\t\tsetSrc();\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\tif ( this.state !== 'complete' ) {\n\t\t\tthis.getStashImageInfo( thumbnailPublisher, [ 'url' ], width, height );\n\t\t} else {\n\t\t\tthis.getImageInfo( thumbnailPublisher, [ 'url' ], width, height );\n\t\t}\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Return the orientation of the image in degrees. Relies on metadata that\n\t * may have been extracted at filereader stage, or after the upload when we fetch metadata. Default returns 0.\n\t *\n\t * @return {number} orientation in degrees: 0, 90, 180 or 270\n\t */\n\tmw.UploadWizardUpload.prototype.getOrientationDegrees = function () {\n\t\tlet orientation = 0;\n\t\tif ( this.imageinfo && this.imageinfo.metadata && this.imageinfo.metadata.orientation ) {\n\t\t\tswitch ( this.imageinfo.metadata.orientation ) {\n\t\t\t\tcase 8:\n\t\t\t\t\t// 'top left' -> 'left bottom'\n\t\t\t\t\torientation = 90;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\t// 'top left' -> 'bottom right'\n\t\t\t\t\torientation = 180;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 6:\n\t\t\t\t\t// 'top left' -> 'right top'\n\t\t\t\t\torientation = 270;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t// 'top left' -> 'top left'\n\t\t\t\t\torientation = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\t\t}\n\t\treturn orientation;\n\t};\n\n\t/**\n\t * Fit an image into width & height constraints with scaling factor\n\t *\n\t * @private\n\t * @param {HTMLImageElement} image\n\t * @param {Object} constraints Width & height properties\n\t * @return {number}\n\t */\n\tmw.UploadWizardUpload.prototype.getScalingFromConstraints = function ( image, constraints ) {\n\t\tlet scaling = 1;\n\t\tObject.keys( constraints ).forEach( ( dim ) => {\n\t\t\tlet s,\n\t\t\t\tconstraint = constraints[ dim ];\n\t\t\tif ( constraint && image[ dim ] > constraint ) {\n\t\t\t\ts = constraint / image[ dim ];\n\t\t\t\tif ( s < scaling ) {\n\t\t\t\t\tscaling = s;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\treturn scaling;\n\t};\n\n\t/**\n\t * Given an image (already loaded), dimension constraints\n\t * return canvas object scaled & transformed ( & rotated if metadata indicates it's needed )\n\t *\n\t * @private\n\t * @param {HTMLImageElement} image\n\t * @param {Object} constraints Width & height constraints\n\t * @return {HTMLCanvasElement|null}\n\t */\n\tmw.UploadWizardUpload.prototype.getTransformedCanvasElement = function ( image, constraints ) {\n\t\tlet angle, scaling, width, height,\n\t\t\tdimensions, dx, dy, x, y, $canvas, ctx,\n\t\t\tscaleConstraints = constraints,\n\t\t\trotation = 0;\n\n\t\t// if this wiki can rotate images to match their EXIF metadata,\n\t\t// we should do the same in our preview\n\t\tif ( mw.config.get( 'wgFileCanRotate' ) ) {\n\t\t\tangle = this.getOrientationDegrees();\n\t\t\trotation = angle ? 360 - angle : 0;\n\t\t}\n\n\t\t// swap scaling constraints if needed by rotation...\n\t\tif ( rotation === 90 || rotation === 270 ) {\n\t\t\tscaleConstraints = {};\n\t\t\tif ( 'height' in constraints ) {\n\t\t\t\tscaleConstraints.width = constraints.height;\n\t\t\t}\n\t\t\tif ( 'width' in constraints ) {\n\t\t\t\tscaleConstraints.height = constraints.width;\n\t\t\t}\n\t\t}\n\n\t\tscaling = this.getScalingFromConstraints( image, scaleConstraints );\n\n\t\twidth = image.width * scaling;\n\t\theight = image.height * scaling;\n\n\t\tdimensions = { width: width, height: height };\n\t\tif ( rotation === 90 || rotation === 270 ) {\n\t\t\tdimensions = { width: height, height: width };\n\t\t}\n\n\t\t// Start drawing at offset 0,0\n\t\tdx = 0;\n\t\tdy = 0;\n\n\t\tswitch ( rotation ) {\n\t\t\t// If a rotation is applied, the direction of the axis\n\t\t\t// changes as well. You can derive the values below by\n\t\t\t// drawing on paper an axis system, rotate it and see\n\t\t\t// where the positive axis direction is\n\t\t\tcase 90:\n\t\t\t\tx = dx;\n\t\t\t\ty = dy - height;\n\t\t\t\tbreak;\n\t\t\tcase 180:\n\t\t\t\tx = dx - width;\n\t\t\t\ty = dy - height;\n\t\t\t\tbreak;\n\t\t\tcase 270:\n\t\t\t\tx = dx - width;\n\t\t\t\ty = dy;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tx = dx;\n\t\t\t\ty = dy;\n\t\t\t\tbreak;\n\t\t}\n\n\t\t$canvas = $( '<canvas>' ).attr( dimensions );\n\t\tctx = $canvas[ 0 ].getContext( '2d' );\n\t\tctx.clearRect( dx, dy, width, height );\n\t\tctx.rotate( rotation / 180 * Math.PI );\n\t\ttry {\n\t\t\t// Calling #drawImage likes to throw all kinds of ridiculous exceptions in various browsers,\n\t\t\t// including but not limited to:\n\t\t\t// * (Firefox) NS_ERROR_NOT_AVAILABLE:\n\t\t\t// * (Internet Explorer / Edge) Not enough storage is available to complete this operation.\n\t\t\t// * (Internet Explorer / Edge) Unspecified error.\n\t\t\t// * (Internet Explorer / Edge) The GPU device instance has been suspended. Use GetDeviceRemovedReason to determine the appropriate action.\n\t\t\t// * (Safari) IndexSizeError: Index or size was negative, or greater than the allowed value.\n\t\t\t// There is nothing we can do about this. It's okay though, there just won't be a thumbnail.\n\t\t\tctx.drawImage( image, x, y, width, height );\n\t\t} catch ( err ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn $canvas;\n\t};\n\n\t/**\n\t * Return a browser-scaled image element, given an image and constraints.\n\t *\n\t * @private\n\t * @param {HTMLImageElement} image\n\t * @param {Object} constraints Width and height properties\n\t * @return {HTMLImageElement} with same src, but different attrs\n\t */\n\tmw.UploadWizardUpload.prototype.getBrowserScaledImageElement = function ( image, constraints ) {\n\t\tconst scaling = this.getScalingFromConstraints( image, constraints );\n\t\treturn $( '<img>' )\n\t\t\t.attr( {\n\t\t\t\twidth: parseInt( image.width * scaling, 10 ),\n\t\t\t\theight: parseInt( image.height * scaling, 10 ),\n\t\t\t\tsrc: image.src\n\t\t\t} );\n\t};\n\n\t/**\n\t * Return an element suitable for the preview of a certain size. Uses canvas when possible\n\t *\n\t * @private\n\t * @param {HTMLImageElement} image\n\t * @param {number} width\n\t * @param {number} height\n\t * @return {HTMLCanvasElement|HTMLImageElement}\n\t */\n\tmw.UploadWizardUpload.prototype.getScaledImageElement = function ( image, width, height ) {\n\t\tlet constraints = {},\n\t\t\ttransform;\n\n\t\tif ( width ) {\n\t\t\tconstraints.width = width;\n\t\t}\n\t\tif ( height ) {\n\t\t\tconstraints.height = height;\n\t\t}\n\n\t\tif ( mw.canvas.isAvailable() ) {\n\t\t\ttransform = this.getTransformedCanvasElement( image, constraints );\n\t\t\tif ( transform ) {\n\t\t\t\treturn transform;\n\t\t\t}\n\t\t}\n\n\t\t// No canvas support or canvas drawing failed mysteriously, fall back\n\t\treturn this.getBrowserScaledImageElement( image, constraints );\n\t};\n\n\t/**\n\t * Acquire a thumbnail for this upload.\n\t *\n\t * @param {number} width\n\t * @param {number} height\n\t * @return {jQuery.Promise} Promise resolved with the HTMLImageElement or HTMLCanvasElement\n\t *   containing a thumbnail, or resolved with `null` when one can't be produced\n\t */\n\tmw.UploadWizardUpload.prototype.getThumbnail = function ( width, height ) {\n\t\tconst upload = this,\n\t\t\tdeferred = $.Deferred();\n\n\t\tif ( this.thumbnailPromise[ width + 'x' + height ] ) {\n\t\t\treturn this.thumbnailPromise[ width + 'x' + height ];\n\t\t}\n\t\tthis.thumbnailPromise[ width + 'x' + height ] = deferred.promise();\n\n\t\t/**\n\t\t * @param {HTMLImageElement|null} image\n\t\t */\n\t\tfunction imageCallback( image ) {\n\t\t\tif ( image === null ) {\n\t\t\t\tupload.ui.setStatus( 'mediauploader-thumbnail-failed' );\n\t\t\t\tdeferred.resolve( image );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\timage = upload.getScaledImageElement( image, width, height );\n\t\t\tdeferred.resolve( image );\n\t\t}\n\n\t\tthis.extractMetadataFromJpegMeta()\n\t\t\t.then( upload.makePreview.bind( upload, width ) )\n\t\t\t.done( imageCallback )\n\t\t\t.fail( () => {\n\t\t\t\t// Can't generate the thumbnail locally, get the thumbnail via API after\n\t\t\t\t// the file is uploaded. Queries are cached, so if this thumbnail was\n\t\t\t\t// already fetched for some reason, we'll get it immediately.\n\t\t\t\tif ( upload.state !== 'new' && upload.state !== 'transporting' && upload.state !== 'error' ) {\n\t\t\t\t\tupload.getApiThumbnail( width, height ).done( imageCallback );\n\t\t\t\t} else {\n\t\t\t\t\tupload.once( 'success', () => {\n\t\t\t\t\t\tupload.getApiThumbnail( width, height ).done( imageCallback );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\n\t\treturn this.thumbnailPromise[ width + 'x' + height ];\n\t};\n\n\t/**\n\t * Notification that the file input has changed and it's fine...set info.\n\t */\n\tmw.UploadWizardUpload.prototype.fileChangedOk = function () {\n\t\tthis.ui.fileChangedOk( this.imageinfo, this.file );\n\t};\n\n\t/**\n\t * Make a preview for the file.\n\t *\n\t * @private\n\t * @param {number} width\n\t * @return {jQuery.Promise}\n\t */\n\tmw.UploadWizardUpload.prototype.makePreview = function ( width ) {\n\t\tlet first, video, url, dataUrlReader,\n\t\t\tdeferred = $.Deferred(),\n\t\t\tupload = this;\n\n\t\t// do preview if we can\n\t\tif ( this.isPreviewable() ) {\n\t\t\t// open video and get frame via canvas\n\t\t\tif ( this.isVideo() ) {\n\t\t\t\tfirst = true;\n\t\t\t\tvideo = document.createElement( 'video' );\n\n\t\t\t\tvideo.addEventListener( 'loadedmetadata', () => {\n\t\t\t\t\t// seek 2 seconds into video or to half if shorter\n\t\t\t\t\tvideo.currentTime = Math.min( 2, video.duration / 2 );\n\t\t\t\t\tvideo.volume = 0;\n\t\t\t\t} );\n\t\t\t\tvideo.addEventListener( 'seeked', () => {\n\t\t\t\t\t// Firefox 16 sometimes does not work on first seek, seek again\n\t\t\t\t\tif ( first ) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t\tvideo.currentTime = Math.min( 2, video.duration / 2 );\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Chrome sometimes shows black frames if grabbing right away.\n\t\t\t\t\t\t// wait 500ms before grabbing frame\n\t\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\t\tlet context,\n\t\t\t\t\t\t\t\tcanvas = document.createElement( 'canvas' );\n\t\t\t\t\t\t\tcanvas.width = width;\n\t\t\t\t\t\t\tcanvas.height = Math.round( canvas.width * video.videoHeight / video.videoWidth );\n\t\t\t\t\t\t\tcontext = canvas.getContext( '2d' );\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// More ridiculous exceptions, see the comment in #getTransformedCanvasElement\n\t\t\t\t\t\t\t\tcontext.drawImage( video, 0, 0, canvas.width, canvas.height );\n\t\t\t\t\t\t\t} catch ( err ) {\n\t\t\t\t\t\t\t\tdeferred.reject();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tupload.loadImage( canvas.toDataURL(), deferred );\n\t\t\t\t\t\t\tupload.URL().revokeObjectURL( video.url );\n\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\turl = this.URL().createObjectURL( this.file );\n\t\t\t\tvideo.src = url;\n\t\t\t\t// If we can't get a frame within 10 seconds, something is probably seriously wrong.\n\t\t\t\t// This can happen for broken files where we can't actually seek to the time we wanted.\n\t\t\t\tsetTimeout( () => {\n\t\t\t\t\tdeferred.reject();\n\t\t\t\t\tupload.URL().revokeObjectURL( video.url );\n\t\t\t\t}, 10000 );\n\t\t\t} else {\n\t\t\t\tdataUrlReader = new FileReader();\n\t\t\t\tdataUrlReader.onload = function () {\n\t\t\t\t\t// this step (inserting image-as-dataurl into image object) is slow for large images, which\n\t\t\t\t\t// is why this is optional and has a control attached to it to load the preview.\n\t\t\t\t\tupload.loadImage( dataUrlReader.result, deferred );\n\t\t\t\t};\n\t\t\t\tdataUrlReader.readAsDataURL( this.file );\n\t\t\t}\n\t\t} else {\n\t\t\tdeferred.reject();\n\t\t}\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Loads an image preview.\n\t *\n\t * @param {string} url\n\t * @param {jQuery.Deferred} deferred\n\t */\n\tmw.UploadWizardUpload.prototype.loadImage = function ( url, deferred ) {\n\t\tconst image = document.createElement( 'img' );\n\t\timage.onload = function () {\n\t\t\tdeferred.resolve( image );\n\t\t};\n\t\timage.onerror = function () {\n\t\t\tdeferred.reject();\n\t\t};\n\t\ttry {\n\t\t\timage.src = url;\n\t\t} catch ( er ) {\n\t\t\t// On Internet Explorer 11 and Edge, this occasionally causes an exception (possibly\n\t\t\t// localised) like \"Not enough storage is available to complete this operation\". (T136239)\n\t\t\tdeferred.reject();\n\t\t}\n\t};\n\n\t/**\n\t * Check if the file is previewable.\n\t *\n\t * @return {boolean}\n\t */\n\tmw.UploadWizardUpload.prototype.isPreviewable = function () {\n\t\treturn this.file && mw.fileApi.isPreviewableFile( this.file );\n\t};\n\n\t/**\n\t * Finds the right URL object to use.\n\t *\n\t * @return {URL}\n\t */\n\tmw.UploadWizardUpload.prototype.URL = function () {\n\t\t// This functionality is missing on IE 11\n\t\treturn window.URL || window.webkitURL || window.mozURL;\n\t};\n\n\t/**\n\t * Checks if this upload is a video.\n\t *\n\t * @return {boolean}\n\t */\n\tmw.UploadWizardUpload.prototype.isVideo = function () {\n\t\treturn mw.fileApi.isPreviewableVideo( this.file );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardUploadInterface.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":206,"column":3,"nodeType":"CallExpression","endLine":209,"endColumn":6}],"suppressedMessages":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":101,"column":3,"nodeType":"CallExpression","endLine":101,"endColumn":36,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\t/**\n\t * Create an interface fragment corresponding to a file input, suitable for Upload Wizard.\n\t *\n\t * @class mw.UploadWizardUploadInterface\n\t * @constructor\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tmw.UploadWizardUploadInterface = function MWUploadWizardUploadInterface( upload ) {\n\t\tconst ui = this;\n\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.upload = upload;\n\n\t\t// May need to collaborate with the particular upload type sometimes\n\t\t// for the interface, as well as the uploadwizard. OY.\n\t\tthis.$div = $( '<div>' ).addClass( 'mediauploader-file' );\n\n\t\tthis.isFilled = false;\n\n\t\tthis.statusMessage = new OO.ui.MessageWidget( { inline: true } );\n\t\tthis.statusMessage.toggle( false );\n\t\tthis.$spinner = $.createSpinner( { size: 'small', type: 'inline' } );\n\t\tthis.$spinner.hide();\n\t\tthis.$indicator = $( '<div>' ).addClass( 'mediauploader-file-indicator' ).append(\n\t\t\tthis.$spinner,\n\t\t\tthis.statusMessage.$element\n\t\t);\n\n\t\tthis.$visibleFilenameDiv = $( '<div>' ).addClass( 'mediauploader-visible-file' ).append(\n\t\t\tthis.$indicator,\n\t\t\t$( '<div>' ).addClass( 'mediauploader-visible-file-filename' ).append(\n\t\t\t\t$( '<div>' ).addClass( 'mediauploader-file-preview' ),\n\t\t\t\t$( '<div>' ).addClass( 'mediauploader-file-texts' ).append(\n\t\t\t\t\t$( '<div>' ).addClass( 'mediauploader-visible-file-filename-text' ),\n\t\t\t\t\t$( '<div>' ).addClass( 'mediauploader-file-status-line' ).append(\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mediauploader-file-status' )\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\n\t\tthis.removeCtrl = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-remove' ).text(),\n\t\t\ttitle: mw.message( 'mediauploader-remove-upload' ).text(),\n\t\t\tflags: 'destructive',\n\t\t\ticon: 'trash',\n\t\t\tframed: false\n\t\t} ).on( 'click', () => {\n\t\t\tui.emit( 'upload-removed' );\n\t\t} );\n\n\t\tthis.$visibleFilenameDiv.find( '.mediauploader-file-status-line' )\n\t\t\t.append( this.removeCtrl.$element );\n\n\t\tthis.$form = $( '<form>' )\n\t\t\t.addClass( 'mediauploader-form' )\n\t\t\t.append( this.$visibleFilenameDiv );\n\n\t\tthis.$div.append( this.$form );\n\n\t\t// this.progressBar = ( no progress bar for individual uploads yet )\n\t\t// we bind to the ui div since .off() doesn't work for non-DOM objects\n\t\t// TODO Convert this to an OO.EventEmitter, and use OOjs events\n\t\tthis.$div.on( 'transportProgressEvent', () => {\n\t\t\tui.showTransportProgress();\n\t\t} );\n\t};\n\n\tOO.mixinClass( mw.UploadWizardUploadInterface, OO.EventEmitter );\n\n\t/**\n\t * Change the graphic indicator at the far end of the row for this file\n\t *\n\t * @param {string} [status] Either a OO.ui.MessageWidget type (error/success/...) or 'progress'.\n\t *  Omit to hide the indicator\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showIndicator = function ( status ) {\n\t\tthis.$spinner.hide();\n\t\tthis.statusMessage.toggle( false );\n\n\t\tif ( status === 'progress' ) {\n\t\t\tthis.$spinner.show();\n\t\t} else if ( status ) {\n\t\t\tthis.statusMessage.toggle( true ).setType( status );\n\t\t}\n\t\tthis.$indicator.toggleClass( 'mediauploader-file-indicator-visible', !!status );\n\t};\n\n\t/**\n\t * Set the status line for this upload with an internationalized message string.\n\t *\n\t * @param {string} msgKey Key for the message\n\t * @param {Array} [args] Array of values, in case any need to be fed to the image.\n\t */\n\tmw.UploadWizardUploadInterface.prototype.setStatus = function ( msgKey, args ) {\n\t\t// get the status line for our upload\n\t\tconst $status = this.$div.find( '.mediauploader-file-status' );\n\t\t// eslint-disable-next-line mediawiki/msg-doc\n\t\t$status.msg( msgKey, args || [] ).show();\n\t};\n\n\t/**\n\t * Set status line directly with a string\n\t *\n\t * @param {string} html\n\t */\n\tmw.UploadWizardUploadInterface.prototype.setStatusString = function ( html ) {\n\t\tthis.$div.find( '.mediauploader-file-status' ).html( html ).show();\n\t};\n\n\t/**\n\t * Set additional status information\n\t *\n\t * @param {jQuery} [$status] If not given or null, additional status is cleared\n\t */\n\tmw.UploadWizardUploadInterface.prototype.setAdditionalStatus = function ( $status ) {\n\t\tif ( this.$additionalStatus ) {\n\t\t\tthis.$additionalStatus.remove();\n\t\t}\n\t\tthis.$additionalStatus = $status;\n\t\tif ( this.$additionalStatus ) {\n\t\t\tthis.$div.find( '.mediauploader-file-status' ).after( this.$additionalStatus );\n\t\t}\n\t};\n\n\t/**\n\t * Clear the status line for this upload (hide it, in case there are paddings and such which offset other things.)\n\t */\n\tmw.UploadWizardUploadInterface.prototype.clearStatus = function () {\n\t\tthis.$div.find( '.mediauploader-file-status' ).hide();\n\t\tthis.setAdditionalStatus( null );\n\t};\n\n\t/**\n\t * Put the visual state of an individual upload into \"progress\"\n\t *\n\t * @param {number} fraction The fraction of progress. Float between 0 and 1\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showTransportProgress = function () {\n\t\t// if fraction available, update individual progress bar / estimates, etc.\n\t\tthis.showIndicator( 'progress' );\n\t\tthis.setStatus( 'mediauploader-uploading' );\n\t\tthis.setAdditionalStatus( null );\n\t};\n\n\t/**\n\t * Show that upload is transported\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showStashed = function () {\n\t\tthis.showIndicator( 'success' );\n\t\tthis.setStatus( 'mediauploader-stashed-upload' );\n\t\tthis.setAdditionalStatus( null );\n\t};\n\n\t/**\n\t * Show that transport has failed\n\t *\n\t * @param {string} code Error code from API\n\t * @param {string} html Error message\n\t * @param {jQuery} [$additionalStatus]\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showError = function ( code, html, $additionalStatus ) {\n\t\tthis.showIndicator( 'error' );\n\t\tthis.setStatusString( html );\n\t\tthis.setAdditionalStatus( $additionalStatus );\n\t};\n\n\t/**\n\t * Run this when the value of the file input has changed and we know it's acceptable -- this\n\t * will update interface to show as much info as possible, including preview.\n\t * n.b. in older browsers we only will know the filename\n\t *\n\t * @param {Object} imageinfo\n\t * @param {File} file\n\t */\n\tmw.UploadWizardUploadInterface.prototype.fileChangedOk = function ( imageinfo, file ) {\n\t\tconst statusItems = [];\n\n\t\tthis.updateFilename();\n\n\t\t// set the status string - e.g. \"256 Kb, 100 x 200\"\n\t\tif ( imageinfo && imageinfo.width && imageinfo.height ) {\n\t\t\tstatusItems.push( imageinfo.width + '\\u00d7' + imageinfo.height );\n\t\t}\n\n\t\tif ( file && file.size ) {\n\t\t\tstatusItems.push( uw.units.bytes( file.size ) );\n\t\t}\n\n\t\tthis.clearStatus();\n\t\tthis.setStatusString( statusItems.join( ' \\u00b7 ' ) );\n\t};\n\n\t/**\n\t * Display thumbnail preview.\n\t *\n\t * @return {jQuery.Promise} Promise resolved when the thumbnail is displayed or when displaying it\n\t *     fails\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showThumbnail = function () {\n\t\tconst $preview = this.$div.find( '.mediauploader-file-preview' ),\n\t\t\tdeferred = $.Deferred();\n\t\t// This must match the CSS dimensions of .mediauploader-file-preview\n\t\tthis.upload.getThumbnail( 120, 120 ).done( ( thumb ) => {\n\t\t\tmw.UploadWizard.placeThumbnail( $preview, thumb );\n\t\t\tdeferred.resolve();\n\t\t} );\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * this does two things:\n\t *   1 ) since the file input has been hidden with some clever CSS ( to avoid x-browser styling issues ),\n\t *       update the visible filename\n\t *\n\t *   2 ) update the underlying \"title\" which we are targeting to add to mediawiki.\n\t *       TODO silently fix to have unique filename? unnecessary at this point...\n\t */\n\tmw.UploadWizardUploadInterface.prototype.updateFilename = function () {\n\t\tconst path = this.upload.getFilename();\n\n\t\t// visible filename\n\t\tthis.$form.find( '.mediauploader-visible-file-filename-text' )\n\t\t\t.text( path );\n\n\t\tif ( !this.isFilled ) {\n\t\t\tthis.isFilled = true;\n\t\t\tthis.$div.addClass( 'filled' );\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.canvas.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.errorDialog.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.fileApi.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/transports/mw.FormDataTransport.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":97,"column":3,"nodeType":"MemberExpression","messageId":"forbidden","endLine":97,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'deferred' is never reassigned. Use 'const' instead.","line":156,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":156,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'fileSize' is never reassigned. Use 'const' instead.","line":157,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":157,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'chunkSize' is never reassigned. Use 'const' instead.","line":158,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":158,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'transport' is never reassigned. Use 'const' instead.","line":159,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":159,"endColumn":13},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":169,"column":5,"nodeType":"CallExpression","endLine":178,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":170,"column":6,"nodeType":"CallExpression","endLine":171,"endColumn":67},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":170,"column":6,"nodeType":"CallExpression","endLine":172,"endColumn":31},{"ruleId":"prefer-const","severity":2,"message":"'params' is never reassigned. Use 'const' instead.","line":194,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":194,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'transport' is never reassigned. Use 'const' instead.","line":195,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":195,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'bytesAvailable' is never reassigned. Use 'const' instead.","line":196,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":196,"endColumn":18}],"suppressedMessages":[{"ruleId":"no-loop-func","severity":2,"message":"Function declared in a loop contains unsafe references to variable(s) 'prevPromise', 'prevPromise'.","line":164,"column":6,"nodeType":"FunctionExpression","messageId":"unsafeRefs","endLine":180,"endColumn":5,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":10,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t/**\n\t * Represents a \"transport\" for files to upload; using HTML5 FormData.\n\t *\n\t * @constructor\n\t * @class mw.FormDataTransport\n\t * @param {mw.Api} api\n\t * @param {Object} formData Additional form fields required for upload api call\n\t * @param {Object} [config]\n\t * @param {Object} [config.chunkSize]\n\t * @param {Object} [config.maxPhpUploadSize]\n\t * @param {Object} [config.useRetryTimeout]\n\t */\n\tmw.FormDataTransport = function ( api, formData, config ) {\n\t\tthis.config = config || mw.UploadWizard.config;\n\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.formData = formData;\n\t\tthis.aborted = false;\n\t\tthis.api = api;\n\n\t\t// Set chunk size to configured chunk size or max php size,\n\t\t// whichever is smaller.\n\t\tthis.chunkSize = Math.min( this.config.chunkSize, this.config.maxPhpUploadSize );\n\t\tthis.maxRetries = 2;\n\t\tthis.retries = 0;\n\t\tthis.firstPoll = false;\n\n\t\t// running API request\n\t\tthis.request = null;\n\t};\n\n\tOO.mixinClass( mw.FormDataTransport, OO.EventEmitter );\n\n\tmw.FormDataTransport.prototype.abort = function () {\n\t\tthis.aborted = true;\n\n\t\tif ( this.request ) {\n\t\t\tthis.request.abort();\n\t\t}\n\t};\n\n\t/**\n\t * Submits an upload to the API.\n\t *\n\t * @param {Object} params Request params\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.post = function ( params ) {\n\t\tconst deferred = $.Deferred();\n\n\t\tthis.request = this.api.post( params, {\n\t\t\t/*\n\t\t\t * $.ajax is not quite equiped to handle File uploads with params.\n\t\t\t * The most convenient way would be to submit it with a FormData\n\t\t\t * object, but mw.Api will already do that for us: it'll transform\n\t\t\t * params if it encounters a multipart/form-data POST request, and\n\t\t\t * submit it accordingly!\n\t\t\t *\n\t\t\t * @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Submitting_forms_and_uploading_files\n\t\t\t */\n\t\t\tcontentType: 'multipart/form-data',\n\t\t\t/*\n\t\t\t * $.ajax also has no progress event that will allow us to figure\n\t\t\t * out how much of the upload has already gone out, so let's add it!\n\t\t\t */\n\t\t\txhr: function () {\n\t\t\t\tconst xhr = $.ajaxSettings.xhr();\n\t\t\t\txhr.upload.addEventListener( 'progress', ( evt ) => {\n\t\t\t\t\tlet fraction = null;\n\t\t\t\t\tif ( evt.lengthComputable ) {\n\t\t\t\t\t\tfraction = parseFloat( evt.loaded / evt.total );\n\t\t\t\t\t}\n\t\t\t\t\tdeferred.notify( fraction );\n\t\t\t\t}, false );\n\t\t\t\treturn xhr;\n\t\t\t}\n\t\t} );\n\n\t\t// just pass on success & failures\n\t\tthis.request.then( deferred.resolve, deferred.reject );\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Creates the upload API params.\n\t *\n\t * @param {string} filename\n\t * @param {number} [offset] For chunked uploads\n\t * @return {Object}\n\t */\n\tmw.FormDataTransport.prototype.createParams = function ( filename, offset ) {\n\t\tconst params = OO.cloneObject( this.formData );\n\n\t\tObject.assign( params, {\n\t\t\tfilename: filename,\n\n\t\t\t// ignorewarnings is turned on, since warnings are presented in a\n\t\t\t// later step and this transport doesn't know how to deal with them.\n\t\t\t// Also, it's important to allow people to upload files with (for\n\t\t\t// example) blacklisted names, and then rename them later in the\n\t\t\t// wizard.\n\t\t\tignorewarnings: true,\n\n\t\t\toffset: offset || 0\n\t\t} );\n\n\t\treturn params;\n\t};\n\n\t/**\n\t * Start the upload with the provided file.\n\t *\n\t * @param {File} file\n\t * @param {string} tempFileName\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.upload = function ( file, tempFileName ) {\n\t\tlet params, ext;\n\n\t\tthis.tempname = tempFileName;\n\t\t// Limit length to 240 bytes (limit hardcoded in UploadBase.php).\n\t\tif ( this.tempname.length > 240 ) {\n\t\t\text = this.tempname.split( '.' ).pop();\n\t\t\tthis.tempname = this.tempname.slice( 0, Math.max( 0, 240 - ext.length - 1 ) ) + '.' + ext;\n\t\t}\n\n\t\tif ( file.size > this.chunkSize ) {\n\t\t\treturn this.chunkedUpload( file );\n\t\t} else {\n\t\t\tparams = this.createParams( this.tempname );\n\t\t\tparams.file = file;\n\t\t\treturn this.post( params );\n\t\t}\n\t};\n\n\t/**\n\t * This function exists to safely chain several hundred promises without using .then() or nested\n\t * promises. We might divide a 4 GB file into 800 chunks of 5 MB each.\n\t *\n\t * In jQuery 2.x, nested promises result in nested call stacks when resolving/rejecting/notifying\n\t * the last promise in the chain and listening on the first one, and browsers have call stack\n\t * limits low enough that we previously ran into them for files around a couple hundred megabytes\n\t * (the worst is Firefox 47 with a limit of 1024 calls).\n\t *\n\t * @param {File} file\n\t * @return {jQuery.Promise} Promise which behaves identically to a regular non-chunked upload\n\t *   promise from #upload\n\t */\n\tmw.FormDataTransport.prototype.chunkedUpload = function ( file ) {\n\t\tlet\n\t\t\toffset,\n\t\t\tprevPromise = $.Deferred().resolve(),\n\t\t\tdeferred = $.Deferred(),\n\t\t\tfileSize = file.size,\n\t\t\tchunkSize = this.chunkSize,\n\t\t\ttransport = this;\n\n\t\tfor ( offset = 0; offset < fileSize; offset += chunkSize ) {\n\t\t\t// Capture offset in a closure\n\t\t\t// eslint-disable-next-line no-loop-func\n\t\t\t( function ( offset2 ) {\n\t\t\t\tconst\n\t\t\t\t\tnewPromise = $.Deferred(),\n\t\t\t\t\tisLastChunk = offset2 + chunkSize >= fileSize,\n\t\t\t\t\tthisChunkSize = isLastChunk ? ( fileSize % chunkSize ) : chunkSize;\n\t\t\t\tprevPromise.done( () => {\n\t\t\t\t\ttransport.uploadChunk( file, offset2 )\n\t\t\t\t\t\t.done( isLastChunk ? deferred.resolve : newPromise.resolve )\n\t\t\t\t\t\t.fail( deferred.reject )\n\t\t\t\t\t\t.progress( ( fraction ) => {\n\t\t\t\t\t\t\t// The progress notifications give us per-chunk progress.\n\t\t\t\t\t\t\t// Calculate progress for the whole file.\n\t\t\t\t\t\t\tdeferred.notify( ( offset2 + fraction * thisChunkSize ) / fileSize );\n\t\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t\tprevPromise = newPromise;\n\t\t\t}( offset ) );\n\t\t}\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Upload a single chunk.\n\t *\n\t * @param {File} file\n\t * @param {number} offset Offset in bytes.\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.uploadChunk = function ( file, offset ) {\n\t\tlet params = this.createParams( this.tempname, offset ),\n\t\t\ttransport = this,\n\t\t\tbytesAvailable = file.size,\n\t\t\tchunk;\n\n\t\tif ( this.aborted ) {\n\t\t\treturn $.Deferred().reject( 'aborted', {\n\t\t\t\terrors: [ {\n\t\t\t\t\tcode: 'aborted',\n\t\t\t\t\thtml: mw.message( 'mediauploader-api-error-aborted' ).parse()\n\t\t\t\t} ]\n\t\t\t} );\n\t\t}\n\n\t\t// Slice API was changed and has vendor prefix for now\n\t\t// new version now require start/end and not start/length\n\t\tif ( file.mozSlice ) {\n\t\t\tchunk = file.mozSlice( offset, offset + this.chunkSize, file.type );\n\t\t} else if ( file.webkitSlice ) {\n\t\t\tchunk = file.webkitSlice( offset, offset + this.chunkSize, file.type );\n\t\t} else {\n\t\t\tchunk = file.slice( offset, offset + this.chunkSize, file.type );\n\t\t}\n\n\t\t// only enable async if file is larger 10Mb\n\t\tif ( bytesAvailable > 10 * 1024 * 1024 ) {\n\t\t\tparams.async = true;\n\t\t}\n\n\t\t// If offset is 0, we're uploading the file from scratch. filekey may be set if we're retrying\n\t\t// the first chunk. The API errors out if a filekey is given with zero offset (as it's\n\t\t// nonsensical). TODO Why do we need to retry in this case, if we managed to upload something?\n\t\tif ( this.filekey && offset !== 0 ) {\n\t\t\tparams.filekey = this.filekey;\n\t\t}\n\t\tparams.filesize = bytesAvailable;\n\t\tparams.chunk = chunk;\n\n\t\treturn this.post( params ).then( ( response ) => {\n\t\t\tif ( response.upload && response.upload.filekey ) {\n\t\t\t\ttransport.filekey = response.upload.filekey;\n\t\t\t}\n\n\t\t\tif ( response.upload && response.upload.result ) {\n\t\t\t\tswitch ( response.upload.result ) {\n\t\t\t\t\tcase 'Continue':\n\t\t\t\t\t\t// Reset retry counter\n\t\t\t\t\t\ttransport.retries = 0;\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase 'Success':\n\t\t\t\t\t\t// Just pass the response through.\n\t\t\t\t\t\treturn response;\n\t\t\t\t\tcase 'Poll':\n\t\t\t\t\t\t// Need to retry with checkStatus.\n\t\t\t\t\t\treturn transport.retryWithMethod( 'checkStatus' );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn transport.maybeRetry(\n\t\t\t\t\t'on unknown response',\n\t\t\t\t\tresponse.error ? response.error.code : 'unknown-error',\n\t\t\t\t\tresponse,\n\t\t\t\t\t'uploadChunk',\n\t\t\t\t\tfile, offset\n\t\t\t\t);\n\t\t\t}\n\t\t}, ( code, result ) => {\n\t\t\t// Ain't this some great machine readable output eh\n\t\t\tif (\n\t\t\t\tresult.errors &&\n\t\t\t\tresult.errors[ 0 ].code === 'stashfailed' &&\n\t\t\t\tresult.errors[ 0 ].html === mw.message( 'apierror-stashfailed-complete' ).parse()\n\t\t\t) {\n\t\t\t\treturn transport.retryWithMethod( 'checkStatus' );\n\t\t\t}\n\n\t\t\t// Failed to upload, try again in 3 seconds\n\t\t\t// This is really dumb, we should only do this for cases where retrying has a chance to work\n\t\t\t// (so basically, network failures). If your upload was blocked by AbuseFilter you're\n\t\t\t// shafted anyway. But some server-side errors really are temporary...\n\t\t\treturn transport.maybeRetry(\n\t\t\t\t'on error event',\n\t\t\t\tcode,\n\t\t\t\tresult,\n\t\t\t\t'uploadChunk',\n\t\t\t\tfile, offset\n\t\t\t);\n\t\t} );\n\t};\n\n\t/**\n\t * Handle possible retry event - rejected if maximum retries already fired.\n\t *\n\t * @param {string} contextMsg\n\t * @param {string} code\n\t * @param {Object} response\n\t * @param {string} retryMethod\n\t * @param {File} [file]\n\t * @param {number} [offset]\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.maybeRetry = function ( contextMsg, code, response, retryMethod, file, offset ) {\n\t\tthis.retries++;\n\n\t\tif ( this.tooManyRetries() ) {\n\t\t\tmw.log.warn( 'Max retries exceeded ' + contextMsg );\n\t\t\treturn $.Deferred().reject( code, response );\n\t\t} else if ( this.aborted ) {\n\t\t\treturn $.Deferred().reject( code, response );\n\t\t} else {\n\t\t\tmw.log( 'Retry #' + this.retries + ' ' + contextMsg );\n\t\t\treturn this.retryWithMethod( retryMethod, file, offset );\n\t\t}\n\t};\n\n\t/**\n\t * Have we retried too many times already?\n\t *\n\t * @return {boolean}\n\t */\n\tmw.FormDataTransport.prototype.tooManyRetries = function () {\n\t\treturn this.maxRetries > 0 && this.retries >= this.maxRetries;\n\t};\n\n\t/**\n\t * Either retry uploading or checking the status.\n\t *\n\t * @param {'uploadChunk'|'checkStatus'} methodName\n\t * @param {File} [file]\n\t * @param {number} [offset]\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.retryWithMethod = function ( methodName, file, offset ) {\n\t\tconst\n\t\t\ttransport = this,\n\t\t\tretryDeferred = $.Deferred(),\n\t\t\tretry = function () {\n\t\t\t\ttransport[ methodName ]( file, offset ).then( retryDeferred.resolve, retryDeferred.reject );\n\t\t\t};\n\n\t\tif ( this.config.useRetryTimeout !== false ) {\n\t\t\tsetTimeout( retry, 3000 );\n\t\t} else {\n\t\t\tretry();\n\t\t}\n\n\t\treturn retryDeferred.promise();\n\t};\n\n\t/**\n\t * Check the status of the upload.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.checkStatus = function () {\n\t\tconst transport = this,\n\t\t\tparams = OO.cloneObject( this.formData );\n\n\t\tif ( this.aborted ) {\n\t\t\treturn $.Deferred().reject( 'aborted', {\n\t\t\t\terrors: [ {\n\t\t\t\t\tcode: 'aborted',\n\t\t\t\t\thtml: mw.message( 'mediauploader-api-error-aborted' ).parse()\n\t\t\t\t} ]\n\t\t\t} );\n\t\t}\n\n\t\tif ( !this.firstPoll ) {\n\t\t\tthis.firstPoll = Date.now();\n\t\t}\n\t\tparams.checkstatus = true;\n\t\tparams.filekey = this.filekey;\n\t\tthis.request = this.api.post( params )\n\t\t\t.then( ( response ) => {\n\t\t\t\tif ( response.upload && response.upload.result === 'Poll' ) {\n\t\t\t\t\t// If concatenation takes longer than 10 minutes give up\n\t\t\t\t\tif ( ( Date.now() - transport.firstPoll ) > 10 * 60 * 1000 ) {\n\t\t\t\t\t\treturn $.Deferred().reject( 'server-error', { errors: [ {\n\t\t\t\t\t\t\tcode: 'server-error',\n\t\t\t\t\t\t\thtml: mw.message( 'api-clientside-error-timeout' ).parse()\n\t\t\t\t\t\t} ] } );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( response.upload.stage === undefined ) {\n\t\t\t\t\t\t\tmw.log.warn( 'Unable to check file\\'s status' );\n\t\t\t\t\t\t\treturn $.Deferred().reject( 'server-error', { errors: [ {\n\t\t\t\t\t\t\t\tcode: 'server-error',\n\t\t\t\t\t\t\t\thtml: mw.message( 'api-clientside-error-invalidresponse' ).parse()\n\t\t\t\t\t\t\t} ] } );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Statuses that can be returned:\n\t\t\t\t\t\t\t// * queued\n\t\t\t\t\t\t\t// * publish\n\t\t\t\t\t\t\t// * assembling\n\t\t\t\t\t\t\ttransport.emit( 'update-stage', response.upload.stage );\n\t\t\t\t\t\t\treturn transport.retryWithMethod( 'checkStatus' );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn response;\n\t\t\t}, ( code, result ) => $.Deferred().reject( code, result ) );\n\n\t\treturn this.request;\n\t};\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Deed.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":55,"column":3,"nodeType":"CallExpression","endLine":59,"endColumn":6}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard's Deed step.\n\t *\n\t * @class uw.ui.Deed\n\t * @extends uw.ui.Step\n\t * @constructor\n\t */\n\tuw.ui.Deed = function UWUIDeed() {\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'deeds'\n\t\t);\n\n\t\tthis.addPreviousButton();\n\t\tthis.addNextButton();\n\t};\n\n\tOO.inheritClass( uw.ui.Deed, uw.ui.Step );\n\n\tuw.ui.Deed.prototype.load = function ( uploads ) {\n\t\tconst ui = this;\n\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mediauploader-deeds-thumbnails' )\n\t\t\t\t.addClass( 'ui-helper-clearfix' ),\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mediauploader-deeds' )\n\t\t\t\t.addClass( 'ui-helper-clearfix' ),\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mediauploader-deeds-custom' )\n\t\t\t\t.addClass( 'ui-helper-clearfix' )\n\t\t);\n\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\t// hide \"next\" button, controller will only show it once license has\n\t\t\t// been selected\n\t\t\tui.nextButton.$element.hide();\n\t\t} );\n\t};\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Details.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":90,"column":3,"nodeType":"CallExpression","endLine":127,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":183,"column":4,"nodeType":"CallExpression","endLine":183,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":191,"column":4,"nodeType":"CallExpression","endLine":191,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":222,"column":4,"nodeType":"CallExpression","endLine":222,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard's Details step.\n\t *\n\t * @class uw.ui.Details\n\t * @extends uw.ui.Step\n\t * @constructor\n\t */\n\tuw.ui.Details = function UWUIDetails() {\n\t\tconst details = this;\n\n\t\tfunction startDetails() {\n\t\t\tdetails.emit( 'start-details' );\n\t\t}\n\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'details'\n\t\t);\n\n\t\tthis.$errorCount = $( '<div>' )\n\t\t\t.attr( 'id', 'mediauploader-details-error-count' );\n\t\tthis.$warningCount = $( '<div>' )\n\t\t\t.attr( 'id', 'mediauploader-details-warning-count' );\n\n\t\tthis.nextButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-publish-details' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', startDetails );\n\n\t\tthis.nextButtonDespiteFailures = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-next-file-despite-failures' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', () => {\n\t\t\tdetails.emit( 'finalize-details-after-removal' );\n\t\t} );\n\n\t\tthis.retryButtonSomeFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-file-retry' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', startDetails );\n\n\t\tthis.retryButtonAllFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-file-retry' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', startDetails );\n\n\t\tthis.$buttons.append( this.$errorCount, this.$warningCount );\n\t\tthis.addPreviousButton();\n\t\tthis.addNextButton();\n\t};\n\n\tOO.inheritClass( uw.ui.Details, uw.ui.Step );\n\n\tuw.ui.Details.prototype.load = function ( uploads ) {\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mediauploader-macro-files' )\n\t\t\t\t.addClass( 'mediauploader-filled-filelist ui-corner-all' )\n\t\t);\n\n\t\t// set default buttons visibility (can be altered in controller later)\n\t\tthis.$div.find( '.mediauploader-file-next-some-failed' ).hide();\n\t\tthis.$div.find( '.mediauploader-file-next-all-failed' ).hide();\n\t\tthis.$div.find( '.mediauploader-file-next-all-ok' ).show();\n\t};\n\n\tuw.ui.Details.prototype.addNextButton = function () {\n\t\tconst ui = this;\n\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\tui.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mediauploader-file-next-all-ok mediauploader-file-endchoice' )\n\t\t\t\t\t.append( ui.nextButton.$element )\n\t\t\t);\n\n\t\t\tui.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mediauploader-file-next-some-failed mediauploader-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mediauploader-file-some-failed' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tui.nextButtonDespiteFailures,\n\t\t\t\t\t\t\t\tui.retryButtonSomeFailed\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\n\t\t\tui.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mediauploader-file-next-all-failed mediauploader-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mediauploader-file-all-failed' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tui.retryButtonAllFailed\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\t\t} );\n\t};\n\n\t/**\n\t * Hide buttons for moving to the next step.\n\t */\n\tuw.ui.Details.prototype.hideEndButtons = function () {\n\t\tthis.$errorCount.empty();\n\t\tthis.$warningCount.empty();\n\t\tthis.$div\n\t\t\t.find( '.mediauploader-buttons .mediauploader-file-endchoice' )\n\t\t\t.hide();\n\t};\n\n\t/**\n\t * Disable edits to the details.\n\t */\n\tuw.ui.Details.prototype.disableEdits = function () {\n\t\tthis.$div\n\t\t\t.find( '.mediauploader-data' )\n\t\t\t.morphCrossfade( '.mediauploader-submitting' );\n\n\t\tthis.previousButton.$element.hide();\n\t};\n\n\t/**\n\t * Re-enabled edits to the details.\n\t */\n\tuw.ui.Details.prototype.enableEdits = function () {\n\t\tthis.previousButton.$element.show();\n\t};\n\n\t/**\n\t * Show errors in the form.\n\t * The details page can be vertically long so sometimes it is not obvious there are errors above. This counts them and puts the count\n\t * right next to the submit button, so it should be obvious to the user they need to fix things.\n\t * This is a bit of a hack. We should already know how many errors there are, and where.\n\t * This method also opens up \"more info\" if the form has errors.\n\t */\n\tuw.ui.Details.prototype.showErrors = function () {\n\t\tconst $errorElements = this.$div\n\t\t\t\t// TODO Evil\n\t\t\t\t.find( '.oo-ui-fieldLayout-messages-error' ),\n\t\t\terrorCount = $errorElements.length;\n\n\t\t// Open \"more info\" if that part of the form has errors\n\t\t$errorElements.each( function () {\n\t\t\tconst $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );\n\t\t\tif ( $collapsibleWrapper.length ) {\n\t\t\t\t$collapsibleWrapper.data( 'mw-collapsible' ).expand();\n\t\t\t}\n\t\t} );\n\n\t\tif ( errorCount > 0 ) {\n\t\t\t// Errors supersede warnings, so stop any animating to the warnings before we animate to the errors\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( 'html, body' ).stop();\n\n\t\t\tthis.$errorCount\n\t\t\t\t.msg( 'mediauploader-details-error-count', errorCount, this.uploads.length )\n\t\t\t\t// TODO The IconWidget and 'warning' flag is specific to MediaWiki theme, looks weird in Apex\n\t\t\t\t.prepend( new OO.ui.IconWidget( { icon: 'alert', flags: [ 'warning' ] } ).$element, ' ' );\n\t\t\t// Scroll to the first error\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( 'html, body' ).animate( { scrollTop: $( $errorElements[ 0 ] ).offset().top - 50 }, 'slow' );\n\t\t} else {\n\t\t\tthis.$errorCount.empty();\n\t\t}\n\t};\n\n\t/**\n\t * Show warnings in the form.\n\t * See #showErrors for details.\n\t */\n\tuw.ui.Details.prototype.showWarnings = function () {\n\t\tconst $warningElements = this.$div\n\t\t\t\t// TODO Evil\n\t\t\t\t.find( '.oo-ui-fieldLayout-messages-notice' ),\n\t\t\twarningCount = $warningElements.length;\n\n\t\t// Open \"more info\" if that part of the form has warnings\n\t\t$warningElements.each( function () {\n\t\t\tconst $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );\n\t\t\tif ( $collapsibleWrapper.length ) {\n\t\t\t\t$collapsibleWrapper.data( 'mw-collapsible' ).expand();\n\t\t\t}\n\t\t} );\n\n\t\tif ( warningCount > 0 ) {\n\t\t\tthis.$warningCount\n\t\t\t\t.msg( 'mediauploader-details-warning-count', warningCount, this.uploads.length )\n\t\t\t\t// TODO The IconWidget is specific to MediaWiki theme, looks weird in Apex\n\t\t\t\t.prepend( new OO.ui.IconWidget( { icon: 'info' } ).$element, ' ' );\n\t\t\t// Scroll to the first warning\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( 'html, body' ).animate( { scrollTop: $( $warningElements[ 0 ] ).offset().top - 50 }, 'slow' );\n\t\t} else {\n\t\t\tthis.$warningCount.empty();\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Thanks.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'thanks' is never reassigned. Use 'const' instead.","line":30,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":30,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'$header' is never reassigned. Use 'const' instead.","line":48,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":48,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'beginButtonTarget' is never reassigned. Use 'const' instead.","line":69,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":69,"endColumn":20},{"ruleId":"prefer-const","severity":2,"message":"'thumbWikiText' is never reassigned. Use 'const' instead.","line":98,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":98,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'$thanksDiv' is never reassigned. Use 'const' instead.","line":104,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":104,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'$thumbnailWrapDiv' is never reassigned. Use 'const' instead.","line":106,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":106,"endColumn":20},{"ruleId":"prefer-const","severity":2,"message":"'$thumbnailDiv' is never reassigned. Use 'const' instead.","line":109,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":109,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'$thumbnailCaption' is never reassigned. Use 'const' instead.","line":112,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":112,"endColumn":20},{"ruleId":"prefer-const","severity":2,"message":"'$thumbnailLink' is never reassigned. Use 'const' instead.","line":115,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":115,"endColumn":17},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":128,"column":3,"nodeType":"CallExpression","endLine":130,"endColumn":6}],"suppressedMessages":[],"errorCount":10,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard's Thanks step.\n\t *\n\t * @class uw.ui.Thanks\n\t * @extends uw.ui.Step\n\t * @constructor\n\t * @param {Object} config\n\t */\n\tuw.ui.Thanks = function UWUIThanks( config ) {\n\t\tlet $header,\n\t\t\tbeginButtonTarget,\n\t\t\tthanks = this;\n\n\t\tthis.config = config;\n\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'thanks'\n\t\t);\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' ).attr( 'id', 'mediauploader-thanks' )\n\t\t);\n\n\t\t$( '<p>' )\n\t\t\t.addClass( 'mediauploader-thanks-explain' )\n\t\t\t.msg( 'mediauploader-thanks-explain' )\n\t\t\t.prependTo( this.$div );\n\n\t\t$header = $( '<h3>' )\n\t\t\t.addClass( 'mediauploader-thanks-header' )\n\t\t\t.prependTo( this.$div );\n\n\t\tif ( !this.config.display || !this.config.display.thanksLabel ) {\n\t\t\t$header.text( mw.message( 'mediauploader-thanks-intro' ).text() );\n\t\t} else {\n\t\t\t$header.html( this.config.display.thanksLabel );\n\t\t}\n\n\t\tthis.homeButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: this.getButtonConfig( 'homeButton', 'label' ) || mw.message( 'mediauploader-home' ).text(),\n\t\t\thref: this.getButtonConfig( 'homeButton', 'target' ) || mw.config.get( 'wgArticlePath' ).replace( '$1', '' )\n\t\t} );\n\n\t\tthis.beginButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: this.getButtonConfig( 'beginButton', 'label' ) || mw.message( 'mediauploader-upload-another' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} );\n\n\t\t// TODO: make the step order configurable by campaign definitions instead of using these hacks\n\t\tbeginButtonTarget = this.getButtonConfig( 'beginButton', 'target' );\n\t\tif ( !beginButtonTarget ) {\n\t\t\tthis.beginButton.on( 'click', () => {\n\t\t\t\tthanks.emit( 'next-step' );\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.beginButton.setHref( beginButtonTarget );\n\t\t}\n\t\tthis.beginButton.on( 'click', () => {\n\t\t\tmw.DestinationChecker.clearCache();\n\t\t} );\n\n\t\tthis.buttonGroup = new OO.ui.HorizontalLayout( {\n\t\t\titems: [ this.homeButton, this.beginButton ]\n\t\t} );\n\n\t\tthis.$buttons.append( this.buttonGroup.$element );\n\t};\n\n\tOO.inheritClass( uw.ui.Thanks, uw.ui.Step );\n\n\t/**\n\t * Adds an upload to the Thanks interface.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.ui.Thanks.prototype.addUpload = function ( upload ) {\n\t\tlet thumbWikiText, $thanksDiv, $thumbnailWrapDiv, $thumbnailDiv, $thumbnailCaption, $thumbnailLink;\n\n\t\tthumbWikiText = '[[' + [\n\t\t\tupload.details.getTitle().getPrefixedText(),\n\t\t\t'thumb',\n\t\t\tupload.details.getThumbnailCaption()\n\t\t].join( '|' ) + ']]';\n\n\t\t$thanksDiv = $( '<div>' )\n\t\t\t.addClass( 'mediauploader-thanks ui-helper-clearfix' );\n\t\t$thumbnailWrapDiv = $( '<div>' )\n\t\t\t.addClass( 'mediauploader-thumbnail-side' )\n\t\t\t.appendTo( $thanksDiv );\n\t\t$thumbnailDiv = $( '<div>' )\n\t\t\t.addClass( 'mediauploader-thumbnail' )\n\t\t\t.appendTo( $thumbnailWrapDiv );\n\t\t$thumbnailCaption = $( '<div>' )\n\t\t\t.css( { 'text-align': 'center', 'font-size': 'small' } )\n\t\t\t.appendTo( $thumbnailWrapDiv );\n\t\t$thumbnailLink = $( '<a>' )\n\t\t\t.text( upload.details.getTitle().getMainText() )\n\t\t\t.appendTo( $thumbnailCaption );\n\n\t\t$( '<div>' )\n\t\t\t.addClass( 'mediauploader-data' )\n\t\t\t.appendTo( $thanksDiv )\n\t\t\t.append(\n\t\t\t\tthis.makeReadOnlyInput( thumbWikiText, mw.message( 'mediauploader-thanks-wikitext' ).text(), true ),\n\t\t\t\tthis.makeReadOnlyInput( upload.imageinfo.descriptionurl, mw.message( 'mediauploader-thanks-url' ).text() )\n\t\t\t);\n\n\t\t// This must match the CSS dimensions of .mediauploader-thumbnail\n\t\tupload.getThumbnail( 120, 120 ).done( ( thumb ) => {\n\t\t\tmw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );\n\t\t} );\n\n\t\t// Set the thumbnail links so that they point to the image description page\n\t\t$thumbnailLink.add( $thumbnailDiv.find( '.mediauploader-thumbnail-link' ) ).attr( {\n\t\t\thref: upload.imageinfo.descriptionurl,\n\t\t\ttarget: '_blank'\n\t\t} );\n\n\t\tthis.$div.find( '.mediauploader-buttons' ).before( $thanksDiv );\n\t};\n\n\t/**\n\t * Make an mw.widgets.CopyTextLayout, which features a button\n\t * to copy the text provided.\n\t *\n\t * @param {string} value Text it will contain\n\t * @param {string} label Label\n\t * @param {string} [useEditFont] Use edit font (for wikitext values)\n\t * @return {jQuery}\n\t */\n\tuw.ui.Thanks.prototype.makeReadOnlyInput = function ( value, label, useEditFont ) {\n\t\tconst copyText = new mw.widgets.CopyTextLayout( {\n\t\t\talign: 'top',\n\t\t\tlabel: label,\n\t\t\tcopyText: value\n\t\t} );\n\n\t\tif ( useEditFont ) {\n\t\t\t// The following classes are used here:\n\t\t\t// * mw-editfont-monospace\n\t\t\t// * mw-editfont-sans-serif\n\t\t\t// * mw-editfont-serif\n\t\t\tcopyText.textInput.$element.addClass( 'mw-editfont-' + mw.user.options.get( 'editfont' ) );\n\t\t}\n\n\t\treturn copyText.$element;\n\t};\n\n\t/**\n\t * Get button configuration options from a campaign definition\n\t *\n\t * @param {string} buttonName name of the button as defined in campaign configuration\n\t * @param {string} configField name of the button's attributes\n\t * @return {Object|undefined}\n\t */\n\tuw.ui.Thanks.prototype.getButtonConfig = function ( buttonName, configField ) {\n\t\tif ( !this.config.display || !this.config.display[ buttonName ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn this.config.display[ buttonName ][ configField ];\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Tutorial.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":125,"column":3,"nodeType":"CallExpression","endLine":131,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":87,"column":24,"nodeType":"CallExpression","endLine":87,"endColumn":59,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Checkbox with popup information.\n\t *\n\t * @param {Object} config\n\t */\n\tfunction PopupCheckboxInputWidget( config ) {\n\t\t// Parent constructor\n\t\tPopupCheckboxInputWidget.parent.call( this, config );\n\n\t\t// Mixin constructors\n\t\tOO.ui.mixin.PopupElement.call( this, config );\n\n\t\t// Events\n\t\tthis.connect( this, { change: 'onChange' } );\n\n\t\t// Initialization\n\t\tthis.$element\n\t\t\t.addClass( 'oo-ui-popupCheckboxInputWidget' )\n\t\t\t.attr( 'aria-haspopup', 'true' )\n\t\t\t.append( this.popup.$element );\n\t}\n\tOO.inheritClass( PopupCheckboxInputWidget, OO.ui.CheckboxInputWidget );\n\tOO.mixinClass( PopupCheckboxInputWidget, OO.ui.mixin.PopupElement );\n\tPopupCheckboxInputWidget.prototype.onChange = function () {\n\t\tthis.popup.toggle( this.isSelected() );\n\t};\n\n\t/**\n\t * Represents the UI for the wizard's Tutorial step.\n\t *\n\t * @class uw.ui.Tutorial\n\t * @extends uw.ui.Step\n\t * @constructor\n\t */\n\tuw.ui.Tutorial = function UWUITutorial() {\n\t\tconst ui = this;\n\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'tutorial'\n\t\t);\n\n\t\t// 'Skip tutorial' checkbox\n\t\tthis.skipCheckbox = new PopupCheckboxInputWidget( {\n\t\t\tid: 'mediauploader-skip',\n\t\t\t// Add a friendly \"Here's how to get it back\" tooltip for users who check the \"Skip next time\" checkbox\n\t\t\tpopup: {\n\t\t\t\t$content: $( '<p>' ).msg(\n\t\t\t\t\t'mediauploader-tooltip-skiptutorial',\n\t\t\t\t\tmw.config.get( 'wgServer' ) + mw.util.getUrl( 'Special:Preferences' ) + '#mw-prefsection-uploads',\n\t\t\t\t\tmw.message( 'prefs-uploads' ).text(),\n\t\t\t\t\tmw.message( 'prefs-mediauploader-interface' ).text()\n\t\t\t\t),\n\t\t\t\tautoClose: false,\n\t\t\t\tpadded: true\n\t\t\t}\n\t\t} );\n\t\tthis.skipCheckboxLabel = new OO.ui.LabelWidget( {\n\t\t\tinput: this.skipCheckbox,\n\t\t\tlabel: mw.message( 'mediauploader-skip-tutorial-future' ).text()\n\t\t} );\n\n\t\tthis.skipCheckbox.on( 'change', () => {\n\t\t\tui.emit( 'skip-tutorial-click', ui.skipCheckbox.isSelected() );\n\t\t} );\n\n\t\t// grab the tutorial HTML that was injected into this document\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\tthis.$tutorialHtml = $( '#mediauploader-tutorial-html' );\n\n\t\tthis.addPreviousButton();\n\t\tthis.addNextButton();\n\t};\n\n\tOO.inheritClass( uw.ui.Tutorial, uw.ui.Step );\n\n\tuw.ui.Tutorial.prototype.setSelected = function ( selected ) {\n\t\tthis.skipCheckbox.setSelected( selected );\n\t};\n\n\tuw.ui.Tutorial.prototype.load = function ( uploads ) {\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mediauploader-tutorial' )\n\t\t\t\t.append(\n\t\t\t\t\t// TODO move this to JavaScript, too.\n\t\t\t\t\tthis.$tutorialHtml.show()\n\t\t\t\t)\n\t\t);\n\n\t\tthis.skipCheckbox.popup.updateDimensions();\n\t};\n\n\tuw.ui.Tutorial.prototype.addNextButton = function () {\n\t\tconst ui = this;\n\n\t\tthis.nextButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mediauploader-button-next' ],\n\t\t\tlabel: mw.message( 'mediauploader-next' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', () => {\n\t\t\tui.emit( 'next-step' );\n\t\t} );\n\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\tui.$buttons.append(\n\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\titems: [ ui.skipCheckbox, ui.skipCheckboxLabel, ui.nextButton ]\n\t\t\t\t} ).$element\n\t\t\t);\n\t\t} );\n\t};\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Upload.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":210,"column":6,"nodeType":"CallExpression","endLine":212,"endColumn":9},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":222,"column":3,"nodeType":"CallExpression","endLine":270,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":132,"column":4,"nodeType":"CallExpression","endLine":132,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":134,"column":4,"nodeType":"CallExpression","endLine":134,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard's Upload step.\n\t *\n\t * @class uw.ui.Upload\n\t * @extends uw.ui.Step\n\t * @constructor\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.ui.Upload = function UWUIUpload( config ) {\n\t\tconst upload = this;\n\n\t\tthis.config = config;\n\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'file'\n\t\t);\n\n\t\tthis.$addFileContainer = $( '<div>' )\n\t\t\t.attr( 'id', 'mediauploader-add-file-container' )\n\t\t\t.addClass( 'mediauploader-add-files-0' );\n\n\t\tthis.$uploadCtrl = $( '<div>' )\n\t\t\t.attr( 'id', 'mediauploader-upload-ctrls' )\n\t\t\t.addClass( 'mediauploader-file ui-helper-clearfix' )\n\t\t\t.append( this.$addFileContainer );\n\n\t\tthis.addFile = new OO.ui.SelectFileWidget( {\n\t\t\tclasses: [ 'mediauploader-add-file' ],\n\t\t\tmultiple: true,\n\t\t\tshowDropTarget: true,\n\t\t\tbutton: {\n\t\t\t\tlabel: mw.message( 'mediauploader-add-file-0-free' ).text(),\n\t\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t\t}\n\t\t} );\n\n\t\tthis.$addFileContainer.append( this.addFile.$element );\n\n\t\tthis.nextStepButtonAllOk = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-next-file' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', () => {\n\t\t\tupload.emit( 'next-step' );\n\t\t} );\n\n\t\tthis.retryButtonSomeFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-file-retry' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', () => {\n\t\t\tupload.hideEndButtons();\n\t\t\tupload.emit( 'retry' );\n\t\t} );\n\n\t\tthis.nextStepButtonSomeFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-next-file-despite-failures' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', () => {\n\t\t\tupload.emit( 'next-step' );\n\t\t} );\n\n\t\tthis.retryButtonAllFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-file-retry' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', () => {\n\t\t\tupload.hideEndButtons();\n\t\t\tupload.emit( 'retry' );\n\t\t} );\n\n\t\tthis.$fileList = $( '<div>' )\n\t\t\t.attr( 'id', 'mediauploader-filelist' )\n\t\t\t.addClass( 'ui-corner-all' );\n\n\t\tthis.$progress = $( '<div>' )\n\t\t\t.attr( 'id', 'mediauploader-progress' )\n\t\t\t.addClass( 'ui-helper-clearfix' );\n\n\t\tthis.addPreviousButton();\n\t\tthis.addNextButton();\n\t};\n\n\tOO.inheritClass( uw.ui.Upload, uw.ui.Step );\n\n\tuw.ui.Upload.prototype.showProgressBar = function () {\n\t\tthis.$progress.show();\n\t};\n\n\t/**\n\t * Updates the interface based on the number of uploads.\n\t *\n\t * @param {boolean} haveUploads Whether there are any uploads at all.\n\t * @param {boolean} fewerThanMax Whether we can add more uploads.\n\t */\n\tuw.ui.Upload.prototype.updateFileCounts = function ( haveUploads, fewerThanMax ) {\n\t\tthis.$fileList.toggleClass( 'mediauploader-filled-filelist', haveUploads );\n\t\tthis.$addFileContainer.toggleClass( 'mediauploader-add-files-0', !haveUploads );\n\n\t\tthis.setAddButtonText( haveUploads );\n\n\t\tif ( haveUploads ) {\n\t\t\t// we have uploads ready to go, so allow us to proceed\n\t\t\tthis.$addFileContainer.add( this.$buttons ).show();\n\n\t\t\t// fix the rounded corners on file elements.\n\t\t\t// we want them to be rounded only when their edge touched the top or bottom of the filelist.\n\t\t\tthis.$fileListings = this.$fileList.find( '.filled' );\n\n\t\t\tthis.$visibleFileListings = this.$fileListings.find( '.mediauploader-visible-file' );\n\t\t\tthis.$visibleFileListings.removeClass( 'ui-corner-top ui-corner-bottom' );\n\t\t\tthis.$visibleFileListings.first().addClass( 'ui-corner-top' );\n\t\t\tthis.$visibleFileListings.last().addClass( 'ui-corner-bottom' );\n\n\t\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t\tthis.$fileListings.filter( ':odd' ).addClass( 'odd' );\n\t\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t\tthis.$fileListings.filter( ':even' ).removeClass( 'odd' );\n\t\t} else {\n\t\t\tthis.hideEndButtons();\n\t\t}\n\n\t\tthis.addFile.setDisabled( !fewerThanMax );\n\t};\n\n\t/**\n\t * Changes the initial centered invitation button to something like \"add another file\"\n\t *\n\t * @param {boolean} more\n\t */\n\tuw.ui.Upload.prototype.setAddButtonText = function ( more ) {\n\t\tlet msg = 'mediauploader-add-file-';\n\n\t\tif ( more ) {\n\t\t\tmsg += 'n';\n\t\t} else {\n\t\t\tmsg += '0-free';\n\t\t}\n\n\t\t// Messages that can be used here:\n\t\t// * mediauploader-add-file-0-free\n\t\t// * mediauploader-add-file-n\n\t\tthis.addFile.selectButton.setLabel( mw.message( msg ).text() );\n\t};\n\n\tuw.ui.Upload.prototype.load = function ( uploads ) {\n\t\tconst ui = this;\n\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tif ( uploads.length === 0 ) {\n\t\t\tthis.$fileList.removeClass( 'mediauploader-filled-filelist' );\n\t\t}\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mediauploader-files' )\n\t\t\t\t.append(\n\t\t\t\t\tthis.$fileList,\n\t\t\t\t\tthis.$uploadCtrl\n\t\t\t\t)\n\t\t);\n\n\t\tthis.addFile.on( 'change', ( files ) => {\n\t\t\tui.emit( 'files-added', files );\n\t\t\tui.addFile.setValue( null );\n\t\t} );\n\t};\n\n\tuw.ui.Upload.prototype.displayUploads = function ( uploads ) {\n\t\tlet thumbPromise,\n\t\t\t$uploadInterfaceDivs = $( [] );\n\n\t\tuploads.forEach( ( upload ) => {\n\t\t\t// We'll attach all interfaces to the DOM at once rather than one-by-one, for better\n\t\t\t// performance\n\t\t\t$uploadInterfaceDivs = $uploadInterfaceDivs.add( upload.ui.$div );\n\t\t} );\n\n\t\t// Attach all interfaces to the DOM\n\t\tthis.$fileList.append( $uploadInterfaceDivs );\n\n\t\t// Display thumbnails, but not all at once because they're somewhat expensive to generate.\n\t\t// This will wait for each thumbnail to be complete before starting the next one.\n\t\tthumbPromise = $.Deferred().resolve();\n\t\tuploads.forEach( ( upload ) => {\n\t\t\tthumbPromise = thumbPromise.then( () => {\n\t\t\t\tconst deferred = $.Deferred();\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\tif ( this.movedFrom ) {\n\t\t\t\t\t\t// We're no longer displaying any of these thumbnails, stop\n\t\t\t\t\t\tdeferred.reject();\n\t\t\t\t\t}\n\t\t\t\t\tupload.ui.showThumbnail().done( () => {\n\t\t\t\t\t\tdeferred.resolve();\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t\treturn deferred.promise();\n\t\t\t} );\n\t\t} );\n\t};\n\n\tuw.ui.Upload.prototype.addNextButton = function () {\n\t\tconst ui = this;\n\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\tui.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mediauploader-file-next-all-ok mediauploader-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mediauploader-file-all-ok' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tui.nextStepButtonAllOk\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\n\t\t\tui.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mediauploader-file-next-some-failed mediauploader-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mediauploader-file-some-failed' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tui.retryButtonSomeFailed,\n\t\t\t\t\t\t\t\tui.nextStepButtonSomeFailed\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\n\t\t\tui.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mediauploader-file-next-all-failed mediauploader-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mediauploader-file-all-failed' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tui.retryButtonAllFailed\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\n\t\t\tui.$buttons.append( ui.$progress );\n\t\t} );\n\t};\n\n\t/**\n\t * Hide the buttons for moving to the next step.\n\t */\n\tuw.ui.Upload.prototype.hideEndButtons = function () {\n\t\tthis.$div\n\t\t\t.find( '.mediauploader-buttons .mediauploader-file-endchoice' )\n\t\t\t.hide();\n\t};\n\n\t/**\n\t * Shows an error dialog informing the user that some uploads have been omitted\n\t * since they went over the max files limit.\n\t *\n\t * @param {number} filesUploaded The number of files that have been attempted to upload\n\t */\n\tuw.ui.Upload.prototype.showTooManyFilesError = function ( filesUploaded ) {\n\t\tmw.errorDialog(\n\t\t\tmw.message(\n\t\t\t\t'mediauploader-too-many-files-text',\n\t\t\t\tthis.config.maxUploads,\n\t\t\t\tfilesUploaded\n\t\t\t).text(),\n\t\t\tmw.message( 'mediauploader-too-many-files' ).text()\n\t\t);\n\t};\n\n\t/**\n\t * Shows an error dialog informing the user that an upload omitted because\n\t * it is too large.\n\t *\n\t * @param {number} maxSize The max upload file size\n\t * @param {number} size The actual upload file size\n\t */\n\tuw.ui.Upload.prototype.showFileTooLargeError = function ( maxSize, size ) {\n\t\tmw.errorDialog(\n\t\t\tmw.message(\n\t\t\t\t'mediauploader-file-too-large-text',\n\t\t\t\tuw.units.bytes( maxSize ),\n\t\t\t\tuw.units.bytes( size )\n\t\t\t).text(),\n\t\t\tmw.message( 'mediauploader-file-too-large' ).text()\n\t\t);\n\t};\n\n\t/**\n\t * @param {string} filename\n\t * @param {string} extension\n\t */\n\tuw.ui.Upload.prototype.showBadExtensionError = function ( filename, extension ) {\n\t\tconst $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-extension', extension );\n\t\tthis.showFilenameError( $errorMessage );\n\t};\n\n\tuw.ui.Upload.prototype.showMissingExtensionError = function () {\n\t\tconst $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-no-extension' );\n\t\tthis.showFilenameError(\n\t\t\t$( '<div>' ).append(\n\t\t\t\t$errorMessage,\n\t\t\t\t$( '<p>' ).msg( 'mediauploader-allowed-filename-extensions' ),\n\t\t\t\t$( '<blockquote>' ).append( $( '<tt>' ).append(\n\t\t\t\t\tmw.UploadWizard.config.fileExtensions.join( ' ' )\n\t\t\t\t) )\n\t\t\t)\n\t\t);\n\t};\n\n\t/**\n\t * @param {string} filename\n\t * @param {string} basename\n\t */\n\tuw.ui.Upload.prototype.showDuplicateError = function ( filename, basename ) {\n\t\tthis.showFilenameError( $( '<p>' ).msg( 'mediauploader-upload-error-duplicate-filename-error', basename ) );\n\t};\n\n\t/**\n\t * @param {string} filename\n\t */\n\tuw.ui.Upload.prototype.showUnparseableFilenameError = function ( filename ) {\n\t\tthis.showFilenameError( mw.message( 'mediauploader-unparseable-filename', filename ).escaped() );\n\t};\n\n\t/**\n\t * Shows an error dialog informing the user that an upload has been omitted\n\t * over its filename.\n\t *\n\t * @param {jQuery|string} message The error message\n\t */\n\tuw.ui.Upload.prototype.showFilenameError = function ( message ) {\n\t\tmw.errorDialog( message );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/uw.ui.DeedPreview.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":30,"column":3,"nodeType":"CallExpression","endLine":32,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":34,"column":3,"nodeType":"CallExpression","endLine":34,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for a thumbnail in the Deed step.\n\t *\n\t * @class uw.ui.DeedPreview\n\t * @constructor\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.ui.DeedPreview = function UWUIDeedPreview( upload ) {\n\t\tconst $thumbnailDiv = $( '<div>' ).addClass( 'mediauploader-thumbnail' );\n\t\tthis.$thumbnailDiv = $thumbnailDiv;\n\t\t// This must match the CSS dimensions of .mediauploader-thumbnail\n\t\tupload.getThumbnail( 120, 120 ).done( ( thumb ) => {\n\t\t\tmw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );\n\t\t} );\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( '#mediauploader-deeds-thumbnails' ).append( this.$thumbnailDiv );\n\t};\n\n\tuw.ui.DeedPreview.prototype.remove = function () {\n\t\tif ( this.$thumbnailDiv ) {\n\t\t\tthis.$thumbnailDiv.remove();\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/uw.ui.Step.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":101,"column":3,"nodeType":"CallExpression","endLine":103,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":119,"column":3,"nodeType":"CallExpression","endLine":121,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":39,"column":3,"nodeType":"CallExpression","endLine":39,"endColumn":32,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":56,"column":18,"nodeType":"CallExpression","endLine":56,"endColumn":27,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":64,"column":3,"nodeType":"CallExpression","endLine":64,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents a generic UI for a step.\n\t *\n\t * @class uw.ui.Step\n\t * @constructor\n\t * @param {string} name The name of this step\n\t */\n\tuw.ui.Step = function UWUIStep( name ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.name = name;\n\n\t\tthis.$buttons = $( '<div>' ).addClass( 'mediauploader-buttons' );\n\n\t\tthis.$div = $( '<div>' )\n\t\t\t.attr( 'id', 'mediauploader-stepdiv-' + this.name )\n\t\t\t.addClass( 'mediauploader-stepdiv' )\n\t\t\t.hide();\n\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( '#mediauploader-content' ).append( this.$div );\n\n\t\t// this will make sure that buttons will only be added if they've been\n\t\t// set in the controller, otherwise there's nowhere to go...\n\t\tthis.nextButtonPromise = $.Deferred();\n\t\tthis.previousButtonPromise = $.Deferred();\n\t};\n\n\tOO.mixinClass( uw.ui.Step, OO.EventEmitter );\n\n\t/**\n\t * Initialize this step.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t */\n\tuw.ui.Step.prototype.load = function ( uploads ) {\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\tconst offset = $( 'h1' ).first().offset();\n\n\t\tthis.movedFrom = false;\n\n\t\tthis.uploads = uploads;\n\t\tthis.$div.append( this.$buttons ).show();\n\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( 'html, body' ).animate( {\n\t\t\tscrollTop: offset.top,\n\t\t\tscrollLeft: offset.left\n\t\t}, 'slow' );\n\t};\n\n\t/**\n\t * Cleanup this step.\n\t */\n\tuw.ui.Step.prototype.unload = function () {\n\t\tthis.movedFrom = true;\n\n\t\tthis.$div.children().detach();\n\t};\n\n\tuw.ui.Step.prototype.enableNextButton = function () {\n\t\tthis.nextButtonPromise.resolve();\n\t};\n\n\tuw.ui.Step.prototype.enablePreviousButton = function () {\n\t\tthis.previousButtonPromise.resolve();\n\t};\n\n\t/**\n\t * Add a 'next' button to the step's button container\n\t */\n\tuw.ui.Step.prototype.addNextButton = function () {\n\t\tconst ui = this;\n\n\t\tthis.nextButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mediauploader-button-next' ],\n\t\t\tlabel: mw.message( 'mediauploader-next' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', () => {\n\t\t\tui.emit( 'next-step' );\n\t\t} );\n\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\tui.$buttons.append( ui.nextButton.$element );\n\t\t} );\n\t};\n\n\t/**\n\t * Add a 'previous' button to the step's button container\n\t */\n\tuw.ui.Step.prototype.addPreviousButton = function () {\n\t\tconst ui = this;\n\n\t\tthis.previousButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mediauploader-button-previous' ],\n\t\t\tlabel: mw.message( 'mediauploader-previous' ).text()\n\t\t} ).on( 'click', () => {\n\t\t\tui.emit( 'previous-step' );\n\t\t} );\n\n\t\tthis.previousButtonPromise.done( () => {\n\t\t\tui.$buttons.append( ui.previousButton.$element );\n\t\t} );\n\t};\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/uw.ui.Wizard.js","messages":[],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":49,"column":23,"nodeType":"CallExpression","endLine":49,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":66,"column":3,"nodeType":"CallExpression","endLine":66,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/uw.ui.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.ConcurrentQueue.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'index' is never reassigned. Use 'const' instead.","line":117,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":117,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'item' is never reassigned. Use 'const' instead.","line":139,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":139,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'promise' is never reassigned. Use 'const' instead.","line":145,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":145,"endColumn":10}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A queue that will execute the asynchronous function `action` for each item in the queue in\n\t * order, taking care not to allow more than `count` instances to be executing at the same time.\n\t *\n\t * Items can be added or removed (#addItem, #removeItem) while the queue is already being\n\t * executed.\n\t *\n\t * @param {Object} options\n\t * @param {Function} options.action Action to execute for each item, must return a Promise\n\t * @param {number} options.count Number of functions to execute concurrently\n\t */\n\tuw.ConcurrentQueue = function UWConcurrentQueue( options ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.count = options.count;\n\t\tthis.action = options.action;\n\n\t\tthis.queued = [];\n\t\tthis.running = [];\n\t\tthis.done = [];\n\t\tthis.runningPromises = [];\n\n\t\tthis.completed = false;\n\t\tthis.executing = false;\n\t};\n\tOO.initClass( uw.ConcurrentQueue );\n\tOO.mixinClass( uw.ConcurrentQueue, OO.EventEmitter );\n\n\t/**\n\t * A 'progress' event is emitted when one of the functions' promises is resolved or rejected.\n\t *\n\t * @event progress\n\t */\n\n\t/**\n\t * A 'complete' event is emitted when all of the functions' promises have been resolved or rejected.\n\t *\n\t * @event complete\n\t */\n\n\t/**\n\t * A 'change' event is emitted when an item is added to or removed from the queue.\n\t *\n\t * @event change\n\t */\n\n\t/**\n\t * Add an item to the queue.\n\t *\n\t * @param {Object} item\n\t * @return {boolean} true\n\t */\n\tuw.ConcurrentQueue.prototype.addItem = function ( item ) {\n\t\tthis.queued.push( item );\n\t\tthis.emit( 'change' );\n\t\tif ( this.executing ) {\n\t\t\tthis.executeNext();\n\t\t}\n\t\treturn true;\n\t};\n\n\t/**\n\t * Remove an item from the queue.\n\t *\n\t * While it's possible to remove an item that is being executed, it doesn't stop the execution.\n\t *\n\t * @param {Object} item\n\t * @return {boolean} Whether the item was removed\n\t */\n\tuw.ConcurrentQueue.prototype.removeItem = function ( item ) {\n\t\tlet index, found;\n\n\t\tfound = false;\n\n\t\tindex = this.queued.indexOf( item );\n\t\tif ( index !== -1 ) {\n\t\t\tthis.queued.splice( index, 1 );\n\t\t\tfound = true;\n\t\t}\n\n\t\tindex = this.done.indexOf( item );\n\t\tif ( index !== -1 ) {\n\t\t\tthis.done.splice( index, 1 );\n\t\t\tfound = true;\n\t\t}\n\n\t\tindex = this.running.indexOf( item );\n\t\tif ( index !== -1 ) {\n\t\t\t// Try aborting the promise if possible\n\t\t\tif ( this.runningPromises[ index ].abort ) {\n\t\t\t\tthis.runningPromises[ index ].abort();\n\t\t\t}\n\t\t\tthis.running.splice( index, 1 );\n\t\t\tthis.runningPromises.splice( index, 1 );\n\t\t\tfound = true;\n\t\t}\n\n\t\tif ( found ) {\n\t\t\tthis.emit( 'change' );\n\t\t\tthis.checkIfComplete();\n\t\t}\n\n\t\t// Ensure we're still using as many threads as requested\n\t\tthis.executeNext();\n\n\t\treturn found;\n\t};\n\n\t/**\n\t * @private\n\t * @param {Object} item\n\t */\n\tuw.ConcurrentQueue.prototype.promiseComplete = function ( item ) {\n\t\tlet index;\n\t\tindex = this.running.indexOf( item );\n\t\t// Check that this item wasn't removed while it was being executed\n\t\tif ( index !== -1 ) {\n\t\t\tthis.running.splice( index, 1 );\n\t\t\tthis.runningPromises.splice( index, 1 );\n\t\t\tthis.done.push( item );\n\t\t\tthis.emit( 'progress' );\n\t\t}\n\n\t\tthis.checkIfComplete();\n\n\t\tthis.executeNext();\n\t};\n\n\t/**\n\t * @private\n\t */\n\tuw.ConcurrentQueue.prototype.executeNext = function () {\n\t\tlet item, promise;\n\t\tif ( this.running.length === this.count || !this.executing ) {\n\t\t\treturn;\n\t\t}\n\t\titem = this.queued.shift();\n\t\tif ( !item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.running.push( item );\n\t\tpromise = this.action.call( null, item );\n\t\tthis.runningPromises.push( promise );\n\t\tpromise.always( this.promiseComplete.bind( this, item ) );\n\t};\n\n\t/**\n\t * Start executing the queue. If the queue is already executing, do nothing.\n\t *\n\t * When the queue finishes executing, a 'complete' event will be emitted.\n\t */\n\tuw.ConcurrentQueue.prototype.startExecuting = function () {\n\t\tlet i;\n\t\tif ( this.executing ) {\n\t\t\treturn;\n\t\t}\n\t\tthis.completed = false;\n\t\tthis.executing = true;\n\t\tfor ( i = 0; i < this.count; i++ ) {\n\t\t\tthis.executeNext();\n\t\t}\n\t\t// In case the queue was empty\n\t\tthis.checkIfComplete();\n\t};\n\n\t/**\n\t * Abort executing the queue. Remove all queued items and abort running ones.\n\t */\n\tuw.ConcurrentQueue.prototype.abortExecuting = function () {\n\t\twhile ( this.queued.length > 0 ) {\n\t\t\tthis.removeItem( this.queued[ 0 ] );\n\t\t}\n\t\twhile ( this.running.length > 0 ) {\n\t\t\tthis.removeItem( this.running[ 0 ] );\n\t\t}\n\t};\n\n\t/**\n\t * @private\n\t */\n\tuw.ConcurrentQueue.prototype.checkIfComplete = function () {\n\t\tif ( this.running.length === 0 && this.queued.length === 0 ) {\n\t\t\tif ( !this.completed ) {\n\t\t\t\tthis.completed = true;\n\t\t\t\tthis.executing = false;\n\t\t\t\tthis.emit( 'complete' );\n\t\t\t}\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.CopyMetadataWidget.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'checkboxes' is never reassigned. Use 'const' instead.","line":14,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":14,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'$copyMetadataWrapperDiv' is never reassigned. Use 'const' instead.","line":15,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":15,"endColumn":27},{"ruleId":"prefer-const","severity":2,"message":"'$copyMetadataDiv' is never reassigned. Use 'const' instead.","line":16,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":16,"endColumn":20},{"ruleId":"prefer-const","severity":2,"message":"'uploads' is never reassigned. Use 'const' instead.","line":157,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":157,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'sourceUpload' is never reassigned. Use 'const' instead.","line":158,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":158,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'serialized' is never reassigned. Use 'const' instead.","line":159,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":159,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'sourceValue' is never reassigned. Use 'const' instead.","line":161,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":161,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'uploads' is never reassigned. Use 'const' instead.","line":214,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":214,"endColumn":11}],"suppressedMessages":[{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeOut","line":127,"column":3,"nodeType":"CallExpression","endLine":130,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeOut","line":144,"column":3,"nodeType":"CallExpression","endLine":147,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-loop-func","severity":2,"message":"Function declared in a loop contains unsafe references to variable(s) 'i'.","line":196,"column":6,"nodeType":"ArrowFunctionExpression","messageId":"unsafeRefs","endLine":200,"endColumn":7,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":8,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * Metadata copier in UploadWizard's \"Details\" step form.\n\t *\n\t * @extends OO.ui.Widget\n\t * @constructor\n\t * @param {Object} [config] Configuration options\n\t * @cfg {mw.UploadWizardUpload} copyFrom Upload to copy the details from\n\t * @cfg {mw.UploadWizardUpload[]} copyTo Uploads to copy the details to\n\t */\n\tuw.CopyMetadataWidget = function UWCopyMetadataWidget( config ) {\n\t\tlet metadataType, defaultStatus, copyMetadataMsg,\n\t\t\tcheckboxes = [],\n\t\t\t$copyMetadataWrapperDiv = $( '<div>' ),\n\t\t\t$copyMetadataDiv = $( '<div>' );\n\n\t\tuw.CopyMetadataWidget.parent.call( this );\n\n\t\tthis.copyFrom = config.copyFrom;\n\t\tthis.copyTo = config.copyTo;\n\t\tthis.savedSerializedData = [];\n\n\t\tfor ( metadataType in uw.CopyMetadataWidget.static.copyMetadataTypes ) {\n\t\t\tif ( Object.prototype.hasOwnProperty.call( uw.CopyMetadataWidget.static.copyMetadataTypes, metadataType ) ) {\n\t\t\t\tdefaultStatus = uw.CopyMetadataWidget.static.copyMetadataTypes[ metadataType ];\n\t\t\t\t// Messages that can be used here:\n\t\t\t\t// * mediauploader-copy-title\n\t\t\t\t// * mediauploader-copy-description\n\t\t\t\t// * mediauploader-copy-date\n\t\t\t\t// * mediauploader-copy-categories\n\t\t\t\t// * mediauploader-copy-location\n\t\t\t\t// * mediauploader-copy-other\n\t\t\t\tcopyMetadataMsg = mw.message( 'mediauploader-copy-' + metadataType ).text();\n\n\t\t\t\tcheckboxes.push( new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\t\tdata: metadataType,\n\t\t\t\t\tlabel: copyMetadataMsg,\n\t\t\t\t\tselected: defaultStatus\n\t\t\t\t} ) );\n\t\t\t}\n\t\t}\n\n\t\tthis.$success = $( '<span>' );\n\t\tthis.checkboxesWidget = new OO.ui.CheckboxMultiselectWidget( {\n\t\t\titems: checkboxes\n\t\t} );\n\t\tthis.copyButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-copy-metadata-button' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} );\n\t\tthis.undoButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-copy-metadata-button-undo' ).text()\n\t\t} );\n\n\t\tthis.checkboxesWidget.connect( this, {\n\t\t\tselect: 'onCheckboxesSelect'\n\t\t} );\n\t\tthis.copyButton.connect( this, {\n\t\t\tclick: 'onCopyClick'\n\t\t} );\n\t\tthis.undoButton.connect( this, {\n\t\t\tclick: 'onUndoClick'\n\t\t} );\n\n\t\tthis.undoButton.toggle( false );\n\t\t$copyMetadataDiv.append(\n\t\t\tthis.checkboxesWidget.$element,\n\t\t\tthis.copyButton.$element,\n\t\t\tthis.undoButton.$element,\n\t\t\tthis.$success\n\t\t);\n\n\t\t$copyMetadataWrapperDiv\n\t\t\t.append(\n\t\t\t\t$( '<a>' ).text( mw.msg( 'mediauploader-copy-metadata' ) )\n\t\t\t\t\t.prepend( $( '<span>' ).addClass( 'mw-toggle-icon' ) )\n\t\t\t\t\t.addClass( 'mediauploader-details-copy-metadata mw-collapsible-toggle' ),\n\t\t\t\t$copyMetadataDiv.addClass( 'mw-collapsible-content' )\n\t\t\t)\n\t\t\t.makeCollapsible( { collapsed: true } );\n\n\t\tthis.$element\n\t\t\t.addClass( 'mediauploader-copyMetadataWidget' )\n\t\t\t.append( $copyMetadataWrapperDiv );\n\t};\n\tOO.inheritClass( uw.CopyMetadataWidget, OO.ui.Widget );\n\n\t/**\n\t * Metadata which we can copy over to other details objects.\n\t *\n\t * Object with key: metadata name and value: boolean value indicating default checked status\n\t *\n\t * @property {Object}\n\t * @static\n\t */\n\tuw.CopyMetadataWidget.static.copyMetadataTypes = {\n\t\ttitle: true,\n\t\tdescription: true,\n\t\tdate: false,\n\t\tcategories: true,\n\t\tlocation: false,\n\t\tother: true\n\t};\n\n\t/**\n\t * Checkbox multiselect widget select event handler.\n\t *\n\t * @private\n\t */\n\tuw.CopyMetadataWidget.prototype.onCheckboxesSelect = function () {\n\t\tthis.copyButton.setDisabled( this.checkboxesWidget.findSelectedItemsData().length === 0 );\n\t};\n\n\t/**\n\t * Button click event handler.\n\t *\n\t * @private\n\t */\n\tuw.CopyMetadataWidget.prototype.onCopyClick = function () {\n\t\tconst metadataTypes = this.checkboxesWidget.findSelectedItemsData();\n\t\tthis.copyMetadata( metadataTypes );\n\n\t\tthis.undoButton.toggle( true );\n\t\t// FIXME: Use CSS transition\n\t\t// eslint-disable-next-line no-jquery/no-fade\n\t\tthis.$success\n\t\t\t.text( mw.message( 'mediauploader-copied-metadata' ).text() )\n\t\t\t.show()\n\t\t\t.fadeOut( 5000, 'linear' );\n\t};\n\n\t/**\n\t * Button click event handler.\n\t *\n\t * @private\n\t */\n\tuw.CopyMetadataWidget.prototype.onUndoClick = function () {\n\t\tthis.restoreMetadata();\n\n\t\tthis.undoButton.toggle( false );\n\t\t// FIXME: Use CSS transition\n\t\t// eslint-disable-next-line no-jquery/no-fade\n\t\tthis.$success\n\t\t\t.text( mw.message( 'mediauploader-undid-metadata' ).text() )\n\t\t\t.show()\n\t\t\t.fadeOut( 5000, 'linear' );\n\t};\n\n\t/**\n\t * Copy metadata from the first upload to other uploads.\n\t *\n\t * @param {string[]} metadataTypes Types to copy, as defined in the copyMetadataTypes property\n\t */\n\tuw.CopyMetadataWidget.prototype.copyMetadata = function ( metadataTypes ) {\n\t\tlet titleZero, matches, i,\n\t\t\tuploads = this.copyTo,\n\t\t\tsourceUpload = this.copyFrom,\n\t\t\tserialized = sourceUpload.details.getSerialized(),\n\t\t\t// Values to copy\n\t\t\tsourceValue = {},\n\t\t\t// Checks for extra behaviors\n\t\t\tcopyingTitle = false,\n\t\t\tcopyingOther = false;\n\n\t\t// Filter serialized data to only the types we want to copy\n\t\tmetadataTypes.forEach( ( type ) => {\n\t\t\tsourceValue[ type ] = serialized[ type ];\n\t\t\tcopyingTitle = copyingTitle || type === 'title';\n\t\t\tcopyingOther = copyingOther || type === 'other';\n\t\t} );\n\n\t\tif ( copyingOther ) {\n\t\t\t// Campaign fields are grouped with this, hmph\n\t\t\tsourceValue.campaigns = serialized.campaigns;\n\t\t}\n\n\t\tif ( copyingTitle ) {\n\t\t\ttitleZero = sourceValue.title.title;\n\t\t\t// Add number suffix to first title if no numbering present\n\t\t\tmatches = titleZero.match( /(\\D+)(\\d{1,3})(\\.\\D*)?$/ );\n\t\t\tif ( matches === null ) {\n\t\t\t\ttitleZero = titleZero + ' 01';\n\t\t\t}\n\t\t}\n\n\t\t// And apply\n\t\tfor ( i = 0; i < uploads.length; i++ ) {\n\t\t\tif ( copyingTitle ) {\n\t\t\t\t// Overwrite remaining title inputs with first title + increment of rightmost\n\t\t\t\t// number in the title. Note: We ignore numbers with more than three digits, because these\n\t\t\t\t// are more likely to be years (\"Wikimania 2011 Celebration\") or other non-sequence\n\t\t\t\t// numbers.\n\t\t\t\tsourceValue.title.title = titleZero.replace( /(\\D+)(\\d{1,3})(\\D*)$/,\n\t\t\t\t\t// eslint-disable-next-line no-loop-func\n\t\t\t\t\t( str, m1, m2, m3 ) => {\n\t\t\t\t\t\tconst newstr = String( +m2 + i );\n\t\t\t\t\t\treturn m1 + new Array( m2.length + 1 - newstr.length )\n\t\t\t\t\t\t\t.join( '0' ) + newstr + m3;\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.savedSerializedData[ i ] = uploads[ i ].details.getSerialized();\n\t\t\tuploads[ i ].details.setSerialized( sourceValue );\n\t\t}\n\t};\n\n\t/**\n\t * Restore previously saved metadata that we backed up when copying.\n\t */\n\tuw.CopyMetadataWidget.prototype.restoreMetadata = function () {\n\t\tlet i,\n\t\t\tuploads = this.copyTo;\n\n\t\tfor ( i = 0; i < uploads.length; i++ ) {\n\t\t\tuploads[ i ].details.setSerialized( this.savedSerializedData[ i ] );\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.DetailsWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.FieldLayout.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":20,"column":12,"nodeType":"MemberExpression","messageId":"forbidden","endLine":20,"endColumn":25}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * FieldLayout with some UploadWizard-specific bonuses.\n\t *\n\t * @extends OO.ui.FieldLayout\n\t *\n\t * @constructor\n\t * @inheritdoc\n\t * @param {OO.ui.Widget} fieldWidget\n\t * @param {Object} [config]\n\t * @param {boolean} [config.required=false] Whether to mark this field as required\n\t * @param {boolean} [config.align='top']\n\t */\n\tuw.FieldLayout = function UWFieldLayout( fieldWidget, config ) {\n\t\t// FieldLayout will add an icon which, when clicked, reveals more information\n\t\t// about the input. We'll want to display that by default, so we're getting\n\t\t// rid of the \"help\" property here & will later append that after the header\n\t\tconst help = config && config.help ? config.help : '';\n\t\tconfig = Object.assign( { align: 'top', required: false }, config, { help: '' } );\n\n\t\tuw.FieldLayout.parent.call( this, fieldWidget, config );\n\t\tuw.ValidationMessageElement.call( this, { validatedWidget: fieldWidget } );\n\n\t\tthis.required = null;\n\t\tthis.optionalMarker = new OO.ui.LabelWidget( {\n\t\t\tclasses: [ 'mediauploader-fieldLayout-indicator' ],\n\t\t\tlabel: mw.msg( 'mediauploader-label-optional' )\n\t\t} );\n\n\t\tthis.$element.addClass( 'mediauploader-fieldLayout' );\n\n\t\tthis.$element.addClass( 'mediauploader-details-fieldname-input' );\n\t\tthis.$label.addClass( 'mediauploader-details-fieldname' );\n\t\tthis.$field.addClass( 'mediauploader-details-input' );\n\n\t\tif ( help ) {\n\t\t\tthis.help = new OO.ui.LabelWidget( { label: help } );\n\t\t\tthis.$header.after( this.help.$element.addClass( 'mediauploader-details-help' ) );\n\t\t}\n\n\t\tthis.setRequired( config.required );\n\t};\n\tOO.inheritClass( uw.FieldLayout, OO.ui.FieldLayout );\n\tOO.mixinClass( uw.FieldLayout, uw.ValidationMessageElement );\n\n\t/**\n\t * @param {boolean} required Whether to mark this field as required\n\t */\n\tuw.FieldLayout.prototype.setRequired = function ( required ) {\n\t\tthis.required = !!required;\n\t\t// only add 'optional' marker after the label if that label\n\t\t// has content...\n\t\tif ( !this.required && this.$label.text() !== '' ) {\n\t\t\tthis.$header.after( this.optionalMarker.$element );\n\t\t} else {\n\t\t\tthis.optionalMarker.$element.remove();\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.LicenseGroup.js","messages":[{"ruleId":"es-x/no-object-assign","severity":1,"message":"ES2015 'Object.assign' method is forbidden.","line":37,"column":17,"nodeType":"MemberExpression","messageId":"forbidden","endLine":37,"endColumn":30},{"ruleId":"prefer-const","severity":2,"message":"'option' is never reassigned. Use 'const' instead.","line":132,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":132,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'option' is never reassigned. Use 'const' instead.","line":167,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":167,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'self' is never reassigned. Use 'const' instead.","line":191,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":191,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'values' is never reassigned. Use 'const' instead.","line":192,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":192,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'wikiTexts' is never reassigned. Use 'const' instead.","line":194,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":194,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'value' is never reassigned. Use 'const' instead.","line":196,"column":5,"nodeType":"Identifier","messageId":"useConst","endLine":196,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'self' is never reassigned. Use 'const' instead.","line":222,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":222,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'result' is never reassigned. Use 'const' instead.","line":223,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":223,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'self' is never reassigned. Use 'const' instead.","line":248,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":248,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'selectArray' is never reassigned. Use 'const' instead.","line":249,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":249,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'licenseInfo' is never reassigned. Use 'const' instead.","line":303,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":303,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'licenseText' is never reassigned. Use 'const' instead.","line":306,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":306,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'licenseInfo' is never reassigned. Use 'const' instead.","line":319,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":319,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'messageKey' is never reassigned. Use 'const' instead.","line":320,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":320,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'languageCode' is never reassigned. Use 'const' instead.","line":323,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":323,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'$icons' is never reassigned. Use 'const' instead.","line":328,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":328,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'$licenseLink' is never reassigned. Use 'const' instead.","line":334,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":334,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'$label' is never reassigned. Use 'const' instead.","line":343,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":343,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'self' is never reassigned. Use 'const' instead.","line":361,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":361,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'button' is never reassigned. Use 'const' instead.","line":372,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":372,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'input' is never reassigned. Use 'const' instead.","line":397,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":397,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":413,"column":3,"nodeType":"CallExpression","endLine":413,"endColumn":57},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":413,"column":3,"nodeType":"CallExpression","endLine":413,"endColumn":71}],"suppressedMessages":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":89,"column":37,"nodeType":"CallExpression","endLine":91,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":93,"column":38,"nodeType":"CallExpression","endLine":95,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":148,"column":39,"nodeType":"ObjectExpression","endLine":148,"endColumn":75,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":183,"column":47,"nodeType":"ObjectExpression","endLine":183,"endColumn":83,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":338,"column":20,"nodeType":"CallExpression","endLine":338,"endColumn":106,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":343,"column":12,"nodeType":"CallExpression","endLine":344,"endColumn":53,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":23,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * @extends OO.ui.LicenseGroup\n\t *\n\t * @constructor\n\t * @inheritdoc\n\t * @param {Object} config License configuration\n\t * @param {Array} config.licenses Array of license names\n\t * @param {string} [config.head] Header for the group of licenses (if present, the group of\n\t *   licenses will be collapsed and this will be the clickable title to expand the group)\n\t * @param {string} [config.subhead] Subtitle for the group of licenses\n\t * @param {string} [config.special] 'custom' if a text input field should be added\n\t * @param {string} [config.licenseWikitext] Wraps the wikitext of ONE license, $1 is the license.\n\t *   '$1' by default.\n\t * @param {string} [config.licenseSeparator] Used for joining several licenses wrapped by\n\t *   'licenseWikitext'. ' ' by default.\n\t * @param {string} [config.wrapper] Wraps the list of licenses. $1 – licenses, $2 – number of licenses.\n\t *   '$1' by default.\n\t * @param {string} type 'radio' or 'checkbox'\n\t * @param {mw.Api} api API object, used for wikitext previews\n\t * @param {number} count Number of the things we are licensing (it matters to some texts)\n\t */\n\tuw.LicenseGroup = function UWLicenseGroup( config, type, api, count ) {\n\t\tconst self = this;\n\n\t\tuw.LicenseGroup.parent.call( this, {} );\n\n\t\tif ( typeof config.licenses !== 'object' ) {\n\t\t\tthrow new Error( 'improper license config' );\n\t\t}\n\n\t\tif ( ![ 'radio', 'checkbox' ].includes( type ) ) {\n\t\t\tthrow new Error( 'Invalid type: ' + type );\n\t\t}\n\n\t\tthis.config = Object.assign( {\n\t\t\tlicenseWikitext: '$1',\n\t\t\tlicenseSeparator: ' ',\n\t\t\twrapper: '$1'\n\t\t}, config );\n\t\tthis.type = type;\n\t\tthis.api = api;\n\t\tthis.count = count;\n\t\tthis.collapsible = !!this.config.head;\n\t\tthis.textareas = {};\n\t\tthis.previewDialog = new uw.LicensePreviewDialog();\n\t\tthis.windowManager = new OO.ui.WindowManager();\n\t\tthis.windowManager.addWindows( [ this.previewDialog ] );\n\t\t$( document.body ).append( this.windowManager.$element );\n\n\t\tif ( this.type === 'radio' ) {\n\t\t\tthis.group = this.createRadioGroup( [ 'mediauploader-deed-license-group-body' ] );\n\t\t\tthis.group.connect( this, { choose: [ 'emit', 'change', this ] } );\n\t\t} else if ( this.type === 'checkbox' ) {\n\t\t\tthis.group = this.createCheckboxGroup( [ 'mediauploader-deed-license-group-body' ] );\n\t\t\tthis.group.connect( this, { select: [ 'emit', 'change', this ] } );\n\t\t}\n\n\t\t// when selecting an item that has a custom textarea, we'll immediately focus it\n\t\tthis.on( 'change', ( group, item ) => {\n\t\t\tif ( item && item.isSelected && item.isSelected() ) {\n\t\t\t\t// wrapped inside setTimeout to ensure it goes at the end of the call stack,\n\t\t\t\t// just in case something steals focus in the meantime...\n\t\t\t\tsetTimeout( () => {\n\t\t\t\t\tconst name = item.getData();\n\t\t\t\t\tif ( self.textareas[ name ] ) {\n\t\t\t\t\t\tself.textareas[ name ].focus();\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tthis.fieldset = this.createFieldset( this.group );\n\t\tthis.$element = this.fieldset.$element;\n\t};\n\tOO.inheritClass( uw.LicenseGroup, OO.ui.Widget );\n\n\tuw.LicenseGroup.prototype.unload = function () {\n\t\tthis.windowManager.$element.remove();\n\t};\n\n\t/**\n\t * @param {OO.ui.RadioSelectWidget|OO.ui.CheckboxMultiselectInputWidget} group\n\t * @return {OO.ui.FieldsetLayout}\n\t */\n\tuw.LicenseGroup.prototype.createFieldset = function ( group ) {\n\t\t/* eslint-disable mediawiki/msg-doc */\n\t\tconst $head = this.config.head && $( '<a>' )\n\t\t\t\t.addClass( 'mediauploader-deed-license-group-head' )\n\t\t\t\t.msg( this.config.head, this.count )\n\t\t\t\t.prepend( $( '<span>' ).addClass( 'mw-toggle-icon' ) ),\n\t\t\t$subhead = this.config.subhead && $( '<div>' )\n\t\t\t\t.addClass( 'mediauploader-deed-license-group-subhead' )\n\t\t\t\t.msg( this.config.subhead, this.count ),\n\t\t\tfieldset = new OO.ui.FieldsetLayout( {\n\t\t\t\tlabel: $head,\n\t\t\t\titems: [ group ],\n\t\t\t\tclasses: [ 'mediauploader-deed-license-group' ]\n\t\t\t} );\n\t\t/* eslint-enable mediawiki/msg-doc */\n\n\t\tif ( this.collapsible ) {\n\t\t\tfieldset.$group.makeCollapsible( { collapsed: true, $customTogglers: $head, toggleClasses: true } );\n\t\t}\n\t\tif ( this.config.subhead ) {\n\t\t\tfieldset.addItems(\n\t\t\t\t[ new OO.ui.FieldLayout( new OO.ui.Widget( { content: [] } ), { label: $subhead, align: 'top' } ) ],\n\t\t\t\t0 // = index; add to top\n\t\t\t);\n\t\t}\n\n\t\treturn fieldset;\n\t};\n\n\t/**\n\t * @param {Array} classes to add\n\t * @return {OO.ui.RadioSelectWidget}\n\t */\n\tuw.LicenseGroup.prototype.createRadioGroup = function ( classes ) {\n\t\tconst self = this,\n\t\t\toptions = [];\n\n\t\tthis.config.licenses.forEach( ( licenseName ) => {\n\t\t\tlet option;\n\n\t\t\tif ( mw.UploadWizard.config.licenses[ licenseName ] === undefined ) {\n\t\t\t\t// unknown license\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\toption = new OO.ui.RadioOptionWidget( {\n\t\t\t\tlabel: self.createLabel( licenseName ),\n\t\t\t\tdata: licenseName\n\t\t\t} );\n\n\t\t\t// when custom text area receives focus, we should make sure this element is selected\n\t\t\tif ( self.textareas[ licenseName ] ) {\n\t\t\t\tself.textareas[ licenseName ].on( 'focus', () => {\n\t\t\t\t\toption.setSelected( true );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\toptions.push( option );\n\t\t} );\n\n\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\treturn new OO.ui.RadioSelectWidget( { items: options, classes: classes } );\n\t};\n\n\t/**\n\t * @param {Array} classes to add\n\t * @return {OO.ui.CheckboxMultiselectInputWidget}\n\t */\n\tuw.LicenseGroup.prototype.createCheckboxGroup = function ( classes ) {\n\t\tconst self = this,\n\t\t\toptions = [];\n\n\t\tthis.config.licenses.forEach( ( licenseName ) => {\n\t\t\tlet option;\n\n\t\t\tif ( mw.UploadWizard.config.licenses[ licenseName ] === undefined ) {\n\t\t\t\t// unknown license\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\toption = new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\tlabel: self.createLabel( licenseName ),\n\t\t\t\tdata: licenseName\n\t\t\t} );\n\n\t\t\t// when custom text area receives focus, we should make sure this element is selected\n\t\t\tif ( self.textareas[ licenseName ] ) {\n\t\t\t\tself.textareas[ licenseName ].on( 'focus', () => {\n\t\t\t\t\toption.setSelected( true );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\toptions.push( option );\n\t\t} );\n\n\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\treturn new OO.ui.CheckboxMultiselectWidget( { items: options, classes: classes } );\n\t};\n\n\t/**\n\t * @return {string}\n\t */\n\tuw.LicenseGroup.prototype.getWikiText = function () {\n\t\tlet wikiTexts,\n\t\t\tself = this,\n\t\t\tvalues = this.getValue();\n\n\t\twikiTexts = Object.keys( values ).map( ( name ) => {\n\t\t\tlet wikiText = self.getLicenseWikiText( name ),\n\t\t\t\tvalue = values[ name ];\n\t\t\tif ( typeof value === 'string' ) {\n\t\t\t\t// `value` is custom input\n\t\t\t\twikiText += '\\n' + value.trim();\n\t\t\t}\n\t\t\treturn wikiText.trim();\n\t\t} );\n\n\t\treturn this.config.wrapper\n\t\t\t.replace( '$1', wikiTexts.join( this.config.licenseSeparator ).trim() )\n\t\t\t.replace( '$2', Object.keys( values ).length.toString() );\n\t};\n\n\t/**\n\t * Returns a string unique to the group (if defined)\n\t *\n\t * @return {string}\n\t */\n\tuw.LicenseGroup.prototype.getGroup = function () {\n\t\treturn this.config.head || '';\n\t};\n\n\t/**\n\t * @return {Object} Map of { licenseName: true }, or { licenseName: \"custom input\" }\n\t */\n\tuw.LicenseGroup.prototype.getValue = function () {\n\t\tlet self = this,\n\t\t\tresult = {},\n\t\t\tselected,\n\t\t\tname;\n\n\t\tif ( this.type === 'radio' ) {\n\t\t\tselected = this.group.findSelectedItem();\n\t\t\tif ( selected ) {\n\t\t\t\tname = selected.getData();\n\t\t\t\tresult[ name ] = !this.textareas[ name ] || this.textareas[ name ].getValue();\n\t\t\t}\n\t\t} else if ( this.type === 'checkbox' ) {\n\t\t\tselected = this.group.findSelectedItems();\n\t\t\tselected.forEach( ( item ) => {\n\t\t\t\tname = item.getData();\n\t\t\t\tresult[ name ] = !self.textareas[ name ] || self.textareas[ name ].getValue();\n\t\t\t} );\n\t\t}\n\n\t\treturn result;\n\t};\n\n\t/**\n\t * @param {Object} values Map of { licenseName: true }, or { licenseName: \"custom input\" }\n\t */\n\tuw.LicenseGroup.prototype.setValue = function ( values ) {\n\t\tlet self = this,\n\t\t\tselectArray = [],\n\t\t\tselected;\n\n\t\tObject.keys( values ).forEach( ( name ) => {\n\t\t\tconst value = values[ name ];\n\t\t\tif ( typeof value === 'string' && self.textareas[ name ] ) {\n\t\t\t\tself.textareas[ name ].setValue( value );\n\t\t\t\t// add to list of items to select\n\t\t\t\tselectArray.push( name );\n\t\t\t}\n\n\t\t\t// add to list of items to select\n\t\t\t// (only true/string values should be included in `values`, but might\n\t\t\t// as well play it safe...)\n\t\t\tif ( value === true ) {\n\t\t\t\tselectArray.push( name );\n\t\t\t}\n\t\t} );\n\n\t\tif ( this.type === 'radio' ) {\n\t\t\tthis.group.selectItemByData( selectArray[ 0 ] );\n\t\t\tselected = this.group.findSelectedItem() !== null;\n\t\t} else if ( this.type === 'checkbox' ) {\n\t\t\tthis.group.selectItemsByData( selectArray );\n\t\t\tselected = this.group.findSelectedItems().length > 0;\n\t\t}\n\n\t\t// pop open the 'toggle' group if is now on. Do nothing if it is now off.\n\t\tif ( selected && this.collapsible ) {\n\t\t\tthis.fieldset.$group.data( 'mw-collapsible' ).expand();\n\t\t}\n\t};\n\n\t/**\n\t * @private\n\t * @param {string} name\n\t * @return {Object}\n\t */\n\tuw.LicenseGroup.prototype.getLicenseInfo = function ( name ) {\n\t\treturn {\n\t\t\tname: name,\n\t\t\tprops: mw.UploadWizard.config.licenses[ name ]\n\t\t};\n\t};\n\n\t/**\n\t * License templates are these abstract ideas like cc-by-sa.\n\t * The 'license' and 'licensing' configs define how to translate them into wikitext.\n\t *\n\t * @private\n\t * @param {string} name license template name\n\t * @return {string} of wikitext\n\t */\n\tuw.LicenseGroup.prototype.getLicenseWikiText = function ( name ) {\n\t\tlet licenseInfo = this.getLicenseInfo( name ),\n\t\t\tlicenseText;\n\n\t\tlicenseText = licenseInfo.props.wikitext !== undefined ?\n\t\t\tlicenseInfo.props.wikitext : licenseInfo.name;\n\t\treturn this.config.licenseWikitext.replace( '$1', licenseText );\n\t};\n\n\t/**\n\t * Get a label for the form element\n\t *\n\t * @private\n\t * @param {string} name license template name\n\t * @return {jQuery}\n\t */\n\tuw.LicenseGroup.prototype.createLabel = function ( name ) {\n\t\tlet licenseInfo = this.getLicenseInfo( name ),\n\t\t\tmessageKey = licenseInfo.props.msg === undefined ?\n\t\t\t\t'[missing msg for ' + licenseInfo.name + ']' :\n\t\t\t\tlicenseInfo.props.msg,\n\t\t\tlanguageCode = mw.config.get( 'wgUserLanguage' ),\n\t\t\t// The URL is optional, but if the message includes it as $2, we surface the fact\n\t\t\t// that it's missing.\n\t\t\tlicenseURL = licenseInfo.props.url === undefined ? '#missing license URL' : licenseInfo.props.url,\n\t\t\t$licenseLink,\n\t\t\t$icons = $( '<span>' ),\n\t\t\t$label;\n\n\t\tif ( licenseInfo.props.languageCodePrefix !== undefined ) {\n\t\t\tlicenseURL += licenseInfo.props.languageCodePrefix + languageCode;\n\t\t}\n\t\t$licenseLink = $( '<a>' ).attr( { target: '_blank', href: licenseURL } );\n\t\tif ( licenseInfo.props.icons !== undefined ) {\n\t\t\tlicenseInfo.props.icons.forEach( ( icon ) => {\n\t\t\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t\t\t$icons.append( $( '<span>' ).addClass( 'mediauploader-license-icon mediauploader-' + icon + '-icon' ) );\n\t\t\t} );\n\t\t}\n\n\t\t// eslint-disable-next-line mediawiki/msg-doc\n\t\t$label = $( '<label>' )\n\t\t\t.msg( messageKey, this.count || 0, $licenseLink )\n\t\t\t.append( $icons ).addClass( 'mediauploader-copyright-info' );\n\n\t\tif ( this.config.special === 'custom' ) {\n\t\t\t$label.append( this.createCustom( name, licenseInfo.props.defaultText ) );\n\t\t}\n\n\t\treturn $label.contents();\n\t};\n\n\t/**\n\t * @private\n\t * @param {string} name license name\n\t * @param {string} [defaultText] Default custom license text\n\t * @return {jQuery} Wrapped textarea\n\t */\n\tuw.LicenseGroup.prototype.createCustom = function ( name, defaultText ) {\n\t\tlet self = this,\n\t\t\tbutton;\n\n\t\tthis.textareas[ name ] = new OO.ui.MultilineTextInputWidget( {\n\t\t\tvalue: defaultText,\n\t\t\tautosize: true\n\t\t} );\n\n\t\t// Update displayed errors as the user is typing\n\t\tthis.textareas[ name ].on( 'change', OO.ui.debounce( this.emit.bind( this, 'change', this ), 500 ) );\n\n\t\tbutton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mediauploader-license-custom-preview' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', () => {\n\t\t\tself.showPreview( self.textareas[ name ].getValue() );\n\t\t} );\n\n\t\treturn $( '<div>' ).addClass( 'mediauploader-license-custom' ).append(\n\t\t\tbutton.$element,\n\t\t\tthis.textareas[ name ].$element\n\t\t);\n\t};\n\n\t/**\n\t * Preview wikitext in a popup window\n\t *\n\t * @private\n\t * @param {string} wikiText\n\t */\n\tuw.LicenseGroup.prototype.showPreview = function ( wikiText ) {\n\t\tlet input;\n\n\t\tthis.previewDialog.setLoading( true );\n\t\tthis.windowManager.openWindow( this.previewDialog );\n\n\t\tinput = this;\n\n\t\tfunction show( html ) {\n\t\t\tinput.previewDialog.setPreview( html );\n\t\t\tinput.windowManager.openWindow( input.previewDialog );\n\t\t}\n\n\t\tfunction error( code, result ) {\n\t\t\tconst message = result.errors[ 0 ].html;\n\n\t\t\tshow( $( '<div>' ).append(\n\t\t\t\t$( '<h3>' ).append( code ),\n\t\t\t\t$( '<p>' ).append( message )\n\t\t\t) );\n\t\t}\n\n\t\tthis.api.parse( wikiText, { pst: true } ).done( show ).fail( error );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.LicensePreviewDialog.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.ValidationMessageElement.js","messages":[{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"JSDoc @return declaration present but return expression not available in function.","line":39,"column":2,"nodeType":"Block","endLine":44,"endColumn":5},{"ruleId":"prefer-const","severity":2,"message":"'$listItem' is never reassigned. Use 'const' instead.","line":91,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":91,"endColumn":12}],"suppressedMessages":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":91,"column":15,"nodeType":"CallExpression","endLine":92,"endColumn":65,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":1,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * Element that is able to display validation messages from itself or another widget.\n\t *\n\t * @abstract\n\t * @class\n\t *\n\t * @constructor\n\t * @param {Object} [config]\n\t * @param {OO.ui.Widget} [config.validatedWidget] Widget to validate\n\t */\n\tuw.ValidationMessageElement = function UWValidationMessageElement( config ) {\n\t\tconfig = config || {};\n\n\t\tthis.validatedWidget = config.validatedWidget || this;\n\t\tthis.$messages = $( '<ul>' );\n\n\t\tthis.errors = [];\n\t\tthis.warnings = [];\n\t\tthis.successMessages = [];\n\t\tthis.notices = [];\n\n\t\tthis.validatedWidget.connect( this, {\n\t\t\tchange: 'checkValidity'\n\t\t} );\n\n\t\tthis.$messages.addClass( 'oo-ui-fieldLayout-messages' );\n\t\tthis.$element.addClass( 'mediauploader-validationMessageElement' );\n\t};\n\n\t// Hack: Steal methods from OO.ui.FieldLayout.\n\t// TODO: Upstream ValidationMessageElement to OOUI, make FieldLayout use it.\n\tuw.ValidationMessageElement.prototype.makeMessage = OO.ui.FieldLayout.prototype.makeMessage;\n\tuw.ValidationMessageElement.prototype.setErrors = OO.ui.FieldLayout.prototype.setErrors;\n\tuw.ValidationMessageElement.prototype.setNotices = OO.ui.FieldLayout.prototype.setNotices;\n\tuw.ValidationMessageElement.prototype.updateMessages = OO.ui.FieldLayout.prototype.updateMessages;\n\n\t/**\n\t * Check the field's widget for errors and warnings and display them in the UI.\n\t *\n\t * @param {boolean} thorough True to perform a thorough validity check. Defaults to false for a fast on-change check.\n\t * @return {jQuery.Promise}\n\t */\n\tuw.ValidationMessageElement.prototype.checkValidity = function ( thorough ) {\n\t\tconst element = this;\n\t\tthorough = thorough || false;\n\n\t\tif ( !this.validatedWidget.getWarnings || !this.validatedWidget.getErrors ) {\n\t\t\t// Don't do anything for non-Details widgets\n\t\t\treturn;\n\t\t}\n\t\tif ( this.validatedWidget.pushPending ) {\n\t\t\tthis.validatedWidget.pushPending();\n\t\t}\n\n\t\treturn $.when(\n\t\t\tthis.validatedWidget.getWarnings( thorough ),\n\t\t\tthis.validatedWidget.getErrors( thorough )\n\t\t).then( ( warnings, errors ) => {\n\t\t\t// this.notices and this.errors are arrays of mw.Messages and not strings in this subclass\n\t\t\telement.setNotices( warnings );\n\t\t\telement.setErrors( errors );\n\n\t\t\treturn $.Deferred().resolve( warnings, errors ).promise();\n\t\t} ).always( () => {\n\t\t\tif ( element.validatedWidget.popPending ) {\n\t\t\t\telement.validatedWidget.popPending();\n\t\t\t}\n\t\t} );\n\t};\n\n\t/**\n\t * @protected\n\t * @param {string} kind 'error' or 'notice'\n\t * @param {mw.Message|Object} error Message, or an object in { key: ..., html: ... } format\n\t * @return {jQuery}\n\t */\n\tuw.ValidationMessageElement.prototype.makeMessage = function ( kind, error ) {\n\t\tlet code, $content, $listItem;\n\t\tif ( error.parseDom ) {\n\t\t\t// mw.Message object\n\t\t\tcode = error.key;\n\t\t\t$content = error.parseDom();\n\t\t} else {\n\t\t\t// { key: ..., html: ... } object (= formatted API error responses)\n\t\t\tcode = error.code;\n\t\t\t$content = $( $.parseHTML( error.html ) );\n\t\t}\n\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t$listItem = OO.ui.FieldLayout.prototype.makeMessage.call( this, kind, $content )\n\t\t\t.addClass( 'mediauploader-fieldLayout-' + kind + '-' + code );\n\t\treturn $listItem;\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.units.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/schemas/campaign.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/schemas/json-schema-draft-4.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/tables.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Deed.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Details.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'step' is never reassigned. Use 'const' instead.","line":57,"column":7,"nodeType":"Identifier","messageId":"useConst","endLine":57,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'stepUiStub' is never reassigned. Use 'const' instead.","line":61,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":61,"endColumn":14},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":110,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":110,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'donestub' is never reassigned. Use 'const' instead.","line":111,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":111,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'ds' is never reassigned. Use 'const' instead.","line":112,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":112,"endColumn":6},{"ruleId":"prefer-const","severity":2,"message":"'ps' is never reassigned. Use 'const' instead.","line":113,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":113,"endColumn":6},{"ruleId":"prefer-const","severity":2,"message":"'tostub' is never reassigned. Use 'const' instead.","line":117,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":117,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'step' is never reassigned. Use 'const' instead.","line":124,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":124,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":135,"column":3,"nodeType":"CallExpression","endLine":135,"endColumn":40}],"suppressedMessages":[],"errorCount":9,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\tQUnit.module( 'uw.controller.Details', QUnit.newMwEnvironment() );\n\n\tfunction createTestUpload( sandbox, customDeedChooser, aborted ) {\n\t\tconst stubs = {\n\t\t\tucdc: sandbox.stub(),\n\t\t\tgetSerialized: sandbox.stub(),\n\t\t\tsetSerialized: sandbox.stub(),\n\t\t\tattach: sandbox.stub()\n\t\t};\n\n\t\treturn {\n\t\t\tdeedChooser: { deed: { name: customDeedChooser ? 'custom' : 'cc-by-sa-4.0' } },\n\n\t\t\ton: function () {},\n\n\t\t\tdetails: {\n\t\t\t\tuseCustomDeedChooser: stubs.ucdc,\n\t\t\t\tgetSerialized: stubs.getSerialized,\n\t\t\t\tsetSerialized: stubs.setSerialized,\n\t\t\t\tattach: stubs.attach\n\t\t\t},\n\n\t\t\tstate: aborted ? 'aborted' : 'stashed',\n\n\t\t\tstubs: stubs\n\t\t};\n\t}\n\n\tQUnit.test( 'Constructor sanity test', ( assert ) => {\n\t\tconst step = new uw.controller.Details( new mw.Api(), {\n\t\t\tmaxSimultaneousConnections: 1\n\t\t} );\n\t\tassert.true( !!step );\n\t\tassert.true( step instanceof uw.controller.Step );\n\t\tassert.true( !!step.ui );\n\t} );\n\n\tQUnit.test( 'load', function ( assert ) {\n\t\tlet step = new uw.controller.Details( new mw.Api(), {\n\t\t\t\tmaxSimultaneousConnections: 1\n\t\t\t} ),\n\t\t\ttestUpload = createTestUpload( this.sandbox ),\n\t\t\tstepUiStub = this.sandbox.stub( step.ui, 'load' );\n\n\t\t// replace createDetails with a stub; UploadWizardDetails needs way too\n\t\t// much setup to actually be able to create it\n\t\tstep.createDetails = this.sandbox.stub();\n\n\t\tstep.load( [ testUpload ] );\n\n\t\tassert.strictEqual( testUpload.stubs.ucdc.called, false );\n\t\tassert.strictEqual( step.createDetails.callCount, 1 );\n\t\tassert.true( stepUiStub.called );\n\n\t\ttestUpload = createTestUpload( this.sandbox, true );\n\t\tstep.load( [ testUpload ] );\n\n\t\tassert.true( testUpload.stubs.ucdc.called );\n\t\tassert.strictEqual( step.createDetails.callCount, 2 );\n\t\tassert.true( stepUiStub.called );\n\n\t\ttestUpload = createTestUpload( this.sandbox );\n\t\tstep.load( [ testUpload, createTestUpload( this.sandbox ) ] );\n\n\t\tassert.strictEqual( testUpload.stubs.ucdc.called, false );\n\t\tassert.strictEqual( step.createDetails.callCount, 4 );\n\t\tassert.true( stepUiStub.called );\n\n\t\ttestUpload = createTestUpload( this.sandbox );\n\t\tstep.load( [ testUpload, createTestUpload( this.sandbox, false, true ) ] );\n\n\t\tassert.strictEqual( testUpload.stubs.ucdc.called, false );\n\t\tassert.strictEqual( step.createDetails.callCount, 6 );\n\t\tassert.true( stepUiStub.called );\n\t} );\n\n\tQUnit.test( 'canTransition', ( assert ) => {\n\t\tconst upload = {},\n\t\t\tstep = new uw.controller.Details( new mw.Api(), {\n\t\t\t\tmaxSimultaneousConnections: 1\n\t\t\t} );\n\n\t\tassert.strictEqual( step.canTransition( upload ), false );\n\t\tupload.state = 'details';\n\t\tassert.strictEqual( step.canTransition( upload ), true );\n\t\tupload.state = 'complete';\n\t\tassert.strictEqual( step.canTransition( upload ), false );\n\t} );\n\n\tQUnit.test( 'transitionAll', function ( assert ) {\n\t\tlet tostub,\n\t\t\tdone = assert.async(),\n\t\t\tdonestub = this.sandbox.stub(),\n\t\t\tds = [ $.Deferred(), $.Deferred(), $.Deferred() ],\n\t\t\tps = [ ds[ 0 ].promise(), ds[ 1 ].promise(), ds[ 2 ].promise() ],\n\t\t\tcalls = [],\n\t\t\tstep;\n\n\t\ttostub = this.sandbox.stub( uw.controller.Details.prototype, 'transitionOne' );\n\t\ttostub.onFirstCall().returns( ps[ 0 ] );\n\t\ttostub.onSecondCall().returns( ps[ 1 ] );\n\t\ttostub.onThirdCall().returns( ps[ 2 ] );\n\n\t\tthis.sandbox.stub( uw.controller.Details.prototype, 'canTransition' ).returns( true );\n\n\t\tstep = new uw.controller.Details( new mw.Api(), {\n\t\t\tmaxSimultaneousConnections: 3\n\t\t} );\n\n\t\tstep.uploads = [\n\t\t\t{ id: 15 },\n\t\t\tundefined,\n\t\t\t{ id: 21 },\n\t\t\t{ id: 'aoeu' }\n\t\t];\n\n\t\tstep.transitionAll().done( donestub );\n\t\tsetTimeout( () => {\n\t\t\tcalls = [ tostub.getCall( 0 ), tostub.getCall( 1 ), tostub.getCall( 2 ) ];\n\n\t\t\tassert.strictEqual( calls[ 0 ].args[ 0 ].id, 15 );\n\t\t\tassert.strictEqual( calls[ 1 ].args[ 0 ].id, 21 );\n\n\t\t\tds[ 0 ].resolve();\n\t\t\tds[ 1 ].resolve();\n\t\t\tsetTimeout( () => {\n\t\t\t\tassert.strictEqual( donestub.called, false );\n\n\t\t\t\tds[ 2 ].resolve();\n\t\t\t\tsetTimeout( () => {\n\t\t\t\t\tassert.true( donestub.called );\n\n\t\t\t\t\tdone();\n\t\t\t\t} );\n\t\t\t} );\n\t\t} );\n\t} );\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Step.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Thanks.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Tutorial.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'acwStub' is never reassigned. Use 'const' instead.","line":33,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":33,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'mnStub' is never reassigned. Use 'const' instead.","line":54,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":54,"endColumn":9}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\tQUnit.module( 'uw.controller.Tutorial', QUnit.newMwEnvironment() );\n\n\tQUnit.test( 'Constructor sanity test', ( assert ) => {\n\t\tconst step = new uw.controller.Tutorial( new mw.Api() );\n\t\tassert.true( !!step );\n\t\tassert.true( step instanceof uw.controller.Step );\n\t\tassert.true( !!step.ui );\n\t\tassert.true( !!step.api );\n\t} );\n\n\tQUnit.test( 'setSkipPreference', function ( assert ) {\n\t\tlet mnStub,\n\t\t\tapi = new mw.Api(),\n\t\t\tstep = new uw.controller.Tutorial( api ),\n\t\t\tacwStub = { release: this.sandbox.stub() },\n\t\t\tpwtd = $.Deferred();\n\n\t\tthis.sandbox.stub( mw, 'confirmCloseWindow' ).returns( acwStub );\n\t\tthis.sandbox.stub( api, 'postWithToken' ).returns( pwtd.promise() );\n\n\t\tstep.setSkipPreference( true );\n\n\t\tassert.true( mw.confirmCloseWindow.called );\n\t\tassert.true( api.postWithToken.calledWithExactly( 'options', {\n\t\t\taction: 'options',\n\t\t\tchange: 'upwiz_skiptutorial=1'\n\t\t} ) );\n\n\t\tpwtd.resolve();\n\t\tassert.true( acwStub.release.called );\n\n\t\tapi = new mw.Api();\n\t\tstep = new uw.controller.Tutorial( api );\n\t\tacwStub.release.reset();\n\t\tpwtd = $.Deferred();\n\t\tmnStub = this.sandbox.stub( mw, 'notify' );\n\n\t\tthis.sandbox.stub( api, 'postWithToken' ).returns( pwtd.promise() );\n\n\t\tstep.setSkipPreference( true );\n\t\tassert.false( acwStub.release.called );\n\n\t\tpwtd.reject( 'http', { textStatus: 'Foo bar' } );\n\t\tassert.true( mnStub.calledWith( 'Foo bar' ) );\n\t} );\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Upload.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/mw.UploadWizardLicenseInput.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'config' is never reassigned. Use 'const' instead.","line":17,"column":6,"nodeType":"Identifier","messageId":"useConst","endLine":17,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'$fixture' is never reassigned. Use 'const' instead.","line":18,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":18,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'uwLicenseInput' is never reassigned. Use 'const' instead.","line":21,"column":2,"nodeType":"Identifier","messageId":"useConst","endLine":21,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'config' is never reassigned. Use 'const' instead.","line":27,"column":6,"nodeType":"Identifier","messageId":"useConst","endLine":27,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'$fixture' is never reassigned. Use 'const' instead.","line":28,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":28,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'uwLicenseInput' is never reassigned. Use 'const' instead.","line":33,"column":2,"nodeType":"Identifier","messageId":"useConst","endLine":33,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'$input' is never reassigned. Use 'const' instead.","line":37,"column":2,"nodeType":"Identifier","messageId":"useConst","endLine":37,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'$label' is never reassigned. Use 'const' instead.","line":41,"column":2,"nodeType":"Identifier","messageId":"useConst","endLine":41,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'config' is never reassigned. Use 'const' instead.","line":46,"column":6,"nodeType":"Identifier","messageId":"useConst","endLine":46,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'$fixture' is never reassigned. Use 'const' instead.","line":56,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":56,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'uwLicenseInput' is never reassigned. Use 'const' instead.","line":59,"column":2,"nodeType":"Identifier","messageId":"useConst","endLine":59,"endColumn":16}],"suppressedMessages":[],"errorCount":11,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"QUnit.module( 'ext.uploadWizardLicenseInput', QUnit.newMwEnvironment( {\n\tbeforeEach: function () {\n\t\tmw.UploadWizard.config = {\n\t\t\tlicenses: {\n\t\t\t\t'cc-by-sa-3.0': {\n\t\t\t\t\tmsg: 'mediauploader-license-cc-by-sa-3.0',\n\t\t\t\t\ticons: [ 'cc-by', 'cc-sa' ],\n\t\t\t\t\turl: '//creativecommons.org/licenses/by-sa/3.0/',\n\t\t\t\t\tlanguageCodePrefix: 'deed.'\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} ) );\n\nQUnit.test( 'Smoke test', ( assert ) => {\n\tlet config = { type: 'radio', licenses: [] },\n\t\t$fixture = $( '<div>' ),\n\t\tuwLicenseInput;\n\n\tuwLicenseInput = new mw.UploadWizardLicenseInput( config );\n\t$fixture.append( uwLicenseInput.$element );\n\tassert.true( !!uwLicenseInput, 'LicenseInput object created !' );\n} );\n\nQUnit.test( 'createInputs()', ( assert ) => {\n\tlet config = { type: 'radio', licenses: [ 'cc-by-sa-3.0' ] },\n\t\t$fixture = $( '<div>' ),\n\t\tuwLicenseInput,\n\t\t$input,\n\t\t$label;\n\n\tuwLicenseInput = new mw.UploadWizardLicenseInput( config );\n\t$fixture.append( uwLicenseInput.$element );\n\n\t// Check radio button is there\n\t$input = $fixture.find( '.oo-ui-radioInputWidget .oo-ui-inputWidget-input[value=\"cc-by-sa-3.0\"]' );\n\tassert.strictEqual( $input.length, 1, 'Radio button created.' );\n\n\t// Check label is there\n\t$label = $input.closest( '.oo-ui-radioOptionWidget' ).find( '.oo-ui-labelElement-label' );\n\tassert.strictEqual( $label.length, 1, 'Label created.' );\n} );\n\nQUnit.test( 'createGroupedInputs()', ( assert ) => {\n\tlet config = {\n\t\t\ttype: 'checkbox',\n\t\t\tlicenseGroups: [\n\t\t\t\t{\n\t\t\t\t\thead: 'mediauploader-license-cc-head',\n\t\t\t\t\tsubhead: 'mediauploader-license-cc-subhead',\n\t\t\t\t\tlicenses: [ 'cc-by-sa-3.0' ]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t$fixture = $( '<div>' ),\n\t\tuwLicenseInput;\n\n\tuwLicenseInput = new mw.UploadWizardLicenseInput( config );\n\t$fixture.append( uwLicenseInput.$element );\n\n\t// Check license group is there\n\tassert.strictEqual( $fixture.find( '.mediauploader-deed-license-group' ).length, 1, 'License group created.' );\n\n\t// Check subheader is there\n\tassert.strictEqual( $fixture.find( '.mediauploader-deed-license-group-subhead' ).length, 1, 'License subheader created.' );\n\n\t// Check license is there\n\tassert.strictEqual( $fixture.find( '.mediauploader-deed-license-group .oo-ui-fieldsetLayout-group' ).length, 1, 'License created.' );\n} );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/mw.UploadWizardUpload.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'oldconf' is never reassigned. Use 'const' instead.","line":23,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":23,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'upload' is never reassigned. Use 'const' instead.","line":27,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":27,"endColumn":9}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function () {\n\tQUnit.module( 'mw.UploadWizardUpload', QUnit.newMwEnvironment() );\n\n\tfunction createUpload( filename ) {\n\t\tlet upload,\n\t\t\toldconf = mw.UploadWizard.config;\n\n\t\tmw.UploadWizard.config = {};\n\n\t\tupload = new mw.UploadWizardUpload( {\n\t\t\tapi: {\n\t\t\t\tdefaults: {\n\t\t\t\t\tajax: {}\n\t\t\t\t}\n\t\t\t}\n\t\t}, {\n\t\t\tname: filename\n\t\t} );\n\n\t\tmw.UploadWizard.config = oldconf;\n\n\t\treturn upload;\n\t}\n\n\tQUnit.test( 'constructor sanity test', ( assert ) => {\n\t\tconst upload = createUpload();\n\n\t\tassert.true( !!upload );\n\t} );\n\n\tQUnit.test( 'getBasename', ( assert ) => {\n\t\tlet upload;\n\n\t\tupload = createUpload( 'path/to/filename.png' );\n\t\tassert.strictEqual( upload.getBasename(), 'filename.png', 'Path is stripped' );\n\n\t\tupload = createUpload( 'filename.png' );\n\t\tassert.strictEqual( upload.getBasename(), 'filename.png', 'Only filename is left alone' );\n\n\t\tupload = createUpload( '///////////' );\n\t\tassert.strictEqual( upload.getBasename(), '', 'Nonsensical path is just removed' );\n\t} );\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/mw.fileApi.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'testFile' is never reassigned. Use 'const' instead.","line":46,"column":15,"nodeType":"Identifier","messageId":"useConst","endLine":46,"endColumn":23},{"ruleId":"prefer-const","severity":2,"message":"'fakeVideo' is never reassigned. Use 'const' instead.","line":47,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":47,"endColumn":13}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function () {\n\tQUnit.module( 'mw.fileApi', QUnit.newMwEnvironment() );\n\n\tQUnit.test( 'isPreviewableFile', function ( assert ) {\n\t\tconst testFile = {};\n\n\t\ttestFile.type = 'image/png';\n\t\ttestFile.size = 5 * 1024 * 1024;\n\t\tassert.strictEqual( mw.fileApi.isPreviewableFile( testFile ), true );\n\n\t\ttestFile.type = 'image/gif';\n\t\tassert.strictEqual( mw.fileApi.isPreviewableFile( testFile ), true );\n\n\t\ttestFile.type = 'image/jpeg';\n\t\tassert.strictEqual( mw.fileApi.isPreviewableFile( testFile ), true );\n\n\t\ttestFile.size = 11 * 1024 * 1024;\n\t\tassert.strictEqual( mw.fileApi.isPreviewableFile( testFile ), false );\n\n\t\ttestFile.size = 5 * 1024 * 1024;\n\t\ttestFile.type = 'unplayable/type';\n\t\tassert.strictEqual( mw.fileApi.isPreviewableFile( testFile ), false );\n\n\t\tthis.sandbox.stub( mw.fileApi, 'isPreviewableVideo' ).returns( true );\n\t\tassert.strictEqual( mw.fileApi.isPreviewableFile( testFile ), true );\n\t} );\n\n\tQUnit.test( 'isPreviewableVideo', function ( assert ) {\n\t\tlet result, testFile = {},\n\t\t\tfakeVideo = {\n\t\t\t\tcanPlayType: this.sandbox.stub().returns( 'yes' )\n\t\t\t};\n\n\t\tthis.sandbox.stub( document, 'createElement' ).returns( fakeVideo );\n\t\tresult = mw.fileApi.isPreviewableVideo( testFile );\n\t\tdocument.createElement.restore();\n\n\t\tassert.strictEqual( result, true );\n\t\tassert.strictEqual( fakeVideo.canPlayType.callCount, 1 );\n\n\t\tfakeVideo.canPlayType = this.sandbox.stub().returns( 'no' );\n\t\tthis.sandbox.stub( document, 'createElement' ).returns( fakeVideo );\n\t\tresult = mw.fileApi.isPreviewableVideo( testFile );\n\t\tdocument.createElement.restore();\n\n\t\tassert.strictEqual( result, false );\n\t\tassert.strictEqual( fakeVideo.canPlayType.callCount, 1 );\n\t} );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/transports/mw.FormDataTransport.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'config' is never reassigned. Use 'const' instead.","line":27,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":27,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'transport' is never reassigned. Use 'const' instead.","line":86,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":86,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'fakeFile' is never reassigned. Use 'const' instead.","line":87,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":87,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'request' is never reassigned. Use 'const' instead.","line":97,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":97,"endColumn":10},{"ruleId":"prefer-const","severity":2,"message":"'transport' is never reassigned. Use 'const' instead.","line":107,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":107,"endColumn":13},{"ruleId":"prefer-const","severity":2,"message":"'fakeFile' is never reassigned. Use 'const' instead.","line":108,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":108,"endColumn":12},{"ruleId":"prefer-const","severity":2,"message":"'request' is never reassigned. Use 'const' instead.","line":125,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":125,"endColumn":10},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":146,"column":3,"nodeType":"CallExpression","endLine":152,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":179,"column":10,"nodeType":"CallExpression","endLine":182,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":198,"column":10,"nodeType":"CallExpression","endLine":201,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":218,"column":3,"nodeType":"CallExpression","endLine":222,"endColumn":6}],"suppressedMessages":[],"errorCount":11,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function () {\n\tQUnit.module( 'mw.FormDataTransport', QUnit.newMwEnvironment() );\n\n\tfunction createTransport( chunkSize, api ) {\n\t\tlet config;\n\n\t\tchunkSize = chunkSize || 0;\n\t\tapi = api || {};\n\n\t\tconfig = {\n\t\t\tuseRetryTimeout: false,\n\t\t\tchunkSize: chunkSize,\n\t\t\tmaxPhpUploadSize: chunkSize\n\t\t};\n\n\t\treturn new mw.FormDataTransport( api, {}, config );\n\t}\n\n\tQUnit.test( 'Constructor sanity test', ( assert ) => {\n\t\tconst transport = createTransport();\n\n\t\tassert.true( !!transport );\n\t} );\n\n\tQUnit.test( 'abort', function ( assert ) {\n\t\tconst transport = createTransport( 0 ),\n\t\t\trequest = $.Deferred().promise( { abort: this.sandbox.stub() } );\n\n\t\ttransport.request = request;\n\n\t\tassert.true( request.abort.notCalled );\n\n\t\ttransport.abort();\n\n\t\tassert.true( request.abort.called );\n\t\tassert.true( transport.aborted );\n\t} );\n\n\tQUnit.test( 'createParams', ( assert ) => {\n\t\tconst transport = createTransport( 10 ),\n\t\t\tparams = transport.createParams( 'foobar.jpg', 0 );\n\n\t\tassert.true( !!params );\n\n\t\tassert.strictEqual( params.filename, 'foobar.jpg' );\n\t\tassert.strictEqual( params.offset, 0 );\n\t} );\n\n\tQUnit.test( 'post', function ( assert ) {\n\t\tconst stub = this.sandbox.stub(),\n\t\t\t// post() works on a promise and binds .then, so we have to make\n\t\t\t// sure it actually is a promise, but also that it calls our stub\n\t\t\ttransport = createTransport( 10, { post: function () {\n\t\t\t\tstub();\n\t\t\t\treturn $.Deferred().resolve();\n\t\t\t} } );\n\n\t\tthis.sandbox.useFakeServer();\n\n\t\tassert.true( stub.notCalled );\n\n\t\ttransport.post( {} );\n\n\t\tassert.true( stub.called );\n\t} );\n\n\tQUnit.test( 'upload', function ( assert ) {\n\t\tlet request,\n\t\t\ttransport = createTransport( 10, new mw.Api() ),\n\t\t\tfakeFile = {\n\t\t\t\tname: 'test file for fdt.jpg',\n\t\t\t\tsize: 5\n\t\t\t};\n\n\t\tthis.sandbox.useFakeServer();\n\n\t\ttransport.upload( fakeFile, 'test file for fdt.jpg' );\n\n\t\tassert.strictEqual( this.sandbox.server.requests.length, 1 );\n\t\trequest = this.sandbox.server.requests[ 0 ];\n\t\tassert.strictEqual( request.method, 'POST' );\n\t\tassert.strictEqual( request.url, mw.util.wikiScript( 'api' ) );\n\t\tassert.true( request.async );\n\n\t\ttransport.abort();\n\t} );\n\n\tQUnit.test( 'uploadChunk', function ( assert ) {\n\t\tlet request,\n\t\t\ttransport = createTransport( 10, new mw.Api() ),\n\t\t\tfakeFile = {\n\t\t\t\tname: 'test file for fdt.jpg',\n\t\t\t\tsize: 20,\n\t\t\t\tslice: function ( offset ) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tname: 'test file for fdt.jpg',\n\t\t\t\t\t\toffset: offset,\n\t\t\t\t\t\tsize: 10\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t};\n\n\t\tthis.sandbox.useFakeServer();\n\n\t\ttransport.uploadChunk( fakeFile, 0 );\n\n\t\tassert.strictEqual( this.sandbox.server.requests.length, 1 );\n\t\trequest = this.sandbox.server.requests[ 0 ];\n\t\tassert.strictEqual( request.method, 'POST' );\n\t\tassert.strictEqual( request.url, mw.util.wikiScript( 'api' ) );\n\t\tassert.true( request.async );\n\n\t\ttransport.abort();\n\t} );\n\n\t// test invalid server response (in missing 'stage' param)\n\tQUnit.test( 'checkStatus invalid API response', function ( assert ) {\n\t\tconst done = assert.async(),\n\t\t\ttransport = createTransport( 10, new mw.Api() ),\n\t\t\ttstub = this.sandbox.stub(),\n\t\t\tpoststub = this.sandbox.stub( transport.api, 'post' ),\n\t\t\tpostd = $.Deferred();\n\n\t\t// prepare a bogus invalid API result\n\t\tpoststub.returns( postd.promise() );\n\t\tpostd.resolve( { upload: { result: 'Poll' } } );\n\n\t\t// call tstub upon checkStatus failure, and verify it got called correctly\n\t\ttransport.checkStatus().fail( tstub, () => {\n\t\t\tassert.true( tstub.calledWith( 'server-error', { errors: [ {\n\t\t\t\tcode: 'server-error',\n\t\t\t\thtml: mw.message( 'api-clientside-error-invalidresponse' ).parse()\n\t\t\t} ] } ) );\n\t\t\tdone();\n\t\t} );\n\t} );\n\n\t// test retry after server responds upload is still incomplete\n\tQUnit.test( 'checkStatus retry', function ( assert ) {\n\t\tconst transport = createTransport( 10, new mw.Api() ),\n\t\t\tusstub = this.sandbox.stub(),\n\t\t\tpoststub = this.sandbox.stub( transport.api, 'post' ),\n\t\t\tpostd = $.Deferred(),\n\t\t\tpostd2 = $.Deferred();\n\n\t\ttransport.on( 'update-stage', usstub );\n\n\t\t// prepare a first API call that responds with 'Poll' (upload\n\t\t// concatenation is not yet complete) followed by a second call that\n\t\t// marks the upload successful\n\t\tpoststub\n\t\t\t.onFirstCall().returns( postd.promise() )\n\t\t\t.onSecondCall().returns( postd2.promise() );\n\n\t\t// resolve 3 API calls, where server first responds upload is not yet\n\t\t// assembled, and second says it's published\n\t\tpostd.resolve( { upload: { result: 'Poll', stage: 'queued' } } );\n\t\tpostd2.resolve( { upload: { result: 'Success' } } );\n\n\t\t// confirm that, once second API call was successful, status resolves,\n\t\t// 2 API calls have gone out & the failed call updates stage accordingly\n\t\treturn transport.checkStatus().done( () => {\n\t\t\tassert.true( poststub.calledTwice );\n\t\t\tassert.true( usstub.firstCall.calledWith( 'queued' ) );\n\t\t} );\n\t} );\n\n\tQUnit.test( 'checkStatus success', function ( assert ) {\n\t\tconst transport = createTransport( 10, new mw.Api() ),\n\t\t\ttstub = this.sandbox.stub(),\n\t\t\tusstub = this.sandbox.stub(),\n\t\t\tpoststub = this.sandbox.stub( transport.api, 'post' ),\n\t\t\tpostd = $.Deferred();\n\n\t\ttransport.on( 'update-stage', usstub );\n\n\t\t// prepare a bogus valid API result\n\t\tpoststub.returns( postd.promise() );\n\t\tpostd.resolve( 'testing' );\n\n\t\treturn transport.checkStatus().done( tstub, () => {\n\t\t\tassert.true( tstub.calledWith( 'testing' ) );\n\t\t\tassert.false( usstub.called );\n\t\t} );\n\t} );\n\n\tQUnit.test( 'checkStatus error API response', function ( assert ) {\n\t\tconst done = assert.async(),\n\t\t\ttransport = createTransport( 10, new mw.Api() ),\n\t\t\ttstub = this.sandbox.stub(),\n\t\t\tusstub = this.sandbox.stub(),\n\t\t\tpoststub = this.sandbox.stub( transport.api, 'post' ),\n\t\t\tpostd = $.Deferred();\n\n\t\ttransport.on( 'update-stage', usstub );\n\n\t\t// prepare an error API response\n\t\tpoststub.returns( postd.promise() );\n\t\tpostd.reject( 'testing', { error: 'testing' } );\n\n\t\ttransport.checkStatus().fail( tstub, () => {\n\t\t\tassert.true( tstub.calledWith( 'testing', { error: 'testing' } ) );\n\t\t\tassert.false( usstub.called );\n\t\t\tdone();\n\t\t} );\n\t} );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/uw.ConcurrentQueue.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'calls' is never reassigned. Use 'const' instead.","line":38,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":38,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":65,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":65,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'action' is never reassigned. Use 'const' instead.","line":66,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":66,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'queue' is never reassigned. Use 'const' instead.","line":67,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":67,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":98,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":98,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'changeHandler' is never reassigned. Use 'const' instead.","line":99,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":99,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'progressHandler' is never reassigned. Use 'const' instead.","line":100,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":100,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'completeHandler' is never reassigned. Use 'const' instead.","line":101,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":101,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'queue' is never reassigned. Use 'const' instead.","line":102,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":102,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":139,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":139,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'queue' is never reassigned. Use 'const' instead.","line":140,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":140,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":167,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":167,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'queue' is never reassigned. Use 'const' instead.","line":168,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":168,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":184,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":184,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'changeHandler' is never reassigned. Use 'const' instead.","line":185,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":185,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'progressHandler' is never reassigned. Use 'const' instead.","line":186,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":186,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'completeHandler' is never reassigned. Use 'const' instead.","line":187,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":187,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'queue' is never reassigned. Use 'const' instead.","line":188,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":188,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":240,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":240,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'changeHandler' is never reassigned. Use 'const' instead.","line":241,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":241,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'progressHandler' is never reassigned. Use 'const' instead.","line":242,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":242,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'completeHandler' is never reassigned. Use 'const' instead.","line":243,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":243,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'queue' is never reassigned. Use 'const' instead.","line":244,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":244,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":297,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":297,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'action' is never reassigned. Use 'const' instead.","line":298,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":298,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'changeHandler' is never reassigned. Use 'const' instead.","line":299,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":299,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'progressHandler' is never reassigned. Use 'const' instead.","line":300,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":300,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'completeHandler' is never reassigned. Use 'const' instead.","line":301,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":301,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'queue' is never reassigned. Use 'const' instead.","line":302,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":302,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":353,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":353,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'action' is never reassigned. Use 'const' instead.","line":355,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":355,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'changeHandler' is never reassigned. Use 'const' instead.","line":356,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":356,"endColumn":16},{"ruleId":"prefer-const","severity":2,"message":"'progressHandler' is never reassigned. Use 'const' instead.","line":357,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":357,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'completeHandler' is never reassigned. Use 'const' instead.","line":358,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":358,"endColumn":18},{"ruleId":"prefer-const","severity":2,"message":"'queue' is never reassigned. Use 'const' instead.","line":359,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":359,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'onProgress' is never reassigned. Use 'const' instead.","line":402,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":402,"endColumn":13}],"suppressedMessages":[],"errorCount":36,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension MediaUploader.\n *\n * MediaUploader is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * MediaUploader is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with MediaUploader.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\tQUnit.module( 'uw.ConcurrentQueue', QUnit.newMwEnvironment() );\n\n\t// This is a bogus action that will be executed for every item added to the\n\t// queue. We just need to make sure that the action doesn't complete\n\t// immediately, or the order some methods are called in could be slightly\n\t// different (e.g. when adding a new item after one has just completed will\n\t// trigger the next one to execute, which would terminate immediately,\n\t// instead of giving time for a second new thingy to be added)\n\tfunction queueAction() {\n\t\tconst deferred = $.Deferred();\n\t\tsetTimeout( deferred.resolve, 10 );\n\t\treturn deferred.promise();\n\t}\n\n\t// Asserts that the given stub functions were called in the given order.\n\t// SinonJS's assert.callOrder doesn't allow to check individual calls.\n\tfunction assertCalledInOrder() {\n\t\tlet calls, i, currSpyCall, nextSpyCall;\n\t\t// Map stubs to specific calls\n\t\tcalls = Array.prototype.map.call( arguments, ( spy ) => {\n\t\t\tif ( !spy.assertCallsInOrderLastCall ) {\n\t\t\t\tspy.assertCallsInOrderLastCall = 0;\n\t\t\t}\n\t\t\treturn spy.getCall( spy.assertCallsInOrderLastCall++ );\n\t\t} );\n\t\t// Assert stuff\n\t\tfor ( i = 0; i < calls.length - 1; i++ ) {\n\t\t\tcurrSpyCall = calls[ i ];\n\t\t\tnextSpyCall = calls[ i + 1 ];\n\t\t\tif ( currSpyCall ) {\n\t\t\t\tQUnit.assert.true(\n\t\t\t\t\tcurrSpyCall.callId < ( nextSpyCall ? nextSpyCall.callId : -1 ),\n\t\t\t\t\t'Call ' + ( i + 1 ) + ' (callId ' + currSpyCall.callId + ') is in the right order'\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tQUnit.assert.true( false, 'Call ' + ( i + 1 ) + ' (never called) is in the right order' );\n\t\t\t}\n\t\t}\n\t\tQUnit.assert.true(\n\t\t\t!!nextSpyCall,\n\t\t\t'Call ' + calls.length + ' is in the right order'\n\t\t);\n\t}\n\n\tQUnit.test( 'Basic behavior', ( assert ) => {\n\t\tlet done, action, queue;\n\t\tdone = assert.async();\n\t\taction = sinon.spy( queueAction );\n\t\tqueue = new uw.ConcurrentQueue( {\n\t\t\tcount: 3,\n\t\t\taction: action\n\t\t} );\n\n\t\tqueue.on( 'progress', () => {\n\t\t\tQUnit.assert.true( queue.running.length <= 3, 'No more than 3 items are executing' );\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\t// All items executed\n\t\t\tsinon.assert.callCount( action, 5 );\n\t\t\t// All items executed in the expected order\n\t\t\tsinon.assert.calledWith( action.getCall( 0 ), 'a' );\n\t\t\tsinon.assert.calledWith( action.getCall( 1 ), 'b' );\n\t\t\tsinon.assert.calledWith( action.getCall( 2 ), 'c' );\n\t\t\tsinon.assert.calledWith( action.getCall( 3 ), 'd' );\n\t\t\tsinon.assert.calledWith( action.getCall( 4 ), 'e' );\n\n\t\t\tdone();\n\t\t} );\n\n\t\t[ 'a', 'b', 'c', 'd', 'e' ].forEach( ( v ) => {\n\t\t\tqueue.addItem( v );\n\t\t} );\n\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Event emitting', ( assert ) => {\n\t\tlet done, changeHandler, progressHandler, completeHandler, queue;\n\t\tdone = assert.async();\n\t\tchangeHandler = sinon.stub();\n\t\tprogressHandler = sinon.stub();\n\t\tcompleteHandler = sinon.stub();\n\t\tqueue = new uw.ConcurrentQueue( {\n\t\t\tcount: 3,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tsinon.assert.callCount( changeHandler, 3 );\n\t\t\tsinon.assert.callCount( progressHandler, 3 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Restarting a completed queue', ( assert ) => {\n\t\tlet done, queue;\n\t\tdone = assert.async();\n\t\tqueue = new uw.ConcurrentQueue( {\n\t\t\tcount: 3,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\n\t\tqueue.once( 'complete', () => {\n\t\t\tQUnit.assert.equal( queue.completed, true );\n\t\t\tqueue.addItem( 'd' );\n\t\t\tqueue.addItem( 'e' );\n\n\t\t\tqueue.once( 'complete', () => {\n\t\t\t\tQUnit.assert.equal( queue.completed, true );\n\t\t\t\tdone();\n\t\t\t} );\n\n\t\t\tqueue.startExecuting();\n\t\t} );\n\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Empty queue completes', ( assert ) => {\n\t\tlet done, queue;\n\t\tdone = assert.async();\n\t\tqueue = new uw.ConcurrentQueue( {\n\t\t\tcount: 3,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tQUnit.assert.equal( queue.completed, true );\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Adding new items while queue running', ( assert ) => {\n\t\tlet done, changeHandler, progressHandler, completeHandler, queue;\n\t\tdone = assert.async();\n\t\tchangeHandler = sinon.stub();\n\t\tprogressHandler = sinon.stub();\n\t\tcompleteHandler = sinon.stub();\n\t\tqueue = new uw.ConcurrentQueue( {\n\t\t\tcount: 2,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tsinon.assert.callCount( changeHandler, 6 );\n\t\t\tsinon.assert.callCount( progressHandler, 6 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tprogressHandler, // Finished 'a' or 'b'\n\t\t\t\tchangeHandler, // Added 'd'\n\t\t\t\tchangeHandler, // Added 'e'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c' or 'd'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c', 'd' or 'e'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c', 'd' or 'e'\n\t\t\t\tchangeHandler, // Added 'f'\n\t\t\t\tprogressHandler, // Finished f'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.once( 'progress', () => {\n\t\t\tqueue.addItem( 'd' );\n\t\t\tqueue.addItem( 'e' );\n\t\t} );\n\t\tqueue.on( 'progress', () => {\n\t\t\tif ( queue.done.length === 5 ) {\n\t\t\t\tqueue.addItem( 'f' );\n\t\t\t}\n\t\t} );\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Deleting items while queue running', ( assert ) => {\n\t\tlet done, changeHandler, progressHandler, completeHandler, queue;\n\t\tdone = assert.async();\n\t\tchangeHandler = sinon.stub();\n\t\tprogressHandler = sinon.stub();\n\t\tcompleteHandler = sinon.stub();\n\t\tqueue = new uw.ConcurrentQueue( {\n\t\t\tcount: 2,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tsinon.assert.callCount( changeHandler, 8 );\n\t\t\tsinon.assert.callCount( progressHandler, 4 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tchangeHandler, // Added 'd'\n\t\t\t\tchangeHandler, // Added 'e'\n\t\t\t\tchangeHandler, // Added 'f'\n\t\t\t\tprogressHandler, // Finished 'a' or 'b'\n\t\t\t\tchangeHandler, // Removed first of the queued (not executing), which is 'd'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tchangeHandler, // Removed the last one queued (not executing), which is 'f'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c' or 'e'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c' or 'e'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.addItem( 'd' );\n\t\tqueue.addItem( 'e' );\n\t\tqueue.addItem( 'f' );\n\t\tqueue.once( 'progress', () => {\n\t\t\tqueue.removeItem( queue.queued[ 0 ] );\n\n\t\t\tqueue.once( 'progress', () => {\n\t\t\t\tqueue.removeItem( queue.queued[ 0 ] );\n\t\t\t} );\n\t\t} );\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Deleting currently running item', ( assert ) => {\n\t\tlet done, action, changeHandler, progressHandler, completeHandler, queue;\n\t\tdone = assert.async();\n\t\taction = sinon.spy( queueAction );\n\t\tchangeHandler = sinon.stub();\n\t\tprogressHandler = sinon.stub();\n\t\tcompleteHandler = sinon.stub();\n\t\tqueue = new uw.ConcurrentQueue( {\n\t\t\tcount: 2,\n\t\t\taction: action\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\t// Every item in the queue was executed...\n\t\t\tsinon.assert.callCount( action, 4 );\n\n\t\t\tsinon.assert.callCount( changeHandler, 5 );\n\t\t\t// ...but the one we removed wasn't registered as finished\n\t\t\tsinon.assert.callCount( progressHandler, 3 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tchangeHandler, // Added 'd'\n\t\t\t\taction, // Started 'a'\n\t\t\t\taction, // Started 'b'\n\t\t\t\tprogressHandler, // Finished 'a' or 'b'\n\t\t\t\tchangeHandler, // Removed first of the executing, which is 'a' or 'b'\n\t\t\t\taction, // Started 'c'\n\t\t\t\taction, // Started 'd' - note how two threads are running still\n\t\t\t\tprogressHandler, // Finished 'c' or 'd'\n\t\t\t\tprogressHandler, // Finished 'c' or 'd'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.addItem( 'd' );\n\t\tqueue.once( 'progress', () => {\n\t\t\tqueue.removeItem( queue.running[ 0 ] );\n\t\t} );\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Adding a new item when almost done', ( assert ) => {\n\t\tlet done, action, changeHandler, progressHandler, completeHandler, queue, onProgress;\n\t\tdone = assert.async();\n\t\t// This test seems extra flaky and was occasionally failing, double the delays\n\t\taction = sinon.spy( queueAction );\n\t\tchangeHandler = sinon.stub();\n\t\tprogressHandler = sinon.stub();\n\t\tcompleteHandler = sinon.stub();\n\t\tqueue = new uw.ConcurrentQueue( {\n\t\t\tcount: 2,\n\t\t\taction: action\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tsinon.assert.callCount( action, 5 );\n\t\t\tsinon.assert.callCount( changeHandler, 5 );\n\t\t\tsinon.assert.callCount( progressHandler, 5 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tchangeHandler, // Added 'd'\n\t\t\t\taction, // Started 'a'\n\t\t\t\taction, // Started 'b'\n\t\t\t\tprogressHandler, // Finished 'a' or 'b'\n\t\t\t\taction, // Started 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\taction, // Started 'd'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c' or 'd'\n\t\t\t\tchangeHandler, // Added 'e'\n\t\t\t\taction, // Started 'e' -- this starts a new thread\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c', 'd' or 'e'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c', 'd' or 'e'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.addItem( 'd' );\n\t\tonProgress = function () {\n\t\t\tif ( queue.done.length === 3 ) {\n\t\t\t\tqueue.addItem( 'e' );\n\t\t\t\tqueue.off( 'progress', onProgress );\n\t\t\t}\n\t\t};\n\t\tqueue.on( 'progress', onProgress );\n\t\tqueue.startExecuting();\n\t} );\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/uw.TitleDetailsWidget.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'fileNs' is never reassigned. Use 'const' instead.","line":5,"column":2,"nodeType":"Identifier","messageId":"useConst","endLine":5,"endColumn":8},{"ruleId":"prefer-const","severity":2,"message":"'makeTitleInFileNSCases' is never reassigned. Use 'const' instead.","line":6,"column":2,"nodeType":"Identifier","messageId":"useConst","endLine":6,"endColumn":24}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\t'use strict';\n\n\tlet fileNs, makeTitleInFileNSCases;\n\tfileNs = mw.config.get( 'wgFormattedNamespaces' )[ 6 ];\n\tmakeTitleInFileNSCases = [ {\n\t\tfilename: 'foo.png',\n\t\tprefixedText: fileNs + ':Foo.png',\n\t\tdesc: 'filename without namespace starting with a lower case letter'\n\t}, {\n\t\tfilename: 'foo_bar-baz.jpg',\n\t\tprefixedText: fileNs + ':Foo bar-baz.jpg',\n\t\tdesc: 'filename without namespace with space in it'\n\t}, {\n\t\tfilename: 'MediaWiki:foo_bar.jpg',\n\t\tprefixedText: null,\n\t\tdesc: 'filename starting with MediaWiki: (colons are disallowed)'\n\t}, {\n\t\tfilename: 'File:foo_bar.jpg',\n\t\tprefixedText: fileNs + ':Foo bar.jpg',\n\t\tdesc: 'filename starting with File:'\n\t}, {\n\t\tfilename: 'file:foo_bar.jpg',\n\t\tprefixedText: fileNs + ':Foo bar.jpg',\n\t\tdesc: 'filename starting with file:'\n\t}, {\n\t\tfilename: 'Foo part 1/2.jpg',\n\t\tprefixedText: null,\n\t\tdesc: 'filename with characters disallowed in file names'\n\t}, {\n\t\tfilename: 'Foo #1.jpg',\n\t\tprefixedText: null,\n\t\tdesc: 'filename including a # (disallowed in file names)'\n\t} ];\n\n\tQUnit.module( 'uw.TitleDetailsWidget', QUnit.newMwEnvironment() );\n\n\tQUnit.test( '.static.makeTitleInFileNS()', ( assert ) => {\n\t\tconst makeTitleInFileNS = uw.TitleDetailsWidget.static.makeTitleInFileNS;\n\n\t\tmakeTitleInFileNSCases.forEach( ( test ) => {\n\t\t\tconst title = makeTitleInFileNS( test.filename );\n\t\t\tassert.strictEqual(\n\t\t\t\ttitle ? title.getPrefixedText() : title,\n\t\t\t\ttest.prefixedText,\n\t\t\t\ttest.desc\n\t\t\t);\n\t\t} );\n\t} );\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]}]

--- end ---
Disabling eslint rule 'no-mixed-spaces-and-tabs' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'implicit-arrow-linebreak' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-mixed-spaces-and-tabs' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'implicit-arrow-linebreak' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-mixed-spaces-and-tabs' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'implicit-arrow-linebreak' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-mixed-spaces-and-tabs' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'implicit-arrow-linebreak' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-mixed-spaces-and-tabs' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'implicit-arrow-linebreak' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-redeclare' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in .eslintrc.json) on .eslintrc.json
Disabling eslint rule 'prefer-const' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'prefer-const' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'prefer-const' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'prefer-const' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'prefer-const' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'prefer-const' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'prefer-const' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
Disabling eslint rule 'prefer-const' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
$ ./node_modules/.bin/grunt stylelint
--- stdout ---
Running "stylelint:all" (stylelint) task
>> Linted 14 files without errors

Done.

--- end ---
$ /usr/bin/npm ci
--- stdout ---

added 438 packages, and audited 439 packages in 5s

97 packages are looking for funding
  run `npm fund` for details

1 high severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

--- end ---
$ /usr/bin/npm test
--- stdout ---

> test
> grunt test

Running "eslint:all" (eslint) task

/src/repo/resources/controller/uw.controller.Deed.js
  44:4  warning  'deedController' is never reassigned. Use 'const' instead  prefer-const
  52:3  warning  'valid' is never reassigned. Use 'const' instead           prefer-const
  57:4  warning  Mixed spaces and tabs                                      no-mixed-spaces-and-tabs
  57:6  warning  Expected no linebreak before this expression               implicit-arrow-linebreak
  58:3  warning  Mixed spaces and tabs                                      no-mixed-spaces-and-tabs

/src/repo/resources/controller/uw.controller.Details.js
   65:4  warning  'serialized' is never reassigned. Use 'const' instead     prefer-const
   96:4  warning  'invalidStates' is never reassigned. Use 'const' instead  prefer-const
   97:4  warning  'invalids' is never reassigned. Use 'const' instead       prefer-const
   98:4  warning  'valids' is never reassigned. Use 'const' instead         prefer-const
  153:3  warning  Prefer .then to .done                                     no-jquery/no-done-fail
  238:4  warning  '$message' is never reassigned. Use 'const' instead       prefer-const
  239:4  warning  '$ul' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/controller/uw.controller.Step.js
  223:7  warning  'okCount' is never reassigned. Use 'const' instead   prefer-const
  233:3  warning  '$buttons' is never reassigned. Use 'const' instead  prefer-const
  324:4  warning  'copy' is never reassigned. Use 'const' instead      prefer-const

/src/repo/resources/controller/uw.controller.Tutorial.js
  63:3  warning  Prefer .then to .done  no-jquery/no-done-fail
  63:3  warning  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/controller/uw.controller.Upload.js
   69:4  warning  'max' is never reassigned. Use 'const' instead            prefer-const
   71:3  warning  'haveUploads' is never reassigned. Use 'const' instead    prefer-const
   72:3  warning  'fewerThanMax' is never reassigned. Use 'const' instead   prefer-const
  223:3  warning  'upload' is never reassigned. Use 'const' instead         prefer-const
  251:4  warning  'uploadObjs' is never reassigned. Use 'const' instead     prefer-const
  252:4  warning  'controller' is never reassigned. Use 'const' instead     prefer-const
  307:4  warning  'actualMaxSize' is never reassigned. Use 'const' instead  prefer-const
  311:4  warning  'filename' is never reassigned. Use 'const' instead       prefer-const
  312:4  warning  'basename' is never reassigned. Use 'const' instead       prefer-const
  335:3  warning  'extension' is never reassigned. Use 'const' instead      prefer-const

/src/repo/resources/deed/uw.deed.External.js
  66:10  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/deed/uw.deed.OwnWork.js
   29:7   warning  'deed' is never reassigned. Use 'const' instead                 prefer-const
   88:3   warning  'deed' is never reassigned. Use 'const' instead                 prefer-const
   89:3   warning  'languageCode' is never reassigned. Use 'const' instead         prefer-const
   91:3   warning  'defaultLicense' is never reassigned. Use 'const' instead       prefer-const
   92:3   warning  'defaultLicConfig' is never reassigned. Use 'const' instead     prefer-const
   99:3   warning  '$defaultLicenseLink' is never reassigned. Use 'const' instead  prefer-const
  125:3   warning  '$crossfader' is never reassigned. Use 'const' instead          prefer-const
  128:3   warning  '$customDiv' is never reassigned. Use 'const' instead           prefer-const
  136:3   warning  'crossfaderWidget' is never reassigned. Use 'const' instead     prefer-const
  148:3   warning  '$formFields' is never reassigned. Use 'const' instead          prefer-const
  152:3   warning  '$toggler' is never reassigned. Use 'const' instead             prefer-const
  192:7   warning  'author' is never reassigned. Use 'const' instead               prefer-const
  200:3   warning  'userPageTitle' is never reassigned. Use 'const' instead        prefer-const
  215:10  warning  ES2015 'Object.assign' method is forbidden                      es-x/no-object-assign
  255:16  warning  'ownWork' is never reassigned. Use 'const' instead              prefer-const
  277:3   warning  Prefer .then to .done                                           no-jquery/no-done-fail
  297:3   warning  Prefer .then to .done                                           no-jquery/no-done-fail

/src/repo/resources/deed/uw.deed.ThirdParty.js
  178:10  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.CategoriesDetailsWidget.js
   87:3  warning  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
   87:5  warning  Expected no linebreak before this expression           implicit-arrow-linebreak
   88:2  warning  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
   98:3  warning  'categories' is never reassigned. Use 'const' instead  prefer-const
  128:3  warning  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
  128:5  warning  Expected no linebreak before this expression           implicit-arrow-linebreak
  129:2  warning  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs

/src/repo/resources/details/uw.DropdownWidget.js
  13:12  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.LocationDetailsWidget.js
   12:17  warning  ES2015 'Object.assign' method is forbidden             es-x/no-object-assign
   71:3   warning  Prefer .then to .done                                  no-jquery/no-done-fail
   84:3   warning  Prefer .then to .done                                  no-jquery/no-done-fail
  115:7   warning  'errors' is never reassigned. Use 'const' instead      prefer-const
  116:4   warning  'serialized' is never reassigned. Use 'const' instead  prefer-const
  117:4   warning  'parsed' is never reassigned. Use 'const' instead      prefer-const
  165:4   warning  'serialized' is never reassigned. Use 'const' instead  prefer-const
  194:4   warning  'result' is never reassigned. Use 'const' instead      prefer-const
  210:4   warning  'result' is never reassigned. Use 'const' instead      prefer-const
  211:4   warning  'serialized' is never reassigned. Use 'const' instead  prefer-const
  258:7   warning  'sign' is never reassigned. Use 'const' instead        prefer-const
  268:3   warning  'parts' is never reassigned. Use 'const' instead       prefer-const

/src/repo/resources/details/uw.MultipleLanguageInputWidget.js
   16:17  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   50:26  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   60:7   warning  'allLanguages' is never reassigned. Use 'const' instead     prefer-const
   61:4   warning  'unusedLanguages' is never reassigned. Use 'const' instead  prefer-const
   73:16  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   78:12  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   82:3   warning  'item' is never reassigned. Use 'const' instead             prefer-const
  100:7   warning  'allLanguages' is never reassigned. Use 'const' instead     prefer-const
  101:4   warning  'unusedLanguages' is never reassigned. Use 'const' instead  prefer-const
  102:4   warning  'items' is never reassigned. Use 'const' instead            prefer-const
  114:16  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
  192:4   warning  'errors' is never reassigned. Use 'const' instead           prefer-const
  215:7   warning  'values' is never reassigned. Use 'const' instead           prefer-const
  216:4   warning  'widgets' is never reassigned. Use 'const' instead          prefer-const
  272:13  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign

/src/repo/resources/details/uw.SingleLanguageInputWidget.js
   17:17  warning  ES2015 'Object.assign' method is forbidden       es-x/no-object-assign
  226:4   warning  'text' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/details/uw.TextWidget.js
  13:17  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.TitleDetailsWidget.js
   49:4  warning  'illegalFileChars' is never reassigned. Use 'const' instead  prefer-const
   82:3  warning  'value' is never reassigned. Use 'const' instead             prefer-const
   94:3  warning  'title' is never reassigned. Use 'const' instead             prefer-const
  156:7  warning  Mixed spaces and tabs                                        no-mixed-spaces-and-tabs
  156:9  warning  Expected no linebreak before this expression                 implicit-arrow-linebreak
  157:6  warning  Mixed spaces and tabs                                        no-mixed-spaces-and-tabs
  181:3  warning  'errors' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/handlers/mw.ApiUploadHandler.js
  224:7   warning  'allDuplicates' is never reassigned. Use 'const' instead  prefer-const
  224:23  warning  ES2015 'Object.assign' method is forbidden                es-x/no-object-assign
  225:4   warning  '$extra' is never reassigned. Use 'const' instead         prefer-const
  226:4   warning  '$ul' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/jquery.arrowSteps/jquery.arrowSteps.js
  39:4  warning  '$el' is never reassigned. Use 'const' instead     prefer-const
  42:3  warning  '$steps' is never reassigned. Use 'const' instead  prefer-const
  44:3  warning  'width' is never reassigned. Use 'const' instead   prefer-const
  71:4  warning  '$steps' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.DestinationChecker.js
   77:4  warning  Mixed spaces and tabs                                no-mixed-spaces-and-tabs
   77:6  warning  Expected no linebreak before this expression         implicit-arrow-linebreak
   78:3  warning  Mixed spaces and tabs                                no-mixed-spaces-and-tabs
   94:8  warning  'checker' is never reassigned. Use 'const' instead   prefer-const
   95:5  warning  'NS_FILE' is never reassigned. Use 'const' instead   prefer-const
   98:4  warning  'titleObj' is never reassigned. Use 'const' instead  prefer-const
   99:4  warning  'ext' is never reassigned. Use 'const' instead       prefer-const
  101:4  warning  'prefix' is never reassigned. Use 'const' instead    prefer-const

/src/repo/resources/mw.Escaper.js
  31:4   warning  'extractedTemplates' is never reassigned. Use 'const' instead  prefer-const
  32:4   warning  'extractedLinks' is never reassigned. Use 'const' instead      prefer-const
  34:43  warning  ES2015 'Object.assign' method is forbidden                     es-x/no-object-assign
  52:8   warning  'extracts' is never reassigned. Use 'const' instead            prefer-const
  61:5   warning  'regex' is never reassigned. Use 'const' instead               prefer-const
  62:5   warning  'callback' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/mw.GroupProgressBar.js
   59:8  warning  'bar' is never reassigned. Use 'const' instead            prefer-const
  146:5  warning  'remainingTime' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.UploadWizard.js
    4:1  warning  Missing JSDoc @param "uw" type                           jsdoc/require-param-type
   22:3  warning  'maxSimPref' is never reassigned. Use 'const' instead    prefer-const
   64:8  warning  'self' is never reassigned. Use 'const' instead          prefer-const
   65:5  warning  'steps' is never reassigned. Use 'const' instead         prefer-const
   74:4  warning  'uploadStep' is never reassigned. Use 'const' instead    prefer-const
  127:5  warning  ES2015 'Object.assign' method is forbidden               es-x/no-object-assign
  134:5  warning  'original' is never reassigned. Use 'const' instead      prefer-const
  138:5  warning  'override' is never reassigned. Use 'const' instead      prefer-const
  187:4  warning  'deeds' is never reassigned. Use 'const' instead         prefer-const
  188:4  warning  'doOwnWork' is never reassigned. Use 'const' instead     prefer-const
  189:4  warning  'doThirdParty' is never reassigned. Use 'const' instead  prefer-const
  197:3  warning  'api' is never reassigned. Use 'const' instead           prefer-const

/src/repo/resources/mw.UploadWizardDetails.js
   45:8   warning  '$moreDetailsWrapperDiv' is never reassigned. Use 'const' instead                  prefer-const
   47:5   warning  'details' is never reassigned. Use 'const' instead                                 prefer-const
   48:5   warning  'config' is never reassigned. Use 'const' instead                                  prefer-const
   56:13  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   73:48  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   83:40  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   90:55  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   98:57  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  105:44  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  113:47  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  118:51  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  123:53  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  151:4   warning  '$moreDetailsDiv' is never reassigned. Use 'const' instead                         prefer-const
  215:5   warning  Prefer .then to .done                                                              no-jquery/no-done-fail
  255:4   warning  Prefer .then to .done                                                              no-jquery/no-done-fail
  383:4   warning  Mixed spaces and tabs                                                              no-mixed-spaces-and-tabs
  383:6   warning  Expected no linebreak before this expression                                       implicit-arrow-linebreak
  384:3   warning  Mixed spaces and tabs                                                              no-mixed-spaces-and-tabs
  448:5   warning  'yyyyMmDdRegex' is never reassigned. Use 'const' instead                           prefer-const
  449:5   warning  'timeRegex' is never reassigned. Use 'const' instead                               prefer-const
  470:7   warning  'dateInfo' is never reassigned. Use 'const' instead                                prefer-const
  508:4   warning  'saneTime' is never reassigned. Use 'const' instead                                prefer-const
  601:5   warning  'm' is never reassigned. Use 'const' instead                                       prefer-const
  603:5   warning  'values' is never reassigned. Use 'const' instead                                  prefer-const
  653:4   warning  'languages' is never reassigned. Use 'const' instead                               prefer-const
  662:3   warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  672:21  warning  'serialized' is never reassigned. Use 'const' instead                              prefer-const
  734:5   warning  'substitutions' is never reassigned. Use 'const' instead                           prefer-const
  734:25  warning  'substList' is never reassigned. Use 'const' instead                               prefer-const
  735:5   warning  'deed' is never reassigned. Use 'const' instead                                    prefer-const
  793:10  warning  ES2015 RegExp 'u' flag is forbidden                                                es-x/no-regexp-u-flag
  813:8   warning  'details' is never reassigned. Use 'const' instead                                 prefer-const
  823:4   warning  'wikitext' is never reassigned. Use 'const' instead                                prefer-const
  824:4   warning  'promise' is never reassigned. Use 'const' instead                                 prefer-const
  843:5   warning  'tags' is never reassigned. Use 'const' instead                                    prefer-const
  844:5   warning  'deed' is never reassigned. Use 'const' instead                                    prefer-const
  846:5   warning  'config' is never reassigned. Use 'const' instead                                  prefer-const
  869:4   warning  'params' is never reassigned. Use 'const' instead                                  prefer-const
  936:5   warning  'details' is never reassigned. Use 'const' instead                                 prefer-const
  939:5   warning  'deferred' is never reassigned. Use 'const' instead                                prefer-const

/src/repo/resources/mw.UploadWizardLicenseInput.js
   17:7   warning  'self' is never reassigned. Use 'const' instead            prefer-const
   18:4   warning  'groups' is never reassigned. Use 'const' instead          prefer-const
   77:2   warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign
  183:9   warning  'templates' is never reassigned. Use 'const' instead       prefer-const
  209:5   warning  'addError' is never reassigned. Use 'const' instead        prefer-const
  216:5   warning  'selectedInputs' is never reassigned. Use 'const' instead  prefer-const
  226:7   warning  'data' is never reassigned. Use 'const' instead            prefer-const
  232:6   warning  'wikitext' is never reassigned. Use 'const' instead        prefer-const
  268:28  warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign

/src/repo/resources/mw.UploadWizardPage.js
  31:4  warning  'config' is never reassigned. Use 'const' instead        prefer-const
  53:3  warning  'uploadWizard' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.UploadWizardUpload.js
    8:1   warning  Missing JSDoc @param "uw" type                                 jsdoc/require-param-type
   11:14  warning  'uw' is defined but never used                                 no-unused-vars
  204:4   warning  'deferred' is never reassigned. Use 'const' instead            prefer-const
  205:4   warning  'upload' is never reassigned. Use 'const' instead              prefer-const
  222:16  warning  'Uint8Array' is already defined as a built-in global variable  no-redeclare
  223:16  warning  ES2015 'Uint8Array' is forbidden                               es-x/no-typed-arrays
  314:4   warning  'upload' is never reassigned. Use 'const' instead              prefer-const
  382:3   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  382:3   warning  Prefer .then to .fail                                          no-jquery/no-done-fail
  396:7   warning  'requestedTitle' is never reassigned. Use 'const' instead      prefer-const
  430:3   warning  'params' is never reassigned. Use 'const' instead              prefer-const
  448:3   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  448:3   warning  Prefer .then to .fail                                          no-jquery/no-done-fail
  488:21  warning  'image' is never reassigned. Use 'const' instead               prefer-const
  585:5   warning  'constraint' is never reassigned. Use 'const' instead          prefer-const
  629:3   warning  'scaling' is never reassigned. Use 'const' instead             prefer-const
  631:3   warning  'width' is never reassigned. Use 'const' instead               prefer-const
  632:3   warning  'height' is never reassigned. Use 'const' instead              prefer-const
  640:3   warning  'dx' is never reassigned. Use 'const' instead                  prefer-const
  641:3   warning  'dy' is never reassigned. Use 'const' instead                  prefer-const
  666:3   warning  '$canvas' is never reassigned. Use 'const' instead             prefer-const
  667:3   warning  'ctx' is never reassigned. Use 'const' instead                 prefer-const
  715:7   warning  'constraints' is never reassigned. Use 'const' instead         prefer-const
  767:3   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  767:3   warning  Prefer .then to .fail                                          no-jquery/no-done-fail
  775:6   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  778:7   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  802:4   warning  'deferred' is never reassigned. Use 'const' instead            prefer-const
  803:4   warning  'upload' is never reassigned. Use 'const' instead              prefer-const
  828:9   warning  'canvas' is never reassigned. Use 'const' instead              prefer-const
  831:8   warning  'context' is never reassigned. Use 'const' instead             prefer-const

/src/repo/resources/mw.UploadWizardUploadInterface.js
  206:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/transports/mw.FormDataTransport.js
   97:3  warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign
  156:4  warning  'deferred' is never reassigned. Use 'const' instead        prefer-const
  157:4  warning  'fileSize' is never reassigned. Use 'const' instead        prefer-const
  158:4  warning  'chunkSize' is never reassigned. Use 'const' instead       prefer-const
  159:4  warning  'transport' is never reassigned. Use 'const' instead       prefer-const
  169:5  warning  Prefer .then to .done                                      no-jquery/no-done-fail
  170:6  warning  Prefer .then to .done                                      no-jquery/no-done-fail
  170:6  warning  Prefer .then to .fail                                      no-jquery/no-done-fail
  194:7  warning  'params' is never reassigned. Use 'const' instead          prefer-const
  195:4  warning  'transport' is never reassigned. Use 'const' instead       prefer-const
  196:4  warning  'bytesAvailable' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/ui/steps/uw.ui.Deed.js
  55:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Details.js
  90:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Thanks.js
   30:4  warning  'thanks' is never reassigned. Use 'const' instead             prefer-const
   48:3  warning  '$header' is never reassigned. Use 'const' instead            prefer-const
   69:3  warning  'beginButtonTarget' is never reassigned. Use 'const' instead  prefer-const
   98:3  warning  'thumbWikiText' is never reassigned. Use 'const' instead      prefer-const
  104:3  warning  '$thanksDiv' is never reassigned. Use 'const' instead         prefer-const
  106:3  warning  '$thumbnailWrapDiv' is never reassigned. Use 'const' instead  prefer-const
  109:3  warning  '$thumbnailDiv' is never reassigned. Use 'const' instead      prefer-const
  112:3  warning  '$thumbnailCaption' is never reassigned. Use 'const' instead  prefer-const
  115:3  warning  '$thumbnailLink' is never reassigned. Use 'const' instead     prefer-const
  128:3  warning  Prefer .then to .done                                         no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Tutorial.js
  125:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Upload.js
  210:6  warning  Prefer .then to .done  no-jquery/no-done-fail
  222:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/uw.ui.DeedPreview.js
  30:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/uw.ui.Step.js
  101:3  warning  Prefer .then to .done  no-jquery/no-done-fail
  119:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/uw.ConcurrentQueue.js
  117:3  warning  'index' is never reassigned. Use 'const' instead    prefer-const
  139:3  warning  'item' is never reassigned. Use 'const' instead     prefer-const
  145:3  warning  'promise' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/uw.CopyMetadataWidget.js
   14:4  warning  'checkboxes' is never reassigned. Use 'const' instead               prefer-const
   15:4  warning  '$copyMetadataWrapperDiv' is never reassigned. Use 'const' instead  prefer-const
   16:4  warning  '$copyMetadataDiv' is never reassigned. Use 'const' instead         prefer-const
  157:4  warning  'uploads' is never reassigned. Use 'const' instead                  prefer-const
  158:4  warning  'sourceUpload' is never reassigned. Use 'const' instead             prefer-const
  159:4  warning  'serialized' is never reassigned. Use 'const' instead               prefer-const
  161:4  warning  'sourceValue' is never reassigned. Use 'const' instead              prefer-const
  214:4  warning  'uploads' is never reassigned. Use 'const' instead                  prefer-const

/src/repo/resources/uw.FieldLayout.js
  20:12  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/uw.LicenseGroup.js
   37:17  warning  ES2015 'Object.assign' method is forbidden               es-x/no-object-assign
  132:4   warning  'option' is never reassigned. Use 'const' instead        prefer-const
  167:4   warning  'option' is never reassigned. Use 'const' instead        prefer-const
  191:4   warning  'self' is never reassigned. Use 'const' instead          prefer-const
  192:4   warning  'values' is never reassigned. Use 'const' instead        prefer-const
  194:3   warning  'wikiTexts' is never reassigned. Use 'const' instead     prefer-const
  196:5   warning  'value' is never reassigned. Use 'const' instead         prefer-const
  222:7   warning  'self' is never reassigned. Use 'const' instead          prefer-const
  223:4   warning  'result' is never reassigned. Use 'const' instead        prefer-const
  248:7   warning  'self' is never reassigned. Use 'const' instead          prefer-const
  249:4   warning  'selectArray' is never reassigned. Use 'const' instead   prefer-const
  303:7   warning  'licenseInfo' is never reassigned. Use 'const' instead   prefer-const
  306:3   warning  'licenseText' is never reassigned. Use 'const' instead   prefer-const
  319:7   warning  'licenseInfo' is never reassigned. Use 'const' instead   prefer-const
  320:4   warning  'messageKey' is never reassigned. Use 'const' instead    prefer-const
  323:4   warning  'languageCode' is never reassigned. Use 'const' instead  prefer-const
  328:4   warning  '$icons' is never reassigned. Use 'const' instead        prefer-const
  334:3   warning  '$licenseLink' is never reassigned. Use 'const' instead  prefer-const
  343:3   warning  '$label' is never reassigned. Use 'const' instead        prefer-const
  361:7   warning  'self' is never reassigned. Use 'const' instead          prefer-const
  372:3   warning  'button' is never reassigned. Use 'const' instead        prefer-const
  397:3   warning  'input' is never reassigned. Use 'const' instead         prefer-const
  413:3   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  413:3   warning  Prefer .then to .fail                                    no-jquery/no-done-fail

/src/repo/resources/uw.ValidationMessageElement.js
  39:2  warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  91:3  warning  '$listItem' is never reassigned. Use 'const' instead                               prefer-const

/src/repo/tests/qunit/controller/uw.controller.Details.test.js
   57:7  warning  'step' is never reassigned. Use 'const' instead        prefer-const
   61:4  warning  'stepUiStub' is never reassigned. Use 'const' instead  prefer-const
  110:4  warning  'done' is never reassigned. Use 'const' instead        prefer-const
  111:4  warning  'donestub' is never reassigned. Use 'const' instead    prefer-const
  112:4  warning  'ds' is never reassigned. Use 'const' instead          prefer-const
  113:4  warning  'ps' is never reassigned. Use 'const' instead          prefer-const
  117:3  warning  'tostub' is never reassigned. Use 'const' instead      prefer-const
  124:3  warning  'step' is never reassigned. Use 'const' instead        prefer-const
  135:3  warning  Prefer .then to .done                                  no-jquery/no-done-fail

/src/repo/tests/qunit/controller/uw.controller.Tutorial.test.js
  33:4  warning  'acwStub' is never reassigned. Use 'const' instead  prefer-const
  54:3  warning  'mnStub' is never reassigned. Use 'const' instead   prefer-const

/src/repo/tests/qunit/mw.UploadWizardLicenseInput.test.js
  17:6  warning  'config' is never reassigned. Use 'const' instead          prefer-const
  18:3  warning  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  21:2  warning  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const
  27:6  warning  'config' is never reassigned. Use 'const' instead          prefer-const
  28:3  warning  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  33:2  warning  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const
  37:2  warning  '$input' is never reassigned. Use 'const' instead          prefer-const
  41:2  warning  '$label' is never reassigned. Use 'const' instead          prefer-const
  46:6  warning  'config' is never reassigned. Use 'const' instead          prefer-const
  56:3  warning  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  59:2  warning  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const

/src/repo/tests/qunit/mw.UploadWizardUpload.test.js
  23:4  warning  'oldconf' is never reassigned. Use 'const' instead  prefer-const
  27:3  warning  'upload' is never reassigned. Use 'const' instead   prefer-const

/src/repo/tests/qunit/mw.fileApi.test.js
  46:15  warning  'testFile' is never reassigned. Use 'const' instead   prefer-const
  47:4   warning  'fakeVideo' is never reassigned. Use 'const' instead  prefer-const

/src/repo/tests/qunit/transports/mw.FormDataTransport.test.js
   27:3   warning  'config' is never reassigned. Use 'const' instead     prefer-const
   86:4   warning  'transport' is never reassigned. Use 'const' instead  prefer-const
   87:4   warning  'fakeFile' is never reassigned. Use 'const' instead   prefer-const
   97:3   warning  'request' is never reassigned. Use 'const' instead    prefer-const
  107:4   warning  'transport' is never reassigned. Use 'const' instead  prefer-const
  108:4   warning  'fakeFile' is never reassigned. Use 'const' instead   prefer-const
  125:3   warning  'request' is never reassigned. Use 'const' instead    prefer-const
  146:3   warning  Prefer .then to .fail                                 no-jquery/no-done-fail
  179:10  warning  Prefer .then to .done                                 no-jquery/no-done-fail
  198:10  warning  Prefer .then to .done                                 no-jquery/no-done-fail
  218:3   warning  Prefer .then to .fail                                 no-jquery/no-done-fail

/src/repo/tests/qunit/uw.ConcurrentQueue.test.js
   38:3  warning  'calls' is never reassigned. Use 'const' instead            prefer-const
   65:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
   66:3  warning  'action' is never reassigned. Use 'const' instead           prefer-const
   67:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
   98:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
   99:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  100:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  101:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  102:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  139:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  140:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  167:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  168:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  184:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  185:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  186:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  187:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  188:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  240:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  241:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  242:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  243:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  244:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  297:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  298:3  warning  'action' is never reassigned. Use 'const' instead           prefer-const
  299:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  300:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  301:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  302:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  353:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  355:3  warning  'action' is never reassigned. Use 'const' instead           prefer-const
  356:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  357:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  358:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  359:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  402:3  warning  'onProgress' is never reassigned. Use 'const' instead       prefer-const

/src/repo/tests/qunit/uw.TitleDetailsWidget.test.js
  5:2  warning  'fileNs' is never reassigned. Use 'const' instead                  prefer-const
  6:2  warning  'makeTitleInFileNSCases' is never reassigned. Use 'const' instead  prefer-const

✖ 352 problems (0 errors, 352 warnings)


Running "stylelint:all" (stylelint) task
>> Linted 14 files without errors

Running "banana:MediaUploader" (banana) task
>> 3 message directories checked.

Done.

--- end ---
Upgrading c:mediawiki/mediawiki-codesniffer from 45.0.0 -> 47.0.0
$ /usr/bin/composer update
--- stderr ---
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 2 updates, 0 removals
  - Upgrading mediawiki/mediawiki-codesniffer (v45.0.0 => v47.0.0)
  - Upgrading squizlabs/php_codesniffer (3.10.3 => 3.12.2)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 2 updates, 0 removals
    0 [>---------------------------]    0 [->--------------------------]
  - Upgrading squizlabs/php_codesniffer (3.10.3 => 3.12.2): Extracting archive
  - Upgrading mediawiki/mediawiki-codesniffer (v45.0.0 => v47.0.0): Extracting archive
 0/2 [>---------------------------]   0%
 1/2 [==============>-------------]  50%
 2/2 [============================] 100%
Generating autoload files
17 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found
--- stdout ---
PHP CodeSniffer Config installed_paths set to ../../mediawiki/mediawiki-codesniffer,../../phpcsstandards/phpcsextra,../../phpcsstandards/phpcsutils

--- end ---
Previously failing phpcs rules: {'MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic', 'MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment'}
$ vendor/bin/phpcs --report=json
--- stdout ---
{"totals":{"errors":3,"warnings":1,"fixable":0},"files":{"\/src\/repo\/defines.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/MediaUploader.namespaces.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/BaseCampaignException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/InvalidFormatException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/InvalidCampaignException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/MediaUploaderResourceModuleFactory.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/IncompleteRecordException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/RawConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks\/RegistrationHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigBase.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/MediaUploaderResourceModule.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigUnitTestCase.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/GlobalConfigAnchorUpdateJob.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigCacheInvalidator.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/ServiceWiring.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/GlobalParsedConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks\/Hooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignRecord.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigFactoryTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/MediaUploader.alias.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/RequestConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/.phan\/config.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Api\/QueryAllCampaigns.php":{"errors":3,"warnings":0,"messages":[{"message":"Missing function doc comment","source":"MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic","severity":5,"fixable":false,"type":"ERROR","line":159,"column":12},{"message":"Missing function doc comment","source":"MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic","severity":5,"fixable":false,"type":"ERROR","line":163,"column":12},{"message":"Missing function doc comment","source":"MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic","severity":5,"fixable":false,"type":"ERROR","line":189,"column":12}]},"\/src\/repo\/includes\/Campaign\/Validator.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/InvalidSchemaException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Special\/Campaigns.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Special\/MediaUploaderSimpleForm.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/MediaUploaderServices.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/RequestConfigTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/CampaignParsedConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks\/CampaignContentHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/InvalidCampaignExceptionTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ParsedConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/CampaignStoreTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigParserFactory.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/MediaUploader.config.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigBaseTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignContent.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/Api\/QueryAllCampaignsTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigCacheInvalidatorTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/RawConfigTest.php":{"errors":0,"warnings":1,"messages":[{"message":"Comments should start on new line.","source":"MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment","severity":5,"fixable":false,"type":"WARNING","line":32,"column":49}]},"\/src\/repo\/includes\/Config\/ConfigParser.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignPageFormatter.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/maintenance\/MigrateCampaigns.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigFactory.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/CampaignRecordTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/MediaUploaderResourceModuleTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks\/CampaignHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignContentHandler.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignStore.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignSelectQueryBuilder.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/CampaignStatsTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/CampaignStoreTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Hooks\/CampaignContentHooksTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/MaintenanceMigrateCampaignsTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/ConfigParserTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/GlobalParsedConfigTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignStats.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/GlobalConfigAnchorUpdateJobTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/MediaUploaderServicesTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/SpecialMediaUploaderTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/CampaignContentTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Hooks\/CampaignHooksTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ParsedConfigTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Special\/MediaUploader.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Hooks\/RegistrationHooksTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigParserTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/ValidatorTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/CampaignParsedConfigTest.php":{"errors":0,"warnings":0,"messages":[]}}}

--- end ---
PHPCS run failed
$ vendor/bin/phpcs --report=json
--- stdout ---
{"totals":{"errors":3,"warnings":1,"fixable":0},"files":{"\/src\/repo\/MediaUploader.namespaces.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/defines.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/BaseCampaignException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/InvalidFormatException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/InvalidCampaignException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/MediaUploaderResourceModuleFactory.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/IncompleteRecordException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/RawConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/GlobalConfigAnchorUpdateJob.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigUnitTestCase.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigBase.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/MediaUploaderResourceModule.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/ServiceWiring.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks\/RegistrationHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/GlobalParsedConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigCacheInvalidator.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks\/Hooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/MediaUploader.alias.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/RequestConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignRecord.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/.phan\/config.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigFactoryTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Special\/Campaigns.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Validator.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/Exception\/InvalidSchemaException.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Special\/MediaUploaderSimpleForm.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/CampaignParsedConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignContent.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks\/CampaignContentHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/RequestConfigTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/MediaUploaderServices.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigParserFactory.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ParsedConfig.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Api\/QueryAllCampaigns.php":{"errors":3,"warnings":0,"messages":[{"message":"Missing function doc comment","source":"MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic","severity":5,"fixable":false,"type":"ERROR","line":159,"column":12},{"message":"Missing function doc comment","source":"MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic","severity":5,"fixable":false,"type":"ERROR","line":163,"column":12},{"message":"Missing function doc comment","source":"MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic","severity":5,"fixable":false,"type":"ERROR","line":189,"column":12}]},"\/src\/repo\/tests\/phpunit\/integration\/Api\/QueryAllCampaignsTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/InvalidCampaignExceptionTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/MediaUploader.config.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignSelectQueryBuilder.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/CampaignStoreTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigParser.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigBaseTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/RawConfigTest.php":{"errors":0,"warnings":1,"messages":[{"message":"Comments should start on new line.","source":"MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment","severity":5,"fixable":false,"type":"WARNING","line":32,"column":49}]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/CampaignRecordTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignPageFormatter.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigCacheInvalidatorTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config\/ConfigFactory.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignContentHandler.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/maintenance\/MigrateCampaigns.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/CampaignStoreTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/MediaUploaderResourceModuleTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Hooks\/CampaignContentHooksTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/MaintenanceMigrateCampaignsTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/MediaUploaderServicesTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignStore.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks\/CampaignHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/SpecialMediaUploaderTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/ConfigParserTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ParsedConfigTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/GlobalParsedConfigTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/CampaignStatsTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Special\/MediaUploader.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign\/CampaignStats.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/ConfigParserTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Hooks\/CampaignHooksTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/CampaignContentTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/integration\/GlobalConfigAnchorUpdateJobTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Hooks\/RegistrationHooksTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Campaign\/ValidatorTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/unit\/Config\/CampaignParsedConfigTest.php":{"errors":0,"warnings":0,"messages":[]}}}

--- end ---
$ git checkout .phpcs.xml
--- stderr ---
Updated 1 path from the index
--- stdout ---

--- end ---
$ /usr/bin/composer install
--- stderr ---
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating autoload files
17 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
--- stdout ---

--- end ---
$ /usr/bin/composer test
--- stderr ---
> parallel-lint . --exclude vendor --exclude node_modules
> phpcs -sp --cache
> minus-x check .
--- stdout ---
PHP 8.2.28 | 10 parallel jobs
............................................................ 60/69 ( 86%)
.........                                                    69/69 (100%)


Checked 69 files in 0.3 seconds
No syntax error found
................................... 35 / 35 (100%)


Time: 249ms; Memory: 10MB

MinusX
======
Processing /src/repo...
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................

All good!

--- end ---
$ /usr/bin/npm audit --json
--- stdout ---
{
  "auditReportVersion": 2,
  "vulnerabilities": {
    "cross-spawn": {
      "name": "cross-spawn",
      "severity": "high",
      "isDirect": false,
      "via": [
        {
          "source": 1104664,
          "name": "cross-spawn",
          "dependency": "cross-spawn",
          "title": "Regular Expression Denial of Service (ReDoS) in cross-spawn",
          "url": "https://github.com/advisories/GHSA-3xgq-45jj-v275",
          "severity": "high",
          "cwe": [
            "CWE-1333"
          ],
          "cvss": {
            "score": 7.5,
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
          },
          "range": ">=7.0.0 <7.0.5"
        }
      ],
      "effects": [],
      "range": "7.0.0 - 7.0.4",
      "nodes": [
        "node_modules/cross-spawn"
      ],
      "fixAvailable": true
    }
  },
  "metadata": {
    "vulnerabilities": {
      "info": 0,
      "low": 0,
      "moderate": 0,
      "high": 1,
      "critical": 0,
      "total": 1
    },
    "dependencies": {
      "prod": 1,
      "dev": 438,
      "optional": 0,
      "peer": 1,
      "peerOptional": 0,
      "total": 438
    }
  }
}

--- end ---
Attempting to npm audit fix
$ /usr/bin/npm audit fix --dry-run --only=dev --json
--- stderr ---
npm WARN invalid config only="dev" set in command line options
npm WARN invalid config Must be one of: null, prod, production
--- stdout ---
{
  "added": 0,
  "removed": 0,
  "changed": 1,
  "audited": 439,
  "funding": 97,
  "audit": {
    "auditReportVersion": 2,
    "vulnerabilities": {
      "cross-spawn": {
        "name": "cross-spawn",
        "severity": "high",
        "isDirect": false,
        "via": [
          {
            "source": 1104664,
            "name": "cross-spawn",
            "dependency": "cross-spawn",
            "title": "Regular Expression Denial of Service (ReDoS) in cross-spawn",
            "url": "https://github.com/advisories/GHSA-3xgq-45jj-v275",
            "severity": "high",
            "cwe": [
              "CWE-1333"
            ],
            "cvss": {
              "score": 7.5,
              "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
            },
            "range": ">=7.0.0 <7.0.5"
          }
        ],
        "effects": [],
        "range": "7.0.0 - 7.0.4",
        "nodes": [
          ""
        ],
        "fixAvailable": true
      }
    },
    "metadata": {
      "vulnerabilities": {
        "info": 0,
        "low": 0,
        "moderate": 0,
        "high": 1,
        "critical": 0,
        "total": 1
      },
      "dependencies": {
        "prod": 1,
        "dev": 438,
        "optional": 0,
        "peer": 1,
        "peerOptional": 0,
        "total": 438
      }
    }
  }
}

--- end ---
{"added": 0, "removed": 0, "changed": 1, "audited": 439, "funding": 97, "audit": {"auditReportVersion": 2, "vulnerabilities": {"cross-spawn": {"name": "cross-spawn", "severity": "high", "isDirect": false, "via": [{"source": 1104664, "name": "cross-spawn", "dependency": "cross-spawn", "title": "Regular Expression Denial of Service (ReDoS) in cross-spawn", "url": "https://github.com/advisories/GHSA-3xgq-45jj-v275", "severity": "high", "cwe": ["CWE-1333"], "cvss": {"score": 7.5, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}, "range": ">=7.0.0 <7.0.5"}], "effects": [], "range": "7.0.0 - 7.0.4", "nodes": [""], "fixAvailable": true}}, "metadata": {"vulnerabilities": {"info": 0, "low": 0, "moderate": 0, "high": 1, "critical": 0, "total": 1}, "dependencies": {"prod": 1, "dev": 438, "optional": 0, "peer": 1, "peerOptional": 0, "total": 438}}}}
$ /usr/bin/npm audit fix --only=dev
--- stderr ---
npm WARN invalid config only="dev" set in command line options
npm WARN invalid config Must be one of: null, prod, production
--- stdout ---

up to date, audited 439 packages in 1s

97 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

--- end ---
Verifying that tests still pass
$ /usr/bin/npm ci
--- stdout ---

added 438 packages, and audited 439 packages in 4s

97 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

--- end ---
$ /usr/bin/npm test
--- stdout ---

> test
> grunt test

Running "eslint:all" (eslint) task

/src/repo/resources/controller/uw.controller.Deed.js
  44:4  warning  'deedController' is never reassigned. Use 'const' instead  prefer-const
  52:3  warning  'valid' is never reassigned. Use 'const' instead           prefer-const
  57:4  warning  Mixed spaces and tabs                                      no-mixed-spaces-and-tabs
  57:6  warning  Expected no linebreak before this expression               implicit-arrow-linebreak
  58:3  warning  Mixed spaces and tabs                                      no-mixed-spaces-and-tabs

/src/repo/resources/controller/uw.controller.Details.js
   65:4  warning  'serialized' is never reassigned. Use 'const' instead     prefer-const
   96:4  warning  'invalidStates' is never reassigned. Use 'const' instead  prefer-const
   97:4  warning  'invalids' is never reassigned. Use 'const' instead       prefer-const
   98:4  warning  'valids' is never reassigned. Use 'const' instead         prefer-const
  153:3  warning  Prefer .then to .done                                     no-jquery/no-done-fail
  238:4  warning  '$message' is never reassigned. Use 'const' instead       prefer-const
  239:4  warning  '$ul' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/controller/uw.controller.Step.js
  223:7  warning  'okCount' is never reassigned. Use 'const' instead   prefer-const
  233:3  warning  '$buttons' is never reassigned. Use 'const' instead  prefer-const
  324:4  warning  'copy' is never reassigned. Use 'const' instead      prefer-const

/src/repo/resources/controller/uw.controller.Tutorial.js
  63:3  warning  Prefer .then to .done  no-jquery/no-done-fail
  63:3  warning  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/controller/uw.controller.Upload.js
   69:4  warning  'max' is never reassigned. Use 'const' instead            prefer-const
   71:3  warning  'haveUploads' is never reassigned. Use 'const' instead    prefer-const
   72:3  warning  'fewerThanMax' is never reassigned. Use 'const' instead   prefer-const
  223:3  warning  'upload' is never reassigned. Use 'const' instead         prefer-const
  251:4  warning  'uploadObjs' is never reassigned. Use 'const' instead     prefer-const
  252:4  warning  'controller' is never reassigned. Use 'const' instead     prefer-const
  307:4  warning  'actualMaxSize' is never reassigned. Use 'const' instead  prefer-const
  311:4  warning  'filename' is never reassigned. Use 'const' instead       prefer-const
  312:4  warning  'basename' is never reassigned. Use 'const' instead       prefer-const
  335:3  warning  'extension' is never reassigned. Use 'const' instead      prefer-const

/src/repo/resources/deed/uw.deed.External.js
  66:10  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/deed/uw.deed.OwnWork.js
   29:7   warning  'deed' is never reassigned. Use 'const' instead                 prefer-const
   88:3   warning  'deed' is never reassigned. Use 'const' instead                 prefer-const
   89:3   warning  'languageCode' is never reassigned. Use 'const' instead         prefer-const
   91:3   warning  'defaultLicense' is never reassigned. Use 'const' instead       prefer-const
   92:3   warning  'defaultLicConfig' is never reassigned. Use 'const' instead     prefer-const
   99:3   warning  '$defaultLicenseLink' is never reassigned. Use 'const' instead  prefer-const
  125:3   warning  '$crossfader' is never reassigned. Use 'const' instead          prefer-const
  128:3   warning  '$customDiv' is never reassigned. Use 'const' instead           prefer-const
  136:3   warning  'crossfaderWidget' is never reassigned. Use 'const' instead     prefer-const
  148:3   warning  '$formFields' is never reassigned. Use 'const' instead          prefer-const
  152:3   warning  '$toggler' is never reassigned. Use 'const' instead             prefer-const
  192:7   warning  'author' is never reassigned. Use 'const' instead               prefer-const
  200:3   warning  'userPageTitle' is never reassigned. Use 'const' instead        prefer-const
  215:10  warning  ES2015 'Object.assign' method is forbidden                      es-x/no-object-assign
  255:16  warning  'ownWork' is never reassigned. Use 'const' instead              prefer-const
  277:3   warning  Prefer .then to .done                                           no-jquery/no-done-fail
  297:3   warning  Prefer .then to .done                                           no-jquery/no-done-fail

/src/repo/resources/deed/uw.deed.ThirdParty.js
  178:10  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.CategoriesDetailsWidget.js
   87:3  warning  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
   87:5  warning  Expected no linebreak before this expression           implicit-arrow-linebreak
   88:2  warning  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
   98:3  warning  'categories' is never reassigned. Use 'const' instead  prefer-const
  128:3  warning  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs
  128:5  warning  Expected no linebreak before this expression           implicit-arrow-linebreak
  129:2  warning  Mixed spaces and tabs                                  no-mixed-spaces-and-tabs

/src/repo/resources/details/uw.DropdownWidget.js
  13:12  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.LocationDetailsWidget.js
   12:17  warning  ES2015 'Object.assign' method is forbidden             es-x/no-object-assign
   71:3   warning  Prefer .then to .done                                  no-jquery/no-done-fail
   84:3   warning  Prefer .then to .done                                  no-jquery/no-done-fail
  115:7   warning  'errors' is never reassigned. Use 'const' instead      prefer-const
  116:4   warning  'serialized' is never reassigned. Use 'const' instead  prefer-const
  117:4   warning  'parsed' is never reassigned. Use 'const' instead      prefer-const
  165:4   warning  'serialized' is never reassigned. Use 'const' instead  prefer-const
  194:4   warning  'result' is never reassigned. Use 'const' instead      prefer-const
  210:4   warning  'result' is never reassigned. Use 'const' instead      prefer-const
  211:4   warning  'serialized' is never reassigned. Use 'const' instead  prefer-const
  258:7   warning  'sign' is never reassigned. Use 'const' instead        prefer-const
  268:3   warning  'parts' is never reassigned. Use 'const' instead       prefer-const

/src/repo/resources/details/uw.MultipleLanguageInputWidget.js
   16:17  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   50:26  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   60:7   warning  'allLanguages' is never reassigned. Use 'const' instead     prefer-const
   61:4   warning  'unusedLanguages' is never reassigned. Use 'const' instead  prefer-const
   73:16  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   78:12  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
   82:3   warning  'item' is never reassigned. Use 'const' instead             prefer-const
  100:7   warning  'allLanguages' is never reassigned. Use 'const' instead     prefer-const
  101:4   warning  'unusedLanguages' is never reassigned. Use 'const' instead  prefer-const
  102:4   warning  'items' is never reassigned. Use 'const' instead            prefer-const
  114:16  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign
  192:4   warning  'errors' is never reassigned. Use 'const' instead           prefer-const
  215:7   warning  'values' is never reassigned. Use 'const' instead           prefer-const
  216:4   warning  'widgets' is never reassigned. Use 'const' instead          prefer-const
  272:13  warning  ES2015 'Object.assign' method is forbidden                  es-x/no-object-assign

/src/repo/resources/details/uw.SingleLanguageInputWidget.js
   17:17  warning  ES2015 'Object.assign' method is forbidden       es-x/no-object-assign
  226:4   warning  'text' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/details/uw.TextWidget.js
  13:17  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/details/uw.TitleDetailsWidget.js
   49:4  warning  'illegalFileChars' is never reassigned. Use 'const' instead  prefer-const
   82:3  warning  'value' is never reassigned. Use 'const' instead             prefer-const
   94:3  warning  'title' is never reassigned. Use 'const' instead             prefer-const
  156:7  warning  Mixed spaces and tabs                                        no-mixed-spaces-and-tabs
  156:9  warning  Expected no linebreak before this expression                 implicit-arrow-linebreak
  157:6  warning  Mixed spaces and tabs                                        no-mixed-spaces-and-tabs
  181:3  warning  'errors' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/handlers/mw.ApiUploadHandler.js
  224:7   warning  'allDuplicates' is never reassigned. Use 'const' instead  prefer-const
  224:23  warning  ES2015 'Object.assign' method is forbidden                es-x/no-object-assign
  225:4   warning  '$extra' is never reassigned. Use 'const' instead         prefer-const
  226:4   warning  '$ul' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/jquery.arrowSteps/jquery.arrowSteps.js
  39:4  warning  '$el' is never reassigned. Use 'const' instead     prefer-const
  42:3  warning  '$steps' is never reassigned. Use 'const' instead  prefer-const
  44:3  warning  'width' is never reassigned. Use 'const' instead   prefer-const
  71:4  warning  '$steps' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.DestinationChecker.js
   77:4  warning  Mixed spaces and tabs                                no-mixed-spaces-and-tabs
   77:6  warning  Expected no linebreak before this expression         implicit-arrow-linebreak
   78:3  warning  Mixed spaces and tabs                                no-mixed-spaces-and-tabs
   94:8  warning  'checker' is never reassigned. Use 'const' instead   prefer-const
   95:5  warning  'NS_FILE' is never reassigned. Use 'const' instead   prefer-const
   98:4  warning  'titleObj' is never reassigned. Use 'const' instead  prefer-const
   99:4  warning  'ext' is never reassigned. Use 'const' instead       prefer-const
  101:4  warning  'prefix' is never reassigned. Use 'const' instead    prefer-const

/src/repo/resources/mw.Escaper.js
  31:4   warning  'extractedTemplates' is never reassigned. Use 'const' instead  prefer-const
  32:4   warning  'extractedLinks' is never reassigned. Use 'const' instead      prefer-const
  34:43  warning  ES2015 'Object.assign' method is forbidden                     es-x/no-object-assign
  52:8   warning  'extracts' is never reassigned. Use 'const' instead            prefer-const
  61:5   warning  'regex' is never reassigned. Use 'const' instead               prefer-const
  62:5   warning  'callback' is never reassigned. Use 'const' instead            prefer-const

/src/repo/resources/mw.GroupProgressBar.js
   59:8  warning  'bar' is never reassigned. Use 'const' instead            prefer-const
  146:5  warning  'remainingTime' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.UploadWizard.js
    4:1  warning  Missing JSDoc @param "uw" type                           jsdoc/require-param-type
   22:3  warning  'maxSimPref' is never reassigned. Use 'const' instead    prefer-const
   64:8  warning  'self' is never reassigned. Use 'const' instead          prefer-const
   65:5  warning  'steps' is never reassigned. Use 'const' instead         prefer-const
   74:4  warning  'uploadStep' is never reassigned. Use 'const' instead    prefer-const
  127:5  warning  ES2015 'Object.assign' method is forbidden               es-x/no-object-assign
  134:5  warning  'original' is never reassigned. Use 'const' instead      prefer-const
  138:5  warning  'override' is never reassigned. Use 'const' instead      prefer-const
  187:4  warning  'deeds' is never reassigned. Use 'const' instead         prefer-const
  188:4  warning  'doOwnWork' is never reassigned. Use 'const' instead     prefer-const
  189:4  warning  'doThirdParty' is never reassigned. Use 'const' instead  prefer-const
  197:3  warning  'api' is never reassigned. Use 'const' instead           prefer-const

/src/repo/resources/mw.UploadWizardDetails.js
   45:8   warning  '$moreDetailsWrapperDiv' is never reassigned. Use 'const' instead                  prefer-const
   47:5   warning  'details' is never reassigned. Use 'const' instead                                 prefer-const
   48:5   warning  'config' is never reassigned. Use 'const' instead                                  prefer-const
   56:13  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   73:48  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   83:40  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   90:55  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
   98:57  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  105:44  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  113:47  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  118:51  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  123:53  warning  ES2015 'Object.assign' method is forbidden                                         es-x/no-object-assign
  151:4   warning  '$moreDetailsDiv' is never reassigned. Use 'const' instead                         prefer-const
  215:5   warning  Prefer .then to .done                                                              no-jquery/no-done-fail
  255:4   warning  Prefer .then to .done                                                              no-jquery/no-done-fail
  383:4   warning  Mixed spaces and tabs                                                              no-mixed-spaces-and-tabs
  383:6   warning  Expected no linebreak before this expression                                       implicit-arrow-linebreak
  384:3   warning  Mixed spaces and tabs                                                              no-mixed-spaces-and-tabs
  448:5   warning  'yyyyMmDdRegex' is never reassigned. Use 'const' instead                           prefer-const
  449:5   warning  'timeRegex' is never reassigned. Use 'const' instead                               prefer-const
  470:7   warning  'dateInfo' is never reassigned. Use 'const' instead                                prefer-const
  508:4   warning  'saneTime' is never reassigned. Use 'const' instead                                prefer-const
  601:5   warning  'm' is never reassigned. Use 'const' instead                                       prefer-const
  603:5   warning  'values' is never reassigned. Use 'const' instead                                  prefer-const
  653:4   warning  'languages' is never reassigned. Use 'const' instead                               prefer-const
  662:3   warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  672:21  warning  'serialized' is never reassigned. Use 'const' instead                              prefer-const
  734:5   warning  'substitutions' is never reassigned. Use 'const' instead                           prefer-const
  734:25  warning  'substList' is never reassigned. Use 'const' instead                               prefer-const
  735:5   warning  'deed' is never reassigned. Use 'const' instead                                    prefer-const
  793:10  warning  ES2015 RegExp 'u' flag is forbidden                                                es-x/no-regexp-u-flag
  813:8   warning  'details' is never reassigned. Use 'const' instead                                 prefer-const
  823:4   warning  'wikitext' is never reassigned. Use 'const' instead                                prefer-const
  824:4   warning  'promise' is never reassigned. Use 'const' instead                                 prefer-const
  843:5   warning  'tags' is never reassigned. Use 'const' instead                                    prefer-const
  844:5   warning  'deed' is never reassigned. Use 'const' instead                                    prefer-const
  846:5   warning  'config' is never reassigned. Use 'const' instead                                  prefer-const
  869:4   warning  'params' is never reassigned. Use 'const' instead                                  prefer-const
  936:5   warning  'details' is never reassigned. Use 'const' instead                                 prefer-const
  939:5   warning  'deferred' is never reassigned. Use 'const' instead                                prefer-const

/src/repo/resources/mw.UploadWizardLicenseInput.js
   17:7   warning  'self' is never reassigned. Use 'const' instead            prefer-const
   18:4   warning  'groups' is never reassigned. Use 'const' instead          prefer-const
   77:2   warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign
  183:9   warning  'templates' is never reassigned. Use 'const' instead       prefer-const
  209:5   warning  'addError' is never reassigned. Use 'const' instead        prefer-const
  216:5   warning  'selectedInputs' is never reassigned. Use 'const' instead  prefer-const
  226:7   warning  'data' is never reassigned. Use 'const' instead            prefer-const
  232:6   warning  'wikitext' is never reassigned. Use 'const' instead        prefer-const
  268:28  warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign

/src/repo/resources/mw.UploadWizardPage.js
  31:4  warning  'config' is never reassigned. Use 'const' instead        prefer-const
  53:3  warning  'uploadWizard' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/mw.UploadWizardUpload.js
    8:1   warning  Missing JSDoc @param "uw" type                                 jsdoc/require-param-type
   11:14  warning  'uw' is defined but never used                                 no-unused-vars
  204:4   warning  'deferred' is never reassigned. Use 'const' instead            prefer-const
  205:4   warning  'upload' is never reassigned. Use 'const' instead              prefer-const
  222:16  warning  'Uint8Array' is already defined as a built-in global variable  no-redeclare
  223:16  warning  ES2015 'Uint8Array' is forbidden                               es-x/no-typed-arrays
  314:4   warning  'upload' is never reassigned. Use 'const' instead              prefer-const
  382:3   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  382:3   warning  Prefer .then to .fail                                          no-jquery/no-done-fail
  396:7   warning  'requestedTitle' is never reassigned. Use 'const' instead      prefer-const
  430:3   warning  'params' is never reassigned. Use 'const' instead              prefer-const
  448:3   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  448:3   warning  Prefer .then to .fail                                          no-jquery/no-done-fail
  488:21  warning  'image' is never reassigned. Use 'const' instead               prefer-const
  585:5   warning  'constraint' is never reassigned. Use 'const' instead          prefer-const
  629:3   warning  'scaling' is never reassigned. Use 'const' instead             prefer-const
  631:3   warning  'width' is never reassigned. Use 'const' instead               prefer-const
  632:3   warning  'height' is never reassigned. Use 'const' instead              prefer-const
  640:3   warning  'dx' is never reassigned. Use 'const' instead                  prefer-const
  641:3   warning  'dy' is never reassigned. Use 'const' instead                  prefer-const
  666:3   warning  '$canvas' is never reassigned. Use 'const' instead             prefer-const
  667:3   warning  'ctx' is never reassigned. Use 'const' instead                 prefer-const
  715:7   warning  'constraints' is never reassigned. Use 'const' instead         prefer-const
  767:3   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  767:3   warning  Prefer .then to .fail                                          no-jquery/no-done-fail
  775:6   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  778:7   warning  Prefer .then to .done                                          no-jquery/no-done-fail
  802:4   warning  'deferred' is never reassigned. Use 'const' instead            prefer-const
  803:4   warning  'upload' is never reassigned. Use 'const' instead              prefer-const
  828:9   warning  'canvas' is never reassigned. Use 'const' instead              prefer-const
  831:8   warning  'context' is never reassigned. Use 'const' instead             prefer-const

/src/repo/resources/mw.UploadWizardUploadInterface.js
  206:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/transports/mw.FormDataTransport.js
   97:3  warning  ES2015 'Object.assign' method is forbidden                 es-x/no-object-assign
  156:4  warning  'deferred' is never reassigned. Use 'const' instead        prefer-const
  157:4  warning  'fileSize' is never reassigned. Use 'const' instead        prefer-const
  158:4  warning  'chunkSize' is never reassigned. Use 'const' instead       prefer-const
  159:4  warning  'transport' is never reassigned. Use 'const' instead       prefer-const
  169:5  warning  Prefer .then to .done                                      no-jquery/no-done-fail
  170:6  warning  Prefer .then to .done                                      no-jquery/no-done-fail
  170:6  warning  Prefer .then to .fail                                      no-jquery/no-done-fail
  194:7  warning  'params' is never reassigned. Use 'const' instead          prefer-const
  195:4  warning  'transport' is never reassigned. Use 'const' instead       prefer-const
  196:4  warning  'bytesAvailable' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/ui/steps/uw.ui.Deed.js
  55:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Details.js
  90:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Thanks.js
   30:4  warning  'thanks' is never reassigned. Use 'const' instead             prefer-const
   48:3  warning  '$header' is never reassigned. Use 'const' instead            prefer-const
   69:3  warning  'beginButtonTarget' is never reassigned. Use 'const' instead  prefer-const
   98:3  warning  'thumbWikiText' is never reassigned. Use 'const' instead      prefer-const
  104:3  warning  '$thanksDiv' is never reassigned. Use 'const' instead         prefer-const
  106:3  warning  '$thumbnailWrapDiv' is never reassigned. Use 'const' instead  prefer-const
  109:3  warning  '$thumbnailDiv' is never reassigned. Use 'const' instead      prefer-const
  112:3  warning  '$thumbnailCaption' is never reassigned. Use 'const' instead  prefer-const
  115:3  warning  '$thumbnailLink' is never reassigned. Use 'const' instead     prefer-const
  128:3  warning  Prefer .then to .done                                         no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Tutorial.js
  125:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/steps/uw.ui.Upload.js
  210:6  warning  Prefer .then to .done  no-jquery/no-done-fail
  222:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/uw.ui.DeedPreview.js
  30:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/ui/uw.ui.Step.js
  101:3  warning  Prefer .then to .done  no-jquery/no-done-fail
  119:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/uw.ConcurrentQueue.js
  117:3  warning  'index' is never reassigned. Use 'const' instead    prefer-const
  139:3  warning  'item' is never reassigned. Use 'const' instead     prefer-const
  145:3  warning  'promise' is never reassigned. Use 'const' instead  prefer-const

/src/repo/resources/uw.CopyMetadataWidget.js
   14:4  warning  'checkboxes' is never reassigned. Use 'const' instead               prefer-const
   15:4  warning  '$copyMetadataWrapperDiv' is never reassigned. Use 'const' instead  prefer-const
   16:4  warning  '$copyMetadataDiv' is never reassigned. Use 'const' instead         prefer-const
  157:4  warning  'uploads' is never reassigned. Use 'const' instead                  prefer-const
  158:4  warning  'sourceUpload' is never reassigned. Use 'const' instead             prefer-const
  159:4  warning  'serialized' is never reassigned. Use 'const' instead               prefer-const
  161:4  warning  'sourceValue' is never reassigned. Use 'const' instead              prefer-const
  214:4  warning  'uploads' is never reassigned. Use 'const' instead                  prefer-const

/src/repo/resources/uw.FieldLayout.js
  20:12  warning  ES2015 'Object.assign' method is forbidden  es-x/no-object-assign

/src/repo/resources/uw.LicenseGroup.js
   37:17  warning  ES2015 'Object.assign' method is forbidden               es-x/no-object-assign
  132:4   warning  'option' is never reassigned. Use 'const' instead        prefer-const
  167:4   warning  'option' is never reassigned. Use 'const' instead        prefer-const
  191:4   warning  'self' is never reassigned. Use 'const' instead          prefer-const
  192:4   warning  'values' is never reassigned. Use 'const' instead        prefer-const
  194:3   warning  'wikiTexts' is never reassigned. Use 'const' instead     prefer-const
  196:5   warning  'value' is never reassigned. Use 'const' instead         prefer-const
  222:7   warning  'self' is never reassigned. Use 'const' instead          prefer-const
  223:4   warning  'result' is never reassigned. Use 'const' instead        prefer-const
  248:7   warning  'self' is never reassigned. Use 'const' instead          prefer-const
  249:4   warning  'selectArray' is never reassigned. Use 'const' instead   prefer-const
  303:7   warning  'licenseInfo' is never reassigned. Use 'const' instead   prefer-const
  306:3   warning  'licenseText' is never reassigned. Use 'const' instead   prefer-const
  319:7   warning  'licenseInfo' is never reassigned. Use 'const' instead   prefer-const
  320:4   warning  'messageKey' is never reassigned. Use 'const' instead    prefer-const
  323:4   warning  'languageCode' is never reassigned. Use 'const' instead  prefer-const
  328:4   warning  '$icons' is never reassigned. Use 'const' instead        prefer-const
  334:3   warning  '$licenseLink' is never reassigned. Use 'const' instead  prefer-const
  343:3   warning  '$label' is never reassigned. Use 'const' instead        prefer-const
  361:7   warning  'self' is never reassigned. Use 'const' instead          prefer-const
  372:3   warning  'button' is never reassigned. Use 'const' instead        prefer-const
  397:3   warning  'input' is never reassigned. Use 'const' instead         prefer-const
  413:3   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  413:3   warning  Prefer .then to .fail                                    no-jquery/no-done-fail

/src/repo/resources/uw.ValidationMessageElement.js
  39:2  warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  91:3  warning  '$listItem' is never reassigned. Use 'const' instead                               prefer-const

/src/repo/tests/qunit/controller/uw.controller.Details.test.js
   57:7  warning  'step' is never reassigned. Use 'const' instead        prefer-const
   61:4  warning  'stepUiStub' is never reassigned. Use 'const' instead  prefer-const
  110:4  warning  'done' is never reassigned. Use 'const' instead        prefer-const
  111:4  warning  'donestub' is never reassigned. Use 'const' instead    prefer-const
  112:4  warning  'ds' is never reassigned. Use 'const' instead          prefer-const
  113:4  warning  'ps' is never reassigned. Use 'const' instead          prefer-const
  117:3  warning  'tostub' is never reassigned. Use 'const' instead      prefer-const
  124:3  warning  'step' is never reassigned. Use 'const' instead        prefer-const
  135:3  warning  Prefer .then to .done                                  no-jquery/no-done-fail

/src/repo/tests/qunit/controller/uw.controller.Tutorial.test.js
  33:4  warning  'acwStub' is never reassigned. Use 'const' instead  prefer-const
  54:3  warning  'mnStub' is never reassigned. Use 'const' instead   prefer-const

/src/repo/tests/qunit/mw.UploadWizardLicenseInput.test.js
  17:6  warning  'config' is never reassigned. Use 'const' instead          prefer-const
  18:3  warning  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  21:2  warning  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const
  27:6  warning  'config' is never reassigned. Use 'const' instead          prefer-const
  28:3  warning  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  33:2  warning  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const
  37:2  warning  '$input' is never reassigned. Use 'const' instead          prefer-const
  41:2  warning  '$label' is never reassigned. Use 'const' instead          prefer-const
  46:6  warning  'config' is never reassigned. Use 'const' instead          prefer-const
  56:3  warning  '$fixture' is never reassigned. Use 'const' instead        prefer-const
  59:2  warning  'uwLicenseInput' is never reassigned. Use 'const' instead  prefer-const

/src/repo/tests/qunit/mw.UploadWizardUpload.test.js
  23:4  warning  'oldconf' is never reassigned. Use 'const' instead  prefer-const
  27:3  warning  'upload' is never reassigned. Use 'const' instead   prefer-const

/src/repo/tests/qunit/mw.fileApi.test.js
  46:15  warning  'testFile' is never reassigned. Use 'const' instead   prefer-const
  47:4   warning  'fakeVideo' is never reassigned. Use 'const' instead  prefer-const

/src/repo/tests/qunit/transports/mw.FormDataTransport.test.js
   27:3   warning  'config' is never reassigned. Use 'const' instead     prefer-const
   86:4   warning  'transport' is never reassigned. Use 'const' instead  prefer-const
   87:4   warning  'fakeFile' is never reassigned. Use 'const' instead   prefer-const
   97:3   warning  'request' is never reassigned. Use 'const' instead    prefer-const
  107:4   warning  'transport' is never reassigned. Use 'const' instead  prefer-const
  108:4   warning  'fakeFile' is never reassigned. Use 'const' instead   prefer-const
  125:3   warning  'request' is never reassigned. Use 'const' instead    prefer-const
  146:3   warning  Prefer .then to .fail                                 no-jquery/no-done-fail
  179:10  warning  Prefer .then to .done                                 no-jquery/no-done-fail
  198:10  warning  Prefer .then to .done                                 no-jquery/no-done-fail
  218:3   warning  Prefer .then to .fail                                 no-jquery/no-done-fail

/src/repo/tests/qunit/uw.ConcurrentQueue.test.js
   38:3  warning  'calls' is never reassigned. Use 'const' instead            prefer-const
   65:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
   66:3  warning  'action' is never reassigned. Use 'const' instead           prefer-const
   67:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
   98:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
   99:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  100:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  101:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  102:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  139:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  140:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  167:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  168:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  184:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  185:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  186:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  187:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  188:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  240:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  241:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  242:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  243:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  244:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  297:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  298:3  warning  'action' is never reassigned. Use 'const' instead           prefer-const
  299:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  300:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  301:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  302:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  353:3  warning  'done' is never reassigned. Use 'const' instead             prefer-const
  355:3  warning  'action' is never reassigned. Use 'const' instead           prefer-const
  356:3  warning  'changeHandler' is never reassigned. Use 'const' instead    prefer-const
  357:3  warning  'progressHandler' is never reassigned. Use 'const' instead  prefer-const
  358:3  warning  'completeHandler' is never reassigned. Use 'const' instead  prefer-const
  359:3  warning  'queue' is never reassigned. Use 'const' instead            prefer-const
  402:3  warning  'onProgress' is never reassigned. Use 'const' instead       prefer-const

/src/repo/tests/qunit/uw.TitleDetailsWidget.test.js
  5:2  warning  'fileNs' is never reassigned. Use 'const' instead                  prefer-const
  6:2  warning  'makeTitleInFileNSCases' is never reassigned. Use 'const' instead  prefer-const

✖ 352 problems (0 errors, 352 warnings)


Running "stylelint:all" (stylelint) task
>> Linted 14 files without errors

Running "banana:MediaUploader" (banana) task
>> 3 message directories checked.

Done.

--- end ---
{"1104664": {"source": 1104664, "name": "cross-spawn", "dependency": "cross-spawn", "title": "Regular Expression Denial of Service (ReDoS) in cross-spawn", "url": "https://github.com/advisories/GHSA-3xgq-45jj-v275", "severity": "high", "cwe": ["CWE-1333"], "cvss": {"score": 7.5, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}, "range": ">=7.0.0 <7.0.5"}}
Upgrading n:cross-spawn from 7.0.3 -> 7.0.6
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json

--- end ---
build: Updating dependencies

composer:
* mediawiki/mediawiki-codesniffer: 45.0.0 → 47.0.0

npm:
* eslint-config-wikimedia: 0.28.2 → 0.30.0
  The following rules are failing and were disabled:
  * prefer-const
  * implicit-arrow-linebreak
  * no-redeclare
  * no-mixed-spaces-and-tabs
  * no-jquery/no-done-fail
  * tests/qunit:
    * prefer-const
    * no-jquery/no-done-fail
* stylelint-config-wikimedia: 0.17.2 → 0.18.0
* cross-spawn: 7.0.3 → 7.0.6
  * https://github.com/advisories/GHSA-3xgq-45jj-v275


Additional changes:
* eslint: Replaced `wikimedia/client-es5` with `wikimedia/client`.
* Enable stylelint caching.

$ git add .
--- stdout ---

--- end ---
$ git commit -F /tmp/tmpstg4lr5k
--- stdout ---
[master 1457af7] build: Updating dependencies
 71 files changed, 1164 insertions(+), 1454 deletions(-)

--- end ---
$ git format-patch HEAD~1 --stdout
--- stdout ---
From 1457af7bc5ac356a42dca4340daf6416b69533cd Mon Sep 17 00:00:00 2001
From: libraryupgrader <tools.libraryupgrader@tools.wmflabs.org>
Date: Mon, 9 Jun 2025 02:04:43 +0000
Subject: [PATCH] build: Updating dependencies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

composer:
* mediawiki/mediawiki-codesniffer: 45.0.0 → 47.0.0

npm:
* eslint-config-wikimedia: 0.28.2 → 0.30.0
  The following rules are failing and were disabled:
  * prefer-const
  * implicit-arrow-linebreak
  * no-redeclare
  * no-mixed-spaces-and-tabs
  * no-jquery/no-done-fail
  * tests/qunit:
    * prefer-const
    * no-jquery/no-done-fail
* stylelint-config-wikimedia: 0.17.2 → 0.18.0
* cross-spawn: 7.0.3 → 7.0.6
  * https://github.com/advisories/GHSA-3xgq-45jj-v275

Additional changes:
* eslint: Replaced `wikimedia/client-es5` with `wikimedia/client`.
* Enable stylelint caching.

Change-Id: I92b0c69af575439577c117a721c6cb226aa1967f
---
 .eslintrc.json                                |    9 +-
 .gitignore                                    |    1 +
 Gruntfile.js                                  |    5 +-
 composer.json                                 |    2 +-
 package-lock.json                             | 1283 +++++++----------
 package.json                                  |    4 +-
 resources/controller/uw.controller.Deed.js    |   18 +-
 resources/controller/uw.controller.Details.js |   54 +-
 resources/controller/uw.controller.Step.js    |   42 +-
 resources/controller/uw.controller.Thanks.js  |    4 +-
 .../controller/uw.controller.Tutorial.js      |   12 +-
 resources/controller/uw.controller.Upload.js  |   28 +-
 resources/deed/uw.deed.OwnWork.js             |   32 +-
 resources/deed/uw.deed.ThirdParty.js          |    8 +-
 .../details/uw.CategoriesDetailsWidget.js     |   40 +-
 resources/details/uw.DateDetailsWidget.js     |   14 +-
 .../details/uw.DeedChooserDetailsWidget.js    |    4 +-
 resources/details/uw.DropdownWidget.js        |    8 +-
 .../details/uw.LanguageDropdownWidget.js      |   16 +-
 resources/details/uw.LocationDetailsWidget.js |   26 +-
 .../details/uw.MultipleLanguageInputWidget.js |   42 +-
 .../details/uw.SingleLanguageInputWidget.js   |   10 +-
 resources/details/uw.TextWidget.js            |    4 +-
 resources/details/uw.TitleDetailsWidget.js    |   28 +-
 resources/details/uw.UlsWidget.js             |    8 +-
 resources/ext.mediaUploader.campaignEditor.js |    2 +-
 .../handlers/mw.ApiUploadFormDataHandler.js   |   12 +-
 resources/handlers/mw.ApiUploadHandler.js     |   56 +-
 .../jquery.arrowSteps/jquery.arrowSteps.js    |    6 +-
 resources/jquery/jquery.morphCrossfade.js     |   12 +-
 resources/mw.DestinationChecker.js            |   36 +-
 resources/mw.Escaper.js                       |   20 +-
 resources/mw.GroupProgressBar.js              |   24 +-
 resources/mw.QuickTitleChecker.js             |    8 +-
 resources/mw.UploadWizard.js                  |   22 +-
 resources/mw.UploadWizardDeedChooser.js       |   22 +-
 resources/mw.UploadWizardDetails.js           |   88 +-
 resources/mw.UploadWizardLicenseInput.js      |   56 +-
 resources/mw.UploadWizardPage.js              |    6 +-
 resources/mw.UploadWizardUpload.js            |   74 +-
 resources/mw.UploadWizardUploadInterface.js   |   16 +-
 resources/mw.fileApi.js                       |    6 +-
 resources/transports/mw.FormDataTransport.js  |   36 +-
 resources/ui/steps/uw.ui.Deed.js              |    4 +-
 resources/ui/steps/uw.ui.Details.js           |   16 +-
 resources/ui/steps/uw.ui.Thanks.js            |   12 +-
 resources/ui/steps/uw.ui.Tutorial.js          |   10 +-
 resources/ui/steps/uw.ui.Upload.js            |   36 +-
 resources/ui/uw.ui.DeedPreview.js             |    4 +-
 resources/ui/uw.ui.Step.js                    |   14 +-
 resources/ui/uw.ui.Wizard.js                  |   14 +-
 resources/uw.ConcurrentQueue.js               |    8 +-
 resources/uw.CopyMetadataWidget.js            |   14 +-
 resources/uw.FieldLayout.js                   |    2 +-
 resources/uw.LicenseGroup.js                  |   58 +-
 resources/uw.LicensePreviewDialog.js          |    8 +-
 resources/uw.ValidationMessageElement.js      |    8 +-
 resources/uw.units.js                         |    4 +-
 tests/qunit/.eslintrc.json                    |    4 +
 .../controller/uw.controller.Deed.test.js     |    6 +-
 .../controller/uw.controller.Details.test.js  |   20 +-
 .../controller/uw.controller.Step.test.js     |    4 +-
 .../controller/uw.controller.Thanks.test.js   |   10 +-
 .../controller/uw.controller.Tutorial.test.js |    6 +-
 .../controller/uw.controller.Upload.test.js   |   12 +-
 .../qunit/mw.UploadWizardLicenseInput.test.js |   12 +-
 tests/qunit/mw.UploadWizardUpload.test.js     |   10 +-
 tests/qunit/mw.fileApi.test.js                |    4 +-
 .../transports/mw.FormDataTransport.test.js   |   34 +-
 tests/qunit/uw.ConcurrentQueue.test.js        |   70 +-
 tests/qunit/uw.TitleDetailsWidget.test.js     |   10 +-
 71 files changed, 1164 insertions(+), 1454 deletions(-)

diff --git a/.eslintrc.json b/.eslintrc.json
index feb9364..66461eb 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,7 +1,7 @@
 {
 	"root": true,
 	"extends": [
-		"wikimedia/client-es5",
+		"wikimedia/client",
 		"wikimedia/jquery",
 		"wikimedia/mediawiki"
 	],
@@ -23,6 +23,11 @@
 		"es-x/no-regexp-u-flag": "warn",
 		"es-x/no-typed-arrays": "warn",
 		"no-unused-vars": "warn",
-		"es-x/no-object-assign": "warn"
+		"es-x/no-object-assign": "warn",
+		"no-mixed-spaces-and-tabs": "warn",
+		"prefer-const": "warn",
+		"implicit-arrow-linebreak": "warn",
+		"no-jquery/no-done-fail": "warn",
+		"no-redeclare": "warn"
 	}
 }
diff --git a/.gitignore b/.gitignore
index de0ffeb..39e6140 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ vendor
 composer.lock
 .DS_Store
 .eslintcache
+/.stylelintcache
diff --git a/Gruntfile.js b/Gruntfile.js
index d870d7c..3b065aa 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -5,7 +5,7 @@
 /* eslint-env node */
 
 module.exports = function ( grunt ) {
-	var conf = grunt.file.readJSON( 'extension.json' );
+	const conf = grunt.file.readJSON( 'extension.json' );
 
 	grunt.loadNpmTasks( 'grunt-banana-checker' );
 	grunt.loadNpmTasks( 'grunt-contrib-watch' );
@@ -21,6 +21,9 @@ module.exports = function ( grunt ) {
 			all: '.'
 		},
 		stylelint: {
+			options: {
+				cache: true
+			},
 			all: 'resources/{**/,}*.{css,less}'
 		},
 		banana: conf.MessagesDirs,
diff --git a/composer.json b/composer.json
index ca9ae93..3e0546b 100644
--- a/composer.json
+++ b/composer.json
@@ -5,7 +5,7 @@
 		"ext-json": "*"
 	},
 	"require-dev": {
-		"mediawiki/mediawiki-codesniffer": "45.0.0",
+		"mediawiki/mediawiki-codesniffer": "47.0.0",
 		"mediawiki/mediawiki-phan-config": "0.15.1",
 		"mediawiki/minus-x": "1.1.3",
 		"php-parallel-lint/php-console-highlighter": "1.0.0",
diff --git a/package-lock.json b/package-lock.json
index 89c6fb1..3b9381f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,13 +6,13 @@
 		"": {
 			"name": "MediaUploader",
 			"devDependencies": {
-				"eslint-config-wikimedia": "0.28.2",
+				"eslint-config-wikimedia": "0.30.0",
 				"grunt": "1.6.1",
 				"grunt-banana-checker": "0.13.0",
 				"grunt-contrib-watch": "1.1.0",
 				"grunt-eslint": "24.3.0",
 				"grunt-stylelint": "0.20.1",
-				"stylelint-config-wikimedia": "0.17.2"
+				"stylelint-config-wikimedia": "0.18.0"
 			}
 		},
 		"node_modules/@babel/code-frame": {
@@ -124,9 +124,9 @@
 			}
 		},
 		"node_modules/@csstools/css-parser-algorithms": {
-			"version": "2.7.1",
-			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz",
-			"integrity": "sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==",
+			"version": "3.0.5",
+			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
+			"integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
 			"dev": true,
 			"funding": [
 				{
@@ -139,16 +139,16 @@
 				}
 			],
 			"engines": {
-				"node": "^14 || ^16 || >=18"
+				"node": ">=18"
 			},
 			"peerDependencies": {
-				"@csstools/css-tokenizer": "^2.4.1"
+				"@csstools/css-tokenizer": "^3.0.4"
 			}
 		},
 		"node_modules/@csstools/css-tokenizer": {
-			"version": "2.4.1",
-			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.4.1.tgz",
-			"integrity": "sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==",
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
+			"integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
 			"dev": true,
 			"funding": [
 				{
@@ -161,36 +161,13 @@
 				}
 			],
 			"engines": {
-				"node": "^14 || ^16 || >=18"
+				"node": ">=18"
 			}
 		},
 		"node_modules/@csstools/media-query-list-parser": {
-			"version": "2.1.13",
-			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.13.tgz",
-			"integrity": "sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==",
-			"dev": true,
-			"funding": [
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/csstools"
-				},
-				{
-					"type": "opencollective",
-					"url": "https://opencollective.com/csstools"
-				}
-			],
-			"engines": {
-				"node": "^14 || ^16 || >=18"
-			},
-			"peerDependencies": {
-				"@csstools/css-parser-algorithms": "^2.7.1",
-				"@csstools/css-tokenizer": "^2.4.1"
-			}
-		},
-		"node_modules/@csstools/selector-specificity": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz",
-			"integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==",
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz",
+			"integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==",
 			"dev": true,
 			"funding": [
 				{
@@ -203,10 +180,11 @@
 				}
 			],
 			"engines": {
-				"node": "^14 || ^16 || >=18"
+				"node": ">=18"
 			},
 			"peerDependencies": {
-				"postcss-selector-parser": "^6.0.13"
+				"@csstools/css-parser-algorithms": "^3.0.1",
+				"@csstools/css-tokenizer": "^3.0.1"
 			}
 		},
 		"node_modules/@dual-bundle/import-meta-resolve": {
@@ -397,40 +375,40 @@
 			}
 		},
 		"node_modules/@stylistic/stylelint-config": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-config/-/stylelint-config-1.0.1.tgz",
-			"integrity": "sha512-JgFP88HZEyo34k9RpWVdcQJtLPrMxYE58IO3qypXhmvE/NmZohj+xjDtQ8UfaarnYsLecnldw57/GHum07Ctdw==",
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-config/-/stylelint-config-2.0.0.tgz",
+			"integrity": "sha512-8J4YAxggy2Nzkb8KJIOLbtMXTPZ5gpKVmyhiiuKEUgCl9XFND5lM0e/ZZBMGEYZ68h5qcsS/jgg1wh235erRAw==",
 			"dev": true,
 			"dependencies": {
-				"@stylistic/stylelint-plugin": "^2.0.0"
+				"@stylistic/stylelint-plugin": "^3.0.0"
 			},
 			"engines": {
 				"node": "^18.12 || >=20.9"
 			},
 			"peerDependencies": {
-				"stylelint": "^16.0.2"
+				"stylelint": "^16.8.0"
 			}
 		},
 		"node_modules/@stylistic/stylelint-plugin": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.0.0.tgz",
-			"integrity": "sha512-dHKuT6PGd1WGZLOTuozAM7GdQzdmlmnFXYzvV1jYJXXpcCpV/OJ3+n8TXpMkoOeKHpJydY43EOoZTO1W/FOA4Q==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.1.tgz",
+			"integrity": "sha512-XagAHHIa528EvyGybv8EEYGK5zrVW74cHpsjhtovVATbhDRuJYfE+X4HCaAieW9lCkwbX6L+X0I4CiUG3w/hFw==",
 			"dev": true,
 			"dependencies": {
-				"@csstools/css-parser-algorithms": "^2.3.2",
-				"@csstools/css-tokenizer": "^2.2.1",
-				"@csstools/media-query-list-parser": "^2.1.5",
+				"@csstools/css-parser-algorithms": "^3.0.1",
+				"@csstools/css-tokenizer": "^3.0.1",
+				"@csstools/media-query-list-parser": "^3.0.1",
 				"is-plain-object": "^5.0.0",
-				"postcss-selector-parser": "^6.0.13",
+				"postcss-selector-parser": "^6.1.2",
 				"postcss-value-parser": "^4.2.0",
 				"style-search": "^0.1.0",
-				"stylelint": "^16.0.2"
+				"stylelint": "^16.8.2"
 			},
 			"engines": {
 				"node": "^18.12 || >=20.9"
 			},
 			"peerDependencies": {
-				"stylelint": "^16.0.2"
+				"stylelint": "^16.8.0"
 			}
 		},
 		"node_modules/@stylistic/stylelint-plugin/node_modules/is-plain-object": {
@@ -442,6 +420,19 @@
 				"node": ">=0.10.0"
 			}
 		},
+		"node_modules/@stylistic/stylelint-plugin/node_modules/postcss-selector-parser": {
+			"version": "6.1.2",
+			"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+			"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+			"dev": true,
+			"dependencies": {
+				"cssesc": "^3.0.0",
+				"util-deprecate": "^1.0.2"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
 		"node_modules/@types/eslint": {
 			"version": "8.56.10",
 			"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
@@ -804,9 +795,9 @@
 			}
 		},
 		"node_modules/browserslist": {
-			"version": "4.23.0",
-			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
-			"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
+			"version": "4.25.0",
+			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz",
+			"integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==",
 			"dev": true,
 			"funding": [
 				{
@@ -823,10 +814,10 @@
 				}
 			],
 			"dependencies": {
-				"caniuse-lite": "^1.0.30001587",
-				"electron-to-chromium": "^1.4.668",
-				"node-releases": "^2.0.14",
-				"update-browserslist-db": "^1.0.13"
+				"caniuse-lite": "^1.0.30001718",
+				"electron-to-chromium": "^1.5.160",
+				"node-releases": "^2.0.19",
+				"update-browserslist-db": "^1.1.3"
 			},
 			"bin": {
 				"browserslist": "cli.js"
@@ -882,9 +873,9 @@
 			}
 		},
 		"node_modules/caniuse-lite": {
-			"version": "1.0.30001612",
-			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
-			"integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
+			"version": "1.0.30001721",
+			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz",
+			"integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==",
 			"dev": true,
 			"funding": [
 				{
@@ -1085,9 +1076,9 @@
 			}
 		},
 		"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==",
+			"version": "7.0.6",
+			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+			"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
 			"dev": true,
 			"dependencies": {
 				"path-key": "^3.1.0",
@@ -1114,9 +1105,9 @@
 			}
 		},
 		"node_modules/css-functions-list": {
-			"version": "3.2.2",
-			"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz",
-			"integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==",
+			"version": "3.2.3",
+			"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz",
+			"integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==",
 			"dev": true,
 			"engines": {
 				"node": ">=12 || >=16"
@@ -1133,12 +1124,12 @@
 			}
 		},
 		"node_modules/css-tree": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
-			"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
+			"integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==",
 			"dev": true,
 			"dependencies": {
-				"mdn-data": "2.0.30",
+				"mdn-data": "2.12.2",
 				"source-map-js": "^1.0.1"
 			},
 			"engines": {
@@ -1167,12 +1158,12 @@
 			}
 		},
 		"node_modules/debug": {
-			"version": "4.3.5",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
-			"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+			"version": "4.4.1",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+			"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
 			"dev": true,
 			"dependencies": {
-				"ms": "2.1.2"
+				"ms": "^2.1.3"
 			},
 			"engines": {
 				"node": ">=6.0"
@@ -1223,20 +1214,19 @@
 			}
 		},
 		"node_modules/doiuse": {
-			"version": "6.0.2",
-			"resolved": "https://registry.npmjs.org/doiuse/-/doiuse-6.0.2.tgz",
-			"integrity": "sha512-eBTs23NOX+EAYPr4RbCR6J4DRW/TML3uMo37y0X1whlkersDYFCk9HmCl09KX98cis22VKsV1QaxfVNauJ3NBw==",
+			"version": "6.0.5",
+			"resolved": "https://registry.npmjs.org/doiuse/-/doiuse-6.0.5.tgz",
+			"integrity": "sha512-ljuf9ndGqKST0GlPAYyCg04hbQAeR1xIIWVDjQaDDkoTY/Y1Vb+8FNoy6NuVuJIEEKe/nKUH8NRWjG7JJxZ9Eg==",
 			"dev": true,
 			"dependencies": {
-				"browserslist": "^4.21.5",
-				"caniuse-lite": "^1.0.30001487",
+				"browserslist": "^4.24.0",
+				"caniuse-lite": "^1.0.30001669",
 				"css-tokenize": "^1.0.1",
-				"duplexify": "^4.1.2",
-				"ldjson-stream": "^1.2.1",
+				"duplexify": "^4.1.3",
 				"multimatch": "^5.0.0",
-				"postcss": "^8.4.21",
+				"postcss": "^8.4.47",
 				"source-map": "^0.7.4",
-				"yargs": "^17.7.1"
+				"yargs": "^17.7.2"
 			},
 			"bin": {
 				"doiuse": "bin/cli.js"
@@ -1287,9 +1277,9 @@
 			}
 		},
 		"node_modules/domutils": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
-			"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+			"version": "3.2.2",
+			"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+			"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
 			"dev": true,
 			"dependencies": {
 				"dom-serializer": "^2.0.0",
@@ -1336,9 +1326,9 @@
 			}
 		},
 		"node_modules/electron-to-chromium": {
-			"version": "1.4.750",
-			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.750.tgz",
-			"integrity": "sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==",
+			"version": "1.5.165",
+			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.165.tgz",
+			"integrity": "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==",
 			"dev": true
 		},
 		"node_modules/emoji-regex": {
@@ -1410,9 +1400,9 @@
 			}
 		},
 		"node_modules/escalade": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-			"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+			"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
 			"dev": true,
 			"engines": {
 				"node": ">=6"
@@ -1501,9 +1491,9 @@
 			}
 		},
 		"node_modules/eslint-config-wikimedia": {
-			"version": "0.28.2",
-			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.28.2.tgz",
-			"integrity": "sha512-5+rdnT7wH1gpKAO6tHYThg78eMhZMruJzvqku3Y5iaEY/A7kSKLFpA/vOj/snys9fKjDHC9BXmArQh+agkOoJQ==",
+			"version": "0.30.0",
+			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.30.0.tgz",
+			"integrity": "sha512-i8ESzSoo0x3Jur/0JhAgCVPxbV51zfdI3MN3MVQPnjiFdmo21CNKmiBBmw8JnJ3fx/d5zHDrBa+yDjxSLpnDlA==",
 			"dev": true,
 			"dependencies": {
 				"browserslist-config-wikimedia": "^0.7.0",
@@ -1516,13 +1506,16 @@
 				"eslint-plugin-mediawiki": "^0.7.0",
 				"eslint-plugin-mocha": "^10.4.3",
 				"eslint-plugin-n": "^17.7.0",
-				"eslint-plugin-no-jquery": "^3.0.1",
+				"eslint-plugin-no-jquery": "^3.1.1",
 				"eslint-plugin-qunit": "^8.1.1",
 				"eslint-plugin-security": "^1.7.1",
 				"eslint-plugin-unicorn": "^53.0.0",
 				"eslint-plugin-vue": "^9.26.0",
 				"eslint-plugin-wdio": "^8.24.12",
 				"eslint-plugin-yml": "^1.14.0"
+			},
+			"engines": {
+				"node": ">=18 <23"
 			}
 		},
 		"node_modules/eslint-plugin-compat": {
@@ -1720,9 +1713,9 @@
 			}
 		},
 		"node_modules/eslint-plugin-no-jquery": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.0.2.tgz",
-			"integrity": "sha512-n/+6p6PFhWDNPVLJj1463hw4OTIRBbROGcbhmtOHTgw7yihSKzkwZiQ00EJTneyeR3jRiw5lpWSMCCBhtb8t2g==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
+			"integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
 			"dev": true,
 			"peerDependencies": {
 				"eslint": ">=8.0.0"
@@ -2167,10 +2160,20 @@
 			"dev": true
 		},
 		"node_modules/fast-uri": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
-			"integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==",
-			"dev": true
+			"version": "3.0.6",
+			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
+			"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/fastify"
+				},
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/fastify"
+				}
+			]
 		},
 		"node_modules/fastest-levenshtein": {
 			"version": "1.0.16",
@@ -3156,21 +3159,11 @@
 			}
 		},
 		"node_modules/known-css-properties": {
-			"version": "0.34.0",
-			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz",
-			"integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
+			"version": "0.35.0",
+			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz",
+			"integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==",
 			"dev": true
 		},
-		"node_modules/ldjson-stream": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz",
-			"integrity": "sha512-xw/nNEXafuPSLu8NjjG3+atVVw+8U1APZAQylmwQn19Hgw6rC7QjHvP6MupnHWCrzSm9m0xs5QWkCLuRvBPjgQ==",
-			"dev": true,
-			"dependencies": {
-				"split2": "^0.2.1",
-				"through2": "^0.6.1"
-			}
-		},
 		"node_modules/levn": {
 			"version": "0.4.1",
 			"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -3301,9 +3294,9 @@
 			}
 		},
 		"node_modules/mdn-data": {
-			"version": "2.0.30",
-			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
-			"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+			"version": "2.12.2",
+			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
+			"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
 			"dev": true
 		},
 		"node_modules/meow": {
@@ -3362,9 +3355,9 @@
 			}
 		},
 		"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==",
+			"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/multimatch": {
@@ -3387,9 +3380,9 @@
 			}
 		},
 		"node_modules/nanoid": {
-			"version": "3.3.7",
-			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
-			"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+			"version": "3.3.11",
+			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+			"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
 			"dev": true,
 			"funding": [
 				{
@@ -3411,9 +3404,9 @@
 			"dev": true
 		},
 		"node_modules/node-releases": {
-			"version": "2.0.14",
-			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
-			"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
+			"version": "2.0.19",
+			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+			"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
 			"dev": true
 		},
 		"node_modules/nopt": {
@@ -3738,9 +3731,9 @@
 			}
 		},
 		"node_modules/picocolors": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
-			"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+			"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
 			"dev": true
 		},
 		"node_modules/picomatch": {
@@ -3765,9 +3758,9 @@
 			}
 		},
 		"node_modules/postcss": {
-			"version": "8.4.39",
-			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz",
-			"integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==",
+			"version": "8.5.4",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
+			"integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
 			"dev": true,
 			"funding": [
 				{
@@ -3784,22 +3777,22 @@
 				}
 			],
 			"dependencies": {
-				"nanoid": "^3.3.7",
-				"picocolors": "^1.0.1",
-				"source-map-js": "^1.2.0"
+				"nanoid": "^3.3.11",
+				"picocolors": "^1.1.1",
+				"source-map-js": "^1.2.1"
 			},
 			"engines": {
 				"node": "^10 || ^12 || >=14"
 			}
 		},
 		"node_modules/postcss-html": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.6.0.tgz",
-			"integrity": "sha512-OWgQ9/Pe23MnNJC0PL4uZp8k0EDaUvqpJFSiwFxOLClAhmD7UEisyhO3x5hVsD4xFrjReVTXydlrMes45dJ71w==",
+			"version": "1.7.0",
+			"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.7.0.tgz",
+			"integrity": "sha512-MfcMpSUIaR/nNgeVS8AyvyDugXlADjN9AcV7e5rDfrF1wduIAGSkL4q2+wgrZgA3sHVAHLDO9FuauHhZYW2nBw==",
 			"dev": true,
 			"dependencies": {
 				"htmlparser2": "^8.0.0",
-				"js-tokens": "^8.0.0",
+				"js-tokens": "^9.0.0",
 				"postcss": "^8.4.0",
 				"postcss-safe-parser": "^6.0.0"
 			},
@@ -3808,27 +3801,11 @@
 			}
 		},
 		"node_modules/postcss-html/node_modules/js-tokens": {
-			"version": "8.0.3",
-			"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz",
-			"integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==",
+			"version": "9.0.1",
+			"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+			"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
 			"dev": true
 		},
-		"node_modules/postcss-html/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-less": {
 			"version": "6.0.0",
 			"resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-6.0.0.tgz",
@@ -3842,35 +3819,25 @@
 			}
 		},
 		"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=",
+			"version": "0.1.6",
+			"resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz",
+			"integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==",
 			"dev": true
 		},
 		"node_modules/postcss-safe-parser": {
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz",
-			"integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==",
+			"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,
-			"funding": [
-				{
-					"type": "opencollective",
-					"url": "https://opencollective.com/postcss/"
-				},
-				{
-					"type": "tidelift",
-					"url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
-				},
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/ai"
-				}
-			],
 			"engines": {
-				"node": ">=18.0"
+				"node": ">=12.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/postcss/"
 			},
 			"peerDependencies": {
-				"postcss": "^8.4.31"
+				"postcss": "^8.3.3"
 			}
 		},
 		"node_modules/postcss-selector-parser": {
@@ -4409,9 +4376,9 @@
 			}
 		},
 		"node_modules/source-map-js": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
-			"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+			"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
 			"dev": true,
 			"engines": {
 				"node": ">=0.10.0"
@@ -4459,15 +4426,6 @@
 			"integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==",
 			"dev": true
 		},
-		"node_modules/split2": {
-			"version": "0.2.1",
-			"resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz",
-			"integrity": "sha512-D/oTExYAkC9nWleOCTOyNmAuzfAT/6rHGBA9LIK7FVnGo13CSvrKCUzKenwH6U1s2znY9MqH6v0UQTEDa3vJmg==",
-			"dev": true,
-			"dependencies": {
-				"through2": "~0.6.1"
-			}
-		},
 		"node_modules/sprintf-js": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -4549,9 +4507,9 @@
 			"dev": true
 		},
 		"node_modules/stylelint": {
-			"version": "16.7.0",
-			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.7.0.tgz",
-			"integrity": "sha512-Q1ATiXlz+wYr37a7TGsfvqYn2nSR3T/isw3IWlZQzFzCNoACHuGBb6xBplZXz56/uDRJHIygxjh7jbV/8isewA==",
+			"version": "16.12.0",
+			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.12.0.tgz",
+			"integrity": "sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg==",
 			"dev": true,
 			"funding": [
 				{
@@ -4564,44 +4522,43 @@
 				}
 			],
 			"dependencies": {
-				"@csstools/css-parser-algorithms": "^2.7.1",
-				"@csstools/css-tokenizer": "^2.4.1",
-				"@csstools/media-query-list-parser": "^2.1.13",
-				"@csstools/selector-specificity": "^3.1.1",
+				"@csstools/css-parser-algorithms": "^3.0.4",
+				"@csstools/css-tokenizer": "^3.0.3",
+				"@csstools/media-query-list-parser": "^4.0.2",
+				"@csstools/selector-specificity": "^5.0.0",
 				"@dual-bundle/import-meta-resolve": "^4.1.0",
 				"balanced-match": "^2.0.0",
 				"colord": "^2.9.3",
 				"cosmiconfig": "^9.0.0",
-				"css-functions-list": "^3.2.2",
-				"css-tree": "^2.3.1",
-				"debug": "^4.3.5",
+				"css-functions-list": "^3.2.3",
+				"css-tree": "^3.0.1",
+				"debug": "^4.3.7",
 				"fast-glob": "^3.3.2",
 				"fastest-levenshtein": "^1.0.16",
-				"file-entry-cache": "^9.0.0",
+				"file-entry-cache": "^9.1.0",
 				"global-modules": "^2.0.0",
 				"globby": "^11.1.0",
 				"globjoin": "^0.1.4",
 				"html-tags": "^3.3.1",
-				"ignore": "^5.3.1",
+				"ignore": "^6.0.2",
 				"imurmurhash": "^0.1.4",
 				"is-plain-object": "^5.0.0",
-				"known-css-properties": "^0.34.0",
+				"known-css-properties": "^0.35.0",
 				"mathml-tag-names": "^2.1.3",
 				"meow": "^13.2.0",
-				"micromatch": "^4.0.7",
+				"micromatch": "^4.0.8",
 				"normalize-path": "^3.0.0",
-				"picocolors": "^1.0.1",
-				"postcss": "^8.4.39",
-				"postcss-resolve-nested-selector": "^0.1.1",
-				"postcss-safe-parser": "^7.0.0",
-				"postcss-selector-parser": "^6.1.0",
+				"picocolors": "^1.1.1",
+				"postcss": "^8.4.49",
+				"postcss-resolve-nested-selector": "^0.1.6",
+				"postcss-safe-parser": "^7.0.1",
+				"postcss-selector-parser": "^7.0.0",
 				"postcss-value-parser": "^4.2.0",
 				"resolve-from": "^5.0.0",
 				"string-width": "^4.2.3",
-				"strip-ansi": "^7.1.0",
-				"supports-hyperlinks": "^3.0.0",
+				"supports-hyperlinks": "^3.1.0",
 				"svg-tags": "^1.0.0",
-				"table": "^6.8.2",
+				"table": "^6.9.0",
 				"write-file-atomic": "^5.0.1"
 			},
 			"bin": {
@@ -4612,200 +4569,105 @@
 			}
 		},
 		"node_modules/stylelint-config-recommended": {
-			"version": "14.0.0",
-			"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.0.tgz",
-			"integrity": "sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==",
+			"version": "14.0.1",
+			"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz",
+			"integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==",
 			"dev": true,
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/stylelint"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/stylelint"
+				}
+			],
 			"engines": {
 				"node": ">=18.12.0"
 			},
 			"peerDependencies": {
-				"stylelint": "^16.0.0"
+				"stylelint": "^16.1.0"
 			}
 		},
 		"node_modules/stylelint-config-wikimedia": {
-			"version": "0.17.2",
-			"resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.17.2.tgz",
-			"integrity": "sha512-cc3PYhe1O/GTgsMOp+Ri3ru579YBbZ3Me0oU7xNb06n4iwyXYPz8qO5G4iQ13UH19UW2NIS8Tk0goPRrJ1RAfw==",
+			"version": "0.18.0",
+			"resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.18.0.tgz",
+			"integrity": "sha512-Lr45NIe7pG8i7BPcMc6EddO1pRK8/KNG8gp4o/oOG1Ez10hglJuJb/QT17BlzX8NPkhtP2KdY63NS2f/Wcj6Ww==",
 			"dev": true,
 			"dependencies": {
-				"@stylistic/stylelint-config": "1.0.1",
-				"@stylistic/stylelint-plugin": "2.0.0",
+				"@stylistic/stylelint-config": "2.0.0",
+				"@stylistic/stylelint-plugin": "3.1.1",
 				"browserslist-config-wikimedia": "0.7.0",
-				"postcss-html": "1.6.0",
+				"postcss-html": "1.7.0",
 				"postcss-less": "6.0.0",
-				"stylelint": "16.2.0",
-				"stylelint-config-recommended": "14.0.0",
-				"stylelint-no-unsupported-browser-features": "8.0.1"
+				"stylelint": "16.12.0",
+				"stylelint-config-recommended": "14.0.1",
+				"stylelint-no-unsupported-browser-features": "8.0.2"
 			},
 			"peerDependencies": {
 				"postcss-less": "^6.0.0"
 			}
 		},
-		"node_modules/stylelint-config-wikimedia/node_modules/ansi-regex": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-			"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-			"dev": true,
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/ansi-regex?sponsor=1"
-			}
-		},
-		"node_modules/stylelint-config-wikimedia/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-config-wikimedia/node_modules/file-entry-cache": {
-			"version": "8.0.0",
-			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
-			"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
-			"dev": true,
-			"dependencies": {
-				"flat-cache": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=16.0.0"
-			}
-		},
-		"node_modules/stylelint-config-wikimedia/node_modules/flat-cache": {
-			"version": "4.0.1",
-			"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
-			"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
-			"dev": true,
-			"dependencies": {
-				"flatted": "^3.2.9",
-				"keyv": "^4.5.4"
-			},
-			"engines": {
-				"node": ">=16"
-			}
-		},
-		"node_modules/stylelint-config-wikimedia/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-config-wikimedia/node_modules/known-css-properties": {
-			"version": "0.29.0",
-			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz",
-			"integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==",
-			"dev": true
-		},
-		"node_modules/stylelint-config-wikimedia/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/stylelint-config-wikimedia/node_modules/strip-ansi": {
-			"version": "7.1.0",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-			"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
-			"dev": true,
-			"dependencies": {
-				"ansi-regex": "^6.0.1"
-			},
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/strip-ansi?sponsor=1"
-			}
-		},
-		"node_modules/stylelint-config-wikimedia/node_modules/stylelint": {
-			"version": "16.2.0",
-			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.2.0.tgz",
-			"integrity": "sha512-gwqU5AkIb52wrAzzn+359S3NIJDMl02TXLUaV2tzA/L6jUdpTwNt+MCxHlc8+Hb2bUHlYVo92YeSIryF2gJthA==",
+		"node_modules/stylelint-no-unsupported-browser-features": {
+			"version": "8.0.2",
+			"resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-8.0.2.tgz",
+			"integrity": "sha512-4PY2qJ3ZTEje9RgGfaQ82eJoPioXxs6hazeKpji/wzLNVzTX2wd4b0Ds3ewdLkH3ID+o63IInuTquU2MNJO3YQ==",
 			"dev": true,
 			"dependencies": {
-				"@csstools/css-parser-algorithms": "^2.5.0",
-				"@csstools/css-tokenizer": "^2.2.3",
-				"@csstools/media-query-list-parser": "^2.1.7",
-				"@csstools/selector-specificity": "^3.0.1",
-				"balanced-match": "^2.0.0",
-				"colord": "^2.9.3",
-				"cosmiconfig": "^9.0.0",
-				"css-functions-list": "^3.2.1",
-				"css-tree": "^2.3.1",
-				"debug": "^4.3.4",
-				"fast-glob": "^3.3.2",
-				"fastest-levenshtein": "^1.0.16",
-				"file-entry-cache": "^8.0.0",
-				"global-modules": "^2.0.0",
-				"globby": "^11.1.0",
-				"globjoin": "^0.1.4",
-				"html-tags": "^3.3.1",
-				"ignore": "^5.3.0",
-				"imurmurhash": "^0.1.4",
-				"is-plain-object": "^5.0.0",
-				"known-css-properties": "^0.29.0",
-				"mathml-tag-names": "^2.1.3",
-				"meow": "^13.1.0",
-				"micromatch": "^4.0.5",
-				"normalize-path": "^3.0.0",
-				"picocolors": "^1.0.0",
-				"postcss": "^8.4.33",
-				"postcss-resolve-nested-selector": "^0.1.1",
-				"postcss-safe-parser": "^7.0.0",
-				"postcss-selector-parser": "^6.0.15",
-				"postcss-value-parser": "^4.2.0",
-				"resolve-from": "^5.0.0",
-				"string-width": "^4.2.3",
-				"strip-ansi": "^7.1.0",
-				"supports-hyperlinks": "^3.0.0",
-				"svg-tags": "^1.0.0",
-				"table": "^6.8.1",
-				"write-file-atomic": "^5.0.1"
-			},
-			"bin": {
-				"stylelint": "bin/stylelint.mjs"
+				"doiuse": "^6.0.5",
+				"postcss": "^8.4.32"
 			},
 			"engines": {
 				"node": ">=18.12.0"
 			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/stylelint"
+			"peerDependencies": {
+				"stylelint": "^16.0.2"
 			}
 		},
-		"node_modules/stylelint-no-unsupported-browser-features": {
-			"version": "8.0.1",
-			"resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-8.0.1.tgz",
-			"integrity": "sha512-tc8Xn5DaqJhxTmbA4H8gZbYdAz027NfuSZv5+cVieQb7BtBrF/1/iKYdpcGwXPl3GtqkQrisiXuGqKkKnzWcLw==",
+		"node_modules/stylelint/node_modules/@csstools/media-query-list-parser": {
+			"version": "4.0.3",
+			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz",
+			"integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==",
 			"dev": true,
-			"dependencies": {
-				"doiuse": "^6.0.2",
-				"postcss": "^8.4.32"
-			},
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/csstools"
+				},
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/csstools"
+				}
+			],
 			"engines": {
-				"node": ">=18.12.0"
+				"node": ">=18"
 			},
 			"peerDependencies": {
-				"stylelint": "^16.0.2"
+				"@csstools/css-parser-algorithms": "^3.0.5",
+				"@csstools/css-tokenizer": "^3.0.4"
 			}
 		},
-		"node_modules/stylelint/node_modules/ansi-regex": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-			"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+		"node_modules/stylelint/node_modules/@csstools/selector-specificity": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz",
+			"integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==",
 			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/csstools"
+				},
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/csstools"
+				}
+			],
 			"engines": {
-				"node": ">=12"
+				"node": ">=18"
 			},
-			"funding": {
-				"url": "https://github.com/chalk/ansi-regex?sponsor=1"
+			"peerDependencies": {
+				"postcss-selector-parser": "^7.0.0"
 			}
 		},
 		"node_modules/stylelint/node_modules/balanced-match": {
@@ -4815,9 +4677,9 @@
 			"dev": true
 		},
 		"node_modules/stylelint/node_modules/file-entry-cache": {
-			"version": "9.0.0",
-			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz",
-			"integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==",
+			"version": "9.1.0",
+			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz",
+			"integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==",
 			"dev": true,
 			"dependencies": {
 				"flat-cache": "^5.0.0"
@@ -4839,6 +4701,15 @@
 				"node": ">=18"
 			}
 		},
+		"node_modules/stylelint/node_modules/ignore": {
+			"version": "6.0.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz",
+			"integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==",
+			"dev": true,
+			"engines": {
+				"node": ">= 4"
+			}
+		},
 		"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",
@@ -4848,28 +4719,52 @@
 				"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==",
+		"node_modules/stylelint/node_modules/postcss-safe-parser": {
+			"version": "7.0.1",
+			"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
+			"integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
 			"dev": true,
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/postcss/"
+				},
+				{
+					"type": "tidelift",
+					"url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
 			"engines": {
-				"node": ">=8"
+				"node": ">=18.0"
+			},
+			"peerDependencies": {
+				"postcss": "^8.4.31"
 			}
 		},
-		"node_modules/stylelint/node_modules/strip-ansi": {
+		"node_modules/stylelint/node_modules/postcss-selector-parser": {
 			"version": "7.1.0",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-			"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+			"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+			"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
 			"dev": true,
 			"dependencies": {
-				"ansi-regex": "^6.0.1"
+				"cssesc": "^3.0.0",
+				"util-deprecate": "^1.0.2"
 			},
 			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/strip-ansi?sponsor=1"
+				"node": ">=4"
+			}
+		},
+		"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/supports-color": {
@@ -4885,9 +4780,9 @@
 			}
 		},
 		"node_modules/supports-hyperlinks": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz",
-			"integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==",
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz",
+			"integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==",
 			"dev": true,
 			"dependencies": {
 				"has-flag": "^4.0.0",
@@ -4895,6 +4790,9 @@
 			},
 			"engines": {
 				"node": ">=14.18"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/supports-hyperlinks?sponsor=1"
 			}
 		},
 		"node_modules/supports-preserve-symlinks-flag": {
@@ -4916,9 +4814,9 @@
 			"dev": true
 		},
 		"node_modules/table": {
-			"version": "6.8.2",
-			"resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
-			"integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
+			"version": "6.9.0",
+			"resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
+			"integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==",
 			"dev": true,
 			"dependencies": {
 				"ajv": "^8.0.1",
@@ -4968,28 +4866,6 @@
 			"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
 			"dev": true
 		},
-		"node_modules/through2": {
-			"version": "0.6.5",
-			"resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
-			"integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==",
-			"dev": true,
-			"dependencies": {
-				"readable-stream": ">=1.0.33-1 <1.1.0-0",
-				"xtend": ">=4.0.0 <4.1.0-0"
-			}
-		},
-		"node_modules/through2/node_modules/readable-stream": {
-			"version": "1.0.34",
-			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
-			"integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
-			"dev": true,
-			"dependencies": {
-				"core-util-is": "~1.0.0",
-				"inherits": "~2.0.1",
-				"isarray": "0.0.1",
-				"string_decoder": "~0.10.x"
-			}
-		},
 		"node_modules/tiny-lr": {
 			"version": "1.1.1",
 			"resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz",
@@ -5108,9 +4984,9 @@
 			}
 		},
 		"node_modules/update-browserslist-db": {
-			"version": "1.0.13",
-			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
-			"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+			"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
 			"dev": true,
 			"funding": [
 				{
@@ -5127,8 +5003,8 @@
 				}
 			],
 			"dependencies": {
-				"escalade": "^3.1.1",
-				"picocolors": "^1.0.0"
+				"escalade": "^3.2.0",
+				"picocolors": "^1.1.1"
 			},
 			"bin": {
 				"update-browserslist-db": "cli.js"
@@ -5471,29 +5347,22 @@
 			}
 		},
 		"@csstools/css-parser-algorithms": {
-			"version": "2.7.1",
-			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz",
-			"integrity": "sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==",
+			"version": "3.0.5",
+			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
+			"integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
 			"dev": true,
 			"requires": {}
 		},
 		"@csstools/css-tokenizer": {
-			"version": "2.4.1",
-			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.4.1.tgz",
-			"integrity": "sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==",
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
+			"integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
 			"dev": true
 		},
 		"@csstools/media-query-list-parser": {
-			"version": "2.1.13",
-			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.13.tgz",
-			"integrity": "sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==",
-			"dev": true,
-			"requires": {}
-		},
-		"@csstools/selector-specificity": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz",
-			"integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==",
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz",
+			"integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==",
 			"dev": true,
 			"requires": {}
 		},
@@ -5637,28 +5506,28 @@
 			}
 		},
 		"@stylistic/stylelint-config": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-config/-/stylelint-config-1.0.1.tgz",
-			"integrity": "sha512-JgFP88HZEyo34k9RpWVdcQJtLPrMxYE58IO3qypXhmvE/NmZohj+xjDtQ8UfaarnYsLecnldw57/GHum07Ctdw==",
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-config/-/stylelint-config-2.0.0.tgz",
+			"integrity": "sha512-8J4YAxggy2Nzkb8KJIOLbtMXTPZ5gpKVmyhiiuKEUgCl9XFND5lM0e/ZZBMGEYZ68h5qcsS/jgg1wh235erRAw==",
 			"dev": true,
 			"requires": {
-				"@stylistic/stylelint-plugin": "^2.0.0"
+				"@stylistic/stylelint-plugin": "^3.0.0"
 			}
 		},
 		"@stylistic/stylelint-plugin": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.0.0.tgz",
-			"integrity": "sha512-dHKuT6PGd1WGZLOTuozAM7GdQzdmlmnFXYzvV1jYJXXpcCpV/OJ3+n8TXpMkoOeKHpJydY43EOoZTO1W/FOA4Q==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.1.tgz",
+			"integrity": "sha512-XagAHHIa528EvyGybv8EEYGK5zrVW74cHpsjhtovVATbhDRuJYfE+X4HCaAieW9lCkwbX6L+X0I4CiUG3w/hFw==",
 			"dev": true,
 			"requires": {
-				"@csstools/css-parser-algorithms": "^2.3.2",
-				"@csstools/css-tokenizer": "^2.2.1",
-				"@csstools/media-query-list-parser": "^2.1.5",
+				"@csstools/css-parser-algorithms": "^3.0.1",
+				"@csstools/css-tokenizer": "^3.0.1",
+				"@csstools/media-query-list-parser": "^3.0.1",
 				"is-plain-object": "^5.0.0",
-				"postcss-selector-parser": "^6.0.13",
+				"postcss-selector-parser": "^6.1.2",
 				"postcss-value-parser": "^4.2.0",
 				"style-search": "^0.1.0",
-				"stylelint": "^16.0.2"
+				"stylelint": "^16.8.2"
 			},
 			"dependencies": {
 				"is-plain-object": {
@@ -5666,6 +5535,16 @@
 					"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
 					"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
 					"dev": true
+				},
+				"postcss-selector-parser": {
+					"version": "6.1.2",
+					"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+					"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+					"dev": true,
+					"requires": {
+						"cssesc": "^3.0.0",
+						"util-deprecate": "^1.0.2"
+					}
 				}
 			}
 		},
@@ -5939,15 +5818,15 @@
 			}
 		},
 		"browserslist": {
-			"version": "4.23.0",
-			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
-			"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
+			"version": "4.25.0",
+			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz",
+			"integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==",
 			"dev": true,
 			"requires": {
-				"caniuse-lite": "^1.0.30001587",
-				"electron-to-chromium": "^1.4.668",
-				"node-releases": "^2.0.14",
-				"update-browserslist-db": "^1.0.13"
+				"caniuse-lite": "^1.0.30001718",
+				"electron-to-chromium": "^1.5.160",
+				"node-releases": "^2.0.19",
+				"update-browserslist-db": "^1.1.3"
 			}
 		},
 		"browserslist-config-wikimedia": {
@@ -5985,9 +5864,9 @@
 			"dev": true
 		},
 		"caniuse-lite": {
-			"version": "1.0.30001612",
-			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
-			"integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
+			"version": "1.0.30001721",
+			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz",
+			"integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==",
 			"dev": true
 		},
 		"chalk": {
@@ -6124,9 +6003,9 @@
 			}
 		},
 		"cross-spawn": {
-			"version": "7.0.3",
-			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-			"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+			"version": "7.0.6",
+			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+			"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
 			"dev": true,
 			"requires": {
 				"path-key": "^3.1.0",
@@ -6146,9 +6025,9 @@
 			}
 		},
 		"css-functions-list": {
-			"version": "3.2.2",
-			"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz",
-			"integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==",
+			"version": "3.2.3",
+			"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz",
+			"integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==",
 			"dev": true
 		},
 		"css-tokenize": {
@@ -6162,12 +6041,12 @@
 			}
 		},
 		"css-tree": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
-			"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
+			"integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==",
 			"dev": true,
 			"requires": {
-				"mdn-data": "2.0.30",
+				"mdn-data": "2.12.2",
 				"source-map-js": "^1.0.1"
 			}
 		},
@@ -6184,12 +6063,12 @@
 			"dev": true
 		},
 		"debug": {
-			"version": "4.3.5",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
-			"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+			"version": "4.4.1",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+			"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
 			"dev": true,
 			"requires": {
-				"ms": "2.1.2"
+				"ms": "^2.1.3"
 			}
 		},
 		"deep-is": {
@@ -6223,20 +6102,19 @@
 			}
 		},
 		"doiuse": {
-			"version": "6.0.2",
-			"resolved": "https://registry.npmjs.org/doiuse/-/doiuse-6.0.2.tgz",
-			"integrity": "sha512-eBTs23NOX+EAYPr4RbCR6J4DRW/TML3uMo37y0X1whlkersDYFCk9HmCl09KX98cis22VKsV1QaxfVNauJ3NBw==",
+			"version": "6.0.5",
+			"resolved": "https://registry.npmjs.org/doiuse/-/doiuse-6.0.5.tgz",
+			"integrity": "sha512-ljuf9ndGqKST0GlPAYyCg04hbQAeR1xIIWVDjQaDDkoTY/Y1Vb+8FNoy6NuVuJIEEKe/nKUH8NRWjG7JJxZ9Eg==",
 			"dev": true,
 			"requires": {
-				"browserslist": "^4.21.5",
-				"caniuse-lite": "^1.0.30001487",
+				"browserslist": "^4.24.0",
+				"caniuse-lite": "^1.0.30001669",
 				"css-tokenize": "^1.0.1",
-				"duplexify": "^4.1.2",
-				"ldjson-stream": "^1.2.1",
+				"duplexify": "^4.1.3",
 				"multimatch": "^5.0.0",
-				"postcss": "^8.4.21",
+				"postcss": "^8.4.47",
 				"source-map": "^0.7.4",
-				"yargs": "^17.7.1"
+				"yargs": "^17.7.2"
 			}
 		},
 		"dom-serializer": {
@@ -6266,9 +6144,9 @@
 			}
 		},
 		"domutils": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
-			"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+			"version": "3.2.2",
+			"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+			"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
 			"dev": true,
 			"requires": {
 				"dom-serializer": "^2.0.0",
@@ -6311,9 +6189,9 @@
 			}
 		},
 		"electron-to-chromium": {
-			"version": "1.4.750",
-			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.750.tgz",
-			"integrity": "sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==",
+			"version": "1.5.165",
+			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.165.tgz",
+			"integrity": "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==",
 			"dev": true
 		},
 		"emoji-regex": {
@@ -6373,9 +6251,9 @@
 			}
 		},
 		"escalade": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-			"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+			"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
 			"dev": true
 		},
 		"escape-string-regexp": {
@@ -6475,9 +6353,9 @@
 			}
 		},
 		"eslint-config-wikimedia": {
-			"version": "0.28.2",
-			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.28.2.tgz",
-			"integrity": "sha512-5+rdnT7wH1gpKAO6tHYThg78eMhZMruJzvqku3Y5iaEY/A7kSKLFpA/vOj/snys9fKjDHC9BXmArQh+agkOoJQ==",
+			"version": "0.30.0",
+			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.30.0.tgz",
+			"integrity": "sha512-i8ESzSoo0x3Jur/0JhAgCVPxbV51zfdI3MN3MVQPnjiFdmo21CNKmiBBmw8JnJ3fx/d5zHDrBa+yDjxSLpnDlA==",
 			"dev": true,
 			"requires": {
 				"browserslist-config-wikimedia": "^0.7.0",
@@ -6490,7 +6368,7 @@
 				"eslint-plugin-mediawiki": "^0.7.0",
 				"eslint-plugin-mocha": "^10.4.3",
 				"eslint-plugin-n": "^17.7.0",
-				"eslint-plugin-no-jquery": "^3.0.1",
+				"eslint-plugin-no-jquery": "^3.1.1",
 				"eslint-plugin-qunit": "^8.1.1",
 				"eslint-plugin-security": "^1.7.1",
 				"eslint-plugin-unicorn": "^53.0.0",
@@ -6625,9 +6503,9 @@
 			}
 		},
 		"eslint-plugin-no-jquery": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.0.2.tgz",
-			"integrity": "sha512-n/+6p6PFhWDNPVLJj1463hw4OTIRBbROGcbhmtOHTgw7yihSKzkwZiQ00EJTneyeR3jRiw5lpWSMCCBhtb8t2g==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
+			"integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
 			"dev": true,
 			"requires": {}
 		},
@@ -6914,9 +6792,9 @@
 			"dev": true
 		},
 		"fast-uri": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
-			"integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==",
+			"version": "3.0.6",
+			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
+			"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
 			"dev": true
 		},
 		"fastest-levenshtein": {
@@ -7659,21 +7537,11 @@
 			"dev": true
 		},
 		"known-css-properties": {
-			"version": "0.34.0",
-			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz",
-			"integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
+			"version": "0.35.0",
+			"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz",
+			"integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==",
 			"dev": true
 		},
-		"ldjson-stream": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz",
-			"integrity": "sha512-xw/nNEXafuPSLu8NjjG3+atVVw+8U1APZAQylmwQn19Hgw6rC7QjHvP6MupnHWCrzSm9m0xs5QWkCLuRvBPjgQ==",
-			"dev": true,
-			"requires": {
-				"split2": "^0.2.1",
-				"through2": "^0.6.1"
-			}
-		},
 		"levn": {
 			"version": "0.4.1",
 			"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -7781,9 +7649,9 @@
 			"dev": true
 		},
 		"mdn-data": {
-			"version": "2.0.30",
-			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
-			"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+			"version": "2.12.2",
+			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
+			"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
 			"dev": true
 		},
 		"meow": {
@@ -7824,9 +7692,9 @@
 			}
 		},
 		"ms": {
-			"version": "2.1.2",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+			"version": "2.1.3",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+			"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
 			"dev": true
 		},
 		"multimatch": {
@@ -7843,9 +7711,9 @@
 			}
 		},
 		"nanoid": {
-			"version": "3.3.7",
-			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
-			"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+			"version": "3.3.11",
+			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+			"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
 			"dev": true
 		},
 		"natural-compare": {
@@ -7855,9 +7723,9 @@
 			"dev": true
 		},
 		"node-releases": {
-			"version": "2.0.14",
-			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
-			"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
+			"version": "2.0.19",
+			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+			"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
 			"dev": true
 		},
 		"nopt": {
@@ -8100,9 +7968,9 @@
 			"dev": true
 		},
 		"picocolors": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
-			"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+			"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
 			"dev": true
 		},
 		"picomatch": {
@@ -8118,40 +7986,33 @@
 			"dev": true
 		},
 		"postcss": {
-			"version": "8.4.39",
-			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz",
-			"integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==",
+			"version": "8.5.4",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
+			"integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
 			"dev": true,
 			"requires": {
-				"nanoid": "^3.3.7",
-				"picocolors": "^1.0.1",
-				"source-map-js": "^1.2.0"
+				"nanoid": "^3.3.11",
+				"picocolors": "^1.1.1",
+				"source-map-js": "^1.2.1"
 			}
 		},
 		"postcss-html": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.6.0.tgz",
-			"integrity": "sha512-OWgQ9/Pe23MnNJC0PL4uZp8k0EDaUvqpJFSiwFxOLClAhmD7UEisyhO3x5hVsD4xFrjReVTXydlrMes45dJ71w==",
+			"version": "1.7.0",
+			"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.7.0.tgz",
+			"integrity": "sha512-MfcMpSUIaR/nNgeVS8AyvyDugXlADjN9AcV7e5rDfrF1wduIAGSkL4q2+wgrZgA3sHVAHLDO9FuauHhZYW2nBw==",
 			"dev": true,
 			"requires": {
 				"htmlparser2": "^8.0.0",
-				"js-tokens": "^8.0.0",
+				"js-tokens": "^9.0.0",
 				"postcss": "^8.4.0",
 				"postcss-safe-parser": "^6.0.0"
 			},
 			"dependencies": {
 				"js-tokens": {
-					"version": "8.0.3",
-					"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz",
-					"integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==",
+					"version": "9.0.1",
+					"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+					"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
 					"dev": true
-				},
-				"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,
-					"requires": {}
 				}
 			}
 		},
@@ -8163,15 +8024,15 @@
 			"requires": {}
 		},
 		"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=",
+			"version": "0.1.6",
+			"resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz",
+			"integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==",
 			"dev": true
 		},
 		"postcss-safe-parser": {
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz",
-			"integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==",
+			"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,
 			"requires": {}
 		},
@@ -8544,9 +8405,9 @@
 			"dev": true
 		},
 		"source-map-js": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
-			"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+			"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
 			"dev": true
 		},
 		"spdx-correct": {
@@ -8593,15 +8454,6 @@
 			"integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==",
 			"dev": true
 		},
-		"split2": {
-			"version": "0.2.1",
-			"resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz",
-			"integrity": "sha512-D/oTExYAkC9nWleOCTOyNmAuzfAT/6rHGBA9LIK7FVnGo13CSvrKCUzKenwH6U1s2znY9MqH6v0UQTEDa3vJmg==",
-			"dev": true,
-			"requires": {
-				"through2": "~0.6.1"
-			}
-		},
 		"sprintf-js": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -8668,57 +8520,64 @@
 			"dev": true
 		},
 		"stylelint": {
-			"version": "16.7.0",
-			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.7.0.tgz",
-			"integrity": "sha512-Q1ATiXlz+wYr37a7TGsfvqYn2nSR3T/isw3IWlZQzFzCNoACHuGBb6xBplZXz56/uDRJHIygxjh7jbV/8isewA==",
+			"version": "16.12.0",
+			"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.12.0.tgz",
+			"integrity": "sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg==",
 			"dev": true,
 			"requires": {
-				"@csstools/css-parser-algorithms": "^2.7.1",
-				"@csstools/css-tokenizer": "^2.4.1",
-				"@csstools/media-query-list-parser": "^2.1.13",
-				"@csstools/selector-specificity": "^3.1.1",
+				"@csstools/css-parser-algorithms": "^3.0.4",
+				"@csstools/css-tokenizer": "^3.0.3",
+				"@csstools/media-query-list-parser": "^4.0.2",
+				"@csstools/selector-specificity": "^5.0.0",
 				"@dual-bundle/import-meta-resolve": "^4.1.0",
 				"balanced-match": "^2.0.0",
 				"colord": "^2.9.3",
 				"cosmiconfig": "^9.0.0",
-				"css-functions-list": "^3.2.2",
-				"css-tree": "^2.3.1",
-				"debug": "^4.3.5",
+				"css-functions-list": "^3.2.3",
+				"css-tree": "^3.0.1",
+				"debug": "^4.3.7",
 				"fast-glob": "^3.3.2",
 				"fastest-levenshtein": "^1.0.16",
-				"file-entry-cache": "^9.0.0",
+				"file-entry-cache": "^9.1.0",
 				"global-modules": "^2.0.0",
 				"globby": "^11.1.0",
 				"globjoin": "^0.1.4",
 				"html-tags": "^3.3.1",
-				"ignore": "^5.3.1",
+				"ignore": "^6.0.2",
 				"imurmurhash": "^0.1.4",
 				"is-plain-object": "^5.0.0",
-				"known-css-properties": "^0.34.0",
+				"known-css-properties": "^0.35.0",
 				"mathml-tag-names": "^2.1.3",
 				"meow": "^13.2.0",
-				"micromatch": "^4.0.7",
+				"micromatch": "^4.0.8",
 				"normalize-path": "^3.0.0",
-				"picocolors": "^1.0.1",
-				"postcss": "^8.4.39",
-				"postcss-resolve-nested-selector": "^0.1.1",
-				"postcss-safe-parser": "^7.0.0",
-				"postcss-selector-parser": "^6.1.0",
+				"picocolors": "^1.1.1",
+				"postcss": "^8.4.49",
+				"postcss-resolve-nested-selector": "^0.1.6",
+				"postcss-safe-parser": "^7.0.1",
+				"postcss-selector-parser": "^7.0.0",
 				"postcss-value-parser": "^4.2.0",
 				"resolve-from": "^5.0.0",
 				"string-width": "^4.2.3",
-				"strip-ansi": "^7.1.0",
-				"supports-hyperlinks": "^3.0.0",
+				"supports-hyperlinks": "^3.1.0",
 				"svg-tags": "^1.0.0",
-				"table": "^6.8.2",
+				"table": "^6.9.0",
 				"write-file-atomic": "^5.0.1"
 			},
 			"dependencies": {
-				"ansi-regex": {
-					"version": "6.0.1",
-					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-					"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-					"dev": true
+				"@csstools/media-query-list-parser": {
+					"version": "4.0.3",
+					"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz",
+					"integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==",
+					"dev": true,
+					"requires": {}
+				},
+				"@csstools/selector-specificity": {
+					"version": "5.0.0",
+					"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz",
+					"integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==",
+					"dev": true,
+					"requires": {}
 				},
 				"balanced-match": {
 					"version": "2.0.0",
@@ -8727,9 +8586,9 @@
 					"dev": true
 				},
 				"file-entry-cache": {
-					"version": "9.0.0",
-					"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz",
-					"integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==",
+					"version": "9.1.0",
+					"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz",
+					"integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==",
 					"dev": true,
 					"requires": {
 						"flat-cache": "^5.0.0"
@@ -8745,165 +8604,73 @@
 						"keyv": "^4.5.4"
 					}
 				},
+				"ignore": {
+					"version": "6.0.2",
+					"resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz",
+					"integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==",
+					"dev": true
+				},
 				"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
 				},
-				"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
+				"postcss-safe-parser": {
+					"version": "7.0.1",
+					"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
+					"integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
+					"dev": true,
+					"requires": {}
 				},
-				"strip-ansi": {
+				"postcss-selector-parser": {
 					"version": "7.1.0",
-					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-					"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+					"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+					"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
 					"dev": true,
 					"requires": {
-						"ansi-regex": "^6.0.1"
+						"cssesc": "^3.0.0",
+						"util-deprecate": "^1.0.2"
 					}
+				},
+				"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
 				}
 			}
 		},
 		"stylelint-config-recommended": {
-			"version": "14.0.0",
-			"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.0.tgz",
-			"integrity": "sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==",
+			"version": "14.0.1",
+			"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz",
+			"integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==",
 			"dev": true,
 			"requires": {}
 		},
 		"stylelint-config-wikimedia": {
-			"version": "0.17.2",
-			"resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.17.2.tgz",
-			"integrity": "sha512-cc3PYhe1O/GTgsMOp+Ri3ru579YBbZ3Me0oU7xNb06n4iwyXYPz8qO5G4iQ13UH19UW2NIS8Tk0goPRrJ1RAfw==",
+			"version": "0.18.0",
+			"resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.18.0.tgz",
+			"integrity": "sha512-Lr45NIe7pG8i7BPcMc6EddO1pRK8/KNG8gp4o/oOG1Ez10hglJuJb/QT17BlzX8NPkhtP2KdY63NS2f/Wcj6Ww==",
 			"dev": true,
 			"requires": {
-				"@stylistic/stylelint-config": "1.0.1",
-				"@stylistic/stylelint-plugin": "2.0.0",
+				"@stylistic/stylelint-config": "2.0.0",
+				"@stylistic/stylelint-plugin": "3.1.1",
 				"browserslist-config-wikimedia": "0.7.0",
-				"postcss-html": "1.6.0",
+				"postcss-html": "1.7.0",
 				"postcss-less": "6.0.0",
-				"stylelint": "16.2.0",
-				"stylelint-config-recommended": "14.0.0",
-				"stylelint-no-unsupported-browser-features": "8.0.1"
-			},
-			"dependencies": {
-				"ansi-regex": {
-					"version": "6.0.1",
-					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-					"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-					"dev": true
-				},
-				"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
-				},
-				"file-entry-cache": {
-					"version": "8.0.0",
-					"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
-					"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
-					"dev": true,
-					"requires": {
-						"flat-cache": "^4.0.0"
-					}
-				},
-				"flat-cache": {
-					"version": "4.0.1",
-					"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
-					"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
-					"dev": true,
-					"requires": {
-						"flatted": "^3.2.9",
-						"keyv": "^4.5.4"
-					}
-				},
-				"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
-				},
-				"known-css-properties": {
-					"version": "0.29.0",
-					"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz",
-					"integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==",
-					"dev": true
-				},
-				"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": "7.1.0",
-					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-					"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
-					"dev": true,
-					"requires": {
-						"ansi-regex": "^6.0.1"
-					}
-				},
-				"stylelint": {
-					"version": "16.2.0",
-					"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.2.0.tgz",
-					"integrity": "sha512-gwqU5AkIb52wrAzzn+359S3NIJDMl02TXLUaV2tzA/L6jUdpTwNt+MCxHlc8+Hb2bUHlYVo92YeSIryF2gJthA==",
-					"dev": true,
-					"requires": {
-						"@csstools/css-parser-algorithms": "^2.5.0",
-						"@csstools/css-tokenizer": "^2.2.3",
-						"@csstools/media-query-list-parser": "^2.1.7",
-						"@csstools/selector-specificity": "^3.0.1",
-						"balanced-match": "^2.0.0",
-						"colord": "^2.9.3",
-						"cosmiconfig": "^9.0.0",
-						"css-functions-list": "^3.2.1",
-						"css-tree": "^2.3.1",
-						"debug": "^4.3.4",
-						"fast-glob": "^3.3.2",
-						"fastest-levenshtein": "^1.0.16",
-						"file-entry-cache": "^8.0.0",
-						"global-modules": "^2.0.0",
-						"globby": "^11.1.0",
-						"globjoin": "^0.1.4",
-						"html-tags": "^3.3.1",
-						"ignore": "^5.3.0",
-						"imurmurhash": "^0.1.4",
-						"is-plain-object": "^5.0.0",
-						"known-css-properties": "^0.29.0",
-						"mathml-tag-names": "^2.1.3",
-						"meow": "^13.1.0",
-						"micromatch": "^4.0.5",
-						"normalize-path": "^3.0.0",
-						"picocolors": "^1.0.0",
-						"postcss": "^8.4.33",
-						"postcss-resolve-nested-selector": "^0.1.1",
-						"postcss-safe-parser": "^7.0.0",
-						"postcss-selector-parser": "^6.0.15",
-						"postcss-value-parser": "^4.2.0",
-						"resolve-from": "^5.0.0",
-						"string-width": "^4.2.3",
-						"strip-ansi": "^7.1.0",
-						"supports-hyperlinks": "^3.0.0",
-						"svg-tags": "^1.0.0",
-						"table": "^6.8.1",
-						"write-file-atomic": "^5.0.1"
-					}
-				}
+				"stylelint": "16.12.0",
+				"stylelint-config-recommended": "14.0.1",
+				"stylelint-no-unsupported-browser-features": "8.0.2"
 			}
 		},
 		"stylelint-no-unsupported-browser-features": {
-			"version": "8.0.1",
-			"resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-8.0.1.tgz",
-			"integrity": "sha512-tc8Xn5DaqJhxTmbA4H8gZbYdAz027NfuSZv5+cVieQb7BtBrF/1/iKYdpcGwXPl3GtqkQrisiXuGqKkKnzWcLw==",
+			"version": "8.0.2",
+			"resolved": "https://registry.npmjs.org/stylelint-no-unsupported-browser-features/-/stylelint-no-unsupported-browser-features-8.0.2.tgz",
+			"integrity": "sha512-4PY2qJ3ZTEje9RgGfaQ82eJoPioXxs6hazeKpji/wzLNVzTX2wd4b0Ds3ewdLkH3ID+o63IInuTquU2MNJO3YQ==",
 			"dev": true,
 			"requires": {
-				"doiuse": "^6.0.2",
+				"doiuse": "^6.0.5",
 				"postcss": "^8.4.32"
 			}
 		},
@@ -8917,9 +8684,9 @@
 			}
 		},
 		"supports-hyperlinks": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz",
-			"integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==",
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz",
+			"integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==",
 			"dev": true,
 			"requires": {
 				"has-flag": "^4.0.0",
@@ -8939,9 +8706,9 @@
 			"dev": true
 		},
 		"table": {
-			"version": "6.8.2",
-			"resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
-			"integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
+			"version": "6.9.0",
+			"resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
+			"integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==",
 			"dev": true,
 			"requires": {
 				"ajv": "^8.0.1",
@@ -8983,30 +8750,6 @@
 			"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
 			"dev": true
 		},
-		"through2": {
-			"version": "0.6.5",
-			"resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
-			"integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==",
-			"dev": true,
-			"requires": {
-				"readable-stream": ">=1.0.33-1 <1.1.0-0",
-				"xtend": ">=4.0.0 <4.1.0-0"
-			},
-			"dependencies": {
-				"readable-stream": {
-					"version": "1.0.34",
-					"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
-					"integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
-					"dev": true,
-					"requires": {
-						"core-util-is": "~1.0.0",
-						"inherits": "~2.0.1",
-						"isarray": "0.0.1",
-						"string_decoder": "~0.10.x"
-					}
-				}
-			}
-		},
 		"tiny-lr": {
 			"version": "1.1.1",
 			"resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz",
@@ -9093,13 +8836,13 @@
 			"dev": true
 		},
 		"update-browserslist-db": {
-			"version": "1.0.13",
-			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
-			"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+			"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
 			"dev": true,
 			"requires": {
-				"escalade": "^3.1.1",
-				"picocolors": "^1.0.0"
+				"escalade": "^3.2.0",
+				"picocolors": "^1.1.1"
 			}
 		},
 		"uri-js": {
diff --git a/package.json b/package.json
index ee929ed..6bb576e 100644
--- a/package.json
+++ b/package.json
@@ -6,12 +6,12 @@
 		"test-fix": "grunt test --fix"
 	},
 	"devDependencies": {
-		"eslint-config-wikimedia": "0.28.2",
+		"eslint-config-wikimedia": "0.30.0",
 		"grunt": "1.6.1",
 		"grunt-banana-checker": "0.13.0",
 		"grunt-contrib-watch": "1.1.0",
 		"grunt-eslint": "24.3.0",
 		"grunt-stylelint": "0.20.1",
-		"stylelint-config-wikimedia": "0.17.2"
+		"stylelint-config-wikimedia": "0.18.0"
 	}
 }
diff --git a/resources/controller/uw.controller.Deed.js b/resources/controller/uw.controller.Deed.js
index d843eaf..533e591 100644
--- a/resources/controller/uw.controller.Deed.js
+++ b/resources/controller/uw.controller.Deed.js
@@ -40,7 +40,7 @@
 	OO.inheritClass( uw.controller.Deed, uw.controller.Step );
 
 	uw.controller.Deed.prototype.moveNext = function () {
-		var
+		let
 			deedController = this,
 			valid, fields, validityPromises;
 
@@ -52,10 +52,10 @@
 		valid = this.deedChooser.valid();
 		if ( valid ) {
 			fields = this.deedChooser.deed.getFields();
-			validityPromises = fields.map( function ( fieldLayout ) {
+			validityPromises = fields.map( ( fieldLayout ) =>
 				// Update any error/warning messages
-				return fieldLayout.checkValidity( true );
-			} );
+				 fieldLayout.checkValidity( true )
+			 );
 			if ( validityPromises.length === 1 ) {
 				// validityPromises will hold all promises for all uploads;
 				// adding a bogus promise (no warnings & errors) to
@@ -73,7 +73,7 @@
 
 				// TODO Handle warnings with a confirmation dialog
 
-				var i;
+				let i;
 				for ( i = 0; i < arguments.length; i++ ) {
 					if ( arguments[ i ][ 1 ].length ) {
 						// One of the fields has errors; refuse to proceed!
@@ -87,10 +87,10 @@
 	};
 
 	uw.controller.Deed.prototype.unload = function () {
-		var deedController = this;
+		const deedController = this;
 		uw.controller.Step.prototype.unload.call( this );
 
-		Object.keys( this.deeds ).forEach( function ( name ) {
+		Object.keys( this.deeds ).forEach( ( name ) => {
 			deedController.deeds[ name ].unload();
 		} );
 	};
@@ -101,7 +101,7 @@
 	 * @param {mw.UploadWizardUpload[]} uploads
 	 */
 	uw.controller.Deed.prototype.load = function ( uploads ) {
-		var customDeed, previousDeed;
+		let customDeed, previousDeed;
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 
@@ -130,7 +130,7 @@
 			.insertBefore( this.deedChooser.$selector.find( '.mediauploader-deed-ownwork' ) )
 			.msg( 'mediauploader-deeds-macro-prompt', this.uploads.length, mw.user );
 
-		uploads.forEach( function ( upload ) {
+		uploads.forEach( ( upload ) => {
 			// Add previews and details to the DOM
 			upload.deedPreview = new uw.ui.DeedPreview( upload );
 		} );
diff --git a/resources/controller/uw.controller.Details.js b/resources/controller/uw.controller.Details.js
index 843a65b..82aa27b 100644
--- a/resources/controller/uw.controller.Details.js
+++ b/resources/controller/uw.controller.Details.js
@@ -51,15 +51,15 @@
 	 * @param {mw.UploadWizardUpload[]} uploads List of uploads being carried forward.
 	 */
 	uw.controller.Details.prototype.load = function ( uploads ) {
-		var controller = this;
+		const controller = this;
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 
 		// make sure queue is empty before starting this step
 		this.queue.abortExecuting();
 
-		this.uploads.forEach( function ( upload ) {
-			var serialized;
+		this.uploads.forEach( ( upload ) => {
+			let serialized;
 
 			// get existing details
 			serialized = upload.details ? upload.details.getSerialized() : null;
@@ -90,7 +90,7 @@
 	};
 
 	uw.controller.Details.prototype.addCopyMetadataFeature = function () {
-		var first,
+		let first,
 			// uploads can only be edited when they're in a certain state:
 			// a flat out upload failure or a completed upload can not be edited
 			invalidStates = [ 'aborted', 'error', 'complete' ],
@@ -107,8 +107,8 @@
 		// rest failed because of abusefilter (or another recoverable error), in
 		// which case we'll want the "copy" feature to appear below the 2nd
 		// upload (or the first not-yet-completed not flat-out-failed upload)
-		this.uploads.some( function ( upload ) {
-			if ( upload && invalidStates.indexOf( upload.state ) === -1 ) {
+		this.uploads.some( ( upload ) => {
+			if ( upload && !invalidStates.includes( upload.state ) ) {
 				first = upload;
 				return true; // Break Array.some loop
 			}
@@ -148,9 +148,9 @@
 	 * TODO move the rest of the logic here from mw.UploadWizard
 	 */
 	uw.controller.Details.prototype.startDetails = function () {
-		var details = this;
+		const details = this;
 
-		this.valid().done( function ( valid ) {
+		this.valid().done( ( valid ) => {
 			if ( valid ) {
 				details.ui.hideEndButtons();
 				details.submit();
@@ -166,7 +166,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.controller.Details.prototype.valid = function () {
-		var detailsController = this,
+		const detailsController = this,
 			// validityPromises will hold all promises for all uploads;
 			// prefilling with a bogus promise (no warnings & errors) to
 			// ensure $.when always resolves with an array of multiple
@@ -176,14 +176,14 @@
 			validityPromises = [ $.Deferred().resolve( [], [] ).promise() ],
 			titles = [];
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			// Update any error/warning messages about all DetailsWidgets
-			var promise = upload.details.checkValidity( true ).then( function () {
-				var warnings = [],
+			const promise = upload.details.checkValidity( true ).then( function () {
+				let warnings = [],
 					errors = [],
 					title;
 
-				Array.prototype.forEach.call( arguments, function ( result ) {
+				Array.prototype.forEach.call( arguments, ( result ) => {
 					warnings = warnings.concat( result[ 0 ] );
 					errors = errors.concat( result[ 1 ] );
 				} );
@@ -211,10 +211,10 @@
 		// validityPromises is an array of promises that each resolve with [warnings, errors]
 		// for each upload - now iterate them all to figure out if we can proceed
 		return $.when.apply( $, validityPromises ).then( function () {
-			var warnings = [],
+			let warnings = [],
 				errors = [];
 
-			Array.prototype.forEach.call( arguments, function ( result ) {
+			Array.prototype.forEach.call( arguments, ( result ) => {
 				warnings = warnings.concat( result[ 0 ] );
 				errors = errors.concat( result[ 1 ] );
 			} );
@@ -234,19 +234,15 @@
 	};
 
 	uw.controller.Details.prototype.confirmationDialog = function ( warnings ) {
-		var i,
+		let i,
 			$message = $( '<p>' ).text( mw.message( 'mediauploader-dialog-warning' ).text() ),
 			$ul = $( '<ul>' );
 
 		// parse warning messages
-		warnings = warnings.map( function ( warning ) {
-			return warning.text();
-		} );
+		warnings = warnings.map( ( warning ) => warning.text() );
 
 		// omit duplicates
-		warnings = warnings.filter( function ( warning, j, warningsOld ) {
-			return warningsOld.indexOf( warning ) === j;
-		} );
+		warnings = warnings.filter( ( warning, j, warningsOld ) => warningsOld.indexOf( warning ) === j );
 
 		for ( i = 0; i < warnings.length; i++ ) {
 			$ul.append( $( '<li>' ).text( warnings[ i ] ) );
@@ -265,9 +261,7 @@
 					label: mw.msg( 'mediauploader-dialog-continue' )
 				}
 			]
-		} ).closed.then( function ( data ) {
-			return !!( data && data.action === 'continue' );
-		} );
+		} ).closed.then( ( data ) => !!( data && data.action === 'continue' ) );
 	};
 
 	uw.controller.Details.prototype.canTransition = function ( upload ) {
@@ -293,11 +287,11 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.controller.Details.prototype.transitionAll = function () {
-		var
+		const
 			deferred = $.Deferred(),
 			details = this;
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			if ( details.canTransition( upload ) ) {
 				details.queue.addItem( upload );
 			}
@@ -315,9 +309,9 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.controller.Details.prototype.submit = function () {
-		var details = this;
+		const details = this;
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			// Clear error state
 			if ( upload.state === 'error' || upload.state === 'recoverable-error' ) {
 				upload.state = details.stepName;
@@ -331,7 +325,7 @@
 		this.ui.disableEdits();
 		this.removeCopyMetadataFeature();
 
-		return this.transitionAll().then( function () {
+		return this.transitionAll().then( () => {
 			details.showErrors();
 
 			if ( details.showNext() ) {
diff --git a/resources/controller/uw.controller.Step.js b/resources/controller/uw.controller.Step.js
index f981299..fcea7f8 100644
--- a/resources/controller/uw.controller.Step.js
+++ b/resources/controller/uw.controller.Step.js
@@ -26,7 +26,7 @@
 	 * @param {Object} config UploadWizard config object.
 	 */
 	uw.controller.Step = function UWControllerStep( ui, api, config ) {
-		var step = this;
+		const step = this;
 
 		OO.EventEmitter.call( this );
 
@@ -60,11 +60,11 @@
 			'remove-upload': this.removeUpload
 		};
 
-		this.ui.on( 'next-step', function () {
+		this.ui.on( 'next-step', () => {
 			step.moveNext();
 		} );
 
-		this.ui.on( 'previous-step', function () {
+		this.ui.on( 'previous-step', () => {
 			step.movePrevious();
 		} );
 
@@ -109,7 +109,7 @@
 	 * @param {mw.UploadWizardUpload[]} uploads List of uploads being carried forward.
 	 */
 	uw.controller.Step.prototype.load = function ( uploads ) {
-		var step = this;
+		const step = this;
 
 		this.emit( 'load' );
 
@@ -120,7 +120,7 @@
 			test: step.hasData.bind( this )
 		} );
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			upload.state = step.stepName;
 
 			step.bindUploadHandlers( upload );
@@ -133,9 +133,9 @@
 	 * Cleanup this step.
 	 */
 	uw.controller.Step.prototype.unload = function () {
-		var step = this;
+		const step = this;
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			step.unbindUploadHandlers( upload );
 		} );
 
@@ -173,10 +173,10 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.controller.Step.prototype.bindUploadHandlers = function ( upload ) {
-		var controller = this;
+		const controller = this;
 
-		Object.keys( this.uploadHandlers ).forEach( function ( event ) {
-			var callback = controller.uploadHandlers[ event ];
+		Object.keys( this.uploadHandlers ).forEach( ( event ) => {
+			const callback = controller.uploadHandlers[ event ];
 			upload.on( event, callback, [ upload ], controller );
 		} );
 	};
@@ -187,10 +187,10 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.controller.Step.prototype.unbindUploadHandlers = function ( upload ) {
-		var controller = this;
+		const controller = this;
 
-		Object.keys( this.uploadHandlers ).forEach( function ( event ) {
-			var callback = controller.uploadHandlers[ event ];
+		Object.keys( this.uploadHandlers ).forEach( ( event ) => {
+			const callback = controller.uploadHandlers[ event ];
 			upload.off( event, callback, controller );
 		} );
 	};
@@ -220,7 +220,7 @@
 	 * @return {boolean} Whether all of the uploads are in a successful state.
 	 */
 	uw.controller.Step.prototype.showNext = function () {
-		var okCount = this.getUploadStatesCount( this.finishState ),
+		let okCount = this.getUploadStatesCount( this.finishState ),
 			$buttons;
 
 		// abort if all uploads have been removed
@@ -256,13 +256,13 @@
 	 * @return {number}
 	 */
 	uw.controller.Step.prototype.getUploadStatesCount = function ( states ) {
-		var count = 0;
+		let count = 0;
 
 		// normalize to array of states, even though input can be 1 string
 		states = Array.isArray( states ) ? states : [ states ];
 
-		this.uploads.forEach( function ( upload ) {
-			if ( states.indexOf( upload.state ) > -1 ) {
+		this.uploads.forEach( ( upload ) => {
+			if ( states.includes( upload.state ) ) {
 				count++;
 			}
 		} );
@@ -302,7 +302,7 @@
 	 */
 	uw.controller.Step.prototype.removeUpload = function ( upload ) {
 		// remove the upload from the uploads array
-		var index = this.uploads.indexOf( upload );
+		const index = this.uploads.indexOf( upload );
 		if ( index !== -1 ) {
 			this.uploads.splice( index, 1 );
 		}
@@ -317,7 +317,7 @@
 	 * @param {mw.UploadWizardUpload[]} uploads
 	 */
 	uw.controller.Step.prototype.removeUploads = function ( uploads ) {
-		var i,
+		let i,
 			// clone the array of uploads, just to be sure it's not a reference
 			// to this.uploads, which will be modified (and we can't have that
 			// while we're looping it)
@@ -334,8 +334,8 @@
 	uw.controller.Step.prototype.removeErrorUploads = function () {
 		// We must not remove items from an array while iterating over it with $.each (it causes the
 		// next item to be skipped). Find and queue them first, then remove them.
-		var toRemove = [];
-		this.uploads.forEach( function ( upload ) {
+		const toRemove = [];
+		this.uploads.forEach( ( upload ) => {
 			if ( upload.state === 'error' || upload.state === 'recoverable-error' ) {
 				toRemove.push( upload );
 			}
diff --git a/resources/controller/uw.controller.Thanks.js b/resources/controller/uw.controller.Thanks.js
index 45a81ac..e660395 100644
--- a/resources/controller/uw.controller.Thanks.js
+++ b/resources/controller/uw.controller.Thanks.js
@@ -38,7 +38,7 @@
 	OO.inheritClass( uw.controller.Thanks, uw.controller.Step );
 
 	uw.controller.Thanks.prototype.load = function ( uploads ) {
-		var thanks = this;
+		const thanks = this;
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 
@@ -48,7 +48,7 @@
 			return;
 		}
 
-		uploads.forEach( function ( upload ) {
+		uploads.forEach( ( upload ) => {
 			thanks.ui.addUpload( upload );
 		} );
 	};
diff --git a/resources/controller/uw.controller.Tutorial.js b/resources/controller/uw.controller.Tutorial.js
index 2aee890..5c26eb8 100644
--- a/resources/controller/uw.controller.Tutorial.js
+++ b/resources/controller/uw.controller.Tutorial.js
@@ -26,7 +26,7 @@
 	 * @param {Object} config UploadWizard config object.
 	 */
 	uw.controller.Tutorial = function UWControllerTutorial( api, config ) {
-		var controller = this;
+		const controller = this;
 
 		this.skipPreference = Boolean( mw.user.options.get( 'upwiz_skiptutorial' ) );
 		this.newSkipPreference = this.skipPreference;
@@ -35,7 +35,7 @@
 		uw.controller.Step.call(
 			this,
 			new uw.ui.Tutorial()
-				.on( 'skip-tutorial-click', function ( skipped ) {
+				.on( 'skip-tutorial-click', ( skipped ) => {
 					// indicate that the skip preference has changed, so we can
 					// alter the preference when we move to another step
 					controller.newSkipPreference = skipped;
@@ -57,23 +57,23 @@
 	 * @param {boolean} skip
 	 */
 	uw.controller.Tutorial.prototype.setSkipPreference = function ( skip ) {
-		var controller = this,
+		const controller = this,
 			allowCloseWindow = mw.confirmCloseWindow();
 
 		this.api.postWithToken( 'options', {
 			action: 'options',
 			change: skip ? 'upwiz_skiptutorial=1' : 'upwiz_skiptutorial'
-		} ).done( function () {
+		} ).done( () => {
 			allowCloseWindow.release();
 			controller.skipPreference = skip;
-		} ).fail( function ( code, err ) {
+		} ).fail( ( code, err ) => {
 			mw.notify( err.textStatus );
 		} );
 	};
 
 	uw.controller.Tutorial.prototype.load = function ( uploads ) {
 		// tutorial can be skipped via preference, or config (e.g. campaign config)
-		var shouldSkipTutorial = this.skipPreference || ( this.config.tutorial && this.config.tutorial.skip );
+		const shouldSkipTutorial = this.skipPreference || ( this.config.tutorial && this.config.tutorial.skip );
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 
diff --git a/resources/controller/uw.controller.Upload.js b/resources/controller/uw.controller.Upload.js
index 1fb75e2..43d416e 100644
--- a/resources/controller/uw.controller.Upload.js
+++ b/resources/controller/uw.controller.Upload.js
@@ -26,7 +26,7 @@
 	 * @param {Object} config UploadWizard config object.
 	 */
 	uw.controller.Upload = function UWControllerUpload( api, config ) {
-		var step = this;
+		const step = this;
 
 		uw.controller.Step.call(
 			this,
@@ -47,8 +47,8 @@
 		} );
 		this.queue.on( 'complete', this.showNext.bind( this ) );
 
-		this.ui.on( 'files-added', function ( files ) {
-			var totalFiles = files.length + step.uploads.length,
+		this.ui.on( 'files-added', ( files ) => {
+			const totalFiles = files.length + step.uploads.length,
 				tooManyFiles = totalFiles > step.config.maxUploads;
 
 			if ( tooManyFiles ) {
@@ -65,7 +65,7 @@
 	 * Updates the upload step data when a file is added or removed.
 	 */
 	uw.controller.Upload.prototype.updateFileCounts = function () {
-		var fewerThanMax, haveUploads,
+		let fewerThanMax, haveUploads,
 			max = this.config.maxUploads;
 
 		haveUploads = this.uploads.length > 0;
@@ -76,7 +76,7 @@
 	};
 
 	uw.controller.Upload.prototype.load = function ( uploads ) {
-		var controller = this;
+		const controller = this;
 
 		uw.controller.Step.prototype.load.call( this, uploads );
 		this.updateFileCounts();
@@ -96,7 +96,7 @@
 			 * with new uploads, and still understand the existing files that
 			 * we've just reset the state for.
 			 */
-			uploads.forEach( function ( upload ) {
+			uploads.forEach( ( upload ) => {
 				upload.state = upload.fileKey === undefined ? 'error' : controller.finishState;
 			} );
 
@@ -167,7 +167,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.controller.Upload.prototype.transitionOne = function ( upload ) {
-		var promise = upload.start();
+		const promise = upload.start();
 		this.maybeStartProgressBar();
 		return promise;
 	};
@@ -191,9 +191,9 @@
 	};
 
 	uw.controller.Upload.prototype.retry = function () {
-		var controller = this;
+		const controller = this;
 
-		this.uploads.forEach( function ( upload ) {
+		this.uploads.forEach( ( upload ) => {
 			if ( upload.state === 'error' ) {
 				// reset any uploads in error state back to be shiny & new
 				upload.state = 'new';
@@ -214,7 +214,7 @@
 	 * @return {mw.UploadWizardUpload|boolean} The new upload, or false if it can't be added
 	 */
 	uw.controller.Upload.prototype.addFile = function ( file ) {
-		var upload;
+		let upload;
 
 		if ( this.uploads.length >= this.config.maxUploads ) {
 			return false;
@@ -244,7 +244,7 @@
 	 * @param {FileList} files
 	 */
 	uw.controller.Upload.prototype.addFiles = function ( files ) {
-		var
+		let
 			uploadObj,
 			i,
 			file,
@@ -302,7 +302,7 @@
 	 * @return {boolean} Error in [code, info] format, or empty [] for no errors
 	 */
 	uw.controller.Upload.prototype.validateFile = function ( upload ) {
-		var extension,
+		let extension,
 			i,
 			actualMaxSize = mw.UploadWizard.config.maxMwUploadSize,
 
@@ -322,7 +322,7 @@
 		// check if the filename is valid
 		upload.setTitle( basename );
 		if ( !upload.title ) {
-			if ( basename.indexOf( '.' ) === -1 ) {
+			if ( !basename.includes( '.' ) ) {
 				this.ui.showMissingExtensionError( filename );
 				return false;
 			} else {
@@ -340,7 +340,7 @@
 
 		if (
 			mw.UploadWizard.config.fileExtensions !== null &&
-			mw.UploadWizard.config.fileExtensions.indexOf( extension.toLowerCase() ) === -1
+			!mw.UploadWizard.config.fileExtensions.includes( extension.toLowerCase() )
 		) {
 			this.ui.showBadExtensionError( filename, extension );
 			return false;
diff --git a/resources/deed/uw.deed.OwnWork.js b/resources/deed/uw.deed.OwnWork.js
index 50881cb..f287b98 100644
--- a/resources/deed/uw.deed.OwnWork.js
+++ b/resources/deed/uw.deed.OwnWork.js
@@ -26,7 +26,7 @@
 	 * @param {mw.Api} api API object - useful for doing previews
 	 */
 	uw.deed.OwnWork = function UWDeedOwnWork( config, uploads, api ) {
-		var deed = this,
+		let deed = this,
 			prefAuthName = mw.user.options.get( 'upwiz_licensename' );
 
 		uw.deed.Abstract.call( this, 'ownwork', config );
@@ -49,7 +49,7 @@
 			value: prefAuthName,
 			classes: [ 'mediauploader-sign' ]
 		} );
-		this.authorInput.on( 'change', function () {
+		this.authorInput.on( 'change', () => {
 			deed.fakeAuthorInput.setValue( deed.authorInput.getValue() );
 		} );
 
@@ -80,7 +80,7 @@
 	};
 
 	uw.deed.OwnWork.prototype.setFormFields = function ( $selector ) {
-		var $customDiv, $formFields, $toggler, crossfaderWidget, defaultLicense,
+		let $customDiv, $formFields, $toggler, crossfaderWidget, defaultLicense,
 			defaultLicenseURL, $defaultLicenseLink, $standardDiv, $crossfader,
 			deed, languageCode, defaultLicConfig;
 
@@ -141,7 +141,7 @@
 
 		this.authorInputField = new uw.FieldLayout( crossfaderWidget );
 		// Aggregate 'change' event
-		this.authorInput.on( 'change', OO.ui.debounce( function () {
+		this.authorInput.on( 'change', OO.ui.debounce( () => {
 			crossfaderWidget.emit( 'change' );
 		}, 500 ) );
 
@@ -152,7 +152,7 @@
 		$toggler = $( '<p>' ).addClass( 'mwe-more-options' ).css( 'text-align', 'right' )
 			.append( $( '<a>' )
 				.msg( 'mediauploader-license-show-all' )
-				.on( 'click', function () {
+				.on( 'click', () => {
 					if ( $crossfader.data( 'crossfadeDisplay' ).get( 0 ) === $customDiv.get( 0 ) ) {
 						deed.standardLicense();
 					} else {
@@ -171,8 +171,8 @@
 	};
 
 	uw.deed.OwnWork.prototype.setDefaultLicenses = function () {
-		var defaultLicenses = {};
-		this.getDefaultLicenses().forEach( function ( licName ) {
+		const defaultLicenses = {};
+		this.getDefaultLicenses().forEach( ( licName ) => {
 			defaultLicenses[ licName ] = true;
 		} );
 		this.licenseInput.setValues( defaultLicenses );
@@ -189,10 +189,10 @@
 	 * @inheritdoc
 	 */
 	uw.deed.OwnWork.prototype.getAuthorWikiText = function () {
-		var author = this.authorInput.getValue(),
+		let author = this.authorInput.getValue(),
 			userPageTitle;
 
-		if ( author.indexOf( '[' ) >= 0 || author.indexOf( '{' ) >= 0 ) {
+		if ( author.includes( '[' ) || author.includes( '{' ) ) {
 			return author;
 		}
 
@@ -236,7 +236,7 @@
 	};
 
 	uw.deed.OwnWork.prototype.swapNodes = function ( a, b ) {
-		var
+		const
 			parentA = a.parentNode,
 			parentB = b.parentNode,
 			nextA = a.nextSibling,
@@ -252,7 +252,7 @@
 	 * @return {string[]}
 	 */
 	uw.deed.OwnWork.prototype.getDefaultLicenses = function () {
-		var license, ownWork = this.config.licensing.ownWork;
+		let license, ownWork = this.config.licensing.ownWork;
 
 		if ( this.config.licensing.defaultType === 'ownWork' ) {
 			license = ownWork.defaults;
@@ -267,7 +267,7 @@
 	};
 
 	uw.deed.OwnWork.prototype.standardLicense = function () {
-		var deed = this,
+		const deed = this,
 			$crossfader = this.$selector.find( '.mediauploader-crossfader' ),
 			$standardDiv = this.$selector.find( '.mediauploader-standard' ),
 			$toggler = this.$selector.find( '.mwe-more-options a' );
@@ -275,7 +275,7 @@
 		this.setDefaultLicenses();
 
 		$crossfader.morphCrossfade( $standardDiv )
-			.promise().done( function () {
+			.promise().done( () => {
 				deed.swapNodes( deed.authorInput.$element[ 0 ], deed.fakeAuthorInput.$element[ 0 ] );
 			} );
 
@@ -289,13 +289,13 @@
 	};
 
 	uw.deed.OwnWork.prototype.customLicense = function () {
-		var deed = this,
+		const deed = this,
 			$crossfader = this.$selector.find( '.mediauploader-crossfader' ),
 			$customDiv = this.$selector.find( '.mediauploader-custom' ),
 			$toggler = this.$selector.find( '.mwe-more-options a' );
 
 		$crossfader.morphCrossfade( $customDiv )
-			.promise().done( function () {
+			.promise().done( () => {
 				deed.swapNodes( deed.authorInput.$element[ 0 ], deed.fakeAuthorInput.$element[ 0 ] );
 			} );
 
@@ -313,7 +313,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.deed.OwnWork.prototype.getAuthorErrors = function ( input ) {
-		var
+		const
 			errors = [],
 			minLength = this.config.minAuthorLength,
 			maxLength = this.config.maxAuthorLength,
diff --git a/resources/deed/uw.deed.ThirdParty.js b/resources/deed/uw.deed.ThirdParty.js
index 0d70235..e2eebf8 100644
--- a/resources/deed/uw.deed.ThirdParty.js
+++ b/resources/deed/uw.deed.ThirdParty.js
@@ -26,7 +26,7 @@
 	 * @param {mw.Api} api API object - useful for doing previews
 	 */
 	uw.deed.ThirdParty = function UWDeedThirdParty( config, uploads, api ) {
-		var deed = this;
+		const deed = this;
 
 		uw.deed.Abstract.call( this, 'thirdparty', config );
 
@@ -40,7 +40,7 @@
 		this.sourceInput.$input.attr( 'id', 'mwe-source-' + this.getInstanceCount() );
 		// See uw.DetailsWidget
 		this.sourceInput.getErrors = function () {
-			var
+			const
 				errors = [],
 				minLength = deed.config.minSourceLength,
 				maxLength = deed.config.maxSourceLength,
@@ -74,7 +74,7 @@
 		this.authorInput.$input.attr( 'id', 'mwe-author-' + this.getInstanceCount() );
 		// See uw.DetailsWidget
 		this.authorInput.getErrors = function () {
-			var
+			const
 				errors = [],
 				minLength = deed.config.minAuthorLength,
 				maxLength = deed.config.maxAuthorLength,
@@ -127,7 +127,7 @@
 	};
 
 	uw.deed.ThirdParty.prototype.setFormFields = function ( $selector ) {
-		var $formFields = $( '<div>' ).addClass( 'mediauploader-deed-form-internal' );
+		const $formFields = $( '<div>' ).addClass( 'mediauploader-deed-form-internal' );
 
 		this.$form = $( '<form>' );
 
diff --git a/resources/details/uw.CategoriesDetailsWidget.js b/resources/details/uw.CategoriesDetailsWidget.js
index 1d12511..90c456a 100644
--- a/resources/details/uw.CategoriesDetailsWidget.js
+++ b/resources/details/uw.CategoriesDetailsWidget.js
@@ -1,6 +1,6 @@
 ( function ( uw ) {
 
-	var NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;
+	const NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;
 
 	/**
 	 * A categories field in UploadWizard's "Details" step form.
@@ -9,7 +9,7 @@
 	 * @param {Object} config
 	 */
 	uw.CategoriesDetailsWidget = function UWCategoriesDetailsWidget( config ) {
-		var catDetails = this;
+		const catDetails = this;
 		this.config = config;
 
 		uw.CategoriesDetailsWidget.parent.call( this, this.config );
@@ -19,7 +19,7 @@
 		} );
 
 		this.categoriesWidget.createTagItemWidget = function ( data ) {
-			var widget = this.constructor.prototype.createTagItemWidget.call( this, data );
+			const widget = this.constructor.prototype.createTagItemWidget.call( this, data );
 			if ( !widget ) {
 				return null;
 			}
@@ -43,7 +43,7 @@
 	 * @inheritdoc
 	 */
 	uw.CategoriesDetailsWidget.prototype.getErrors = function () {
-		var errors = [];
+		const errors = [];
 
 		if ( this.config.required && this.categoriesWidget.getItems().length === 0 ) {
 			errors.push( mw.message( 'mediauploader-error-blank' ) );
@@ -56,12 +56,10 @@
 	 * @inheritdoc
 	 */
 	uw.CategoriesDetailsWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.categoriesWidget.getItems().length === 0, warnings );
 
-		if ( this.categoriesWidget.getItems().some( function ( item ) {
-			return item.missing;
-		} ) ) {
+		if ( this.categoriesWidget.getItems().some( ( item ) => item.missing ) ) {
 			warnings.push( mw.message( 'mediauploader-categories-missing' ) );
 		}
 		return $.Deferred().resolve( warnings ).promise();
@@ -71,7 +69,7 @@
 	 * @inheritdoc
 	 */
 	uw.CategoriesDetailsWidget.prototype.getWikiText = function () {
-		var hiddenCats, missingCatsWikiText, categories, wikiText;
+		let hiddenCats, missingCatsWikiText, categories, wikiText;
 
 		hiddenCats = [];
 		if ( this.config.hiddenDefault ) {
@@ -84,10 +82,10 @@
 				hiddenCats.push( mw.UploadWizard.config.trackingCategory.campaign );
 			}
 		}
-		hiddenCats = hiddenCats.filter( function ( cat ) {
+		hiddenCats = hiddenCats.filter( ( cat ) =>
 			// Keep only valid titles
-			return !!mw.Title.makeTitle( NS_CATEGORY, cat );
-		} );
+			 !!mw.Title.makeTitle( NS_CATEGORY, cat )
+		 );
 
 		missingCatsWikiText = null;
 		if (
@@ -97,15 +95,11 @@
 			missingCatsWikiText = this.config.missingWikitext;
 		}
 
-		categories = this.categoriesWidget.getItems().map( function ( item ) {
-			return item.data;
-		} );
+		categories = this.categoriesWidget.getItems().map( ( item ) => item.data );
 
 		// add all categories
 		wikiText = categories.concat( hiddenCats )
-			.map( function ( cat ) {
-				return '[[' + mw.Title.makeTitle( NS_CATEGORY, cat ).getPrefixedText() + ']]';
-			} )
+			.map( ( cat ) => '[[' + mw.Title.makeTitle( NS_CATEGORY, cat ).getPrefixedText() + ']]' )
 			.join( '\n' );
 
 		// if so configured, and there are no user-visible categories, add warning
@@ -121,9 +115,7 @@
 	 * @return {Object} See #setSerialized
 	 */
 	uw.CategoriesDetailsWidget.prototype.getSerialized = function () {
-		return this.categoriesWidget.getItems().map( function ( item ) {
-			return item.data;
-		} );
+		return this.categoriesWidget.getItems().map( ( item ) => item.data );
 	};
 
 	/**
@@ -131,10 +123,10 @@
 	 * @param {string[]} serialized List of categories
 	 */
 	uw.CategoriesDetailsWidget.prototype.setSerialized = function ( serialized ) {
-		var categories = ( serialized || [] ).filter( function ( cat ) {
+		const categories = ( serialized || [] ).filter( ( cat ) =>
 			// Keep only valid titles
-			return !!mw.Title.makeTitle( NS_CATEGORY, cat );
-		} );
+			 !!mw.Title.makeTitle( NS_CATEGORY, cat )
+		 );
 		this.categoriesWidget.setValue( categories );
 	};
 
diff --git a/resources/details/uw.DateDetailsWidget.js b/resources/details/uw.DateDetailsWidget.js
index 198e7e2..f2fabc5 100644
--- a/resources/details/uw.DateDetailsWidget.js
+++ b/resources/details/uw.DateDetailsWidget.js
@@ -31,10 +31,10 @@
 			disabled: this.config.disabled
 		} )
 			.selectItemByData( 'calendar' )
-			.on( 'choose', function ( selectedItem ) {
+			.on( 'choose', ( selectedItem ) => {
 				this.setupDateInput( selectedItem.getData() );
 				this.dateInputWidget.focus();
-			}.bind( this ) );
+			} );
 
 		this.$element.addClass( 'mediauploader-dateDetailsWidget' );
 		this.$element.append(
@@ -52,7 +52,7 @@
 	 * @private
 	 */
 	uw.DateDetailsWidget.prototype.setupDateInput = function ( mode ) {
-		var
+		const
 			oldDateInputWidget = this.dateInputWidget;
 
 		if ( mode === undefined ) {
@@ -75,13 +75,13 @@
 			} );
 			// If the user types '{{', assume that they are trying to input template wikitext and switch
 			// to 'arbitrary' mode. This might help confused power-users (T110026#1567714).
-			this.dateInputWidget.textInput.on( 'change', function ( value ) {
+			this.dateInputWidget.textInput.on( 'change', ( value ) => {
 				if ( value === '{{' ) {
 					this.setupDateInput( 'arbitrary' );
 					this.dateInputWidget.setValue( '{{' );
 					this.dateInputWidget.moveCursorToEnd();
 				}
-			}.bind( this ) );
+			} );
 		}
 
 		if ( oldDateInputWidget ) {
@@ -121,7 +121,7 @@
 	 * @inheritdoc
 	 */
 	uw.DateDetailsWidget.prototype.getWarnings = function () {
-		var warnings = [],
+		const warnings = [],
 			dateVal = Date.parse( this.dateInputWidget.getValue().trim() ),
 			now = new Date();
 
@@ -143,7 +143,7 @@
 	 * @inheritdoc
 	 */
 	uw.DateDetailsWidget.prototype.getErrors = function () {
-		var errors = [];
+		const errors = [];
 
 		if ( this.config.required && this.dateInputWidget.getValue().trim() === '' ) {
 			errors.push( mw.message( 'mediauploader-error-blank' ) );
diff --git a/resources/details/uw.DeedChooserDetailsWidget.js b/resources/details/uw.DeedChooserDetailsWidget.js
index 94e4fd9..1560271 100644
--- a/resources/details/uw.DeedChooserDetailsWidget.js
+++ b/resources/details/uw.DeedChooserDetailsWidget.js
@@ -25,7 +25,7 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.DeedChooserDetailsWidget.prototype.useCustomDeedChooser = function ( upload ) {
-		var $deedDiv;
+		let $deedDiv;
 
 		// Defining own deedChooser for uploads coming from external service
 		if ( upload.file.fromURL ) {
@@ -74,7 +74,7 @@
 	 * @inheritdoc
 	 */
 	uw.DeedChooserDetailsWidget.prototype.getErrors = function () {
-		var errors = [];
+		const errors = [];
 		if ( this.deedChooser ) {
 			if ( !this.deedChooser.deed ) {
 				errors.push( mw.message( 'mediauploader-deeds-need-deed' ) );
diff --git a/resources/details/uw.DropdownWidget.js b/resources/details/uw.DropdownWidget.js
index ab6ec70..17db404 100644
--- a/resources/details/uw.DropdownWidget.js
+++ b/resources/details/uw.DropdownWidget.js
@@ -17,9 +17,7 @@
 		this.wikitext = config.wikitext;
 		this.input = new OO.ui.DropdownInputWidget( {
 			classes: [ 'mwe-idfield', 'mediauploader-dropdownWidget-input' ],
-			options: Object.keys( config.options ).map( function ( key ) {
-				return { data: key, label: config.options[ key ] };
-			} )
+			options: Object.keys( config.options ).map( ( key ) => ( { data: key, label: config.options[ key ] } ) )
 		} );
 
 		// Aggregate 'change' event
@@ -37,7 +35,7 @@
 	 * @inheritdoc
 	 */
 	uw.DropdownWidget.prototype.getErrors = function () {
-		var errors = [];
+		const errors = [];
 		if ( this.required && this.input.getValue().trim() === '' ) {
 			errors.push( mw.message( 'mediauploader-error-blank' ) );
 		}
@@ -48,7 +46,7 @@
 	 * @inheritdoc
 	 */
 	uw.DropdownWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.input.getValue().trim() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
diff --git a/resources/details/uw.LanguageDropdownWidget.js b/resources/details/uw.LanguageDropdownWidget.js
index 8865ae8..b9e163d 100644
--- a/resources/details/uw.LanguageDropdownWidget.js
+++ b/resources/details/uw.LanguageDropdownWidget.js
@@ -28,15 +28,13 @@
 	 * @param {Object} languages
 	 */
 	uw.LanguageDropdownWidget.prototype.updateLanguages = function ( languages ) {
-		var menu = this.languageDropdown.getMenu(),
+		const menu = this.languageDropdown.getMenu(),
 			currentMenuItems = menu.getItems(),
 			currentValue = this.getValue();
 
 		// remove all items except the one currently selected (don't want
 		// to trigger another select by removing it)
-		menu.removeItems( currentMenuItems.filter( function ( item ) {
-			return !item.isSelected();
-		} ) );
+		menu.removeItems( currentMenuItems.filter( ( item ) => !item.isSelected() ) );
 
 		// and add the rest of the languages back in there
 		delete languages[ currentValue ];
@@ -72,12 +70,10 @@
 	 * @return {OO.ui.MenuOptionWidget[]}
 	 */
 	uw.LanguageDropdownWidget.prototype.getLanguageMenuOptionWidgets = function ( languages ) {
-		return Object.keys( languages ).map( function ( code ) {
-			return new OO.ui.MenuOptionWidget( {
-				data: code,
-				label: languages[ code ]
-			} );
-		} );
+		return Object.keys( languages ).map( ( code ) => new OO.ui.MenuOptionWidget( {
+			data: code,
+			label: languages[ code ]
+		} ) );
 	};
 
 }( mw.uploadWizard ) );
diff --git a/resources/details/uw.LocationDetailsWidget.js b/resources/details/uw.LocationDetailsWidget.js
index 76a0c18..b89a46e 100644
--- a/resources/details/uw.LocationDetailsWidget.js
+++ b/resources/details/uw.LocationDetailsWidget.js
@@ -68,10 +68,10 @@
 		this.connect( this, { change: 'onChange' } );
 
 		this.mapButton.toggle( false );
-		mw.loader.using( [ 'ext.kartographer.box', 'ext.kartographer.editing' ] ).done( function () {
+		mw.loader.using( [ 'ext.kartographer.box', 'ext.kartographer.editing' ] ).done( () => {
 			// Kartographer is installed and we'll be able to show the map. Display the button.
 			this.mapButton.toggle( true );
-		}.bind( this ) );
+		} );
 	};
 
 	OO.inheritClass( uw.LocationDetailsWidget, uw.DetailsWidget );
@@ -80,8 +80,8 @@
 	 * @private
 	 */
 	uw.LocationDetailsWidget.prototype.onChange = function () {
-		var widget = this;
-		this.getErrors().done( function ( errors ) {
+		const widget = this;
+		this.getErrors().done( ( errors ) => {
 			widget.mapButton.setDisabled( !( errors.length === 0 && widget.getWikiText() !== '' ) );
 		} );
 	};
@@ -90,7 +90,7 @@
 	 * @private
 	 */
 	uw.LocationDetailsWidget.prototype.onMapButtonClick = function () {
-		var coords = this.getSerializedParsed();
+		const coords = this.getSerializedParsed();
 
 		// Disable clipping because it doesn't play nicely with the map
 		this.mapButton.getPopup().toggleClipping( false );
@@ -112,7 +112,7 @@
 	 * @inheritdoc
 	 */
 	uw.LocationDetailsWidget.prototype.getErrors = function () {
-		var errors = [],
+		let errors = [],
 			serialized = this.getSerialized(),
 			parsed = this.getSerializedParsed(),
 			field;
@@ -132,13 +132,13 @@
 		// coordinates that were derived from the input are 0, without a 0 even
 		// being present in the input
 		if ( this.config.showField.latitude && serialized.latitude ) {
-			if ( isNaN( parsed.latitude ) || parsed.latitude > 90 || parsed.latitude < -90 || ( parsed.latitude === 0 && serialized.latitude.indexOf( '0' ) < 0 ) ) {
+			if ( isNaN( parsed.latitude ) || parsed.latitude > 90 || parsed.latitude < -90 || ( parsed.latitude === 0 && !serialized.latitude.includes( '0' ) ) ) {
 				errors.push( mw.message( 'mediauploader-error-latitude' ) );
 			}
 		}
 
 		if ( this.config.showField.longitude && serialized.longitude ) {
-			if ( isNaN( parsed.longitude ) || parsed.longitude > 180 || parsed.longitude < -180 || ( parsed.longitude === 0 && serialized.longitude.indexOf( '0' ) < 0 ) ) {
+			if ( isNaN( parsed.longitude ) || parsed.longitude > 180 || parsed.longitude < -180 || ( parsed.longitude === 0 && !serialized.longitude.includes( '0' ) ) ) {
 				errors.push( mw.message( 'mediauploader-error-longitude' ) );
 			}
 		}
@@ -160,7 +160,7 @@
 	 * @inheritdoc
 	 */
 	uw.LocationDetailsWidget.prototype.getWikiText = function () {
-		var field,
+		let field,
 			result = '',
 			serialized = this.getSerializedParsed();
 
@@ -190,7 +190,7 @@
 	 * @return {Object} See #setSerialized
 	 */
 	uw.LocationDetailsWidget.prototype.getSerialized = function () {
-		var field,
+		let field,
 			result = {};
 
 		for ( field in this.config.showField ) {
@@ -206,7 +206,7 @@
 	 * @return {Object} Serialized, parsed values of the subfields (numbers)
 	 */
 	uw.LocationDetailsWidget.prototype.getSerializedParsed = function () {
-		var field,
+		let field,
 			result = {},
 			serialized = this.getSerialized();
 
@@ -232,7 +232,7 @@
 	 * @param {string} serialized.heading Heading value
 	 */
 	uw.LocationDetailsWidget.prototype.setSerialized = function ( serialized ) {
-		var field;
+		let field;
 
 		for ( field in this.config.showField ) {
 			if ( serialized[ field ] !== undefined ) {
@@ -255,7 +255,7 @@
 	 * @return {number}
 	 */
 	uw.LocationDetailsWidget.prototype.normalizeCoordinate = function ( coordinate ) {
-		var sign = coordinate.match( /[sw]/i ) ? -1 : 1,
+		let sign = coordinate.match( /[sw]/i ) ? -1 : 1,
 			parts, value;
 
 		// fix commonly used character alternatives
diff --git a/resources/details/uw.MultipleLanguageInputWidget.js b/resources/details/uw.MultipleLanguageInputWidget.js
index 7816114..e3dcf27 100644
--- a/resources/details/uw.MultipleLanguageInputWidget.js
+++ b/resources/details/uw.MultipleLanguageInputWidget.js
@@ -57,7 +57,7 @@
 	 * @param {string} [text]
 	 */
 	uw.MultipleLanguageInputWidget.prototype.addLanguageInput = function ( config, text ) {
-		var allLanguages = this.config.languages,
+		let allLanguages = this.config.languages,
 			unusedLanguages = this.getUnusedLanguages(),
 			languages = {},
 			item;
@@ -97,7 +97,7 @@
 	 * with the updated language selections.
 	 */
 	uw.MultipleLanguageInputWidget.prototype.onChangeLanguages = function () {
-		var allLanguages = this.config.languages,
+		let allLanguages = this.config.languages,
 			unusedLanguages = this.getUnusedLanguages(),
 			items = this.getItems(),
 			languages,
@@ -123,11 +123,11 @@
 	 * @return {Object}
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getUsedLanguages = function () {
-		var allLanguages = this.config.languages,
+		const allLanguages = this.config.languages,
 			items = this.getItems();
 
-		return items.reduce( function ( obj, item ) {
-			var languageCode = item.getLanguage();
+		return items.reduce( ( obj, item ) => {
+			const languageCode = item.getLanguage();
 			obj[ languageCode ] = allLanguages[ languageCode ];
 			return obj;
 		}, {} );
@@ -140,11 +140,11 @@
 	 * @return {Object}
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getUnusedLanguages = function () {
-		var allLanguages = this.config.languages,
+		const allLanguages = this.config.languages,
 			usedLanguageCodes = Object.keys( this.getUsedLanguages() );
 
-		return Object.keys( allLanguages ).reduce( function ( remaining, language ) {
-			if ( usedLanguageCodes.indexOf( language ) < 0 ) {
+		return Object.keys( allLanguages ).reduce( ( remaining, language ) => {
+			if ( !usedLanguageCodes.includes( language ) ) {
 				remaining[ language ] = allLanguages[ language ];
 			}
 			return remaining;
@@ -155,7 +155,7 @@
 	 * Update the button label after adding or removing inputs.
 	 */
 	uw.MultipleLanguageInputWidget.prototype.recount = function () {
-		var text = this.getLabelText(),
+		const text = this.getLabelText(),
 			unusedLanguages = this.getUnusedLanguages();
 
 		this.addButton.setLabel( text );
@@ -174,7 +174,7 @@
 	 * @inheritdoc
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.getWikiText() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
@@ -185,12 +185,10 @@
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getErrors = function () {
 		// Gather errors from each item
-		var errorPromises = this.getItems().map( function ( item ) {
-			return item.getErrors();
-		} );
+		const errorPromises = this.getItems().map( ( item ) => item.getErrors() );
 
 		return $.when.apply( $, errorPromises ).then( function () {
-			var i, errors;
+			let i, errors;
 			errors = [];
 			// Fold all errors into a single one (they are displayed in the UI for each item, but we still
 			// need to return an error here to prevent form submission).
@@ -214,7 +212,7 @@
 	 * @return {Object} Object where the properties are language codes & values are input
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getValues = function () {
-		var values = {},
+		let values = {},
 			widgets = this.getItems(),
 			language,
 			text,
@@ -238,11 +236,7 @@
 	uw.MultipleLanguageInputWidget.prototype.getWikiText = function () {
 		// Some code here and in mw.UploadWizardDetails relies on this function returning an empty
 		// string when there are some inputs, but all are empty.
-		return this.getItems().map( function ( widget ) {
-			return widget.getWikiText();
-		} ).filter( function ( wikiText ) {
-			return !!wikiText;
-		} ).join( '\n' );
+		return this.getItems().map( ( widget ) => widget.getWikiText() ).filter( ( wikiText ) => !!wikiText ).join( '\n' );
 	};
 
 	/**
@@ -250,9 +244,7 @@
 	 * @return {Object} See #setSerialized
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getSerialized = function () {
-		var inputs = this.getItems().map( function ( widget ) {
-			return widget.getSerialized();
-		} );
+		const inputs = this.getItems().map( ( widget ) => widget.getSerialized() );
 		return {
 			inputs: inputs
 		};
@@ -265,7 +257,7 @@
 	 *   see uw.SingleLanguageInputWidget#setSerialized
 	 */
 	uw.MultipleLanguageInputWidget.prototype.setSerialized = function ( serialized ) {
-		var config = this.config,
+		let config = this.config,
 			i;
 
 		if ( typeof serialized === 'string' ) {
@@ -288,7 +280,7 @@
 	 * @return {string}
 	 */
 	uw.MultipleLanguageInputWidget.prototype.getCaption = function () {
-		var items = this.getItems();
+		const items = this.getItems();
 
 		if ( items.length > 0 ) {
 			return items[ 0 ].getCaption();
diff --git a/resources/details/uw.SingleLanguageInputWidget.js b/resources/details/uw.SingleLanguageInputWidget.js
index 53cf62b..7107d37 100644
--- a/resources/details/uw.SingleLanguageInputWidget.js
+++ b/resources/details/uw.SingleLanguageInputWidget.js
@@ -81,7 +81,7 @@
 	 * @private
 	 */
 	uw.SingleLanguageInputWidget.prototype.onRemoveClick = function () {
-		var element = this.getElementGroup();
+		const element = this.getElementGroup();
 
 		if ( element && typeof element.removeItems === 'function' ) {
 			element.removeItems( [ this ] );
@@ -120,7 +120,7 @@
 	 * @return {string}
 	 */
 	uw.SingleLanguageInputWidget.prototype.getDefaultLanguage = function () {
-		var defaultLanguage;
+		let defaultLanguage;
 
 		if ( this.defaultLanguage !== undefined ) {
 			return this.defaultLanguage;
@@ -153,7 +153,7 @@
 	 * @inheritdoc
 	 */
 	uw.SingleLanguageInputWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.textInput.getValue().trim() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
@@ -163,7 +163,7 @@
 	 * @inheritdoc
 	 */
 	uw.SingleLanguageInputWidget.prototype.getErrors = function () {
-		var
+		const
 			errors = [],
 			text = this.textInput.getValue().trim();
 
@@ -221,7 +221,7 @@
 	 * @inheritdoc
 	 */
 	uw.SingleLanguageInputWidget.prototype.getWikiText = function () {
-		var
+		let
 			language = this.getLanguage(),
 			text = this.getText();
 
diff --git a/resources/details/uw.TextWidget.js b/resources/details/uw.TextWidget.js
index 634e005..4a7f1f3 100644
--- a/resources/details/uw.TextWidget.js
+++ b/resources/details/uw.TextWidget.js
@@ -49,7 +49,7 @@
 	 * @inheritdoc
 	 */
 	uw.TextWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.textInput.getValue().trim() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
@@ -59,7 +59,7 @@
 	 * @inheritdoc
 	 */
 	uw.TextWidget.prototype.getErrors = function () {
-		var
+		const
 			errors = [],
 			text = this.textInput.getValue().trim();
 
diff --git a/resources/details/uw.TitleDetailsWidget.js b/resources/details/uw.TitleDetailsWidget.js
index cce0d4c..8e69895 100644
--- a/resources/details/uw.TitleDetailsWidget.js
+++ b/resources/details/uw.TitleDetailsWidget.js
@@ -1,6 +1,6 @@
 ( function ( uw ) {
 
-	var NS_FILE = mw.config.get( 'wgNamespaceIds' ).file,
+	const NS_FILE = mw.config.get( 'wgNamespaceIds' ).file,
 		byteLength = require( 'mediawiki.String' ).byteLength;
 
 	/**
@@ -44,7 +44,7 @@
 	 * @return {mw.Title|null}
 	 */
 	uw.TitleDetailsWidget.static.makeTitleInFileNS = function ( filename ) {
-		var
+		let
 			mwTitle = mw.Title.newFromText( filename, NS_FILE ),
 			illegalFileChars = new RegExp( '[' + mw.config.get( 'wgIllegalFileChars', '' ) + ']' );
 		if ( mwTitle && mwTitle.getNamespaceId() !== NS_FILE ) {
@@ -78,7 +78,7 @@
 	 * @return {mw.Title|null}
 	 */
 	uw.TitleDetailsWidget.prototype.getTitle = function () {
-		var value, extRegex, cleaned, title;
+		let value, extRegex, cleaned, title;
 		value = this.titleInput.getValue().trim();
 		if ( !value ) {
 			return null;
@@ -99,7 +99,7 @@
 	 * @inheritdoc
 	 */
 	uw.TitleDetailsWidget.prototype.getWarnings = function () {
-		var warnings = [];
+		const warnings = [];
 		this.getEmptyWarning( this.titleInput.getValue().trim() === '', warnings );
 
 		return $.Deferred().resolve( warnings ).promise();
@@ -109,7 +109,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.TitleDetailsWidget.prototype.getErrors = function () {
-		var
+		const
 			errors = [],
 			value = this.titleInput.getValue().trim(),
 			processDestinationCheck = this.processDestinationCheck,
@@ -142,28 +142,24 @@
 		}
 
 		return mw.DestinationChecker.checkTitle( title.getPrefixedText() )
-			.then( function ( result ) {
-				var moreErrors = processDestinationCheck( result );
+			.then( ( result ) => {
+				let moreErrors = processDestinationCheck( result );
 				if ( result.blacklist.unavailable ) {
 					// We don't have a title blacklist, so just check for some likely undesirable patterns.
 					moreErrors = moreErrors.concat(
-						mw.QuickTitleChecker.checkTitle( title.getNameText() ).map( function ( errorCode ) {
+						mw.QuickTitleChecker.checkTitle( title.getNameText() ).map( ( errorCode ) =>
 							// Messages that can be used here:
 							// * mediauploader-error-title-invalid
 							// * mediauploader-error-title-senselessimagename
 							// * mediauploader-error-title-thumbnail
 							// * mediauploader-error-title-extension
-							return mw.message( 'mediauploader-error-title-' + errorCode );
-						} )
+							 mw.message( 'mediauploader-error-title-' + errorCode )
+						 )
 					);
 				}
 				return moreErrors;
 			} )
-			.then( function ( moreErrors ) {
-				return [].concat( errors, moreErrors );
-			}, function () {
-				return $.Deferred().resolve( errors );
-			} );
+			.then( ( moreErrors ) => [].concat( errors, moreErrors ), () => $.Deferred().resolve( errors ) );
 	};
 
 	/**
@@ -175,7 +171,7 @@
 	 * @return {mw.Message[]} Error messages
 	 */
 	uw.TitleDetailsWidget.prototype.processDestinationCheck = function ( result ) {
-		var messageParams, errors, titleString;
+		let messageParams, errors, titleString;
 
 		if ( result.unique.isUnique && result.blacklist.notBlacklisted && !result.unique.isProtected ) {
 			return [];
diff --git a/resources/details/uw.UlsWidget.js b/resources/details/uw.UlsWidget.js
index 826aef6..54813ae 100644
--- a/resources/details/uw.UlsWidget.js
+++ b/resources/details/uw.UlsWidget.js
@@ -9,7 +9,7 @@
 	 * @cfg {Array} [classes] Classes to apply to the ULS container div
 	 */
 	uw.UlsWidget = function UWUlsWidget( config ) {
-		var i;
+		let i;
 
 		uw.UlsWidget.parent.call( this, config );
 
@@ -49,7 +49,7 @@
 	OO.mixinClass( uw.UlsWidget, OO.EventEmitter );
 
 	uw.UlsWidget.prototype.initialiseUls = function ( languages ) {
-		var ulsWidget = this;
+		const ulsWidget = this;
 
 		this.languages = languages;
 
@@ -63,7 +63,7 @@
 			onVisible: function () {
 				// Re-position the ULS *after* the widget has been rendered, so that we can be
 				// sure it's in the right place
-				var offset = ulsWidget.$element.offset();
+				const offset = ulsWidget.$element.offset();
 				if ( this.$menu.css( 'direction' ) === 'rtl' ) {
 					offset.left =
 						offset.left - parseInt( this.$menu.css( 'width' ) ) + ulsWidget.$element.width();
@@ -85,7 +85,7 @@
 	 * @param {string} value
 	 */
 	uw.UlsWidget.prototype.setValue = function ( value ) {
-		var current = this.languageValue;
+		const current = this.languageValue;
 		this.languageValue = value;
 		this.$element.find( '.oo-ui-labelElement-label' ).text( this.languages[ value ] );
 		if ( current !== value ) {
diff --git a/resources/ext.mediaUploader.campaignEditor.js b/resources/ext.mediaUploader.campaignEditor.js
index 3ca08a3..49d3aaf 100644
--- a/resources/ext.mediaUploader.campaignEditor.js
+++ b/resources/ext.mediaUploader.campaignEditor.js
@@ -3,7 +3,7 @@
 	/**
 	 * Sets up indentation settings appropriate for YAML if CodeEditor is loaded.
 	 */
-	mw.hook( 'codeEditor.configure' ).add( function ( session ) {
+	mw.hook( 'codeEditor.configure' ).add( ( session ) => {
 		session.setOptions( {
 			useSoftTabs: true,
 			tabSize: 2
diff --git a/resources/handlers/mw.ApiUploadFormDataHandler.js b/resources/handlers/mw.ApiUploadFormDataHandler.js
index d4ec9b1..e1a571f 100644
--- a/resources/handlers/mw.ApiUploadFormDataHandler.js
+++ b/resources/handlers/mw.ApiUploadFormDataHandler.js
@@ -18,7 +18,7 @@
 		this.transport = new mw.FormDataTransport(
 			this.api,
 			this.formData
-		).on( 'update-stage', function ( stage ) {
+		).on( 'update-stage', ( stage ) => {
 			upload.ui.setStatus( 'mediauploader-' + stage );
 		} );
 	};
@@ -33,15 +33,15 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.ApiUploadFormDataHandler.prototype.submit = function () {
-		var handler = this;
+		const handler = this;
 
-		return this.configureEditToken().then( function () {
+		return this.configureEditToken().then( () => {
 			handler.beginTime = Date.now();
 			handler.upload.ui.setStatus( 'mediauploader-transport-started' );
 			handler.upload.ui.showTransportProgress();
 
 			return handler.transport.upload( handler.upload.file, handler.upload.title.getMainText() )
-				.progress( function ( fraction ) {
+				.progress( ( fraction ) => {
 					if ( handler.upload.state === 'aborted' ) {
 						handler.abort();
 						return;
@@ -61,9 +61,9 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.ApiUploadFormDataHandler.prototype.configureEditToken = function () {
-		var handler = this;
+		const handler = this;
 
-		return this.api.getEditToken().then( function ( token ) {
+		return this.api.getEditToken().then( ( token ) => {
 			handler.formData.token = token;
 		} );
 	};
diff --git a/resources/handlers/mw.ApiUploadHandler.js b/resources/handlers/mw.ApiUploadHandler.js
index e84b50a..93beff8 100644
--- a/resources/handlers/mw.ApiUploadHandler.js
+++ b/resources/handlers/mw.ApiUploadHandler.js
@@ -1,5 +1,5 @@
 ( function () {
-	var NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;
+	const NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;
 
 	/**
 	 * @param {mw.UploadWizardUpload} upload
@@ -51,7 +51,7 @@
 	 * @param {Object} result
 	 */
 	mw.ApiUploadHandler.prototype.setTransported = function ( result ) {
-		var code;
+		let code;
 		if ( result.upload && result.upload.warnings ) {
 			for ( code in result.upload.warnings ) {
 				if ( !this.isIgnoredWarning( code ) ) {
@@ -81,7 +81,7 @@
 	 * @param {Object} result The API result in parsed JSON form
 	 */
 	mw.ApiUploadHandler.prototype.setTransportWarning = function ( code, result ) {
-		var param, duplicates, links;
+		let param, duplicates, links;
 
 		switch ( code ) {
 			case 'duplicate':
@@ -124,7 +124,7 @@
 	 * @param {Object} result The API result in parsed JSON form
 	 */
 	mw.ApiUploadHandler.prototype.setTransportError = function ( code, result ) {
-		var $extra;
+		let $extra;
 
 		if ( code === 'badtoken' ) {
 			this.api.badToken( 'csrf' );
@@ -142,10 +142,10 @@
 				title: mw.message( 'mediauploader-override-upload' ).text(),
 				flags: 'progressive',
 				framed: false
-			} ).on( 'click', function () {
+			} ).on( 'click', () => {
 				// No need to ignore the error, AbuseFilter will only return it once
 				this.start();
-			}.bind( this ) ).$element;
+			} ).$element;
 		}
 
 		this.setError( code, result.errors[ 0 ].html, $extra );
@@ -161,18 +161,18 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.ApiUploadHandler.prototype.processDuplicateError = function ( code, result, duplicates ) {
-		var files = this.getFileLinks( duplicates ),
+		const files = this.getFileLinks( duplicates ),
 			unknownAmount = duplicates.length - Object.keys( files ).length;
 
 		return this.getDuplicateSource( Object.keys( files ) ).then(
-			function ( data ) {
+			( data ) => {
 				this.setDuplicateError( code, result, data.local, data.foreign, unknownAmount );
-			}.bind( this ),
-			function () {
+			},
+			() => {
 				// if anything goes wrong trying to figure out the source of
 				// duplicates, just move on with local duplicate handling
 				this.setDuplicateError( code, result, files, {}, unknownAmount );
-			}.bind( this )
+			}
 		);
 	};
 
@@ -181,8 +181,8 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.ApiUploadHandler.prototype.getDuplicateSource = function ( duplicates ) {
-		return this.getImageInfo( duplicates, 'url' ).then( function ( result ) {
-			var local = [],
+		return this.getImageInfo( duplicates, 'url' ).then( ( result ) => {
+			const local = [],
 				foreign = [],
 				normalized = [];
 
@@ -192,13 +192,13 @@
 
 			// map of normalized titles, so we can find original title
 			if ( result.query.normalized ) {
-				result.query.normalized.forEach( function ( data ) {
+				result.query.normalized.forEach( ( data ) => {
 					normalized[ data.to ] = data.from;
 				} );
 			}
 
-			Object.keys( result.query.pages ).forEach( function ( pageId ) {
-				var page = result.query.pages[ pageId ],
+			Object.keys( result.query.pages ).forEach( ( pageId ) => {
+				const page = result.query.pages[ pageId ],
 					title = page.title in normalized ? normalized[ page.title ] : page.title;
 				if ( page.imagerepository === 'local' ) {
 					local[ title ] = page.imageinfo[ 0 ].descriptionurl;
@@ -221,7 +221,7 @@
 	 * @param {number} unknownAmount Amount of unknown filenames (e.g. revdeleted)
 	 */
 	mw.ApiUploadHandler.prototype.setDuplicateError = function ( code, result, localDuplicates, foreignDuplicates, unknownAmount ) {
-		var allDuplicates = Object.assign( {}, localDuplicates, foreignDuplicates ),
+		let allDuplicates = Object.assign( {}, localDuplicates, foreignDuplicates ),
 			$extra = $( '<div>' ),
 			$ul = $( '<ul>' ).appendTo( $extra ),
 			$a,
@@ -230,8 +230,8 @@
 
 		unknownAmount = unknownAmount || 0;
 
-		Object.keys( allDuplicates ).forEach( function ( filename ) {
-			var href = allDuplicates[ filename ];
+		Object.keys( allDuplicates ).forEach( ( filename ) => {
+			const href = allDuplicates[ filename ];
 			$a = $( '<a>' ).text( filename );
 			$a.attr( { href: href, target: '_blank' } );
 			$ul.append( $( '<li>' ).append( $a ) );
@@ -254,11 +254,11 @@
 				title: mw.message( 'mediauploader-override-upload' ).text(),
 				flags: 'progressive',
 				framed: false
-			} ).on( 'click', function () {
+			} ).on( 'click', () => {
 				// mark this warning as ignored & process the API result again
 				this.ignoreWarning( 'duplicate' );
 				this.setTransported( result );
-			}.bind( this ) );
+			} );
 
 			override.$element.appendTo( $extra );
 		}
@@ -274,17 +274,17 @@
 	 * @param {string} duplicate Duplicate filename
 	 */
 	mw.ApiUploadHandler.prototype.setDuplicateArchiveError = function ( code, result, duplicate ) {
-		var filename = mw.Title.makeTitle( NS_FILE, duplicate ).getPrefixedText(),
+		const filename = mw.Title.makeTitle( NS_FILE, duplicate ).getPrefixedText(),
 			uploadDuplicate = new OO.ui.ButtonWidget( {
 				label: mw.message( 'mediauploader-override' ).text(),
 				title: mw.message( 'mediauploader-override-upload' ).text(),
 				flags: 'progressive',
 				framed: false
-			} ).on( 'click', function () {
+			} ).on( 'click', () => {
 				// mark this warning as ignored & process the API result again
 				this.ignoreWarning( 'duplicate-archive' );
 				this.setTransported( result );
-			}.bind( this ) );
+			} );
 
 		this.setError( code, mw.message( 'file-deleted-duplicate', filename ).parse(), uploadDuplicate.$element );
 	};
@@ -310,10 +310,10 @@
 	 * @return {Object} Map of [prefixed filename => url]
 	 */
 	mw.ApiUploadHandler.prototype.getFileLinks = function ( filenames ) {
-		var files = [];
+		const files = [];
 
-		filenames.forEach( function ( filename ) {
-			var title;
+		filenames.forEach( ( filename ) => {
+			let title;
 			try {
 				title = mw.Title.makeTitle( NS_FILE, filename );
 				files[ title.getPrefixedText() ] = title.getUrl( {} );
@@ -357,6 +357,6 @@
 	 * @return {boolean}
 	 */
 	mw.ApiUploadHandler.prototype.isIgnoredWarning = function ( code ) {
-		return this.ignoreWarnings.indexOf( code ) > -1;
+		return this.ignoreWarnings.includes( code );
 	};
 }( mw.uploadWizard ) );
diff --git a/resources/jquery.arrowSteps/jquery.arrowSteps.js b/resources/jquery.arrowSteps/jquery.arrowSteps.js
index 81115f8..b098721 100644
--- a/resources/jquery.arrowSteps/jquery.arrowSteps.js
+++ b/resources/jquery.arrowSteps/jquery.arrowSteps.js
@@ -35,7 +35,7 @@
 	 * @chainable
 	 */
 	$.fn.arrowSteps = function () {
-		var $steps, width,
+		let $steps, width,
 			$el = this;
 
 		$el.addClass( 'arrowSteps' );
@@ -67,10 +67,10 @@
 	 * @param {string} selector
 	 */
 	$.fn.arrowStepsHighlight = function ( selector ) {
-		var $previous,
+		let $previous,
 			$steps = this.data( 'arrowSteps' );
 		$steps.each( function () {
-			var $step = $( this );
+			const $step = $( this );
 			if ( $step.is( selector ) ) {
 				if ( $previous ) {
 					$previous.addClass( 'tail' );
diff --git a/resources/jquery/jquery.morphCrossfade.js b/resources/jquery/jquery.morphCrossfade.js
index bc159ca..d6f79f3 100644
--- a/resources/jquery/jquery.morphCrossfade.js
+++ b/resources/jquery/jquery.morphCrossfade.js
@@ -47,7 +47,7 @@
 	 * @chainable
 	 */
 	$.fn.morphCrossfader = function () {
-		var $this = $( this );
+		const $this = $( this );
 		// the elements that are immediate children are the crossfadables
 		// they must all be "on top" of each other, so position them relative
 		$this.css( {
@@ -64,7 +64,7 @@
 		// should achieve the same result as crossfade( this.children().first() ) but without
 		// animation etc.
 		$this.each( function () {
-			var $container = $( this );
+			const $container = $( this );
 			$container.morphCrossfade( $container.children().first(), 0 );
 		} );
 
@@ -80,14 +80,14 @@
 	 * @chainable
 	 */
 	$.fn.morphCrossfade = function ( newPanelSelector, speed ) {
-		var $this = $( this );
+		const $this = $( this );
 
 		if ( typeof speed === 'undefined' ) {
 			speed = 400;
 		}
 
 		$this.each( function () {
-			var $container = $( this ),
+			const $container = $( this ),
 				$oldPanel = $( $container.data( 'crossfadeDisplay' ) ),
 				$newPanel = ( typeof newPanelSelector === 'string' ) ?
 					$container.find( newPanelSelector ) : $( newPanelSelector );
@@ -102,7 +102,7 @@
 					$oldPanel.css( { position: 'absolute' } );
 					// fade WITHOUT hiding when opacity = 0
 					// eslint-disable-next-line no-jquery/no-animate
-					$oldPanel.stop().animate( { opacity: 0 }, speed, 'linear', function () {
+					$oldPanel.stop().animate( { opacity: 0 }, speed, 'linear', () => {
 						$oldPanel.css( { visibility: 'hidden' } );
 					} );
 				}
@@ -110,7 +110,7 @@
 
 				$newPanel.css( { visibility: 'visible' } );
 				// eslint-disable-next-line no-jquery/no-animate
-				$container.stop().animate( { height: $newPanel.outerHeight() }, speed, 'linear', function () {
+				$container.stop().animate( { height: $newPanel.outerHeight() }, speed, 'linear', () => {
 					// we place it back into the flow, in case its size changes.
 					$newPanel.css( { position: 'relative' } );
 					// and allow the container to grow with it.
diff --git a/resources/mw.DestinationChecker.js b/resources/mw.DestinationChecker.js
index 6768d22..bcc18f6 100644
--- a/resources/mw.DestinationChecker.js
+++ b/resources/mw.DestinationChecker.js
@@ -22,13 +22,11 @@
 			return $.when(
 				this.checkUnique( title ),
 				this.checkBlacklist( title )
-			).then( function ( unique, blacklist ) {
-				return {
-					unique: unique,
-					blacklist: blacklist,
-					title: title
-				};
-			} );
+			).then( ( unique, blacklist ) => ( {
+				unique: unique,
+				blacklist: blacklist,
+				title: title
+			} ) );
 		},
 
 		/**
@@ -43,7 +41,7 @@
 		 *  {string} [return.done.blacklistLine] See mw.Api#isBlacklisted
 		 */
 		checkBlacklist: function ( title ) {
-			var checker = this;
+			const checker = this;
 
 			/**
 			 * Process result of a TitleBlacklist API call.
@@ -53,7 +51,7 @@
 			 * @return {Object}
 			 */
 			function blacklistResultProcessor( blacklistResult ) {
-				var result;
+				let result;
 
 				if ( blacklistResult === false ) {
 					result = { notBlacklisted: true };
@@ -74,12 +72,10 @@
 				return $.Deferred().resolve( this.cachedBlacklist[ title ] );
 			}
 
-			return mw.loader.using( 'mediawiki.api.titleblacklist' ).then( function () {
-				return checker.api.isBlacklisted( title ).then( blacklistResultProcessor );
-			}, function () {
+			return mw.loader.using( 'mediawiki.api.titleblacklist' ).then( () => checker.api.isBlacklisted( title ).then( blacklistResultProcessor ), () =>
 				// it's not blacklisted, because the API isn't even available
-				return $.Deferred().resolve( { notBlacklisted: true, unavailable: true } );
-			} );
+				 $.Deferred().resolve( { notBlacklisted: true, unavailable: true } )
+			 );
 		},
 
 		/**
@@ -95,7 +91,7 @@
 		 *  {string} [return.done.href] URL to file description page
 		 */
 		checkUnique: function ( title ) {
-			var checker = this,
+			let checker = this,
 				NS_FILE = mw.config.get( 'wgNamespaceIds' ).file,
 				titleObj, prefix, ext;
 
@@ -112,7 +108,7 @@
 			 * @return {Object}
 			 */
 			function checkUniqueProcessor( data ) {
-				var result, protection, pageId, ntitle, ntitleObj, img;
+				let result, protection, pageId, ntitle, ntitleObj, img;
 
 				result = { isUnique: true };
 
@@ -124,8 +120,8 @@
 					if ( data.query.pages[ -1 ] && !data.query.pages[ -1 ].imageinfo ) {
 						protection = data.query.pages[ -1 ].protection;
 						if ( protection && protection.length > 0 ) {
-							protection.forEach( function ( val ) {
-								if ( mw.config.get( 'wgUserGroups' ).indexOf( val.level ) === -1 ) {
+							protection.forEach( ( val ) => {
+								if ( !mw.config.get( 'wgUserGroups' ).includes( val.level ) ) {
 									result = {
 										isUnique: true,
 										isProtected: true
@@ -211,8 +207,8 @@
 					iiprop: 'url|mime|size',
 					iiurlwidth: 150
 				} ).then( checkUniqueProcessor )
-			).then( function ( exact, fuzzy ) {
-				var result;
+			).then( ( exact, fuzzy ) => {
+				let result;
 				if ( !exact.isUnique || exact.isProtected ) {
 					result = exact;
 				} else if ( !fuzzy.isUnique || fuzzy.isProtected ) {
diff --git a/resources/mw.Escaper.js b/resources/mw.Escaper.js
index d34b1d4..b5cfb7e 100644
--- a/resources/mw.Escaper.js
+++ b/resources/mw.Escaper.js
@@ -18,14 +18,12 @@
 		 * @return {string}
 		 */
 		escapePipes: function ( wikitext ) {
-			var extractedTemplates, extractedLinks;
+			let extractedTemplates, extractedLinks;
 
 			// Pipes (`|`) must be escaped because we'll be inserting this
 			// content into a templates & pipes would mess up the syntax.
 			// First, urlencode pipes inside links:
-			wikitext = wikitext.replace( /\bhttps?:\/\/[^\s]+/g, function ( match ) {
-				return match.replace( /\|/g, '%7C' );
-			} );
+			wikitext = wikitext.replace( /\bhttps?:\/\/[^\s]+/g, ( match ) => match.replace( /\|/g, '%7C' ) );
 
 			// Second, pipes can be valid inside other templates or links in
 			// wikitext, so we'll first extract those from the content, then
@@ -51,7 +49,7 @@
 		 * @return {Array} [{string} wikitext, {Object} replacements]
 		 */
 		extractTemplates: function ( wikitext ) {
-			var extracts = {},
+			let extracts = {},
 				previousExtracts = {},
 				extracted = wikitext,
 				// the regex explained:
@@ -62,7 +60,7 @@
 				//   sequence, generated by an earlier run of this regex
 				regex = /\{\{([^{]|\{(?!\{)|\{\{[0-9]+\}\})*?\}\}/g,
 				callback = function ( match ) {
-					var replacement = '{{' + Object.keys( extracts ).length + '}}';
+					const replacement = '{{' + Object.keys( extracts ).length + '}}';
 
 					// safeguard for not replacing already-replaced matches
 					// this makes sure that when real content contains something
@@ -96,10 +94,10 @@
 		 * @return {Array} [{string} wikitext, {Object} replacements]
 		 */
 		extractLinks: function ( wikitext ) {
-			var extracts = {};
+			const extracts = {};
 
-			wikitext = wikitext.replace( /\[\[.*?\]\]/g, function ( match ) {
-				var replacement = '[[' + Object.keys( extracts ).length + ']]';
+			wikitext = wikitext.replace( /\[\[.*?\]\]/g, ( match ) => {
+				const replacement = '[[' + Object.keys( extracts ).length + ']]';
 				extracts[ replacement ] = match;
 				return replacement;
 			} );
@@ -117,10 +115,10 @@
 		restoreExtracts: function ( wikitext, replacements ) {
 			// turn search keys into a regular expression, allowing us to match
 			// all of them at once
-			var searchValues = Object.keys( replacements ).map( mw.util.escapeRegExp ),
+			const searchValues = Object.keys( replacements ).map( mw.util.escapeRegExp ),
 				searchRegex = new RegExp( '(' + searchValues.join( '|' ) + ')', 'g' ),
 				callback = function ( match ) {
-					var replacement = replacements[ match ];
+					const replacement = replacements[ match ];
 
 					// we matched something that has no replacement, must be valid
 					// user input that just happens to look like on of the
diff --git a/resources/mw.GroupProgressBar.js b/resources/mw.GroupProgressBar.js
index 10c2bbe..d9c5fe3 100644
--- a/resources/mw.GroupProgressBar.js
+++ b/resources/mw.GroupProgressBar.js
@@ -56,30 +56,30 @@
 		 * loop around the uploads, summing certain properties for a weighted total fraction
 		 */
 		start: function () {
-			var bar = this,
+			let bar = this,
 				shown = false;
 
 			this.setBeginTime();
 
 			function displayer() {
-				var totalWeight = 0.0,
+				let totalWeight = 0.0,
 					fraction = 0.0,
 					successStateCount = 0,
 					errorStateCount = 0,
 					hasData = false;
 
-				bar.uploads.forEach( function ( upload ) {
+				bar.uploads.forEach( ( upload ) => {
 					totalWeight += upload[ bar.weightProperty ];
 				} );
 
-				bar.uploads.forEach( function ( upload ) {
+				bar.uploads.forEach( ( upload ) => {
 					if ( upload.state === 'aborted' ) {
 						return;
 					}
-					if ( bar.successStates.indexOf( upload.state ) !== -1 ) {
+					if ( bar.successStates.includes( upload.state ) ) {
 						successStateCount++;
 					}
-					if ( bar.errorStates.indexOf( upload.state ) !== -1 ) {
+					if ( bar.errorStates.includes( upload.state ) ) {
 						errorStateCount++;
 					}
 					if ( upload[ bar.progressProperty ] !== undefined ) {
@@ -106,7 +106,7 @@
 				} else {
 					bar.showProgress( 1.0 );
 					bar.finished = true;
-					setTimeout( function () {
+					setTimeout( () => {
 						bar.hideBar();
 					}, 500 );
 				}
@@ -142,7 +142,7 @@
 		 * @param {number} fraction The amount of whatever it is that's done whatever it's done
 		 */
 		showProgress: function ( fraction ) {
-			var t, timeString,
+			let t, timeString,
 				remainingTime = this.getRemainingTime( fraction );
 
 			this.progressBarWidget.setProgress( parseInt( fraction * 100, 10 ) );
@@ -168,7 +168,7 @@
 		 * @return {number} Estimated time remaining (in milliseconds)
 		 */
 		getRemainingTime: function ( fraction ) {
-			var elapsedTime, rate;
+			let elapsedTime, rate;
 			if ( this.beginTime ) {
 				elapsedTime = Date.now() - this.beginTime;
 				if ( fraction > 0.0 && elapsedTime > 0 ) { // or some other minimums for good data
@@ -185,7 +185,7 @@
 		 * @param {number} completed The number of items that have done whatever has been done e.g. in "uploaded 2 of 5", this is the 2
 		 */
 		showCount: function ( completed ) {
-			var total = this.uploads.length - this.countRemoved();
+			const total = this.uploads.length - this.countRemoved();
 			this.$selector
 				.find( '.mediauploader-count' )
 				// Hide if there are no uploads, show otherwise
@@ -194,8 +194,8 @@
 		},
 
 		countRemoved: function () {
-			var count = 0;
-			this.uploads.forEach( function ( upload ) {
+			let count = 0;
+			this.uploads.forEach( ( upload ) => {
 				if ( !upload || upload.state === 'aborted' ) {
 					count += 1;
 				}
diff --git a/resources/mw.QuickTitleChecker.js b/resources/mw.QuickTitleChecker.js
index 589cf37..d6723d5 100644
--- a/resources/mw.QuickTitleChecker.js
+++ b/resources/mw.QuickTitleChecker.js
@@ -70,10 +70,10 @@
 	 *   Possible error codes are 'invalid', 'senselessimagename', 'thumbnail', 'extension'.
 	 */
 	mw.QuickTitleChecker.checkTitle = function ( title ) {
-		var errors = [];
-		Object.keys( mw.QuickTitleChecker.regexSets ).forEach( function ( setName ) {
-			var regexes = mw.QuickTitleChecker.regexSets[ setName ];
-			regexes.forEach( function ( regex ) {
+		const errors = [];
+		Object.keys( mw.QuickTitleChecker.regexSets ).forEach( ( setName ) => {
+			const regexes = mw.QuickTitleChecker.regexSets[ setName ];
+			regexes.forEach( ( regex ) => {
 				if ( title.match( regex ) ) {
 					errors.push( setName );
 				}
diff --git a/resources/mw.UploadWizard.js b/resources/mw.UploadWizard.js
index a96c38e..5f3a29e 100644
--- a/resources/mw.UploadWizard.js
+++ b/resources/mw.UploadWizard.js
@@ -7,7 +7,7 @@
 ( function ( uw ) {
 
 	mw.UploadWizard = function ( config ) {
-		var maxSimPref;
+		let maxSimPref;
 
 		this.api = this.getApi( { ajax: { timeout: 0 } } );
 
@@ -49,7 +49,7 @@
 		createInterface: function ( selector ) {
 			this.ui = new uw.ui.Wizard( selector );
 
-			this.initialiseSteps().then( function ( steps ) {
+			this.initialiseSteps().then( ( steps ) => {
 				// "select" the first step - highlight, make it visible, hide all others
 				steps[ 0 ].load( [] );
 			} );
@@ -61,7 +61,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		initialiseSteps: function () {
-			var self = this,
+			let self = this,
 				steps = [],
 				i,
 				uploadStep;
@@ -98,7 +98,7 @@
 			steps[ steps.length - 1 ].setNextStep( uploadStep );
 
 			return $.Deferred().resolve( steps ).promise()
-				.always( function ( stepsInner ) {
+				.always( ( stepsInner ) => {
 					self.steps = stepsInner;
 					self.ui.initialiseSteps( stepsInner );
 				} );
@@ -119,10 +119,10 @@
 		 * @return {mw.Api}
 		 */
 		getApi: function ( options ) {
-			var api = new mw.Api( options );
+			const api = new mw.Api( options );
 
 			api.ajax = function ( parameters, ajaxOptions ) {
-				var original, override;
+				let original, override;
 
 				Object.assign( parameters, {
 					errorformat: 'html',
@@ -137,8 +137,8 @@
 				// output is always, reliably, in the same format
 				override = original.then(
 					null, // done handler - doesn't need overriding
-					function ( code, result ) { // fail handler
-						var response = { errors: [ {
+					( code, result ) => { // fail handler
+						let response = { errors: [ {
 							code: code,
 							html: result.textStatus || mw.message( 'api-clientside-error-invalidresponse' ).parse()
 						} ] };
@@ -183,10 +183,10 @@
 	 * @return {mw.deed.Abstract[]}
 	 */
 	mw.UploadWizard.getLicensingDeeds = function ( uploads, config ) {
-		var deed, api,
+		let deed, api,
 			deeds = {},
-			doOwnWork = config.licensing.showTypes.indexOf( 'ownWork' ) > -1,
-			doThirdParty = config.licensing.showTypes.indexOf( 'thirdParty' ) > -1;
+			doOwnWork = config.licensing.showTypes.includes( 'ownWork' ),
+			doThirdParty = config.licensing.showTypes.includes( 'thirdParty' );
 
 		if ( !config.licensing.enabled ) {
 			return {
diff --git a/resources/mw.UploadWizardDeedChooser.js b/resources/mw.UploadWizardDeedChooser.js
index 3cf37e3..88a7429 100644
--- a/resources/mw.UploadWizardDeedChooser.js
+++ b/resources/mw.UploadWizardDeedChooser.js
@@ -9,7 +9,7 @@
 	 * @param {mw.UploadWizardUpload[]} uploads Uploads that this applies to (this is just to make deleting and plurals work)
 	 */
 	mw.UploadWizardDeedChooser = function ( config, selector, deeds, uploads ) {
-		var chooser = this;
+		const chooser = this;
 		this.$selector = $( selector );
 		this.uploads = uploads;
 		this.deeds = deeds;
@@ -20,8 +20,8 @@
 
 		this.onLayoutReady = function () {};
 
-		Object.keys( this.deeds ).forEach( function ( name ) {
-			var deed = chooser.deeds[ name ],
+		Object.keys( this.deeds ).forEach( ( name ) => {
+			const deed = chooser.deeds[ name ],
 				radio = new OO.ui.RadioSelectWidget( {
 					items: [ new OO.ui.RadioOptionWidget( {
 						// eslint-disable-next-line mediawiki/msg-doc
@@ -53,7 +53,7 @@
 				if ( config.licensing.defaultType.toLowerCase() === deed.name ) {
 					chooser.onLayoutReady = chooser.selectDeed.bind( chooser, deed );
 				}
-				radio.on( 'choose', function () {
+				radio.on( 'choose', () => {
 					chooser.selectDeed( deed );
 				} );
 			}
@@ -84,7 +84,7 @@
 		uploads: [],
 
 		selectDeed: function ( deed ) {
-			var $deedInterface = this.$selector.find( '.mediauploader-deed.mediauploader-deed-' + deed.name );
+			const $deedInterface = this.$selector.find( '.mediauploader-deed.mediauploader-deed-' + deed.name );
 
 			this.choose( deed );
 			this.selectDeedInterface( $deedInterface );
@@ -92,11 +92,11 @@
 		},
 
 		choose: function ( deed ) {
-			var chooser = this;
+			const chooser = this;
 
 			this.deed = deed;
 
-			this.uploads.forEach( function ( upload ) {
+			this.uploads.forEach( ( upload ) => {
 				upload.deedChooser = chooser;
 			} );
 
@@ -112,7 +112,7 @@
 		deselectDeedInterface: function ( $deedSelector ) {
 			$deedSelector.removeClass( 'selected' );
 			$deedSelector.find( '.mediauploader-deed-form' ).each( function () {
-				var $form = $( this );
+				const $form = $( this );
 				// Prevent validation of deselected deeds by disabling all form inputs
 				// TODO: Use a tag selector
 				// eslint-disable-next-line no-jquery/no-sizzle
@@ -134,13 +134,13 @@
 		 * @param {jQuery} $deedSelector
 		 */
 		selectDeedInterface: function ( $deedSelector ) {
-			var $otherDeeds = $deedSelector.siblings().filter( '.mediauploader-deed' );
+			const $otherDeeds = $deedSelector.siblings().filter( '.mediauploader-deed' );
 			this.deselectDeedInterface( $otherDeeds );
 			// FIXME: Use CSS transition
 			// eslint-disable-next-line no-jquery/no-fade
 			$deedSelector.addClass( 'selected' ).fadeTo( 'fast', 1.0 );
 			$deedSelector.find( '.mediauploader-deed-form' ).each( function () {
-				var $form = $( this );
+				const $form = $( this );
 				// (Re-)enable all form inputs
 				// TODO: Use a tag selector
 				// eslint-disable-next-line no-jquery/no-sizzle
@@ -173,7 +173,7 @@
 		 * @param {Object} serialized
 		 */
 		setSerialized: function ( serialized ) {
-			var deed;
+			let deed;
 
 			if ( serialized.name && serialized.name in this.deeds ) {
 				deed = this.deeds[ serialized.name ];
diff --git a/resources/mw.UploadWizardDetails.js b/resources/mw.UploadWizardDetails.js
index c47e21e..30a63a6 100644
--- a/resources/mw.UploadWizardDetails.js
+++ b/resources/mw.UploadWizardDetails.js
@@ -1,6 +1,6 @@
 ( function ( uw ) {
 
-	var NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;
+	const NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;
 
 	/**
 	 * Object that represents the Details (step 2) portion of the UploadWizard
@@ -42,7 +42,7 @@
 		 * Build the interface and attach all elements - do this on demand.
 		 */
 		buildInterface: function () {
-			var $moreDetailsWrapperDiv, $moreDetailsDiv,
+			let $moreDetailsWrapperDiv, $moreDetailsDiv,
 				fKey, fSpec, fieldWidget, fieldWrapper, fConfigBase,
 				details = this,
 				config = mw.UploadWizard.config;
@@ -135,7 +135,7 @@
 				this.fieldMap[ fKey ] = fieldWidget;
 			}
 
-			this.fieldList.sort( function ( a, b ) {
+			this.fieldList.sort( ( a, b ) => {
 				if ( a.order < b.order ) {
 					return -1;
 				}
@@ -175,7 +175,7 @@
 					$moreDetailsDiv.append( fieldWrapper.$element );
 					// If something changes the input "hidden" in the collapsed section,
 					// expand it.
-					fieldWidget.on( 'change', function () {
+					fieldWidget.on( 'change', () => {
 						$moreDetailsWrapperDiv.data( 'mw-collapsible' ).expand();
 					} );
 				} else {
@@ -194,7 +194,7 @@
 				)
 				.makeCollapsible( { collapsed: true } );
 
-			this.$form.on( 'submit', function ( e ) {
+			this.$form.on( 'submit', ( e ) => {
 				// Prevent actual form submission
 				e.preventDefault();
 			} );
@@ -211,10 +211,10 @@
 				flags: 'destructive',
 				icon: 'trash',
 				framed: false
-			} ).on( 'click', function () {
+			} ).on( 'click', () => {
 				OO.ui.confirm( mw.message( 'mediauploader-license-confirm-remove' ).text(), {
 					title: mw.message( 'mediauploader-license-confirm-remove-title' ).text()
-				} ).done( function ( confirmed ) {
+				} ).done( ( confirmed ) => {
 					if ( confirmed ) {
 						details.upload.emit( 'remove-upload' );
 					}
@@ -272,7 +272,7 @@
 		 * Will only append once.
 		 */
 		attach: function () {
-			var $window = $( window ),
+			const $window = $( window ),
 				details = this;
 
 			function maybeBuild() {
@@ -301,7 +301,7 @@
 		 * @return {mw.Title|null}
 		 */
 		getTitle: function () {
-			var titleField = mw.UploadWizard.config.content.titleField;
+			const titleField = mw.UploadWizard.config.content.titleField;
 
 			// title will not be set until we've actually submitted the file
 			if ( this.title === undefined ) {
@@ -320,7 +320,7 @@
 		 * @chainable
 		 */
 		setDuplicateTitleError: function () {
-			var titleField = mw.UploadWizard.config.content.titleField;
+			const titleField = mw.UploadWizard.config.content.titleField;
 			// TODO This should give immediate response, not only when submitting the form
 			this.fieldWrapperMap[ titleField ].setErrors(
 				[ mw.message( 'mediauploader-error-title-duplicate' ) ]
@@ -357,9 +357,7 @@
 		 *   empty arrays.
 		 */
 		getErrors: function () {
-			return $.when.apply( $, this.getAllFields().map( function ( fieldLayout ) {
-				return fieldLayout.fieldWidget.getErrors();
-			} ) );
+			return $.when.apply( $, this.getAllFields().map( ( fieldLayout ) => fieldLayout.fieldWidget.getErrors() ) );
 		},
 
 		/**
@@ -368,9 +366,7 @@
 		 * @return {jQuery.Promise} Same as #getErrors
 		 */
 		getWarnings: function () {
-			return $.when.apply( $, this.getAllFields().map( function ( fieldLayout ) {
-				return fieldLayout.fieldWidget.getWarnings();
-			} ) );
+			return $.when.apply( $, this.getAllFields().map( ( fieldLayout ) => fieldLayout.fieldWidget.getWarnings() ) );
 		},
 
 		/**
@@ -380,12 +376,12 @@
 		 * @return {jQuery.Promise} Combined promise of all fields' validation results.
 		 */
 		checkValidity: function ( thorough ) {
-			var fields = this.getAllFields();
+			const fields = this.getAllFields();
 
-			return $.when.apply( $, fields.map( function ( fieldLayout ) {
+			return $.when.apply( $, fields.map( ( fieldLayout ) =>
 				// Update any error/warning messages
-				return fieldLayout.checkValidity( thorough );
-			} ) );
+				 fieldLayout.checkValidity( thorough )
+			 ) );
 		},
 
 		/**
@@ -394,7 +390,7 @@
 		 * @return {string}
 		 */
 		getThumbnailCaption: function () {
-			var captionField = mw.UploadWizard.config.content.captionField;
+			const captionField = mw.UploadWizard.config.content.captionField;
 
 			// The caption field should be one of:
 			// TextWidget, SingleLanguageInputWidget, MultipleLanguageInputWidget
@@ -409,7 +405,7 @@
 		 * @param {uw.DetailsWidget} widget
 		 */
 		prefillField: function ( fSpec, widget ) {
-			var dynPrefilled = false;
+			let dynPrefilled = false;
 
 			// Try dynamic prefilling, if requested and available for this type
 			if ( fSpec.autoFill ) {
@@ -447,7 +443,7 @@
 		 * @return {boolean}
 		 */
 		prefillDate: function ( widget ) {
-			var dateObj, metadata, dateStr, saneTime,
+			let dateObj, metadata, dateStr, saneTime,
 				dateMode = 'calendar',
 				yyyyMmDdRegex = /^(\d\d\d\d)[:/-](\d\d)[:/-](\d\d)\D.*/,
 				timeRegex = /\D(\d\d):(\d\d):(\d\d)/;
@@ -458,7 +454,7 @@
 			}
 
 			function getSaneTime( date ) {
-				var str = '';
+				let str = '';
 
 				str += pad( date.getHours() ) + ':';
 				str += pad( date.getMinutes() ) + ':';
@@ -469,8 +465,8 @@
 
 			if ( this.upload.imageinfo.metadata ) {
 				metadata = this.upload.imageinfo.metadata;
-				[ 'datetimeoriginal', 'datetimedigitized', 'datetime', 'date' ].some( function ( propName ) {
-					var matches, timeMatches,
+				[ 'datetimeoriginal', 'datetimedigitized', 'datetime', 'date' ].some( ( propName ) => {
+					let matches, timeMatches,
 						dateInfo = metadata[ propName ];
 					if ( dateInfo ) {
 						matches = dateInfo.trim().match( yyyyMmDdRegex );
@@ -551,7 +547,7 @@
 		 * @return {boolean}
 		 */
 		prefillDescription: function ( type, widget ) {
-			var m, descText;
+			let m, descText;
 
 			if (
 				widget.getWikiText() === '' &&
@@ -601,7 +597,7 @@
 		 * @return {boolean}
 		 */
 		prefillLocation: function ( widget ) {
-			var dir,
+			let dir,
 				m = this.upload.imageinfo.metadata,
 				modified = false,
 				values = {};
@@ -652,7 +648,7 @@
 		 * @return {Object}
 		 */
 		getLanguageOptions: function () {
-			var languages, code;
+			let languages, code;
 
 			languages = {};
 			for ( code in mw.UploadWizard.config.languages ) {
@@ -673,7 +669,7 @@
 		 * @return {Object.<string,Object>}
 		 */
 		getSerialized: function () {
-			var fieldWidget, serialized = {};
+			let fieldWidget, serialized = {};
 
 			if ( !this.interfaceBuilt ) {
 				// We don't have the interface yet, but it'll get filled out as
@@ -734,7 +730,7 @@
 		 * @return {string} wikitext representing all details
 		 */
 		getWikiText: function () {
-			var wikiText = mw.UploadWizard.config.content.wikitext,
+			let wikiText = mw.UploadWizard.config.content.wikitext,
 				substitutions = {}, substList = [],
 				deed = this.upload.deedChooser.deed,
 				fieldWidget, serialized, valueType, re, escapedKey, replaceValue;
@@ -750,7 +746,7 @@
 			}
 
 			function addSubstitution( key, value ) {
-				var v = value;
+				let v = value;
 				if ( key in substitutions ) {
 					return;
 				}
@@ -781,7 +777,7 @@
 					return;
 				}
 				// Also add "subfields" based on the serialized values. Just in case.
-				Object.keys( serialized ).forEach( function ( key ) {
+				Object.keys( serialized ).forEach( ( key ) => {
 					replaceValue = serialized[ key ];
 					valueType = typeof replaceValue;
 					if ( valueType === 'string' || valueType === 'number' || valueType === 'boolean' ) {
@@ -791,11 +787,11 @@
 			}, this );
 
 			// Do the substitutions
-			substList.forEach( function ( substKey ) {
+			substList.forEach( ( substKey ) => {
 				replaceValue = substitutions[ substKey ].trim();
 				escapedKey = substKey.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' );
 				re = new RegExp( '\\{\\{\\{ *' + escapedKey + ' *(\\|(.*?))?\\}\\}\\}', 'giu' );
-				wikiText = wikiText.replace( re, function ( match, _, defaultValue ) {
+				wikiText = wikiText.replace( re, ( match, _, defaultValue ) => {
 					if ( !replaceValue ) {
 						return defaultValue || '';
 					} else {
@@ -814,7 +810,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		submit: function () {
-			var details = this,
+			let details = this,
 				wikitext, promise;
 
 			this.$containerDiv.find( 'form' ).trigger( 'submit' );
@@ -827,7 +823,7 @@
 			wikitext = this.getWikiText();
 			promise = this.submitWikiText( wikitext );
 
-			return promise.then( function () {
+			return promise.then( () => {
 				details.showIndicator( 'success' );
 				details.setStatus( mw.message( 'mediauploader-published' ).text() );
 			} );
@@ -843,7 +839,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		submitWikiText: function ( wikiText ) {
-			var params,
+			let params,
 				tags = [ 'uploadwizard' ],
 				deed = this.upload.deedChooser.deed,
 				comment = '',
@@ -900,7 +896,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		submitWikiTextInternal: function ( params ) {
-			var details = this,
+			const details = this,
 				apiPromise = this.upload.api.postWithEditToken( params );
 
 			return apiPromise
@@ -910,7 +906,7 @@
 				.then( this.validateWikiTextSubmitResult.bind( this, params ) )
 				// making it here means the upload is a success, or it would've been
 				// rejected by now (either by HTTP status code, or in validateWikiTextSubmitResult)
-				.then( function ( result ) {
+				.then( ( result ) => {
 					details.title = mw.Title.makeTitle( 6, result.upload.filename );
 					details.upload.extractImageInfo( result.upload.imageinfo );
 					details.upload.thisProgress = 1.0;
@@ -918,7 +914,7 @@
 					return result;
 				} )
 				// uh-oh - something went wrong!
-				.catch( function ( code, result ) {
+				.catch( ( code, result ) => {
 					details.upload.state = 'error';
 					details.processError( code, result );
 					return $.Deferred().reject( code, result );
@@ -936,7 +932,7 @@
 		 * @return {jQuery.Promise}
 		 */
 		validateWikiTextSubmitResult: function ( params, result ) {
-			var wx, warningsKeys, existingFile, existingFileUrl, existingFileExt, ourFileExt, code, message,
+			let wx, warningsKeys, existingFile, existingFileUrl, existingFileExt, ourFileExt, code, message,
 				details = this,
 				warnings = null,
 				ignoreTheseWarnings = false,
@@ -961,7 +957,7 @@
 						// * mediauploader-publish
 						// * mediauploader-assembling
 						this.setStatus( mw.message( 'mediauploader-' + result.upload.stage ).text() );
-						setTimeout( function () {
+						setTimeout( () => {
 							if ( details.upload.state !== 'aborted' ) {
 								details.submitWikiTextInternal( {
 									action: 'upload',
@@ -1055,7 +1051,7 @@
 		 * @param {string} html Error message to show.
 		 */
 		recoverFromError: function ( code, html ) {
-			var titleField = mw.UploadWizard.config.content.titleField;
+			const titleField = mw.UploadWizard.config.content.titleField;
 
 			this.upload.state = 'recoverable-error';
 			this.$dataDiv.morphCrossfade( '.detailsForm' );
@@ -1080,7 +1076,7 @@
 		 * @param {Object} result Result from ajax call
 		 */
 		processError: function ( code, result ) {
-			var recoverable = [
+			const recoverable = [
 				'abusefilter-disallowed',
 				'abusefilter-warning',
 				'spamblacklist',
@@ -1117,7 +1113,7 @@
 				code = 'ratelimited';
 			}
 
-			if ( recoverable.indexOf( code ) > -1 ) {
+			if ( recoverable.includes( code ) ) {
 				this.recoverFromError( code, result.errors[ 0 ].html );
 				return;
 			}
diff --git a/resources/mw.UploadWizardLicenseInput.js b/resources/mw.UploadWizardLicenseInput.js
index b3696aa..00416ef 100644
--- a/resources/mw.UploadWizardLicenseInput.js
+++ b/resources/mw.UploadWizardLicenseInput.js
@@ -14,7 +14,7 @@
 	 * @param {mw.Api} api API object, used for wikitext previews
 	 */
 	mw.UploadWizardLicenseInput = function ( config, count, api ) {
-		var self = this,
+		let self = this,
 			groups = [],
 			group;
 
@@ -45,7 +45,7 @@
 			group = new uw.LicenseGroup( config, this.type, this.api, this.count );
 			groups.push( group );
 		} else {
-			config.licenseGroups.forEach( function ( groupConfig ) {
+			config.licenseGroups.forEach( ( groupConfig ) => {
 				group = new uw.LicenseGroup( groupConfig, self.type, self.api, self.count );
 				groups.push( group );
 
@@ -54,8 +54,8 @@
 				// upon selecting a new item in any group, iterate the other groups and make
 				// sure they're updated accordingly, deselecting previously selected items
 				if ( self.type === 'radio' ) {
-					group.on( 'change', function ( currentGroup ) {
-						var value = currentGroup.getValue(),
+					group.on( 'change', ( currentGroup ) => {
+						const value = currentGroup.getValue(),
 							group2 = currentGroup.getGroup();
 						self.setValues( value, group2 );
 					} );
@@ -76,7 +76,7 @@
 
 	Object.assign( mw.UploadWizardLicenseInput.prototype, {
 		unload: function () {
-			this.getItems().forEach( function ( group ) {
+			this.getItems().forEach( ( group ) => {
 				group.unload();
 			} );
 		},
@@ -89,10 +89,10 @@
 		 * @param {string} [groupName] Name of group, when values are only relevant to this group
 		 */
 		setValues: function ( values, groupName ) {
-			var self = this,
+			const self = this,
 				selectedGroups = [];
 
-			this.getItems().forEach( function ( group ) {
+			this.getItems().forEach( ( group ) => {
 				if ( groupName === undefined || group.getGroup() === groupName ) {
 					group.setValue( values );
 					if ( Object.keys( group.getValue() ).length > 0 ) {
@@ -115,7 +115,7 @@
 				// 1 group
 				// in that case, we're only going to select the *last* occurrence, which is what
 				// a browser would do when trying to find/select a radio that occurs twice
-				selectedGroups.forEach( function ( group ) {
+				selectedGroups.forEach( ( group ) => {
 					group.setValue( {} );
 				} );
 			}
@@ -125,8 +125,8 @@
 		 * Set the default configured licenses
 		 */
 		setDefaultValues: function () {
-			var values = {};
-			this.defaults.forEach( function ( license ) {
+			const values = {};
+			this.defaults.forEach( ( license ) => {
 				values[ license ] = true;
 			} );
 			this.setValues( values );
@@ -139,11 +139,11 @@
 		 * @return {Object}
 		 */
 		getLicenses: function () {
-			var licenses = {};
+			const licenses = {};
 
-			this.getItems().forEach( function ( group ) {
-				var licenseNames = Object.keys( group.getValue() );
-				licenseNames.forEach( function ( name ) {
+			this.getItems().forEach( ( group ) => {
+				const licenseNames = Object.keys( group.getValue() );
+				licenseNames.forEach( ( name ) => {
 					licenses[ name ] = mw.UploadWizard.config.licenses[ name ] || {};
 				} );
 			} );
@@ -157,9 +157,7 @@
 		 * @return {string} of wikitext (empty string if no inputs set)
 		 */
 		getWikiText: function () {
-			return this.getItems().map( function ( group ) {
-				return group.getWikiText();
-			} ).join( '' ).trim();
+			return this.getItems().map( ( group ) => group.getWikiText() ).join( '' ).trim();
 		},
 
 		/**
@@ -169,7 +167,7 @@
 		 * @return {jQuery.Promise} Promise that resolves with an array of template names
 		 */
 		getUsedTemplates: function ( wikitext ) {
-			var input = this;
+			const input = this;
 
 			if ( wikitext in this.templateCache ) {
 				return $.Deferred().resolve( this.templateCache[ wikitext ] ).promise();
@@ -181,8 +179,8 @@
 				prop: 'templates',
 				title: 'File:UploadWizard license verification.png',
 				text: wikitext
-			} ).then( function ( result ) {
-				var templates = [],
+			} ).then( ( result ) => {
+				let templates = [],
 					template, title, i;
 
 				for ( i = 0; i < result.parse.templates.length; i++ ) {
@@ -207,9 +205,9 @@
 		 * @return {jQuery.Promise}
 		 */
 		getErrors: function () {
-			var errors = $.Deferred().resolve( [] ).promise(),
+			let errors = $.Deferred().resolve( [] ).promise(),
 				addError = function ( message ) {
-					errors = errors.then( function ( errorsCopy ) {
+					errors = errors.then( ( errorsCopy ) => {
 						// eslint-disable-next-line mediawiki/msg-doc
 						errorsCopy.push( mw.message( message ) );
 						return errorsCopy;
@@ -223,8 +221,8 @@
 				// It's pretty hard to screw up a radio button, so if even one of them is selected it's okay.
 				// But also check that associated textareas are filled for if the input is selected, and that
 				// they are the appropriate size.
-				Object.keys( selectedInputs ).forEach( function ( name ) {
-					var wikitext,
+				Object.keys( selectedInputs ).forEach( ( name ) => {
+					let wikitext,
 						data = selectedInputs[ name ];
 
 					if ( typeof data !== 'string' ) {
@@ -259,10 +257,10 @@
 		 * @return {Object}
 		 */
 		getSerialized: function () {
-			var values = {};
+			const values = {};
 
-			this.getItems().forEach( function ( group ) {
-				var groupName = group.getGroup(),
+			this.getItems().forEach( ( group ) => {
+				const groupName = group.getGroup(),
 					value = group.getValue();
 
 				if ( Object.keys( value ).length > 0 ) {
@@ -278,9 +276,9 @@
 		 * @param {Object} serialized
 		 */
 		setSerialized: function ( serialized ) {
-			var self = this;
+			const self = this;
 
-			Object.keys( serialized ).forEach( function ( group ) {
+			Object.keys( serialized ).forEach( ( group ) => {
 				self.setValues( serialized[ group ], group );
 			} );
 		}
diff --git a/resources/mw.UploadWizardPage.js b/resources/mw.UploadWizardPage.js
index c874700..02f8086 100644
--- a/resources/mw.UploadWizardPage.js
+++ b/resources/mw.UploadWizardPage.js
@@ -10,7 +10,7 @@
 ( function () {
 
 	function isCompatible() {
-		var
+		const
 			profile = $.client.profile(),
 			// Firefox < 7.0 sends an empty string as filename for Blobs in FormData.
 			// requests. https://bugzilla.mozilla.org/show_bug.cgi?id=649150
@@ -27,7 +27,7 @@
 
 	mw.UploadWizardPage = function () {
 
-		var uploadWizard,
+		let uploadWizard,
 			config = mw.config.get( 'MediaUploaderConfig' );
 
 		// Default configuration value that cannot be removed
@@ -54,7 +54,7 @@
 		uploadWizard.createInterface( '#upload-wizard' );
 	};
 
-	$( function () {
+	$( () => {
 		// show page.
 		mw.UploadWizardPage();
 	} );
diff --git a/resources/mw.UploadWizardUpload.js b/resources/mw.UploadWizardUpload.js
index a8ce368..b6db80f 100644
--- a/resources/mw.UploadWizardUpload.js
+++ b/resources/mw.UploadWizardUpload.js
@@ -167,7 +167,7 @@
 	 * @return {string} basename
 	 */
 	mw.UploadWizardUpload.prototype.getBasename = function () {
-		var path = this.getFilename();
+		const path = this.getFilename();
 
 		if ( path === undefined || path === null ) {
 			return '';
@@ -200,7 +200,7 @@
 	 * @return {jQuery.Promise} A promise, resolved when we're done
 	 */
 	mw.UploadWizardUpload.prototype.extractMetadataFromJpegMeta = function () {
-		var binReader, jpegmeta,
+		let binReader, jpegmeta,
 			deferred = $.Deferred(),
 			upload = this;
 		if ( this.file && this.file.type === 'image/jpeg' ) {
@@ -209,7 +209,7 @@
 				deferred.resolve();
 			};
 			binReader.onload = function () {
-				var binStr, arr, i, meta;
+				let binStr, arr, i, meta;
 				if ( binReader.result === null ) {
 					// Contrary to documentation, this sometimes fires for unsuccessful loads (T136235)
 					deferred.resolve();
@@ -254,7 +254,7 @@
 	 * @param {Object} meta As returned by jpegmeta
 	 */
 	mw.UploadWizardUpload.prototype.extractMetadataFromJpegMetaCallback = function ( meta ) {
-		var pixelHeightDim, pixelWidthDim, degrees;
+		let pixelHeightDim, pixelWidthDim, degrees;
 
 		if ( meta !== undefined && meta !== null && typeof meta === 'object' ) {
 			if ( this.imageinfo.metadata === undefined ) {
@@ -310,7 +310,7 @@
 	 * @param {Object} imageinfo JSON object obtained from API result.
 	 */
 	mw.UploadWizardUpload.prototype.extractImageInfo = function ( imageinfo ) {
-		var key,
+		let key,
 			upload = this;
 
 		for ( key in imageinfo ) {
@@ -320,7 +320,7 @@
 					this.imageinfo.metadata = {};
 				}
 				if ( imageinfo.metadata && imageinfo.metadata.length ) {
-					imageinfo.metadata.forEach( function ( pair ) {
+					imageinfo.metadata.forEach( ( pair ) => {
 						if ( pair !== undefined ) {
 							upload.imageinfo.metadata[ pair.name.toLowerCase() ] = pair.value;
 						}
@@ -343,7 +343,7 @@
 	 * @param {number} [height] Height of thumbnail. Will force 'url' to be added to props
 	 */
 	mw.UploadWizardUpload.prototype.getStashImageInfo = function ( callback, props, width, height ) {
-		var params = {
+		const params = {
 			prop: 'stashimageinfo',
 			siifilekey: this.fileKey,
 			siiprop: props.join( '|' )
@@ -368,7 +368,7 @@
 		}
 
 		if ( width !== undefined || height !== undefined ) {
-			if ( props.indexOf( 'url' ) === -1 ) {
+			if ( !props.includes( 'url' ) ) {
 				props.push( 'url' );
 			}
 			if ( width !== undefined ) {
@@ -393,15 +393,15 @@
 	 * @param {number} [height] Height of thumbnail. Will force 'url' to be added to props
 	 */
 	mw.UploadWizardUpload.prototype.getImageInfo = function ( callback, props, width, height ) {
-		var requestedTitle, params;
+		let requestedTitle, params;
 
 		function ok( data ) {
-			var found;
+			let found;
 
 			if ( data && data.query && data.query.pages ) {
 				found = false;
-				Object.keys( data.query.pages ).forEach( function ( pageId ) {
-					var page = data.query.pages[ pageId ];
+				Object.keys( data.query.pages ).forEach( ( pageId ) => {
+					const page = data.query.pages[ pageId ];
 					if ( page.title && page.title === requestedTitle && page.imageinfo ) {
 						found = true;
 						callback( page.imageinfo );
@@ -434,7 +434,7 @@
 		};
 
 		if ( width !== undefined || height !== undefined ) {
-			if ( props.indexOf( 'url' ) === -1 ) {
+			if ( !props.includes( 'url' ) ) {
 				props.push( 'url' );
 			}
 			if ( width !== undefined ) {
@@ -454,7 +454,7 @@
 	 * @return {mw.ApiUploadFormDataHandler} upload handler object
 	 */
 	mw.UploadWizardUpload.prototype.getUploadHandler = function () {
-		var constructor; // must be the name of a function in 'mw' namespace
+		let constructor; // must be the name of a function in 'mw' namespace
 
 		if ( !this.uploadHandler ) {
 			constructor = 'ApiUploadFormDataHandler';
@@ -473,7 +473,7 @@
 	 *     couldn't be generated
 	 */
 	mw.UploadWizardUpload.prototype.getApiThumbnail = function ( width, height ) {
-		var deferred = $.Deferred();
+		const deferred = $.Deferred();
 
 		function thumbnailPublisher( thumbnails ) {
 			if ( thumbnails === null ) {
@@ -484,8 +484,8 @@
 				// they are actually there yet. Keep trying to set the source ( which should trigger "error" or "load" event )
 				// on the image. If it loads publish the event with the image. If it errors out too many times, give up and publish
 				// the event with a null.
-				thumbnails.forEach( function ( thumb ) {
-					var timeoutMs, image;
+				thumbnails.forEach( ( thumb ) => {
+					let timeoutMs, image;
 
 					if ( thumb.thumberror || ( !( thumb.thumburl && thumb.thumbwidth && thumb.thumbheight ) ) ) {
 						mw.log.warn( 'mw.UploadWizardUpload::getThumbnail> Thumbnail error or missing information' );
@@ -507,14 +507,14 @@
 					image.width = thumb.thumbwidth;
 					image.height = thumb.thumbheight;
 					$( image )
-						.on( 'load', function () {
+						.on( 'load', () => {
 							// publish the image to anyone who wanted it
 							deferred.resolve( image );
 						} )
-						.on( 'error', function () {
+						.on( 'error', () => {
 							// retry with exponential backoff
 							if ( timeoutMs < 8000 ) {
-								setTimeout( function () {
+								setTimeout( () => {
 									timeoutMs = timeoutMs * 2 + Math.round( Math.random() * ( timeoutMs / 10 ) );
 									setSrc();
 								}, timeoutMs );
@@ -545,7 +545,7 @@
 	 * @return {number} orientation in degrees: 0, 90, 180 or 270
 	 */
 	mw.UploadWizardUpload.prototype.getOrientationDegrees = function () {
-		var orientation = 0;
+		let orientation = 0;
 		if ( this.imageinfo && this.imageinfo.metadata && this.imageinfo.metadata.orientation ) {
 			switch ( this.imageinfo.metadata.orientation ) {
 				case 8:
@@ -579,9 +579,9 @@
 	 * @return {number}
 	 */
 	mw.UploadWizardUpload.prototype.getScalingFromConstraints = function ( image, constraints ) {
-		var scaling = 1;
-		Object.keys( constraints ).forEach( function ( dim ) {
-			var s,
+		let scaling = 1;
+		Object.keys( constraints ).forEach( ( dim ) => {
+			let s,
 				constraint = constraints[ dim ];
 			if ( constraint && image[ dim ] > constraint ) {
 				s = constraint / image[ dim ];
@@ -603,7 +603,7 @@
 	 * @return {HTMLCanvasElement|null}
 	 */
 	mw.UploadWizardUpload.prototype.getTransformedCanvasElement = function ( image, constraints ) {
-		var angle, scaling, width, height,
+		let angle, scaling, width, height,
 			dimensions, dx, dy, x, y, $canvas, ctx,
 			scaleConstraints = constraints,
 			rotation = 0;
@@ -693,7 +693,7 @@
 	 * @return {HTMLImageElement} with same src, but different attrs
 	 */
 	mw.UploadWizardUpload.prototype.getBrowserScaledImageElement = function ( image, constraints ) {
-		var scaling = this.getScalingFromConstraints( image, constraints );
+		const scaling = this.getScalingFromConstraints( image, constraints );
 		return $( '<img>' )
 			.attr( {
 				width: parseInt( image.width * scaling, 10 ),
@@ -712,7 +712,7 @@
 	 * @return {HTMLCanvasElement|HTMLImageElement}
 	 */
 	mw.UploadWizardUpload.prototype.getScaledImageElement = function ( image, width, height ) {
-		var constraints = {},
+		let constraints = {},
 			transform;
 
 		if ( width ) {
@@ -742,7 +742,7 @@
 	 *   containing a thumbnail, or resolved with `null` when one can't be produced
 	 */
 	mw.UploadWizardUpload.prototype.getThumbnail = function ( width, height ) {
-		var upload = this,
+		const upload = this,
 			deferred = $.Deferred();
 
 		if ( this.thumbnailPromise[ width + 'x' + height ] ) {
@@ -767,14 +767,14 @@
 		this.extractMetadataFromJpegMeta()
 			.then( upload.makePreview.bind( upload, width ) )
 			.done( imageCallback )
-			.fail( function () {
+			.fail( () => {
 				// Can't generate the thumbnail locally, get the thumbnail via API after
 				// the file is uploaded. Queries are cached, so if this thumbnail was
 				// already fetched for some reason, we'll get it immediately.
 				if ( upload.state !== 'new' && upload.state !== 'transporting' && upload.state !== 'error' ) {
 					upload.getApiThumbnail( width, height ).done( imageCallback );
 				} else {
-					upload.once( 'success', function () {
+					upload.once( 'success', () => {
 						upload.getApiThumbnail( width, height ).done( imageCallback );
 					} );
 				}
@@ -798,7 +798,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.UploadWizardUpload.prototype.makePreview = function ( width ) {
-		var first, video, url, dataUrlReader,
+		let first, video, url, dataUrlReader,
 			deferred = $.Deferred(),
 			upload = this;
 
@@ -809,12 +809,12 @@
 				first = true;
 				video = document.createElement( 'video' );
 
-				video.addEventListener( 'loadedmetadata', function () {
+				video.addEventListener( 'loadedmetadata', () => {
 					// seek 2 seconds into video or to half if shorter
 					video.currentTime = Math.min( 2, video.duration / 2 );
 					video.volume = 0;
 				} );
-				video.addEventListener( 'seeked', function () {
+				video.addEventListener( 'seeked', () => {
 					// Firefox 16 sometimes does not work on first seek, seek again
 					if ( first ) {
 						first = false;
@@ -823,8 +823,8 @@
 					} else {
 						// Chrome sometimes shows black frames if grabbing right away.
 						// wait 500ms before grabbing frame
-						setTimeout( function () {
-							var context,
+						setTimeout( () => {
+							let context,
 								canvas = document.createElement( 'canvas' );
 							canvas.width = width;
 							canvas.height = Math.round( canvas.width * video.videoHeight / video.videoWidth );
@@ -844,7 +844,7 @@
 				video.src = url;
 				// If we can't get a frame within 10 seconds, something is probably seriously wrong.
 				// This can happen for broken files where we can't actually seek to the time we wanted.
-				setTimeout( function () {
+				setTimeout( () => {
 					deferred.reject();
 					upload.URL().revokeObjectURL( video.url );
 				}, 10000 );
@@ -871,7 +871,7 @@
 	 * @param {jQuery.Deferred} deferred
 	 */
 	mw.UploadWizardUpload.prototype.loadImage = function ( url, deferred ) {
-		var image = document.createElement( 'img' );
+		const image = document.createElement( 'img' );
 		image.onload = function () {
 			deferred.resolve( image );
 		};
diff --git a/resources/mw.UploadWizardUploadInterface.js b/resources/mw.UploadWizardUploadInterface.js
index 263787d..610a2bb 100644
--- a/resources/mw.UploadWizardUploadInterface.js
+++ b/resources/mw.UploadWizardUploadInterface.js
@@ -7,7 +7,7 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	mw.UploadWizardUploadInterface = function MWUploadWizardUploadInterface( upload ) {
-		var ui = this;
+		const ui = this;
 
 		OO.EventEmitter.call( this );
 
@@ -47,7 +47,7 @@
 			flags: 'destructive',
 			icon: 'trash',
 			framed: false
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			ui.emit( 'upload-removed' );
 		} );
 
@@ -63,7 +63,7 @@
 		// this.progressBar = ( no progress bar for individual uploads yet )
 		// we bind to the ui div since .off() doesn't work for non-DOM objects
 		// TODO Convert this to an OO.EventEmitter, and use OOjs events
-		this.$div.on( 'transportProgressEvent', function () {
+		this.$div.on( 'transportProgressEvent', () => {
 			ui.showTransportProgress();
 		} );
 	};
@@ -96,7 +96,7 @@
 	 */
 	mw.UploadWizardUploadInterface.prototype.setStatus = function ( msgKey, args ) {
 		// get the status line for our upload
-		var $status = this.$div.find( '.mediauploader-file-status' );
+		const $status = this.$div.find( '.mediauploader-file-status' );
 		// eslint-disable-next-line mediawiki/msg-doc
 		$status.msg( msgKey, args || [] ).show();
 	};
@@ -176,7 +176,7 @@
 	 * @param {File} file
 	 */
 	mw.UploadWizardUploadInterface.prototype.fileChangedOk = function ( imageinfo, file ) {
-		var statusItems = [];
+		const statusItems = [];
 
 		this.updateFilename();
 
@@ -200,10 +200,10 @@
 	 *     fails
 	 */
 	mw.UploadWizardUploadInterface.prototype.showThumbnail = function () {
-		var $preview = this.$div.find( '.mediauploader-file-preview' ),
+		const $preview = this.$div.find( '.mediauploader-file-preview' ),
 			deferred = $.Deferred();
 		// This must match the CSS dimensions of .mediauploader-file-preview
-		this.upload.getThumbnail( 120, 120 ).done( function ( thumb ) {
+		this.upload.getThumbnail( 120, 120 ).done( ( thumb ) => {
 			mw.UploadWizard.placeThumbnail( $preview, thumb );
 			deferred.resolve();
 		} );
@@ -219,7 +219,7 @@
 	 *       TODO silently fix to have unique filename? unnecessary at this point...
 	 */
 	mw.UploadWizardUploadInterface.prototype.updateFilename = function () {
-		var path = this.upload.getFilename();
+		const path = this.upload.getFilename();
 
 		// visible filename
 		this.$form.find( '.mediauploader-visible-file-filename-text' )
diff --git a/resources/mw.fileApi.js b/resources/mw.fileApi.js
index cb80590..9216c24 100644
--- a/resources/mw.fileApi.js
+++ b/resources/mw.fileApi.js
@@ -15,9 +15,9 @@
 		 * @return {boolean}
 		 */
 		isPreviewableFile: function ( file ) {
-			var known = [ 'image/png', 'image/gif', 'image/jpeg' ],
+			const known = [ 'image/png', 'image/gif', 'image/jpeg' ],
 				tooHuge = 10 * 1024 * 1024;
-			return this.isPreviewableVideo( file ) || ( known.indexOf( file.type ) !== -1 ) && file.size > 0 && file.size < tooHuge;
+			return this.isPreviewableVideo( file ) || ( known.includes( file.type ) ) && file.size > 0 && file.size < tooHuge;
 		},
 
 		/**
@@ -27,7 +27,7 @@
 		 * @return {boolean}
 		 */
 		isPreviewableVideo: function ( file ) {
-			var video = document.createElement( 'video' );
+			const video = document.createElement( 'video' );
 			return video.canPlayType && video.canPlayType( file.type ).replace( 'no', '' ) !== '';
 		}
 
diff --git a/resources/transports/mw.FormDataTransport.js b/resources/transports/mw.FormDataTransport.js
index 95daece..b1c86ec 100644
--- a/resources/transports/mw.FormDataTransport.js
+++ b/resources/transports/mw.FormDataTransport.js
@@ -48,7 +48,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.post = function ( params ) {
-		var deferred = $.Deferred();
+		const deferred = $.Deferred();
 
 		this.request = this.api.post( params, {
 			/*
@@ -66,9 +66,9 @@
 			 * out how much of the upload has already gone out, so let's add it!
 			 */
 			xhr: function () {
-				var xhr = $.ajaxSettings.xhr();
-				xhr.upload.addEventListener( 'progress', function ( evt ) {
-					var fraction = null;
+				const xhr = $.ajaxSettings.xhr();
+				xhr.upload.addEventListener( 'progress', ( evt ) => {
+					let fraction = null;
 					if ( evt.lengthComputable ) {
 						fraction = parseFloat( evt.loaded / evt.total );
 					}
@@ -92,7 +92,7 @@
 	 * @return {Object}
 	 */
 	mw.FormDataTransport.prototype.createParams = function ( filename, offset ) {
-		var params = OO.cloneObject( this.formData );
+		const params = OO.cloneObject( this.formData );
 
 		Object.assign( params, {
 			filename: filename,
@@ -118,7 +118,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.upload = function ( file, tempFileName ) {
-		var params, ext;
+		let params, ext;
 
 		this.tempname = tempFileName;
 		// Limit length to 240 bytes (limit hardcoded in UploadBase.php).
@@ -150,7 +150,7 @@
 	 *   promise from #upload
 	 */
 	mw.FormDataTransport.prototype.chunkedUpload = function ( file ) {
-		var
+		let
 			offset,
 			prevPromise = $.Deferred().resolve(),
 			deferred = $.Deferred(),
@@ -162,15 +162,15 @@
 			// Capture offset in a closure
 			// eslint-disable-next-line no-loop-func
 			( function ( offset2 ) {
-				var
+				const
 					newPromise = $.Deferred(),
 					isLastChunk = offset2 + chunkSize >= fileSize,
 					thisChunkSize = isLastChunk ? ( fileSize % chunkSize ) : chunkSize;
-				prevPromise.done( function () {
+				prevPromise.done( () => {
 					transport.uploadChunk( file, offset2 )
 						.done( isLastChunk ? deferred.resolve : newPromise.resolve )
 						.fail( deferred.reject )
-						.progress( function ( fraction ) {
+						.progress( ( fraction ) => {
 							// The progress notifications give us per-chunk progress.
 							// Calculate progress for the whole file.
 							deferred.notify( ( offset2 + fraction * thisChunkSize ) / fileSize );
@@ -191,7 +191,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.uploadChunk = function ( file, offset ) {
-		var params = this.createParams( this.tempname, offset ),
+		let params = this.createParams( this.tempname, offset ),
 			transport = this,
 			bytesAvailable = file.size,
 			chunk;
@@ -229,7 +229,7 @@
 		params.filesize = bytesAvailable;
 		params.chunk = chunk;
 
-		return this.post( params ).then( function ( response ) {
+		return this.post( params ).then( ( response ) => {
 			if ( response.upload && response.upload.filekey ) {
 				transport.filekey = response.upload.filekey;
 			}
@@ -256,7 +256,7 @@
 					file, offset
 				);
 			}
-		}, function ( code, result ) {
+		}, ( code, result ) => {
 			// Ain't this some great machine readable output eh
 			if (
 				result.errors &&
@@ -323,7 +323,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.retryWithMethod = function ( methodName, file, offset ) {
-		var
+		const
 			transport = this,
 			retryDeferred = $.Deferred(),
 			retry = function () {
@@ -345,7 +345,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	mw.FormDataTransport.prototype.checkStatus = function () {
-		var transport = this,
+		const transport = this,
 			params = OO.cloneObject( this.formData );
 
 		if ( this.aborted ) {
@@ -363,7 +363,7 @@
 		params.checkstatus = true;
 		params.filekey = this.filekey;
 		this.request = this.api.post( params )
-			.then( function ( response ) {
+			.then( ( response ) => {
 				if ( response.upload && response.upload.result === 'Poll' ) {
 					// If concatenation takes longer than 10 minutes give up
 					if ( ( Date.now() - transport.firstPoll ) > 10 * 60 * 1000 ) {
@@ -390,9 +390,7 @@
 				}
 
 				return response;
-			}, function ( code, result ) {
-				return $.Deferred().reject( code, result );
-			} );
+			}, ( code, result ) => $.Deferred().reject( code, result ) );
 
 		return this.request;
 	};
diff --git a/resources/ui/steps/uw.ui.Deed.js b/resources/ui/steps/uw.ui.Deed.js
index 21dcf59..e556430 100644
--- a/resources/ui/steps/uw.ui.Deed.js
+++ b/resources/ui/steps/uw.ui.Deed.js
@@ -36,7 +36,7 @@
 	OO.inheritClass( uw.ui.Deed, uw.ui.Step );
 
 	uw.ui.Deed.prototype.load = function ( uploads ) {
-		var ui = this;
+		const ui = this;
 
 		uw.ui.Step.prototype.load.call( this, uploads );
 
@@ -52,7 +52,7 @@
 				.addClass( 'ui-helper-clearfix' )
 		);
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			// hide "next" button, controller will only show it once license has
 			// been selected
 			ui.nextButton.$element.hide();
diff --git a/resources/ui/steps/uw.ui.Details.js b/resources/ui/steps/uw.ui.Details.js
index e5117db..793da75 100644
--- a/resources/ui/steps/uw.ui.Details.js
+++ b/resources/ui/steps/uw.ui.Details.js
@@ -24,7 +24,7 @@
 	 * @constructor
 	 */
 	uw.ui.Details = function UWUIDetails() {
-		var details = this;
+		const details = this;
 
 		function startDetails() {
 			details.emit( 'start-details' );
@@ -48,7 +48,7 @@
 		this.nextButtonDespiteFailures = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-next-file-despite-failures' ).text(),
 			flags: [ 'progressive' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			details.emit( 'finalize-details-after-removal' );
 		} );
 
@@ -85,9 +85,9 @@
 	};
 
 	uw.ui.Details.prototype.addNextButton = function () {
-		var ui = this;
+		const ui = this;
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			ui.$buttons.append(
 				$( '<div>' )
 					.addClass( 'mediauploader-file-next-all-ok mediauploader-file-endchoice' )
@@ -164,14 +164,14 @@
 	 * This method also opens up "more info" if the form has errors.
 	 */
 	uw.ui.Details.prototype.showErrors = function () {
-		var $errorElements = this.$div
+		const $errorElements = this.$div
 				// TODO Evil
 				.find( '.oo-ui-fieldLayout-messages-error' ),
 			errorCount = $errorElements.length;
 
 		// Open "more info" if that part of the form has errors
 		$errorElements.each( function () {
-			var $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );
+			const $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );
 			if ( $collapsibleWrapper.length ) {
 				$collapsibleWrapper.data( 'mw-collapsible' ).expand();
 			}
@@ -199,14 +199,14 @@
 	 * See #showErrors for details.
 	 */
 	uw.ui.Details.prototype.showWarnings = function () {
-		var $warningElements = this.$div
+		const $warningElements = this.$div
 				// TODO Evil
 				.find( '.oo-ui-fieldLayout-messages-notice' ),
 			warningCount = $warningElements.length;
 
 		// Open "more info" if that part of the form has warnings
 		$warningElements.each( function () {
-			var $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );
+			const $collapsibleWrapper = $( this ).closest( '.mwe-more-details' );
 			if ( $collapsibleWrapper.length ) {
 				$collapsibleWrapper.data( 'mw-collapsible' ).expand();
 			}
diff --git a/resources/ui/steps/uw.ui.Thanks.js b/resources/ui/steps/uw.ui.Thanks.js
index 62290aa..fc56af0 100644
--- a/resources/ui/steps/uw.ui.Thanks.js
+++ b/resources/ui/steps/uw.ui.Thanks.js
@@ -25,7 +25,7 @@
 	 * @param {Object} config
 	 */
 	uw.ui.Thanks = function UWUIThanks( config ) {
-		var $header,
+		let $header,
 			beginButtonTarget,
 			thanks = this;
 
@@ -68,13 +68,13 @@
 		// TODO: make the step order configurable by campaign definitions instead of using these hacks
 		beginButtonTarget = this.getButtonConfig( 'beginButton', 'target' );
 		if ( !beginButtonTarget ) {
-			this.beginButton.on( 'click', function () {
+			this.beginButton.on( 'click', () => {
 				thanks.emit( 'next-step' );
 			} );
 		} else {
 			this.beginButton.setHref( beginButtonTarget );
 		}
-		this.beginButton.on( 'click', function () {
+		this.beginButton.on( 'click', () => {
 			mw.DestinationChecker.clearCache();
 		} );
 
@@ -93,7 +93,7 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.ui.Thanks.prototype.addUpload = function ( upload ) {
-		var thumbWikiText, $thanksDiv, $thumbnailWrapDiv, $thumbnailDiv, $thumbnailCaption, $thumbnailLink;
+		let thumbWikiText, $thanksDiv, $thumbnailWrapDiv, $thumbnailDiv, $thumbnailCaption, $thumbnailLink;
 
 		thumbWikiText = '[[' + [
 			upload.details.getTitle().getPrefixedText(),
@@ -125,7 +125,7 @@
 			);
 
 		// This must match the CSS dimensions of .mediauploader-thumbnail
-		upload.getThumbnail( 120, 120 ).done( function ( thumb ) {
+		upload.getThumbnail( 120, 120 ).done( ( thumb ) => {
 			mw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );
 		} );
 
@@ -148,7 +148,7 @@
 	 * @return {jQuery}
 	 */
 	uw.ui.Thanks.prototype.makeReadOnlyInput = function ( value, label, useEditFont ) {
-		var copyText = new mw.widgets.CopyTextLayout( {
+		const copyText = new mw.widgets.CopyTextLayout( {
 			align: 'top',
 			label: label,
 			copyText: value
diff --git a/resources/ui/steps/uw.ui.Tutorial.js b/resources/ui/steps/uw.ui.Tutorial.js
index 1b8d0d4..fa7fd0f 100644
--- a/resources/ui/steps/uw.ui.Tutorial.js
+++ b/resources/ui/steps/uw.ui.Tutorial.js
@@ -51,7 +51,7 @@
 	 * @constructor
 	 */
 	uw.ui.Tutorial = function UWUITutorial() {
-		var ui = this;
+		const ui = this;
 
 		uw.ui.Step.call(
 			this,
@@ -78,7 +78,7 @@
 			label: mw.message( 'mediauploader-skip-tutorial-future' ).text()
 		} );
 
-		this.skipCheckbox.on( 'change', function () {
+		this.skipCheckbox.on( 'change', () => {
 			ui.emit( 'skip-tutorial-click', ui.skipCheckbox.isSelected() );
 		} );
 
@@ -112,17 +112,17 @@
 	};
 
 	uw.ui.Tutorial.prototype.addNextButton = function () {
-		var ui = this;
+		const ui = this;
 
 		this.nextButton = new OO.ui.ButtonWidget( {
 			classes: [ 'mediauploader-button-next' ],
 			label: mw.message( 'mediauploader-next' ).text(),
 			flags: [ 'progressive', 'primary' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			ui.emit( 'next-step' );
 		} );
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			ui.$buttons.append(
 				new OO.ui.HorizontalLayout( {
 					items: [ ui.skipCheckbox, ui.skipCheckboxLabel, ui.nextButton ]
diff --git a/resources/ui/steps/uw.ui.Upload.js b/resources/ui/steps/uw.ui.Upload.js
index 4ec5509..b7e38bf 100644
--- a/resources/ui/steps/uw.ui.Upload.js
+++ b/resources/ui/steps/uw.ui.Upload.js
@@ -25,7 +25,7 @@
 	 * @param {Object} config UploadWizard config object.
 	 */
 	uw.ui.Upload = function UWUIUpload( config ) {
-		var upload = this;
+		const upload = this;
 
 		this.config = config;
 
@@ -58,14 +58,14 @@
 		this.nextStepButtonAllOk = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-next-file' ).text(),
 			flags: [ 'progressive', 'primary' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			upload.emit( 'next-step' );
 		} );
 
 		this.retryButtonSomeFailed = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-file-retry' ).text(),
 			flags: [ 'progressive' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			upload.hideEndButtons();
 			upload.emit( 'retry' );
 		} );
@@ -73,14 +73,14 @@
 		this.nextStepButtonSomeFailed = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-next-file-despite-failures' ).text(),
 			flags: [ 'progressive', 'primary' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			upload.emit( 'next-step' );
 		} );
 
 		this.retryButtonAllFailed = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-file-retry' ).text(),
 			flags: [ 'progressive' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			upload.hideEndButtons();
 			upload.emit( 'retry' );
 		} );
@@ -145,7 +145,7 @@
 	 * @param {boolean} more
 	 */
 	uw.ui.Upload.prototype.setAddButtonText = function ( more ) {
-		var msg = 'mediauploader-add-file-';
+		let msg = 'mediauploader-add-file-';
 
 		if ( more ) {
 			msg += 'n';
@@ -160,7 +160,7 @@
 	};
 
 	uw.ui.Upload.prototype.load = function ( uploads ) {
-		var ui = this;
+		const ui = this;
 
 		uw.ui.Step.prototype.load.call( this, uploads );
 
@@ -177,17 +177,17 @@
 				)
 		);
 
-		this.addFile.on( 'change', function ( files ) {
+		this.addFile.on( 'change', ( files ) => {
 			ui.emit( 'files-added', files );
 			ui.addFile.setValue( null );
 		} );
 	};
 
 	uw.ui.Upload.prototype.displayUploads = function ( uploads ) {
-		var thumbPromise,
+		let thumbPromise,
 			$uploadInterfaceDivs = $( [] );
 
-		uploads.forEach( function ( upload ) {
+		uploads.forEach( ( upload ) => {
 			// We'll attach all interfaces to the DOM at once rather than one-by-one, for better
 			// performance
 			$uploadInterfaceDivs = $uploadInterfaceDivs.add( upload.ui.$div );
@@ -199,15 +199,15 @@
 		// Display thumbnails, but not all at once because they're somewhat expensive to generate.
 		// This will wait for each thumbnail to be complete before starting the next one.
 		thumbPromise = $.Deferred().resolve();
-		uploads.forEach( function ( upload ) {
-			thumbPromise = thumbPromise.then( function () {
-				var deferred = $.Deferred();
+		uploads.forEach( ( upload ) => {
+			thumbPromise = thumbPromise.then( () => {
+				const deferred = $.Deferred();
 				setTimeout( function () {
 					if ( this.movedFrom ) {
 						// We're no longer displaying any of these thumbnails, stop
 						deferred.reject();
 					}
-					upload.ui.showThumbnail().done( function () {
+					upload.ui.showThumbnail().done( () => {
 						deferred.resolve();
 					} );
 				} );
@@ -217,9 +217,9 @@
 	};
 
 	uw.ui.Upload.prototype.addNextButton = function () {
-		var ui = this;
+		const ui = this;
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			ui.$buttons.append(
 				$( '<div>' )
 					.addClass( 'mediauploader-file-next-all-ok mediauploader-file-endchoice' )
@@ -319,12 +319,12 @@
 	 * @param {string} extension
 	 */
 	uw.ui.Upload.prototype.showBadExtensionError = function ( filename, extension ) {
-		var $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-extension', extension );
+		const $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-extension', extension );
 		this.showFilenameError( $errorMessage );
 	};
 
 	uw.ui.Upload.prototype.showMissingExtensionError = function () {
-		var $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-no-extension' );
+		const $errorMessage = $( '<p>' ).msg( 'mediauploader-upload-error-bad-filename-no-extension' );
 		this.showFilenameError(
 			$( '<div>' ).append(
 				$errorMessage,
diff --git a/resources/ui/uw.ui.DeedPreview.js b/resources/ui/uw.ui.DeedPreview.js
index a30f6fb..a7b30b5 100644
--- a/resources/ui/uw.ui.DeedPreview.js
+++ b/resources/ui/uw.ui.DeedPreview.js
@@ -24,10 +24,10 @@
 	 * @param {mw.UploadWizardUpload} upload
 	 */
 	uw.ui.DeedPreview = function UWUIDeedPreview( upload ) {
-		var $thumbnailDiv = $( '<div>' ).addClass( 'mediauploader-thumbnail' );
+		const $thumbnailDiv = $( '<div>' ).addClass( 'mediauploader-thumbnail' );
 		this.$thumbnailDiv = $thumbnailDiv;
 		// This must match the CSS dimensions of .mediauploader-thumbnail
-		upload.getThumbnail( 120, 120 ).done( function ( thumb ) {
+		upload.getThumbnail( 120, 120 ).done( ( thumb ) => {
 			mw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );
 		} );
 		// eslint-disable-next-line no-jquery/no-global-selector
diff --git a/resources/ui/uw.ui.Step.js b/resources/ui/uw.ui.Step.js
index 6b19ffb..af3d8ae 100644
--- a/resources/ui/uw.ui.Step.js
+++ b/resources/ui/uw.ui.Step.js
@@ -53,7 +53,7 @@
 	 */
 	uw.ui.Step.prototype.load = function ( uploads ) {
 		// eslint-disable-next-line no-jquery/no-global-selector
-		var offset = $( 'h1' ).first().offset();
+		const offset = $( 'h1' ).first().offset();
 
 		this.movedFrom = false;
 
@@ -88,17 +88,17 @@
 	 * Add a 'next' button to the step's button container
 	 */
 	uw.ui.Step.prototype.addNextButton = function () {
-		var ui = this;
+		const ui = this;
 
 		this.nextButton = new OO.ui.ButtonWidget( {
 			classes: [ 'mediauploader-button-next' ],
 			label: mw.message( 'mediauploader-next' ).text(),
 			flags: [ 'progressive', 'primary' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			ui.emit( 'next-step' );
 		} );
 
-		this.nextButtonPromise.done( function () {
+		this.nextButtonPromise.done( () => {
 			ui.$buttons.append( ui.nextButton.$element );
 		} );
 	};
@@ -107,16 +107,16 @@
 	 * Add a 'previous' button to the step's button container
 	 */
 	uw.ui.Step.prototype.addPreviousButton = function () {
-		var ui = this;
+		const ui = this;
 
 		this.previousButton = new OO.ui.ButtonWidget( {
 			classes: [ 'mediauploader-button-previous' ],
 			label: mw.message( 'mediauploader-previous' ).text()
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			ui.emit( 'previous-step' );
 		} );
 
-		this.previousButtonPromise.done( function () {
+		this.previousButtonPromise.done( () => {
 			ui.$buttons.append( ui.previousButton.$element );
 		} );
 	};
diff --git a/resources/ui/uw.ui.Wizard.js b/resources/ui/uw.ui.Wizard.js
index 804fbaa..5472285 100644
--- a/resources/ui/uw.ui.Wizard.js
+++ b/resources/ui/uw.ui.Wizard.js
@@ -46,7 +46,7 @@
 	 */
 	uw.ui.Wizard.prototype.initHeader = function ( config ) {
 		// eslint-disable-next-line no-jquery/no-global-selector
-		var $contentSub = $( '#contentSub' );
+		const $contentSub = $( '#contentSub' );
 
 		if ( config.alternativeUploadToolsPage ) {
 			this.$alternativeUploads = $( '<a>' )
@@ -72,7 +72,7 @@
 	 * @param {Object|string} configAltUploadForm A link or map of languages to links, pointing at an alternate form.
 	 */
 	uw.ui.Wizard.prototype.initAltUploadForm = function ( configAltUploadForm ) {
-		var altUploadForm, userLanguage, title;
+		let altUploadForm, userLanguage, title;
 
 		if ( typeof configAltUploadForm === 'object' ) {
 			userLanguage = mw.config.get( 'wgUserLanguage' );
@@ -108,13 +108,13 @@
 	 * @param {uw.controller.Step[]} steps
 	 */
 	uw.ui.Wizard.prototype.initialiseSteps = function ( steps ) {
-		var $steps = $( '<ul>' )
+		const $steps = $( '<ul>' )
 			.attr( 'id', 'mediauploader-steps' )
 			.addClass( 'ui-helper-clearfix' )
 			.insertBefore( '#mediauploader-content' );
 
-		steps.forEach( function ( step ) {
-			var $arrow = $( '<li>' )
+		steps.forEach( ( step ) => {
+			const $arrow = $( '<li>' )
 				.attr( 'id', 'mediauploader-step-' + step.stepName )
 				.append(
 					// Messages that can be used here:
@@ -128,9 +128,9 @@
 			$steps.append( $arrow );
 
 			// once a (new) step loads, highlight it
-			step.on( 'load', function ( $arrow2 ) {
+			step.on( 'load', ( ( $arrow2 ) => {
 				$steps.arrowStepsHighlight( $arrow2 );
-			}.bind( step, $arrow ) );
+			} ).bind( step, $arrow ) );
 		} );
 
 		$steps.arrowSteps();
diff --git a/resources/uw.ConcurrentQueue.js b/resources/uw.ConcurrentQueue.js
index 2ec018f..48383eb 100644
--- a/resources/uw.ConcurrentQueue.js
+++ b/resources/uw.ConcurrentQueue.js
@@ -70,7 +70,7 @@
 	 * @return {boolean} Whether the item was removed
 	 */
 	uw.ConcurrentQueue.prototype.removeItem = function ( item ) {
-		var index, found;
+		let index, found;
 
 		found = false;
 
@@ -113,7 +113,7 @@
 	 * @param {Object} item
 	 */
 	uw.ConcurrentQueue.prototype.promiseComplete = function ( item ) {
-		var index;
+		let index;
 		index = this.running.indexOf( item );
 		// Check that this item wasn't removed while it was being executed
 		if ( index !== -1 ) {
@@ -132,7 +132,7 @@
 	 * @private
 	 */
 	uw.ConcurrentQueue.prototype.executeNext = function () {
-		var item, promise;
+		let item, promise;
 		if ( this.running.length === this.count || !this.executing ) {
 			return;
 		}
@@ -153,7 +153,7 @@
 	 * When the queue finishes executing, a 'complete' event will be emitted.
 	 */
 	uw.ConcurrentQueue.prototype.startExecuting = function () {
-		var i;
+		let i;
 		if ( this.executing ) {
 			return;
 		}
diff --git a/resources/uw.CopyMetadataWidget.js b/resources/uw.CopyMetadataWidget.js
index 784aab0..5fa1180 100644
--- a/resources/uw.CopyMetadataWidget.js
+++ b/resources/uw.CopyMetadataWidget.js
@@ -10,7 +10,7 @@
 	 * @cfg {mw.UploadWizardUpload[]} copyTo Uploads to copy the details to
 	 */
 	uw.CopyMetadataWidget = function UWCopyMetadataWidget( config ) {
-		var metadataType, defaultStatus, copyMetadataMsg,
+		let metadataType, defaultStatus, copyMetadataMsg,
 			checkboxes = [],
 			$copyMetadataWrapperDiv = $( '<div>' ),
 			$copyMetadataDiv = $( '<div>' );
@@ -118,7 +118,7 @@
 	 * @private
 	 */
 	uw.CopyMetadataWidget.prototype.onCopyClick = function () {
-		var metadataTypes = this.checkboxesWidget.findSelectedItemsData();
+		const metadataTypes = this.checkboxesWidget.findSelectedItemsData();
 		this.copyMetadata( metadataTypes );
 
 		this.undoButton.toggle( true );
@@ -153,7 +153,7 @@
 	 * @param {string[]} metadataTypes Types to copy, as defined in the copyMetadataTypes property
 	 */
 	uw.CopyMetadataWidget.prototype.copyMetadata = function ( metadataTypes ) {
-		var titleZero, matches, i,
+		let titleZero, matches, i,
 			uploads = this.copyTo,
 			sourceUpload = this.copyFrom,
 			serialized = sourceUpload.details.getSerialized(),
@@ -164,7 +164,7 @@
 			copyingOther = false;
 
 		// Filter serialized data to only the types we want to copy
-		metadataTypes.forEach( function ( type ) {
+		metadataTypes.forEach( ( type ) => {
 			sourceValue[ type ] = serialized[ type ];
 			copyingTitle = copyingTitle || type === 'title';
 			copyingOther = copyingOther || type === 'other';
@@ -193,8 +193,8 @@
 				// numbers.
 				sourceValue.title.title = titleZero.replace( /(\D+)(\d{1,3})(\D*)$/,
 					// eslint-disable-next-line no-loop-func
-					function ( str, m1, m2, m3 ) {
-						var newstr = String( +m2 + i );
+					( str, m1, m2, m3 ) => {
+						const newstr = String( +m2 + i );
 						return m1 + new Array( m2.length + 1 - newstr.length )
 							.join( '0' ) + newstr + m3;
 					}
@@ -210,7 +210,7 @@
 	 * Restore previously saved metadata that we backed up when copying.
 	 */
 	uw.CopyMetadataWidget.prototype.restoreMetadata = function () {
-		var i,
+		let i,
 			uploads = this.copyTo;
 
 		for ( i = 0; i < uploads.length; i++ ) {
diff --git a/resources/uw.FieldLayout.js b/resources/uw.FieldLayout.js
index 8d52198..7c5f4a5 100644
--- a/resources/uw.FieldLayout.js
+++ b/resources/uw.FieldLayout.js
@@ -16,7 +16,7 @@
 		// FieldLayout will add an icon which, when clicked, reveals more information
 		// about the input. We'll want to display that by default, so we're getting
 		// rid of the "help" property here & will later append that after the header
-		var help = config && config.help ? config.help : '';
+		const help = config && config.help ? config.help : '';
 		config = Object.assign( { align: 'top', required: false }, config, { help: '' } );
 
 		uw.FieldLayout.parent.call( this, fieldWidget, config );
diff --git a/resources/uw.LicenseGroup.js b/resources/uw.LicenseGroup.js
index c5d4f6f..5277ac0 100644
--- a/resources/uw.LicenseGroup.js
+++ b/resources/uw.LicenseGroup.js
@@ -22,7 +22,7 @@
 	 * @param {number} count Number of the things we are licensing (it matters to some texts)
 	 */
 	uw.LicenseGroup = function UWLicenseGroup( config, type, api, count ) {
-		var self = this;
+		const self = this;
 
 		uw.LicenseGroup.parent.call( this, {} );
 
@@ -30,7 +30,7 @@
 			throw new Error( 'improper license config' );
 		}
 
-		if ( [ 'radio', 'checkbox' ].indexOf( type ) < 0 ) {
+		if ( ![ 'radio', 'checkbox' ].includes( type ) ) {
 			throw new Error( 'Invalid type: ' + type );
 		}
 
@@ -58,12 +58,12 @@
 		}
 
 		// when selecting an item that has a custom textarea, we'll immediately focus it
-		this.on( 'change', function ( group, item ) {
+		this.on( 'change', ( group, item ) => {
 			if ( item && item.isSelected && item.isSelected() ) {
 				// wrapped inside setTimeout to ensure it goes at the end of the call stack,
 				// just in case something steals focus in the meantime...
-				setTimeout( function () {
-					var name = item.getData();
+				setTimeout( () => {
+					const name = item.getData();
 					if ( self.textareas[ name ] ) {
 						self.textareas[ name ].focus();
 					}
@@ -86,7 +86,7 @@
 	 */
 	uw.LicenseGroup.prototype.createFieldset = function ( group ) {
 		/* eslint-disable mediawiki/msg-doc */
-		var $head = this.config.head && $( '<a>' )
+		const $head = this.config.head && $( '<a>' )
 				.addClass( 'mediauploader-deed-license-group-head' )
 				.msg( this.config.head, this.count )
 				.prepend( $( '<span>' ).addClass( 'mw-toggle-icon' ) ),
@@ -118,11 +118,11 @@
 	 * @return {OO.ui.RadioSelectWidget}
 	 */
 	uw.LicenseGroup.prototype.createRadioGroup = function ( classes ) {
-		var self = this,
+		const self = this,
 			options = [];
 
-		this.config.licenses.forEach( function ( licenseName ) {
-			var option;
+		this.config.licenses.forEach( ( licenseName ) => {
+			let option;
 
 			if ( mw.UploadWizard.config.licenses[ licenseName ] === undefined ) {
 				// unknown license
@@ -136,7 +136,7 @@
 
 			// when custom text area receives focus, we should make sure this element is selected
 			if ( self.textareas[ licenseName ] ) {
-				self.textareas[ licenseName ].on( 'focus', function () {
+				self.textareas[ licenseName ].on( 'focus', () => {
 					option.setSelected( true );
 				} );
 			}
@@ -153,11 +153,11 @@
 	 * @return {OO.ui.CheckboxMultiselectInputWidget}
 	 */
 	uw.LicenseGroup.prototype.createCheckboxGroup = function ( classes ) {
-		var self = this,
+		const self = this,
 			options = [];
 
-		this.config.licenses.forEach( function ( licenseName ) {
-			var option;
+		this.config.licenses.forEach( ( licenseName ) => {
+			let option;
 
 			if ( mw.UploadWizard.config.licenses[ licenseName ] === undefined ) {
 				// unknown license
@@ -171,7 +171,7 @@
 
 			// when custom text area receives focus, we should make sure this element is selected
 			if ( self.textareas[ licenseName ] ) {
-				self.textareas[ licenseName ].on( 'focus', function () {
+				self.textareas[ licenseName ].on( 'focus', () => {
 					option.setSelected( true );
 				} );
 			}
@@ -187,12 +187,12 @@
 	 * @return {string}
 	 */
 	uw.LicenseGroup.prototype.getWikiText = function () {
-		var wikiTexts,
+		let wikiTexts,
 			self = this,
 			values = this.getValue();
 
-		wikiTexts = Object.keys( values ).map( function ( name ) {
-			var wikiText = self.getLicenseWikiText( name ),
+		wikiTexts = Object.keys( values ).map( ( name ) => {
+			let wikiText = self.getLicenseWikiText( name ),
 				value = values[ name ];
 			if ( typeof value === 'string' ) {
 				// `value` is custom input
@@ -219,7 +219,7 @@
 	 * @return {Object} Map of { licenseName: true }, or { licenseName: "custom input" }
 	 */
 	uw.LicenseGroup.prototype.getValue = function () {
-		var self = this,
+		let self = this,
 			result = {},
 			selected,
 			name;
@@ -232,7 +232,7 @@
 			}
 		} else if ( this.type === 'checkbox' ) {
 			selected = this.group.findSelectedItems();
-			selected.forEach( function ( item ) {
+			selected.forEach( ( item ) => {
 				name = item.getData();
 				result[ name ] = !self.textareas[ name ] || self.textareas[ name ].getValue();
 			} );
@@ -245,12 +245,12 @@
 	 * @param {Object} values Map of { licenseName: true }, or { licenseName: "custom input" }
 	 */
 	uw.LicenseGroup.prototype.setValue = function ( values ) {
-		var self = this,
+		let self = this,
 			selectArray = [],
 			selected;
 
-		Object.keys( values ).forEach( function ( name ) {
-			var value = values[ name ];
+		Object.keys( values ).forEach( ( name ) => {
+			const value = values[ name ];
 			if ( typeof value === 'string' && self.textareas[ name ] ) {
 				self.textareas[ name ].setValue( value );
 				// add to list of items to select
@@ -300,7 +300,7 @@
 	 * @return {string} of wikitext
 	 */
 	uw.LicenseGroup.prototype.getLicenseWikiText = function ( name ) {
-		var licenseInfo = this.getLicenseInfo( name ),
+		let licenseInfo = this.getLicenseInfo( name ),
 			licenseText;
 
 		licenseText = licenseInfo.props.wikitext !== undefined ?
@@ -316,7 +316,7 @@
 	 * @return {jQuery}
 	 */
 	uw.LicenseGroup.prototype.createLabel = function ( name ) {
-		var licenseInfo = this.getLicenseInfo( name ),
+		let licenseInfo = this.getLicenseInfo( name ),
 			messageKey = licenseInfo.props.msg === undefined ?
 				'[missing msg for ' + licenseInfo.name + ']' :
 				licenseInfo.props.msg,
@@ -333,7 +333,7 @@
 		}
 		$licenseLink = $( '<a>' ).attr( { target: '_blank', href: licenseURL } );
 		if ( licenseInfo.props.icons !== undefined ) {
-			licenseInfo.props.icons.forEach( function ( icon ) {
+			licenseInfo.props.icons.forEach( ( icon ) => {
 				// eslint-disable-next-line mediawiki/class-doc
 				$icons.append( $( '<span>' ).addClass( 'mediauploader-license-icon mediauploader-' + icon + '-icon' ) );
 			} );
@@ -358,7 +358,7 @@
 	 * @return {jQuery} Wrapped textarea
 	 */
 	uw.LicenseGroup.prototype.createCustom = function ( name, defaultText ) {
-		var self = this,
+		let self = this,
 			button;
 
 		this.textareas[ name ] = new OO.ui.MultilineTextInputWidget( {
@@ -372,7 +372,7 @@
 		button = new OO.ui.ButtonWidget( {
 			label: mw.message( 'mediauploader-license-custom-preview' ).text(),
 			flags: [ 'progressive' ]
-		} ).on( 'click', function () {
+		} ).on( 'click', () => {
 			self.showPreview( self.textareas[ name ].getValue() );
 		} );
 
@@ -389,7 +389,7 @@
 	 * @param {string} wikiText
 	 */
 	uw.LicenseGroup.prototype.showPreview = function ( wikiText ) {
-		var input;
+		let input;
 
 		this.previewDialog.setLoading( true );
 		this.windowManager.openWindow( this.previewDialog );
@@ -402,7 +402,7 @@
 		}
 
 		function error( code, result ) {
-			var message = result.errors[ 0 ].html;
+			const message = result.errors[ 0 ].html;
 
 			show( $( '<div>' ).append(
 				$( '<h3>' ).append( code ),
diff --git a/resources/uw.LicensePreviewDialog.js b/resources/uw.LicensePreviewDialog.js
index 133d1b5..08f5231 100644
--- a/resources/uw.LicensePreviewDialog.js
+++ b/resources/uw.LicensePreviewDialog.js
@@ -7,7 +7,7 @@
 	uw.LicensePreviewDialog.static.name = 'licensePreviewDialog';
 
 	uw.LicensePreviewDialog.prototype.initialize = function () {
-		var dialog = this;
+		const dialog = this;
 
 		uw.LicensePreviewDialog.parent.prototype.initialize.call( this );
 
@@ -16,7 +16,7 @@
 		this.$spinner = $.createSpinner( { size: 'large', type: 'block' } )
 			.css( { width: 200, padding: 20, float: 'none', margin: '0 auto' } );
 
-		$( document.body ).on( 'click', function ( e ) {
+		$( document.body ).on( 'click', ( e ) => {
 			if ( !$.contains( dialog.$body.get( 0 ), e.target ) ) {
 				dialog.close();
 			}
@@ -24,12 +24,12 @@
 	};
 
 	uw.LicensePreviewDialog.prototype.addCloseButton = function () {
-		var dialog = this,
+		const dialog = this,
 			closeButton = new OO.ui.ButtonWidget( {
 				label: OO.ui.msg( 'ooui-dialog-process-dismiss' )
 			} );
 
-		closeButton.on( 'click', function () {
+		closeButton.on( 'click', () => {
 			dialog.close();
 		} );
 
diff --git a/resources/uw.ValidationMessageElement.js b/resources/uw.ValidationMessageElement.js
index 1a50d13..72c5e89 100644
--- a/resources/uw.ValidationMessageElement.js
+++ b/resources/uw.ValidationMessageElement.js
@@ -43,7 +43,7 @@
 	 * @return {jQuery.Promise}
 	 */
 	uw.ValidationMessageElement.prototype.checkValidity = function ( thorough ) {
-		var element = this;
+		const element = this;
 		thorough = thorough || false;
 
 		if ( !this.validatedWidget.getWarnings || !this.validatedWidget.getErrors ) {
@@ -57,13 +57,13 @@
 		return $.when(
 			this.validatedWidget.getWarnings( thorough ),
 			this.validatedWidget.getErrors( thorough )
-		).then( function ( warnings, errors ) {
+		).then( ( warnings, errors ) => {
 			// this.notices and this.errors are arrays of mw.Messages and not strings in this subclass
 			element.setNotices( warnings );
 			element.setErrors( errors );
 
 			return $.Deferred().resolve( warnings, errors ).promise();
-		} ).always( function () {
+		} ).always( () => {
 			if ( element.validatedWidget.popPending ) {
 				element.validatedWidget.popPending();
 			}
@@ -77,7 +77,7 @@
 	 * @return {jQuery}
 	 */
 	uw.ValidationMessageElement.prototype.makeMessage = function ( kind, error ) {
-		var code, $content, $listItem;
+		let code, $content, $listItem;
 		if ( error.parseDom ) {
 			// mw.Message object
 			code = error.key;
diff --git a/resources/uw.units.js b/resources/uw.units.js
index 9720982..f36f63c 100644
--- a/resources/uw.units.js
+++ b/resources/uw.units.js
@@ -1,6 +1,6 @@
 ( function ( uw ) {
 
-	var scaleMsgKeys = [ 'size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes' ];
+	const scaleMsgKeys = [ 'size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes' ];
 
 	uw.units = {
 		/**
@@ -13,7 +13,7 @@
 		 * @return {string} formatted size
 		 */
 		bytes: function ( size ) {
-			var i = 0;
+			let i = 0;
 			while ( size >= 1024 && i < scaleMsgKeys.length - 1 ) {
 				size /= 1024.0;
 				i++;
diff --git a/tests/qunit/.eslintrc.json b/tests/qunit/.eslintrc.json
index a4f3832..26a9402 100644
--- a/tests/qunit/.eslintrc.json
+++ b/tests/qunit/.eslintrc.json
@@ -5,5 +5,9 @@
 	],
 	"globals": {
 		"sinon": false
+	},
+	"rules": {
+		"prefer-const": "warn",
+		"no-jquery/no-done-fail": "warn"
 	}
 }
diff --git a/tests/qunit/controller/uw.controller.Deed.test.js b/tests/qunit/controller/uw.controller.Deed.test.js
index fa5b40c..98b5cbb 100644
--- a/tests/qunit/controller/uw.controller.Deed.test.js
+++ b/tests/qunit/controller/uw.controller.Deed.test.js
@@ -18,15 +18,15 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Deed', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Deed();
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Deed();
 		assert.true( !!step );
 		assert.true( step instanceof uw.controller.Step );
 		assert.true( !!step.ui );
 	} );
 
 	QUnit.test( 'load', function ( assert ) {
-		var step = new uw.controller.Deed(
+		const step = new uw.controller.Deed(
 				new mw.Api(),
 				{ licensing: {
 					enabled: true,
diff --git a/tests/qunit/controller/uw.controller.Details.test.js b/tests/qunit/controller/uw.controller.Details.test.js
index 689c5f7..7b6a5d9 100644
--- a/tests/qunit/controller/uw.controller.Details.test.js
+++ b/tests/qunit/controller/uw.controller.Details.test.js
@@ -19,7 +19,7 @@
 	QUnit.module( 'uw.controller.Details', QUnit.newMwEnvironment() );
 
 	function createTestUpload( sandbox, customDeedChooser, aborted ) {
-		var stubs = {
+		const stubs = {
 			ucdc: sandbox.stub(),
 			getSerialized: sandbox.stub(),
 			setSerialized: sandbox.stub(),
@@ -44,8 +44,8 @@
 		};
 	}
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Details( new mw.Api(), {
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Details( new mw.Api(), {
 			maxSimultaneousConnections: 1
 		} );
 		assert.true( !!step );
@@ -54,7 +54,7 @@
 	} );
 
 	QUnit.test( 'load', function ( assert ) {
-		var step = new uw.controller.Details( new mw.Api(), {
+		let step = new uw.controller.Details( new mw.Api(), {
 				maxSimultaneousConnections: 1
 			} ),
 			testUpload = createTestUpload( this.sandbox ),
@@ -92,8 +92,8 @@
 		assert.true( stepUiStub.called );
 	} );
 
-	QUnit.test( 'canTransition', function ( assert ) {
-		var upload = {},
+	QUnit.test( 'canTransition', ( assert ) => {
+		const upload = {},
 			step = new uw.controller.Details( new mw.Api(), {
 				maxSimultaneousConnections: 1
 			} );
@@ -106,7 +106,7 @@
 	} );
 
 	QUnit.test( 'transitionAll', function ( assert ) {
-		var tostub,
+		let tostub,
 			done = assert.async(),
 			donestub = this.sandbox.stub(),
 			ds = [ $.Deferred(), $.Deferred(), $.Deferred() ],
@@ -133,7 +133,7 @@
 		];
 
 		step.transitionAll().done( donestub );
-		setTimeout( function () {
+		setTimeout( () => {
 			calls = [ tostub.getCall( 0 ), tostub.getCall( 1 ), tostub.getCall( 2 ) ];
 
 			assert.strictEqual( calls[ 0 ].args[ 0 ].id, 15 );
@@ -141,11 +141,11 @@
 
 			ds[ 0 ].resolve();
 			ds[ 1 ].resolve();
-			setTimeout( function () {
+			setTimeout( () => {
 				assert.strictEqual( donestub.called, false );
 
 				ds[ 2 ].resolve();
-				setTimeout( function () {
+				setTimeout( () => {
 					assert.true( donestub.called );
 
 					done();
diff --git a/tests/qunit/controller/uw.controller.Step.test.js b/tests/qunit/controller/uw.controller.Step.test.js
index a30f7ae..17a5901 100644
--- a/tests/qunit/controller/uw.controller.Step.test.js
+++ b/tests/qunit/controller/uw.controller.Step.test.js
@@ -18,8 +18,8 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Step', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Step( { on: function () {} }, new mw.Api(), {} );
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Step( { on: function () {} }, new mw.Api(), {} );
 		assert.true( !!step );
 		assert.true( !!step.ui );
 	} );
diff --git a/tests/qunit/controller/uw.controller.Thanks.test.js b/tests/qunit/controller/uw.controller.Thanks.test.js
index c19f4d5..0929619 100644
--- a/tests/qunit/controller/uw.controller.Thanks.test.js
+++ b/tests/qunit/controller/uw.controller.Thanks.test.js
@@ -18,15 +18,15 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Thanks', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Thanks( new mw.Api(), { display: { thanksLabel: 'Thanks!' } } );
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Thanks( new mw.Api(), { display: { thanksLabel: 'Thanks!' } } );
 		assert.true( !!step );
 		assert.true( step instanceof uw.controller.Step );
 		assert.true( !!step.ui );
 	} );
 
 	QUnit.test( 'load', function ( assert ) {
-		var step = new uw.controller.Thanks( new mw.Api(), {} ),
+		const step = new uw.controller.Thanks( new mw.Api(), {} ),
 			auStub = this.sandbox.stub( step.ui, 'addUpload' );
 
 		this.sandbox.stub( step.ui, 'load' );
@@ -39,8 +39,8 @@
 		assert.strictEqual( auStub.callCount, 3 );
 	} );
 
-	QUnit.test( 'Custom button configuration', function ( assert ) {
-		var config = {
+	QUnit.test( 'Custom button configuration', ( assert ) => {
+		const config = {
 				display: {
 					homeButton: {
 						label: 'This is just a test',
diff --git a/tests/qunit/controller/uw.controller.Tutorial.test.js b/tests/qunit/controller/uw.controller.Tutorial.test.js
index 2a780a4..86122c1 100644
--- a/tests/qunit/controller/uw.controller.Tutorial.test.js
+++ b/tests/qunit/controller/uw.controller.Tutorial.test.js
@@ -18,8 +18,8 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Tutorial', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Tutorial( new mw.Api() );
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Tutorial( new mw.Api() );
 		assert.true( !!step );
 		assert.true( step instanceof uw.controller.Step );
 		assert.true( !!step.ui );
@@ -27,7 +27,7 @@
 	} );
 
 	QUnit.test( 'setSkipPreference', function ( assert ) {
-		var mnStub,
+		let mnStub,
 			api = new mw.Api(),
 			step = new uw.controller.Tutorial( api ),
 			acwStub = { release: this.sandbox.stub() },
diff --git a/tests/qunit/controller/uw.controller.Upload.test.js b/tests/qunit/controller/uw.controller.Upload.test.js
index 4cd12dd..09febdd 100644
--- a/tests/qunit/controller/uw.controller.Upload.test.js
+++ b/tests/qunit/controller/uw.controller.Upload.test.js
@@ -18,8 +18,8 @@
 ( function ( uw ) {
 	QUnit.module( 'uw.controller.Upload', QUnit.newMwEnvironment() );
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var step = new uw.controller.Upload( new mw.Api(), {
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const step = new uw.controller.Upload( new mw.Api(), {
 			maxUploads: 10,
 			maxSimultaneousConnections: 3
 		} );
@@ -29,7 +29,7 @@
 	} );
 
 	QUnit.test( 'updateFileCounts', function ( assert ) {
-		var step = new uw.controller.Upload( new mw.Api(), {
+		const step = new uw.controller.Upload( new mw.Api(), {
 				maxUploads: 5,
 				maxSimultaneousConnections: 3
 			} ),
@@ -50,8 +50,8 @@
 		assert.true( ufcStub.calledWith( true, false ) );
 	} );
 
-	QUnit.test( 'canTransition', function ( assert ) {
-		var upload = {},
+	QUnit.test( 'canTransition', ( assert ) => {
+		const upload = {},
 			step = new uw.controller.Upload( new mw.Api(), {
 				maxSimultaneousConnections: 1
 			} );
@@ -64,7 +64,7 @@
 	} );
 
 	QUnit.test( 'transitionOne', function ( assert ) {
-		var upload = {
+		const upload = {
 				start: this.sandbox.stub()
 			},
 			step = new uw.controller.Upload( new mw.Api(), {
diff --git a/tests/qunit/mw.UploadWizardLicenseInput.test.js b/tests/qunit/mw.UploadWizardLicenseInput.test.js
index f135b4b..2f84303 100644
--- a/tests/qunit/mw.UploadWizardLicenseInput.test.js
+++ b/tests/qunit/mw.UploadWizardLicenseInput.test.js
@@ -13,8 +13,8 @@ QUnit.module( 'ext.uploadWizardLicenseInput', QUnit.newMwEnvironment( {
 	}
 } ) );
 
-QUnit.test( 'Smoke test', function ( assert ) {
-	var config = { type: 'radio', licenses: [] },
+QUnit.test( 'Smoke test', ( assert ) => {
+	let config = { type: 'radio', licenses: [] },
 		$fixture = $( '<div>' ),
 		uwLicenseInput;
 
@@ -23,8 +23,8 @@ QUnit.test( 'Smoke test', function ( assert ) {
 	assert.true( !!uwLicenseInput, 'LicenseInput object created !' );
 } );
 
-QUnit.test( 'createInputs()', function ( assert ) {
-	var config = { type: 'radio', licenses: [ 'cc-by-sa-3.0' ] },
+QUnit.test( 'createInputs()', ( assert ) => {
+	let config = { type: 'radio', licenses: [ 'cc-by-sa-3.0' ] },
 		$fixture = $( '<div>' ),
 		uwLicenseInput,
 		$input,
@@ -42,8 +42,8 @@ QUnit.test( 'createInputs()', function ( assert ) {
 	assert.strictEqual( $label.length, 1, 'Label created.' );
 } );
 
-QUnit.test( 'createGroupedInputs()', function ( assert ) {
-	var config = {
+QUnit.test( 'createGroupedInputs()', ( assert ) => {
+	let config = {
 			type: 'checkbox',
 			licenseGroups: [
 				{
diff --git a/tests/qunit/mw.UploadWizardUpload.test.js b/tests/qunit/mw.UploadWizardUpload.test.js
index ad76777..0d7673d 100644
--- a/tests/qunit/mw.UploadWizardUpload.test.js
+++ b/tests/qunit/mw.UploadWizardUpload.test.js
@@ -19,7 +19,7 @@
 	QUnit.module( 'mw.UploadWizardUpload', QUnit.newMwEnvironment() );
 
 	function createUpload( filename ) {
-		var upload,
+		let upload,
 			oldconf = mw.UploadWizard.config;
 
 		mw.UploadWizard.config = {};
@@ -39,14 +39,14 @@
 		return upload;
 	}
 
-	QUnit.test( 'constructor sanity test', function ( assert ) {
-		var upload = createUpload();
+	QUnit.test( 'constructor sanity test', ( assert ) => {
+		const upload = createUpload();
 
 		assert.true( !!upload );
 	} );
 
-	QUnit.test( 'getBasename', function ( assert ) {
-		var upload;
+	QUnit.test( 'getBasename', ( assert ) => {
+		let upload;
 
 		upload = createUpload( 'path/to/filename.png' );
 		assert.strictEqual( upload.getBasename(), 'filename.png', 'Path is stripped' );
diff --git a/tests/qunit/mw.fileApi.test.js b/tests/qunit/mw.fileApi.test.js
index 9405e7c..cde0c62 100644
--- a/tests/qunit/mw.fileApi.test.js
+++ b/tests/qunit/mw.fileApi.test.js
@@ -19,7 +19,7 @@
 	QUnit.module( 'mw.fileApi', QUnit.newMwEnvironment() );
 
 	QUnit.test( 'isPreviewableFile', function ( assert ) {
-		var testFile = {};
+		const testFile = {};
 
 		testFile.type = 'image/png';
 		testFile.size = 5 * 1024 * 1024;
@@ -43,7 +43,7 @@
 	} );
 
 	QUnit.test( 'isPreviewableVideo', function ( assert ) {
-		var result, testFile = {},
+		let result, testFile = {},
 			fakeVideo = {
 				canPlayType: this.sandbox.stub().returns( 'yes' )
 			};
diff --git a/tests/qunit/transports/mw.FormDataTransport.test.js b/tests/qunit/transports/mw.FormDataTransport.test.js
index 76b9c4b..f6c3a87 100644
--- a/tests/qunit/transports/mw.FormDataTransport.test.js
+++ b/tests/qunit/transports/mw.FormDataTransport.test.js
@@ -19,7 +19,7 @@
 	QUnit.module( 'mw.FormDataTransport', QUnit.newMwEnvironment() );
 
 	function createTransport( chunkSize, api ) {
-		var config;
+		let config;
 
 		chunkSize = chunkSize || 0;
 		api = api || {};
@@ -33,14 +33,14 @@
 		return new mw.FormDataTransport( api, {}, config );
 	}
 
-	QUnit.test( 'Constructor sanity test', function ( assert ) {
-		var transport = createTransport();
+	QUnit.test( 'Constructor sanity test', ( assert ) => {
+		const transport = createTransport();
 
 		assert.true( !!transport );
 	} );
 
 	QUnit.test( 'abort', function ( assert ) {
-		var transport = createTransport( 0 ),
+		const transport = createTransport( 0 ),
 			request = $.Deferred().promise( { abort: this.sandbox.stub() } );
 
 		transport.request = request;
@@ -53,8 +53,8 @@
 		assert.true( transport.aborted );
 	} );
 
-	QUnit.test( 'createParams', function ( assert ) {
-		var transport = createTransport( 10 ),
+	QUnit.test( 'createParams', ( assert ) => {
+		const transport = createTransport( 10 ),
 			params = transport.createParams( 'foobar.jpg', 0 );
 
 		assert.true( !!params );
@@ -64,7 +64,7 @@
 	} );
 
 	QUnit.test( 'post', function ( assert ) {
-		var stub = this.sandbox.stub(),
+		const stub = this.sandbox.stub(),
 			// post() works on a promise and binds .then, so we have to make
 			// sure it actually is a promise, but also that it calls our stub
 			transport = createTransport( 10, { post: function () {
@@ -82,7 +82,7 @@
 	} );
 
 	QUnit.test( 'upload', function ( assert ) {
-		var request,
+		let request,
 			transport = createTransport( 10, new mw.Api() ),
 			fakeFile = {
 				name: 'test file for fdt.jpg',
@@ -103,7 +103,7 @@
 	} );
 
 	QUnit.test( 'uploadChunk', function ( assert ) {
-		var request,
+		let request,
 			transport = createTransport( 10, new mw.Api() ),
 			fakeFile = {
 				name: 'test file for fdt.jpg',
@@ -132,7 +132,7 @@
 
 	// test invalid server response (in missing 'stage' param)
 	QUnit.test( 'checkStatus invalid API response', function ( assert ) {
-		var done = assert.async(),
+		const done = assert.async(),
 			transport = createTransport( 10, new mw.Api() ),
 			tstub = this.sandbox.stub(),
 			poststub = this.sandbox.stub( transport.api, 'post' ),
@@ -143,7 +143,7 @@
 		postd.resolve( { upload: { result: 'Poll' } } );
 
 		// call tstub upon checkStatus failure, and verify it got called correctly
-		transport.checkStatus().fail( tstub, function () {
+		transport.checkStatus().fail( tstub, () => {
 			assert.true( tstub.calledWith( 'server-error', { errors: [ {
 				code: 'server-error',
 				html: mw.message( 'api-clientside-error-invalidresponse' ).parse()
@@ -154,7 +154,7 @@
 
 	// test retry after server responds upload is still incomplete
 	QUnit.test( 'checkStatus retry', function ( assert ) {
-		var transport = createTransport( 10, new mw.Api() ),
+		const transport = createTransport( 10, new mw.Api() ),
 			usstub = this.sandbox.stub(),
 			poststub = this.sandbox.stub( transport.api, 'post' ),
 			postd = $.Deferred(),
@@ -176,14 +176,14 @@
 
 		// confirm that, once second API call was successful, status resolves,
 		// 2 API calls have gone out & the failed call updates stage accordingly
-		return transport.checkStatus().done( function () {
+		return transport.checkStatus().done( () => {
 			assert.true( poststub.calledTwice );
 			assert.true( usstub.firstCall.calledWith( 'queued' ) );
 		} );
 	} );
 
 	QUnit.test( 'checkStatus success', function ( assert ) {
-		var transport = createTransport( 10, new mw.Api() ),
+		const transport = createTransport( 10, new mw.Api() ),
 			tstub = this.sandbox.stub(),
 			usstub = this.sandbox.stub(),
 			poststub = this.sandbox.stub( transport.api, 'post' ),
@@ -195,14 +195,14 @@
 		poststub.returns( postd.promise() );
 		postd.resolve( 'testing' );
 
-		return transport.checkStatus().done( tstub, function () {
+		return transport.checkStatus().done( tstub, () => {
 			assert.true( tstub.calledWith( 'testing' ) );
 			assert.false( usstub.called );
 		} );
 	} );
 
 	QUnit.test( 'checkStatus error API response', function ( assert ) {
-		var done = assert.async(),
+		const done = assert.async(),
 			transport = createTransport( 10, new mw.Api() ),
 			tstub = this.sandbox.stub(),
 			usstub = this.sandbox.stub(),
@@ -215,7 +215,7 @@
 		poststub.returns( postd.promise() );
 		postd.reject( 'testing', { error: 'testing' } );
 
-		transport.checkStatus().fail( tstub, function () {
+		transport.checkStatus().fail( tstub, () => {
 			assert.true( tstub.calledWith( 'testing', { error: 'testing' } ) );
 			assert.false( usstub.called );
 			done();
diff --git a/tests/qunit/uw.ConcurrentQueue.test.js b/tests/qunit/uw.ConcurrentQueue.test.js
index 2bf97e4..c288d3e 100644
--- a/tests/qunit/uw.ConcurrentQueue.test.js
+++ b/tests/qunit/uw.ConcurrentQueue.test.js
@@ -25,7 +25,7 @@
 	// trigger the next one to execute, which would terminate immediately,
 	// instead of giving time for a second new thingy to be added)
 	function queueAction() {
-		var deferred = $.Deferred();
+		const deferred = $.Deferred();
 		setTimeout( deferred.resolve, 10 );
 		return deferred.promise();
 	}
@@ -33,9 +33,9 @@
 	// Asserts that the given stub functions were called in the given order.
 	// SinonJS's assert.callOrder doesn't allow to check individual calls.
 	function assertCalledInOrder() {
-		var calls, i, currSpyCall, nextSpyCall;
+		let calls, i, currSpyCall, nextSpyCall;
 		// Map stubs to specific calls
-		calls = Array.prototype.map.call( arguments, function ( spy ) {
+		calls = Array.prototype.map.call( arguments, ( spy ) => {
 			if ( !spy.assertCallsInOrderLastCall ) {
 				spy.assertCallsInOrderLastCall = 0;
 			}
@@ -60,8 +60,8 @@
 		);
 	}
 
-	QUnit.test( 'Basic behavior', function ( assert ) {
-		var done, action, queue;
+	QUnit.test( 'Basic behavior', ( assert ) => {
+		let done, action, queue;
 		done = assert.async();
 		action = sinon.spy( queueAction );
 		queue = new uw.ConcurrentQueue( {
@@ -69,11 +69,11 @@
 			action: action
 		} );
 
-		queue.on( 'progress', function () {
+		queue.on( 'progress', () => {
 			QUnit.assert.true( queue.running.length <= 3, 'No more than 3 items are executing' );
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			// All items executed
 			sinon.assert.callCount( action, 5 );
 			// All items executed in the expected order
@@ -86,15 +86,15 @@
 			done();
 		} );
 
-		[ 'a', 'b', 'c', 'd', 'e' ].forEach( function ( v ) {
+		[ 'a', 'b', 'c', 'd', 'e' ].forEach( ( v ) => {
 			queue.addItem( v );
 		} );
 
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Event emitting', function ( assert ) {
-		var done, changeHandler, progressHandler, completeHandler, queue;
+	QUnit.test( 'Event emitting', ( assert ) => {
+		let done, changeHandler, progressHandler, completeHandler, queue;
 		done = assert.async();
 		changeHandler = sinon.stub();
 		progressHandler = sinon.stub();
@@ -110,7 +110,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			sinon.assert.callCount( changeHandler, 3 );
 			sinon.assert.callCount( progressHandler, 3 );
 			sinon.assert.callCount( completeHandler, 1 );
@@ -134,8 +134,8 @@
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Restarting a completed queue', function ( assert ) {
-		var done, queue;
+	QUnit.test( 'Restarting a completed queue', ( assert ) => {
+		let done, queue;
 		done = assert.async();
 		queue = new uw.ConcurrentQueue( {
 			count: 3,
@@ -146,12 +146,12 @@
 		queue.addItem( 'b' );
 		queue.addItem( 'c' );
 
-		queue.once( 'complete', function () {
+		queue.once( 'complete', () => {
 			QUnit.assert.equal( queue.completed, true );
 			queue.addItem( 'd' );
 			queue.addItem( 'e' );
 
-			queue.once( 'complete', function () {
+			queue.once( 'complete', () => {
 				QUnit.assert.equal( queue.completed, true );
 				done();
 			} );
@@ -162,15 +162,15 @@
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Empty queue completes', function ( assert ) {
-		var done, queue;
+	QUnit.test( 'Empty queue completes', ( assert ) => {
+		let done, queue;
 		done = assert.async();
 		queue = new uw.ConcurrentQueue( {
 			count: 3,
 			action: queueAction
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			QUnit.assert.equal( queue.completed, true );
 
 			done();
@@ -179,8 +179,8 @@
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Adding new items while queue running', function ( assert ) {
-		var done, changeHandler, progressHandler, completeHandler, queue;
+	QUnit.test( 'Adding new items while queue running', ( assert ) => {
+		let done, changeHandler, progressHandler, completeHandler, queue;
 		done = assert.async();
 		changeHandler = sinon.stub();
 		progressHandler = sinon.stub();
@@ -196,7 +196,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			sinon.assert.callCount( changeHandler, 6 );
 			sinon.assert.callCount( progressHandler, 6 );
 			sinon.assert.callCount( completeHandler, 1 );
@@ -223,11 +223,11 @@
 		queue.addItem( 'a' );
 		queue.addItem( 'b' );
 		queue.addItem( 'c' );
-		queue.once( 'progress', function () {
+		queue.once( 'progress', () => {
 			queue.addItem( 'd' );
 			queue.addItem( 'e' );
 		} );
-		queue.on( 'progress', function () {
+		queue.on( 'progress', () => {
 			if ( queue.done.length === 5 ) {
 				queue.addItem( 'f' );
 			}
@@ -235,8 +235,8 @@
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Deleting items while queue running', function ( assert ) {
-		var done, changeHandler, progressHandler, completeHandler, queue;
+	QUnit.test( 'Deleting items while queue running', ( assert ) => {
+		let done, changeHandler, progressHandler, completeHandler, queue;
 		done = assert.async();
 		changeHandler = sinon.stub();
 		progressHandler = sinon.stub();
@@ -252,7 +252,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			sinon.assert.callCount( changeHandler, 8 );
 			sinon.assert.callCount( progressHandler, 4 );
 			sinon.assert.callCount( completeHandler, 1 );
@@ -282,18 +282,18 @@
 		queue.addItem( 'd' );
 		queue.addItem( 'e' );
 		queue.addItem( 'f' );
-		queue.once( 'progress', function () {
+		queue.once( 'progress', () => {
 			queue.removeItem( queue.queued[ 0 ] );
 
-			queue.once( 'progress', function () {
+			queue.once( 'progress', () => {
 				queue.removeItem( queue.queued[ 0 ] );
 			} );
 		} );
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Deleting currently running item', function ( assert ) {
-		var done, action, changeHandler, progressHandler, completeHandler, queue;
+	QUnit.test( 'Deleting currently running item', ( assert ) => {
+		let done, action, changeHandler, progressHandler, completeHandler, queue;
 		done = assert.async();
 		action = sinon.spy( queueAction );
 		changeHandler = sinon.stub();
@@ -310,7 +310,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			// Every item in the queue was executed...
 			sinon.assert.callCount( action, 4 );
 
@@ -342,14 +342,14 @@
 		queue.addItem( 'b' );
 		queue.addItem( 'c' );
 		queue.addItem( 'd' );
-		queue.once( 'progress', function () {
+		queue.once( 'progress', () => {
 			queue.removeItem( queue.running[ 0 ] );
 		} );
 		queue.startExecuting();
 	} );
 
-	QUnit.test( 'Adding a new item when almost done', function ( assert ) {
-		var done, action, changeHandler, progressHandler, completeHandler, queue, onProgress;
+	QUnit.test( 'Adding a new item when almost done', ( assert ) => {
+		let done, action, changeHandler, progressHandler, completeHandler, queue, onProgress;
 		done = assert.async();
 		// This test seems extra flaky and was occasionally failing, double the delays
 		action = sinon.spy( queueAction );
@@ -367,7 +367,7 @@
 			complete: completeHandler
 		} );
 
-		queue.on( 'complete', function () {
+		queue.on( 'complete', () => {
 			sinon.assert.callCount( action, 5 );
 			sinon.assert.callCount( changeHandler, 5 );
 			sinon.assert.callCount( progressHandler, 5 );
diff --git a/tests/qunit/uw.TitleDetailsWidget.test.js b/tests/qunit/uw.TitleDetailsWidget.test.js
index 8992c60..571ab1c 100644
--- a/tests/qunit/uw.TitleDetailsWidget.test.js
+++ b/tests/qunit/uw.TitleDetailsWidget.test.js
@@ -1,7 +1,7 @@
 ( function ( uw ) {
 	'use strict';
 
-	var fileNs, makeTitleInFileNSCases;
+	let fileNs, makeTitleInFileNSCases;
 	fileNs = mw.config.get( 'wgFormattedNamespaces' )[ 6 ];
 	makeTitleInFileNSCases = [ {
 		filename: 'foo.png',
@@ -35,11 +35,11 @@
 
 	QUnit.module( 'uw.TitleDetailsWidget', QUnit.newMwEnvironment() );
 
-	QUnit.test( '.static.makeTitleInFileNS()', function ( assert ) {
-		var makeTitleInFileNS = uw.TitleDetailsWidget.static.makeTitleInFileNS;
+	QUnit.test( '.static.makeTitleInFileNS()', ( assert ) => {
+		const makeTitleInFileNS = uw.TitleDetailsWidget.static.makeTitleInFileNS;
 
-		makeTitleInFileNSCases.forEach( function ( test ) {
-			var title = makeTitleInFileNS( test.filename );
+		makeTitleInFileNSCases.forEach( ( test ) => {
+			const title = makeTitleInFileNS( test.filename );
 			assert.strictEqual(
 				title ? title.getPrefixedText() : title,
 				test.prefixedText,
-- 
2.39.5


--- end ---
Source code is licensed under the AGPL.