mediawiki/extensions/UploadWizard: main (log #1236558)

sourcepatches

This run took 62 seconds.

$ date
--- stdout ---
Sun Apr  7 12:55:09 UTC 2024

--- end ---
$ git clone file:///srv/git/mediawiki-extensions-UploadWizard.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 ---
8f3681887eef361e7c5bd66d5f675842eb1f8012 refs/heads/master

--- end ---
$ /usr/bin/npm audit --json
--- stdout ---
{
  "auditReportVersion": 2,
  "vulnerabilities": {},
  "metadata": {
    "vulnerabilities": {
      "info": 0,
      "low": 0,
      "moderate": 0,
      "high": 0,
      "critical": 0,
      "total": 0
    },
    "dependencies": {
      "prod": 1,
      "dev": 469,
      "optional": 0,
      "peer": 7,
      "peerOptional": 0,
      "total": 469
    }
  }
}

--- 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: 39 installs, 0 updates, 0 removals
  - Locking composer/pcre (3.1.3)
  - Locking composer/semver (3.4.0)
  - Locking composer/spdx-licenses (1.5.8)
  - Locking composer/xdebug-handler (3.0.4)
  - Locking dealerdirect/phpcodesniffer-composer-installer (v1.0.0)
  - Locking doctrine/deprecations (1.1.3)
  - Locking felixfbecker/advanced-json-rpc (v3.2.1)
  - Locking mediawiki/mediawiki-codesniffer (v43.0.0)
  - Locking mediawiki/mediawiki-phan-config (0.14.0)
  - Locking mediawiki/minus-x (1.1.1)
  - Locking mediawiki/phan-taint-check-plugin (6.0.0)
  - Locking microsoft/tolerant-php-parser (v0.1.2)
  - Locking netresearch/jsonmapper (v4.4.1)
  - Locking phan/phan (5.4.3)
  - 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.3.2)
  - Locking phpcsstandards/phpcsextra (1.1.2)
  - Locking phpcsstandards/phpcsutils (1.0.9)
  - Locking phpdocumentor/reflection-common (2.2.0)
  - Locking phpdocumentor/reflection-docblock (5.3.0)
  - Locking phpdocumentor/type-resolver (1.8.2)
  - Locking phpstan/phpdoc-parser (1.28.0)
  - Locking psr/container (2.0.2)
  - Locking psr/log (2.0.0)
  - Locking sabre/event (5.1.4)
  - Locking squizlabs/php_codesniffer (3.8.1)
  - Locking symfony/console (v5.4.36)
  - Locking symfony/deprecation-contracts (v3.4.0)
  - Locking symfony/polyfill-ctype (v1.29.0)
  - Locking symfony/polyfill-intl-grapheme (v1.29.0)
  - Locking symfony/polyfill-intl-normalizer (v1.29.0)
  - Locking symfony/polyfill-mbstring (v1.29.0)
  - Locking symfony/polyfill-php73 (v1.29.0)
  - Locking symfony/polyfill-php80 (v1.29.0)
  - Locking symfony/service-contracts (v3.4.2)
  - Locking symfony/string (v6.4.4)
  - 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: 39 installs, 0 updates, 0 removals
    0 [>---------------------------]    0 [->--------------------------]
  - Installing squizlabs/php_codesniffer (3.8.1): Extracting archive
  - Installing dealerdirect/phpcodesniffer-composer-installer (v1.0.0): Extracting archive
  - Installing composer/pcre (3.1.3): Extracting archive
  - Installing symfony/polyfill-php80 (v1.29.0): Extracting archive
  - Installing phpcsstandards/phpcsutils (1.0.9): Extracting archive
  - Installing phpcsstandards/phpcsextra (1.1.2): Extracting archive
  - Installing symfony/polyfill-mbstring (v1.29.0): Extracting archive
  - Installing composer/spdx-licenses (1.5.8): Extracting archive
  - Installing composer/semver (3.4.0): Extracting archive
  - Installing mediawiki/mediawiki-codesniffer (v43.0.0): Extracting archive
  - Installing tysonandre/var_representation_polyfill (0.1.3): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.29.0): Extracting archive
  - Installing symfony/polyfill-intl-grapheme (v1.29.0): Extracting archive
  - Installing symfony/polyfill-ctype (v1.29.0): Extracting archive
  - Installing symfony/string (v6.4.4): Extracting archive
  - Installing psr/container (2.0.2): Extracting archive
  - Installing symfony/service-contracts (v3.4.2): Extracting archive
  - Installing symfony/polyfill-php73 (v1.29.0): Extracting archive
  - Installing symfony/deprecation-contracts (v3.4.0): Extracting archive
  - Installing symfony/console (v5.4.36): Extracting archive
  - Installing sabre/event (5.1.4): Extracting archive
  - Installing netresearch/jsonmapper (v4.4.1): Extracting archive
  - Installing microsoft/tolerant-php-parser (v0.1.2): Extracting archive
  - Installing webmozart/assert (1.11.0): Extracting archive
  - Installing phpstan/phpdoc-parser (1.28.0): Extracting archive
  - Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
  - Installing doctrine/deprecations (1.1.3): Extracting archive
  - Installing phpdocumentor/type-resolver (1.8.2): Extracting archive
  - Installing phpdocumentor/reflection-docblock (5.3.0): Extracting archive
  - Installing felixfbecker/advanced-json-rpc (v3.2.1): Extracting archive
  - Installing psr/log (2.0.0): Extracting archive
  - Installing composer/xdebug-handler (3.0.4): Extracting archive
  - Installing phan/phan (5.4.3): Extracting archive
  - Installing mediawiki/phan-taint-check-plugin (6.0.0): Extracting archive
  - Installing mediawiki/mediawiki-phan-config (0.14.0): Extracting archive
  - Installing mediawiki/minus-x (1.1.1): 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.3.2): Extracting archive
  0/37 [>---------------------------]   0%
 22/37 [================>-----------]  59%
 36/37 [===========================>]  97%
 37/37 [============================] 100%
3 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
16 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.26.0 -> 0.27.0
$ /usr/bin/npm install
--- stderr ---
npm WARN deprecated stylelint-stylistic@0.4.3: This package has been deprecated in favor of @stylistic/stylelint-plugin
--- stdout ---

added 468 packages, and audited 469 packages in 7s

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

found 0 vulnerabilities

--- 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 469 packages in 1s

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

found 0 vulnerabilities

--- 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.Details.js
  244:51  warning  'i' is already declared in the upper scope on line 234 column 7          no-shadow
  244:54  warning  'warnings' is already declared in the upper scope on line 233 column 66  no-shadow

/src/repo/resources/controller/uw.controller.Step.js
  23:1  warning  Invalid JSDoc tag name "mixins"  jsdoc/check-tag-names

/src/repo/resources/deed/dialog/uw.deed.dialog.PatentDialog.js
  116:1  warning  Missing JSDoc @param "ownership" type  jsdoc/require-param-type
  117:1  warning  Missing JSDoc @param "grant" type      jsdoc/require-param-type

/src/repo/resources/deed/uw.deed.Abstract.js
   46:14  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  220:1   warning  Missing JSDoc @return type                                                           jsdoc/require-returns-type

/src/repo/resources/deed/uw.deed.OwnWork.js
  464:1  warning  Missing JSDoc @return type  jsdoc/require-returns-type

/src/repo/resources/deed/uw.deed.ThirdParty.js
  321:6  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/details/uw.DateDetailsWidget.js
  147:20  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  173:70  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  176:70  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  179:70  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/details/uw.LanguageDropdownWidget.js
  14:53  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details  mediawiki/class-doc

/src/repo/resources/details/uw.LocationDetailsWidget.js
  238:28  warning  Unsafe Regular Expression  security/detect-unsafe-regex

/src/repo/resources/details/uw.MultipleLanguageInputWidget.js
    8:1   warning  Invalid JSDoc tag name "mixins"                                                      jsdoc/check-tag-names
  181:10  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/details/uw.TitleDetailsWidget.js
   49:23  warning  Found non-literal argument to RegExp Constructor                                     security/detect-non-literal-regexp
   86:14  warning  Found non-literal argument to RegExp Constructor                                     security/detect-non-literal-regexp
  134:15  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  193:22  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/details/uw.UlsWidget.js
  30:3  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details  mediawiki/class-doc

/src/repo/resources/jquery.arrowSteps/jquery.arrowSteps.js
  88:1  warning  Invalid JSDoc tag name "mixins"  jsdoc/check-tag-names

/src/repo/resources/metadata/uw.MetadataContent.js
  118:1  warning  The type 'change' is undefined  jsdoc/no-undefined-types

/src/repo/resources/mw.DestinationChecker.js
  11:3  warning  Found more than one @return declaration  jsdoc/require-returns
  11:3  warning  Found more than one @return declaration  jsdoc/require-returns-check
  34:3  warning  Found more than one @return declaration  jsdoc/require-returns
  34:3  warning  Found more than one @return declaration  jsdoc/require-returns-check
  85:3  warning  Found more than one @return declaration  jsdoc/require-returns
  85:3  warning  Found more than one @return declaration  jsdoc/require-returns-check

/src/repo/resources/mw.Escaper.js
   63:13  warning  Unsafe Regular Expression                         security/detect-unsafe-regex
  121:19  warning  Found non-literal argument to RegExp Constructor  security/detect-non-literal-regexp

/src/repo/resources/mw.FlickrChecker.js
   73:42  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   75:49  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   76:50  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   77:44  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   78:46  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   79:48  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
  199:1   warning  The type 'getPhotos' is undefined                                    jsdoc/no-undefined-types
  213:26  warning  'data' is already declared in the upper scope on line 206 column 24  no-shadow
  237:1   warning  The type 'getCollection' is undefined                                jsdoc/no-undefined-types
  296:57  warning  'data' is already declared in the upper scope on line 285 column 24  no-shadow
  308:1   warning  The type 'getPhotos' is undefined                                    jsdoc/no-undefined-types
  329:1   warning  The type 'getPhotos' is undefined                                    jsdoc/no-undefined-types
  580:49  warning  ES2019 'Symbol.prototype.description' property is forbidden          es-x/no-symbol-prototype-description
  678:4   warning  ES2019 'Symbol.prototype.description' property is forbidden          es-x/no-symbol-prototype-description
  697:42  warning  ES2019 'Symbol.prototype.description' property is forbidden          es-x/no-symbol-prototype-description

/src/repo/resources/mw.UploadWizard.js
    4:1   warning  Missing JSDoc @param "uw" type                                      jsdoc/require-param-type
   83:23  warning  'steps' is already declared in the upper scope on line 60 column 5  no-shadow
  113:25  warning  'steps' is already declared in the upper scope on line 60 column 5  no-shadow

/src/repo/resources/mw.UploadWizardDeedChooser.js
   7:1   warning  Invalid JSDoc tag name "mixins"                                                      jsdoc/check-tag-names
  36:42  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
  40:6   warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  48:8   warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  60:17  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc

/src/repo/resources/mw.UploadWizardDetails.js
  260:9   warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  264:14  warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  462:10  warning  'matches' is already declared in the upper scope on line 439 column 42             no-shadow
  554:16  warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  644:3   warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  712:9   warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  713:45  warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  763:4   warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  766:5   warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description

/src/repo/resources/mw.UploadWizardLicenseInput.js
   51:41  warning  'group' is already declared in the upper scope on line 38 column 7                   no-shadow
   55:20  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
   64:43  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
   69:51  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
   96:31  warning  'group' is already declared in the upper scope on line 38 column 7                   no-shadow
  293:37  warning  'errors' is already declared in the upper scope on line 291 column 7                 no-shadow
  294:18  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  334:26  warning  'errors' is already declared in the upper scope on line 291 column 7                 no-shadow

/src/repo/resources/mw.UploadWizardUpload.js
    8:1   warning  Missing JSDoc @param "uw" type    jsdoc/require-param-type
   10:14  error    'uw' is defined but never used    no-unused-vars
   22:1   warning  Invalid JSDoc tag name "mixins"   jsdoc/check-tag-names
  226:16  warning  ES2015 'Uint8Array' is forbidden  es-x/no-typed-arrays

/src/repo/resources/mw.UploadWizardUploadInterface.js
    6:1  warning  Invalid JSDoc tag name "mixins"                                                      jsdoc/check-tag-names
  113:3  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/transports/mw.FormDataTransport.js
    7:1   warning  Invalid JSDoc tag name "mixins"                                       jsdoc/check-tag-names
  165:17  warning  'offset' is already declared in the upper scope on line 155 column 4  no-shadow

/src/repo/resources/ui/steps/uw.ui.Thanks.js
  165:4  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details  mediawiki/class-doc

/src/repo/resources/ui/steps/uw.ui.Upload.js
  266:39  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  271:33  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/ui/uw.ui.Step.js
  23:1  warning  Invalid JSDoc tag name "mixins"  jsdoc/check-tag-names

/src/repo/resources/ui/uw.ui.Wizard.js
   23:1   warning  Invalid JSDoc tag name "mixins"                                                      jsdoc/check-tag-names
  144:25  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  149:32  warning  '$arrow' is already declared in the upper scope on line 141 column 8                 no-shadow

/src/repo/resources/uw.ConcurrentQueue.js
  10:1  warning  Invalid JSDoc tag name "mixins"  jsdoc/check-tag-names

/src/repo/resources/uw.CopyMetadataWidget.js
   30:23  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  181:31  warning  Unsafe Regular Expression                                                            security/detect-unsafe-regex

/src/repo/resources/uw.LicenseGroup.js
  140:39  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
  175:47  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
  362:20  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
  366:12  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  381:5   warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/uw.ValidationMessageElement.js
  39:2   warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  90:15  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details  mediawiki/class-doc

/src/repo/resources/uw.units.js
  21:11  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

✖ 98 problems (1 error, 97 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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"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-len","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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/.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":"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":[],"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":"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":"no-shadow","severity":1,"message":"'i' is already declared in the upper scope on line 234 column 7.","line":244,"column":51,"nodeType":"Identifier","messageId":"noShadow","endLine":244,"endColumn":52},{"ruleId":"no-shadow","severity":1,"message":"'warnings' is already declared in the upper scope on line 233 column 66.","line":244,"column":54,"nodeType":"Identifier","messageId":"noShadow","endLine":244,"endColumn":62}],"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":140,"column":56,"nodeType":"CallExpression","endLine":140,"endColumn":85,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  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\tvar 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( function ( upload ) {\n\t\t\tvar 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\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\tvar 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( function ( upload ) {\n\t\t\tif ( upload && invalidStates.indexOf( upload.state ) === -1 ) {\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, $( '#mwe-upwiz-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\tvar details = this;\n\n\t\tthis.valid().done( function ( 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\tvar 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( function ( upload ) {\n\t\t\t// Update any error/warning messages about all DetailsWidgets\n\t\t\tvar promise = upload.details.checkValidity( true ).then( function () {\n\t\t\t\tvar warnings = [],\n\t\t\t\t\terrors = [],\n\t\t\t\t\ttitle;\n\n\t\t\t\tArray.prototype.forEach.call( arguments, function ( 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( 'mwe-upwiz-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\tvar warnings = [],\n\t\t\t\terrors = [];\n\n\t\t\tArray.prototype.forEach.call( arguments, function ( 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\tvar i,\n\t\t\t$message = $( '<p>' ).text( mw.message( 'mwe-upwiz-dialog-warning' ).text() ),\n\t\t\t$ul = $( '<ul>' );\n\n\t\t// parse warning messages\n\t\twarnings = warnings.map( function ( warning ) {\n\t\t\treturn warning.text();\n\t\t} );\n\n\t\t// omit duplicates\n\t\twarnings = warnings.filter( function ( warning, i, warnings ) {\n\t\t\treturn warnings.indexOf( warning ) === i;\n\t\t} );\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.confirm( $message.append( $ul ), {\n\t\t\ttitle: mw.message( 'mwe-upwiz-dialog-title' ).text()\n\t\t} );\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\tvar\n\t\t\tdeferred = $.Deferred(),\n\t\t\tdetails = this;\n\n\t\tthis.uploads.forEach( function ( 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\tvar details = this;\n\n\t\tthis.uploads.forEach( function ( 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( function () {\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":"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.Metadata.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":"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":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":23,"column":1,"nodeType":"Block","endLine":23,"endColumn":1}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  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 * @mixins OO.EventEmitter\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\tvar 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', function () {\n\t\t\tstep.moveNext();\n\t\t} );\n\n\t\tthis.ui.on( 'previous-step', function () {\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\tvar 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( function ( 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\tvar step = this;\n\n\t\tthis.uploads.forEach( function ( 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\tvar controller = this;\n\n\t\tObject.keys( this.uploadHandlers ).forEach( function ( event ) {\n\t\t\tvar 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\tvar controller = this;\n\n\t\tObject.keys( this.uploadHandlers ).forEach( function ( event ) {\n\t\t\tvar 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\tvar okCount = this.getUploadStatesCount( this.finishState );\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\tvar $buttons = this.ui.$div.find( '.mwe-upwiz-buttons' ).show();\n\t\t$buttons.find( '.mwe-upwiz-file-next-all-ok, .mwe-upwiz-file-next-some-failed, .mwe-upwiz-file-next-all-failed' )\n\t\t\t.hide();\n\n\t\tif ( okCount === this.uploads.length ) {\n\t\t\t$buttons.find( '.mwe-upwiz-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( '.mwe-upwiz-file-next-all-failed' ).show();\n\t\t} else if ( this.getUploadStatesCount( 'transporting' ) === 0 ) {\n\t\t\t$buttons.find( '.mwe-upwiz-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\tvar 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( function ( upload ) {\n\t\t\tif ( states.indexOf( upload.state ) > -1 ) {\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\tvar 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\tvar 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\tvar toRemove = [];\n\t\tthis.uploads.forEach( function ( 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":"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":"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":[],"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":"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":[],"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":"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":"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/dialog/uw.deed.dialog.PatentDialog.js","messages":[{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"ownership\" type.","line":116,"column":1,"nodeType":"Block","endLine":116,"endColumn":1},{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"grant\" type.","line":117,"column":1,"nodeType":"Block","endLine":117,"endColumn":1}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * @param {Object} config Dialog config\n\t * @param {Object} uwConfig UploadWizard config\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @constructor\n\t */\n\tuw.PatentDialog = function PatentDialog( config, uwConfig, uploads ) {\n\t\tuw.PatentDialog.super.call( this, config );\n\t\tthis.config = uwConfig;\n\t\tthis.panels = config.panels || [];\n\t\tthis.uploads = uploads;\n\t};\n\n\tOO.inheritClass( uw.PatentDialog, OO.ui.ProcessDialog );\n\tOO.mixinClass( uw.PatentDialog, OO.EventEmitter );\n\n\tuw.PatentDialog.static.name = 'uwPatentDialog';\n\tuw.PatentDialog.static.title = mw.msg( 'mwe-upwiz-patent-dialog-title' );\n\tuw.PatentDialog.static.actions = [\n\t\t{\n\t\t\tflags: [ 'primary', 'progressive' ],\n\t\t\tindicator: 'next',\n\t\t\taction: 'confirm',\n\t\t\tlabel: OO.ui.deferMsg( 'mwe-upwiz-patent-dialog-button-next' ),\n\t\t\tdisabled: true\n\t\t},\n\t\t{\n\t\t\tflags: [ 'safe', 'back' ],\n\t\t\ticon: 'previous',\n\t\t\ttitle: OO.ui.deferMsg( 'mwe-upwiz-patent-dialog-button-back' ),\n\t\t\tframed: false\n\t\t}\n\t];\n\n\tuw.PatentDialog.prototype.initialize = function () {\n\t\tvar filenames = [],\n\t\t\tlabel = new OO.ui.LabelWidget(),\n\t\t\tpanels = new OO.ui.PanelLayout( { padded: true, expanded: false } );\n\n\t\tuw.PatentDialog.super.prototype.initialize.apply( this, arguments );\n\n\t\tthis.uploads.forEach( function ( upload ) {\n\t\t\tfilenames.push(\n\t\t\t\t// use given title (if available already) or fall back to filename\n\t\t\t\tupload.details ? upload.details.getTitle().getMainText() : upload.title.getMainText()\n\t\t\t);\n\t\t} );\n\n\t\tthis.content = new OO.ui.PanelLayout( { padded: false, expanded: false } );\n\t\tthis.content.$element.addClass( 'mwe-upwiz-patent-rights' );\n\n\t\tif ( this.panels.indexOf( 'filelist' ) !== -1 ) {\n\t\t\tlabel.setLabel( mw.msg( 'mwe-upwiz-patent-dialog-title-filename', mw.language.listToText( filenames ) ) );\n\t\t\tlabel.$element.addClass( 'oo-ui-processDialog-title mwe-upwiz-patent-rights-filelist' );\n\t\t\tthis.content.$element.append( label.$element );\n\t\t}\n\n\t\tif ( this.panels.indexOf( 'warranty' ) !== -1 ) {\n\t\t\tpanels.$element.append( this.getWarrantyLayout().$element );\n\t\t}\n\n\t\tif (\n\t\t\tthis.panels.indexOf( 'license-ownership' ) !== -1 ||\n\t\t\tthis.panels.indexOf( 'license-grant' ) !== -1\n\t\t) {\n\t\t\tpanels.$element.append( this.getLicenseLayout(\n\t\t\t\tthis.panels.indexOf( 'license-ownership' ) !== -1,\n\t\t\t\tthis.panels.indexOf( 'license-grant' ) !== -1\n\t\t\t).$element );\n\t\t}\n\n\t\tthis.checkbox = new OO.ui.CheckboxInputWidget();\n\t\tthis.checkbox.connect( this, { change: 'onCheckboxChange' } );\n\t\tpanels.$element.append( this.getCheckboxLayout().$element );\n\n\t\tthis.content.$element.append( panels.$element );\n\t\tthis.$body.append( this.content.$element );\n\t};\n\n\t/**\n\t * @return {OO.ui.PanelLayout}\n\t */\n\tuw.PatentDialog.prototype.getWarrantyLayout = function () {\n\t\tvar layout = new OO.ui.PanelLayout( { padded: true, expanded: false } );\n\n\t\tlayout.$element.append(\n\t\t\t$( '<strong>' ).text( mw.msg( 'mwe-upwiz-patent-dialog-title-warranty' ) ),\n\t\t\t$( '<p>' ).text( mw.msg( 'mwe-upwiz-patent-dialog-text-warranty', this.uploads.length ) ),\n\t\t\t$( '<a>' )\n\t\t\t\t.text( mw.msg( 'mwe-upwiz-patent-dialog-link-warranty' ) )\n\t\t\t\t.attr( { target: '_blank', href: this.config.patents.url.warranty } )\n\t\t);\n\n\t\treturn layout;\n\t};\n\n\t/**\n\t * @param ownership\n\t * @param grant\n\t * @return {OO.ui.PanelLayout}\n\t */\n\tuw.PatentDialog.prototype.getLicenseLayout = function ( ownership, grant ) {\n\t\tvar layout = new OO.ui.PanelLayout( { padded: true, expanded: false } );\n\n\t\tif ( ownership ) {\n\t\t\tlayout.$element.append(\n\t\t\t\t$( '<strong>' ).text( mw.msg( 'mwe-upwiz-patent-dialog-title-license' ) ),\n\t\t\t\t$( '<p>' ).text( mw.msg( 'mwe-upwiz-patent-dialog-text-license', this.uploads.length ) ),\n\t\t\t\t$( '<a>' )\n\t\t\t\t\t.text( mw.msg( 'mwe-upwiz-patent-dialog-link-license' ) )\n\t\t\t\t\t.attr( { target: '_blank', href: this.config.patents.url.license } )\n\t\t\t);\n\t\t}\n\n\t\tif ( grant ) {\n\t\t\tlayout.$element.append(\n\t\t\t\t$( '<p>' ).text( mw.msg( 'mwe-upwiz-patent-dialog-text-license-grant', this.uploads.length ) ),\n\t\t\t\t$( '<a>' )\n\t\t\t\t\t.text( mw.msg( 'mwe-upwiz-patent-dialog-link-license-grant' ) )\n\t\t\t\t\t.attr( { target: '_blank', href: this.config.patents.url.legalcode } )\n\t\t\t);\n\t\t}\n\n\t\treturn layout;\n\t};\n\n\t/**\n\t * @return {OO.ui.PanelLayout}\n\t */\n\tuw.PatentDialog.prototype.getCheckboxLayout = function () {\n\t\tvar checkbox = new OO.ui.FieldLayout( this.checkbox, {\n\t\t\tlabel: mw.msg( 'mwe-upwiz-patent-dialog-checkbox-label' ),\n\t\t\talign: 'inline'\n\t\t} );\n\n\t\treturn new OO.ui.PanelLayout( {\n\t\t\tpadded: true,\n\t\t\texpanded: false,\n\t\t\t$content: checkbox.$element\n\t\t} );\n\t};\n\n\t/**\n\t * @param {boolean} checked\n\t */\n\tuw.PatentDialog.prototype.onCheckboxChange = function ( checked ) {\n\t\tvar button = this.actions.get( { flags: 'primary' } )[ 0 ];\n\t\tbutton.setDisabled( !checked );\n\t};\n\n\t/**\n\t * @param {string} action\n\t * @return {OO.ui.Process} Action process\n\t */\n\tuw.PatentDialog.prototype.getActionProcess = function ( action ) {\n\t\tvar dialog = this;\n\n\t\tif ( action === '' ) {\n\t\t\tthis.emit( 'disagree' );\n\t\t} else if ( action === 'confirm' ) {\n\t\t\treturn new OO.ui.Process( function () {\n\t\t\t\tdialog.emit( 'agree' );\n\t\t\t\tdialog.close( { action: action } );\n\t\t\t} );\n\t\t}\n\n\t\treturn uw.PatentDialog.super.prototype.getActionProcess.call( this, action );\n\t};\n\n\tuw.PatentDialog.prototype.getBodyHeight = function () {\n\t\treturn this.content.$element.outerHeight( true );\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":"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/dialog/uw.deed.dialog.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":"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":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":46,"column":14,"nodeType":"CallExpression","endLine":50,"endColumn":8},{"ruleId":"jsdoc/require-returns-type","severity":1,"message":"Missing JSDoc @return type.","line":220,"column":1,"nodeType":"Block","endLine":220,"endColumn":1}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents a generic deed.\n\t *\n\t * @class uw.deed.Abstract\n\t * @constructor\n\t * @param {string} name The name of this step\n\t * @param {Object} config The UW config\n\t * @param {mw.UploadWizardUpload[]} uploads Array of uploads that this deed refers to\n\t */\n\tuw.deed.Abstract = function UWDeedInterface( name, config, uploads ) {\n\t\tvar tcName, details, field, input;\n\t\tthis.name = name;\n\t\tthis.config = config;\n\t\tuw.deed.Abstract.prototype.instanceCount++;\n\t\tthis.instanceCount = uw.deed.Abstract.prototype.instanceCount;\n\n\t\tthis.templateOptions = {};\n\t\tif ( config.templateOptions && config.templateOptions[ name ] ) {\n\t\t\tfor ( tcName in this.config.templateOptions[ name ] ) {\n\t\t\t\tdetails = this.config.templateOptions[ name ][ tcName ];\n\t\t\t\tinput = new OO.ui.CheckboxInputWidget( {\n\t\t\t\t\tname: tcName,\n\t\t\t\t\tvalue: details.template\n\t\t\t\t} );\n\t\t\t\tfield = new uw.FieldLayout(\n\t\t\t\t\tinput,\n\t\t\t\t\t{\n\t\t\t\t\t\tlabel: mw.message(\n\t\t\t\t\t\t\tdetails.label,\n\t\t\t\t\t\t\tuploads.length,\n\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t).parse(),\n\t\t\t\t\t\talign: 'inline',\n\t\t\t\t\t\trequired: true // not really required, set true so \"optional\" won't display\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tthis.templateOptions[ tcName ] = {\n\t\t\t\t\tfield: field,\n\t\t\t\t\tinput: input\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * @type {number}\n\t */\n\tuw.deed.Abstract.prototype.instanceCount = 0;\n\n\tuw.deed.Abstract.prototype.unload = function () {};\n\n\t/**\n\t * @return {number}\n\t */\n\tuw.deed.Abstract.prototype.getInstanceCount = function () {\n\t\treturn this.instanceCount;\n\t};\n\n\t/**\n\t * @return {uw.FieldLayout[]} Fields that need validation\n\t */\n\tuw.deed.Abstract.prototype.getFields = function () {\n\t\treturn [];\n\t};\n\n\t/**\n\t * @param {jQuery} $selector\n\t */\n\tuw.deed.Abstract.prototype.setFormFields = function () {};\n\n\t/**\n\t * @method\n\t * @abstract\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {string}\n\t */\n\tuw.deed.Abstract.prototype.getSourceWikiText = null;\n\n\t/**\n\t * @method\n\t * @abstract\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {string}\n\t */\n\tuw.deed.Abstract.prototype.getAuthorWikiText = null;\n\n\t/**\n\t * Get wikitext representing the licenses selected in the license object\n\t *\n\t * @method\n\t * @abstract\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {string} wikitext of all applicable license templates.\n\t */\n\tuw.deed.Abstract.prototype.getLicenseWikiText = null;\n\n\t/**\n\t * @return {Object}\n\t */\n\tuw.deed.Abstract.prototype.getSerialized = function () {\n\t\tvar name, selectedTemplateOptions = [];\n\t\tfor ( name in this.templateOptions ) {\n\t\t\tif ( this.templateOptions[ name ].input.isSelected() ) {\n\t\t\t\tselectedTemplateOptions.push( name );\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tselectedTemplateOptions: selectedTemplateOptions\n\t\t};\n\t};\n\n\t/**\n\t * @param {Object} serialized\n\t */\n\tuw.deed.Abstract.prototype.setSerialized = function ( serialized ) {\n\t\tvar self = this;\n\t\tif ( serialized.name ) {\n\t\t\tthis.name = serialized.name;\n\t\t}\n\t\tserialized.selectedTemplateOptions.forEach( function ( name ) {\n\t\t\tself.templateOptions[ name ].input.setSelected( true );\n\t\t} );\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {boolean}\n\t */\n\tuw.deed.Abstract.prototype.needsPatentAgreement = function ( upload ) {\n\t\tvar extensions = this.config.patents ? this.config.patents.extensions : [];\n\n\t\treturn extensions.indexOf( upload.title.getExtension().toLowerCase() ) !== -1;\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @return {uw.FieldLayout}\n\t */\n\tuw.deed.Abstract.prototype.getPatentAgreementField = function ( uploads ) {\n\t\tvar field = new OO.ui.HiddenInputWidget();\n\t\tfield.getErrors = this.getPatentAgreementErrors.bind( this, field, uploads );\n\t\tfield.getWarnings = $.Deferred().resolve( [] ).promise.bind();\n\n\t\treturn new uw.FieldLayout( field );\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @return {uw.PatentDialog}\n\t */\n\tuw.deed.Abstract.prototype.getPatentDialog = function ( uploads ) {\n\t\tvar config = { panels: [ 'warranty' ] };\n\n\t\t// Only show filename list when in \"details\" step & we're showing the dialog for individual files\n\t\tif ( uploads[ 0 ] && uploads[ 0 ].state === 'details' ) {\n\t\t\tconfig.panels.unshift( 'filelist' );\n\t\t}\n\n\t\treturn new uw.PatentDialog( config, this.config, uploads );\n\t};\n\n\t/**\n\t * @param {OO.ui.InputWidget} input\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @param {boolean} thorough\n\t * @return {jQuery.Promise}\n\t */\n\tuw.deed.Abstract.prototype.getPatentAgreementErrors = function ( input, uploads, thorough ) {\n\t\tvar deed = this,\n\t\t\twindowManager, dialog, deferred;\n\n\t\t// We only want to test this on submit\n\t\tif ( !thorough ) {\n\t\t\treturn $.Deferred().resolve( [] ).promise();\n\t\t}\n\n\t\tif ( this.patentAgreed !== true ) {\n\t\t\tdeferred = $.Deferred();\n\t\t\twindowManager = new OO.ui.WindowManager();\n\t\t\tdialog = this.getPatentDialog( uploads );\n\n\t\t\t$( document.body ).append( windowManager.$element );\n\t\t\twindowManager.addWindows( [ dialog ] );\n\t\t\twindowManager.openWindow( dialog );\n\n\t\t\tdialog.on( 'disagree', function () {\n\t\t\t\tdeferred.resolve( [ mw.message( 'mwe-upwiz-error-patent-disagree' ) ] );\n\t\t\t} );\n\t\t\tdialog.on( 'agree', function () {\n\t\t\t\tdeed.patentAgreed = true;\n\t\t\t\tdeferred.resolve( [] );\n\t\t\t} );\n\n\t\t\treturn deferred.promise();\n\t\t} else {\n\t\t\treturn $.Deferred().resolve( [] ).promise();\n\t\t}\n\t};\n\n\t/**\n\t * @return string\n\t */\n\tuw.deed.Abstract.prototype.getTemplateOptionsWikiText = function () {\n\t\tvar name, option, wikitext = '';\n\t\tfor ( name in this.templateOptions ) {\n\t\t\toption = this.templateOptions[ name ].input;\n\t\t\tif ( option.isSelected() ) {\n\t\t\t\twikitext += option.getValue();\n\t\t\t}\n\t\t}\n\t\treturn wikitext;\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":"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":"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":"jsdoc/require-returns-type","severity":1,"message":"Missing JSDoc @return type.","line":464,"column":1,"nodeType":"Block","endLine":464,"endColumn":1}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  If not, see <http://www.gnu.org/licenses/>.\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\tvar self = this,\n\t\t\tprefAuthName = mw.user.options.get( 'upwiz_licensename' ),\n\t\t\trevealOptionContent = function ( $parent, $child ) {\n\t\t\t\t// hide sub-content for all options\n\t\t\t\t$parent\n\t\t\t\t\t.find( '.mwe-upwiz-deed-radio-reveal' )\n\t\t\t\t\t.filter( function () {\n\t\t\t\t\t\t// .mwe-upwiz-deed-radio-reveal reveals content when an option is\n\t\t\t\t\t\t// selected, but we need it to ignore nested instances in order not\n\t\t\t\t\t\t// to reveal content from sub-options until they've been selected\n\t\t\t\t\t\treturn $( this ).parentsUntil( $parent, '.mwe-upwiz-deed-radio-reveal' ).length === 0;\n\t\t\t\t\t} )\n\t\t\t\t\t.hide();\n\t\t\t\t// and reveal only in the selected option\n\t\t\t\t$child\n\t\t\t\t\t.find( '.mwe-upwiz-deed-radio-reveal' )\n\t\t\t\t\t.filter( function () {\n\t\t\t\t\t\treturn $( this ).parentsUntil( $child, '.mwe-upwiz-deed-radio-reveal' ).length === 0;\n\t\t\t\t\t} )\n\t\t\t\t\t.show();\n\t\t\t};\n\n\t\tuw.deed.Abstract.call( this, 'ownwork', config, uploads );\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// Author, hidden\n\t\tthis.authorInput = new OO.ui.HiddenInputWidget( {\n\t\t\tname: 'author',\n\t\t\tvalue: prefAuthName\n\t\t} );\n\n\t\t// Main origin radio\n\t\tthis.originRadio = new OO.ui.RadioSelectWidget( {\n\t\t\titems: [\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: mw.message(\n\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-own',\n\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\tmw.user\n\t\t\t\t\t).parse(),\n\t\t\t\t\tdata: 'own'\n\t\t\t\t} ),\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: $( '<div>' )\n\t\t\t\t\t\t.msg(\n\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others',\n\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra' )\n\t\t\t\t\t\t\t\t.msg(\n\t\t\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others-explain',\n\t\t\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-deed-origin-others-container' )\n\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-deed-radio-reveal' )\n\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-deed-subgroup' )\n\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-deed-title' )\n\t\t\t\t\t\t\t\t\t\t.msg(\n\t\t\t\t\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others-subquestion',\n\t\t\t\t\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t// this.originOthersRadio.$element will be appended in here\n\t\t\t\t\t\t\t\t\t// once it has been created (see below)\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.hide()\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.contents(),\n\t\t\t\t\tdata: 'others'\n\t\t\t\t} ),\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: $( '<div>' )\n\t\t\t\t\t\t.append( self.templateOptions.aiGenerated.field.getLabel() )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-deed-radio-reveal' )\n\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-deed-subgroup' )\n\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-deed-title' )\n\t\t\t\t\t\t\t\t\t\t.msg(\n\t\t\t\t\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-ai-instruction',\n\t\t\t\t\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t\t\t\t// this.aiTextInput.$element will be appended in here\n\t\t\t\t\t\t\t\t\t\t// once it has been created (see below)\n\t\t\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-deed-origin-ai-container' ),\n\t\t\t\t\t\t\t\t\t$( '<p>' )\n\t\t\t\t\t\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra' )\n\t\t\t\t\t\t\t\t\t\t.msg(\n\t\t\t\t\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-ai-description',\n\t\t\t\t\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t).hide()\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.contents(),\n\t\t\t\t\tdata: 'ai'\n\t\t\t\t} )\n\t\t\t],\n\t\t\tclasses: [ 'mwe-upwiz-deed-origin' ]\n\t\t} );\n\t\tthis.originRadio.on( 'select', function ( selectedOption ) {\n\t\t\trevealOptionContent( self.originRadio.$element, selectedOption.$element );\n\n\t\t\t// this radio option implementation doesn't match the existing generic\n\t\t\t// templateOptions implementation (as used for thirdparty works);\n\t\t\t// instead of using it directly, we'll simply forward the selected state\n\t\t\t// of this radio button to the templateOptions input\n\t\t\tself.templateOptions.aiGenerated.input.setSelected( selectedOption.getData() === 'ai' );\n\n\t\t\t// let's also emit a 'change' event to satisfy the listener that checks\n\t\t\t// and shows/hides an error message\n\t\t\tself.originRadio.emit( 'change' );\n\t\t} );\n\n\t\t// Origin sub-radio for \"work of others\" option\n\t\tthis.originOthersRadio = new OO.ui.RadioSelectWidget( {\n\t\t\titems: [\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: new OO.ui.HtmlSnippet(\n\t\t\t\t\t\tmw.message(\n\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others-freelicense',\n\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t).parse()\n\t\t\t\t\t),\n\t\t\t\t\tdata: 'freelicense'\n\t\t\t\t} ),\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: mw.message(\n\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others-nocopyright',\n\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\tmw.user\n\t\t\t\t\t).parse(),\n\t\t\t\t\tdata: 'nocopyright'\n\t\t\t\t} ),\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: $( '<div>' )\n\t\t\t\t\t\t.msg(\n\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others-copyrighted',\n\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\tnew OO.ui.MessageWidget( {\n\t\t\t\t\t\t\t\ttype: 'warning',\n\t\t\t\t\t\t\t\tlabel: new OO.ui.HtmlSnippet(\n\t\t\t\t\t\t\t\t\tmw.message(\n\t\t\t\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others-copyrighted-warning',\n\t\t\t\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t\t\t\t).parse()\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tclasses: [ 'mwe-upwiz-deed-warning', 'mwe-upwiz-deed-radio-reveal' ]\n\t\t\t\t\t\t\t} ).$element.hide()\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.contents(),\n\t\t\t\t\tdata: 'copyrighted'\n\t\t\t\t} ),\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: $( '<div>' )\n\t\t\t\t\t\t.msg(\n\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others-unknown',\n\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\tnew OO.ui.MessageWidget( {\n\t\t\t\t\t\t\t\ttype: 'warning',\n\t\t\t\t\t\t\t\tlabel: new OO.ui.HtmlSnippet(\n\t\t\t\t\t\t\t\t\tmw.message(\n\t\t\t\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-option-others-unknown-warning',\n\t\t\t\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t\t\t\t).parse()\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tclasses: [ 'mwe-upwiz-deed-warning', 'mwe-upwiz-deed-radio-reveal' ]\n\t\t\t\t\t\t\t} ).$element.hide()\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.contents(),\n\t\t\t\t\tdata: 'unknown'\n\t\t\t\t} )\n\t\t\t]\n\t\t} );\n\t\tthis.originRadio.$element.find( '.mwe-upwiz-deed-origin-others-container' ).append( this.originOthersRadio.$element );\n\t\tthis.originOthersRadio.on( 'select', function ( selectedOption ) {\n\t\t\trevealOptionContent( self.originOthersRadio.$element, selectedOption.$element );\n\n\t\t\t// let's also emit a 'change' event on the parent radio to satisfy the listener\n\t\t\t// that checks and shows/hides an error message\n\t\t\tself.originRadio.emit( 'change' );\n\t\t} );\n\n\t\t// Origin text input for \"work generated by an AI\" option\n\t\tthis.aiTextInput = new OO.ui.MultilineTextInputWidget( {\n\t\t\tautosize: true,\n\t\t\tminLength: this.config.minAiInputLength,\n\t\t\tmaxLength: this.config.maxAiInputLength\n\t\t} );\n\t\tthis.aiTextInput.$element.find( 'textarea' ).on( 'click', function () {\n\t\t\t// Note: I have not fully figured out exactly why or what is the culprit,\n\t\t\t// but it appears that some node is preventing clicks from propagating,\n\t\t\t// and it's making it impossible to access this input by mouse;\n\t\t\t// this is just a workaround to resolve that\n\t\t\t$( this ).trigger( 'focus' );\n\t\t} );\n\t\tthis.originRadio.$element.find( '.mwe-upwiz-deed-origin-ai-container' ).append( this.aiTextInput.$element );\n\t\tthis.aiTextInput.on( 'change', function ( value ) {\n\t\t\tself.setAuthorInputValue( value );\n\t\t\t// let's also emit a 'change' event on the parent radio to satisfy the listener\n\t\t\t// that checks and shows/hides an error message\n\t\t\tself.originRadio.emit( 'change' );\n\t\t} );\n\n\t\tthis.originRadio.getErrors = this.getOwnWorkErrors.bind(\n\t\t\tthis,\n\t\t\tthis.originRadio,\n\t\t\tthis.originOthersRadio,\n\t\t\tthis.aiTextInput\n\t\t);\n\t\tthis.originRadio.getWarnings = this.getOwnWorkWarnings.bind(\n\t\t\tthis,\n\t\t\tthis.originRadio,\n\t\t\tthis.originOthersRadio,\n\t\t\tthis.aiTextInput\n\t\t);\n\t\tthis.originRadioField = new uw.FieldLayout( this.originRadio, {\n\t\t\tlabel: $( '<div>' ).append(\n\t\t\t\t$( '<li>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tmw.message(\n\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-origin-label',\n\t\t\t\t\t\t\tthis.uploadCount,\n\t\t\t\t\t\t\tmw.user\n\t\t\t\t\t\t).parseDom()\n\t\t\t\t\t)\n\t\t\t),\n\t\t\trequired: true\n\t\t} );\n\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( 'mwe-upwiz-deed-forms' );\n\t\tthis.licenseInputField = new uw.FieldLayout( this.licenseInput, {\n\t\t\tlabel: $( '<div>' ).append(\n\t\t\t\t$( '<li>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t\t.append( mw.message( 'mwe-upwiz-source-ownwork-question', this.uploadCount, mw.user ).parseDom() )\n\t\t\t),\n\t\t\trequired: true\n\t\t} );\n\n\t\tthis.purposeRadio = new OO.ui.RadioSelectWidget( {\n\t\t\titems: [\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-source-ownwork-purpose-option-knowledge', this.uploadCount, mw.user ).text(),\n\t\t\t\t\tdata: 'knowledge'\n\t\t\t\t} ),\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: $( '<div>' ).msg( 'mwe-upwiz-source-ownwork-purpose-option-personal-use', this.uploadCount, mw.user )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\tnew OO.ui.MessageWidget( {\n\t\t\t\t\t\t\t\ttype: 'warning',\n\t\t\t\t\t\t\t\tlabel: new OO.ui.HtmlSnippet(\n\t\t\t\t\t\t\t\t\tmw.message(\n\t\t\t\t\t\t\t\t\t\t'mwe-upwiz-source-ownwork-purpose-option-personal-warning',\n\t\t\t\t\t\t\t\t\t\tthis.uploadCount\n\t\t\t\t\t\t\t\t\t).parse()\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tclasses: [ 'mwe-upwiz-deed-warning', 'mwe-upwiz-deed-radio-reveal' ]\n\t\t\t\t\t\t\t} ).$element.hide()\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.contents(),\n\t\t\t\t\tdata: 'personal'\n\t\t\t\t} )\n\t\t\t],\n\t\t\tclasses: [ 'mwe-upwiz-deed-purpose' ]\n\t\t} );\n\t\tthis.purposeRadio.on( 'select', function ( selectedOption ) {\n\t\t\trevealOptionContent( self.purposeRadio.$element, selectedOption.$element );\n\n\t\t\t// let's also emit a 'change' event to satisfy the listener that checks\n\t\t\t// and shows/hides an error message\n\t\t\tself.purposeRadio.emit( 'change' );\n\t\t} );\n\t\tthis.purposeRadio.getErrors = function ( thorough ) {\n\t\t\tif ( thorough !== true ) {\n\t\t\t\t// `thorough` is the strict checks executed on submit, but we don't want errors\n\t\t\t\t// to change/display every change event\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif ( !self.purposeRadio.findSelectedItems() ) {\n\t\t\t\treturn [ mw.message( 'mwe-upwiz-deeds-require-selection' ) ];\n\t\t\t}\n\n\t\t\treturn [];\n\t\t};\n\t\tthis.purposeRadio.getWarnings = function () {\n\t\t\t// not actually adding a warning here; there already is one shown immediately\n\t\t\t// on the screen when the \"wrong\" option is selected\n\t\t\treturn [];\n\t\t};\n\t\tthis.purposeField = new uw.FieldLayout( this.purposeRadio, {\n\t\t\tlabel: $( '<div>' ).append(\n\t\t\t\t$( '<li>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t\t.append( mw.message( 'mwe-upwiz-source-ownwork-purpose-label', this.uploadCount, mw.user ).parseDom() )\n\t\t\t),\n\t\t\trequired: true\n\t\t} );\n\n\t\t// grant patent license\n\t\tthis.threeDCount = uploads.filter( this.needsPatentAgreement.bind( this ) ).length;\n\t\tif ( this.threeDCount > 0 ) {\n\t\t\tthis.patentAgreementField = this.getPatentAgreementField( uploads );\n\t\t}\n\t};\n\n\tOO.inheritClass( uw.deed.OwnWork, uw.deed.Abstract );\n\n\tuw.deed.OwnWork.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.OwnWork.prototype.getFields = function () {\n\t\tvar fields = [ this.originRadioField, this.licenseInputField, this.purposeField ];\n\t\tif ( this.threeDCount > 0 ) {\n\t\t\tfields.push( this.patentAgreementField );\n\t\t}\n\t\treturn fields;\n\t};\n\n\tuw.deed.OwnWork.prototype.setFormFields = function ( $selector ) {\n\t\tvar $formFields;\n\n\t\tthis.$selector = $selector;\n\n\t\tthis.$form = $( '<form>' );\n\n\t\t$formFields = $( '<div>' ).addClass( 'mwe-upwiz-deed-form-internal' ).append(\n\t\t\t$( '<ol>' ).append(\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-ownwork-origin' )\n\t\t\t\t\t.append( this.originRadioField.$element ),\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-ownwork-license' )\n\t\t\t\t\t.append( this.licenseInputField.$element ),\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-ownwork-purpose' )\n\t\t\t\t\t.append( this.purposeField.$element )\n\t\t\t)\n\t\t);\n\n\t\t// hidden inputs\n\t\t$formFields.append( this.authorInput.$element );\n\t\tif ( this.threeDCount > 0 ) {\n\t\t\t$formFields.append( this.patentAgreementField.$element );\n\t\t}\n\n\t\tthis.$form.append( $formFields ).appendTo( $selector );\n\n\t\tthis.setDefaultLicense();\n\t};\n\n\t/**\n\t * OwnWork's default value is different to the default LicenseInput defaults...\n\t * LicenseInput supports multiple default values, but this one does not.\n\t */\n\tuw.deed.OwnWork.prototype.setDefaultLicense = function () {\n\t\tvar defaultLicenseKey, defaultLicense = {};\n\t\tdefaultLicenseKey = this.getDefaultLicense();\n\t\tif ( defaultLicenseKey ) {\n\t\t\tdefaultLicense[ defaultLicenseKey ] = true;\n\t\t\tthis.licenseInput.setValues( defaultLicense );\n\t\t}\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.OwnWork.prototype.getSourceWikiText = function () {\n\t\treturn '{{own}}';\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.OwnWork.prototype.getAuthorWikiText = function () {\n\t\tvar author = this.getAuthorInputValue();\n\n\t\tif ( author.indexOf( '[' ) >= 0 || author.indexOf( '{' ) >= 0 ) {\n\t\t\treturn author;\n\t\t}\n\n\t\treturn '[[User:' + mw.config.get( 'wgUserName' ) + '|' + author + ']]';\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.OwnWork.prototype.getLicenseWikiText = function ( upload ) {\n\t\tvar wikitext = '';\n\n\t\twikitext += this.licenseInput.getWikiText();\n\n\t\tif ( this.needsPatentAgreement( upload ) ) {\n\t\t\twikitext += '\\n{{' + this.config.patents.template + '|ownwork}}';\n\t\t}\n\n\t\treturn wikitext;\n\t};\n\n\t/**\n\t * There's no getValue() on a hidden input in OOUI.\n\t * Also handle an AI-generated work.\n\t *\n\t * @return string\n\t */\n\tuw.deed.OwnWork.prototype.getAuthorInputValue = function () {\n\t\treturn this.authorInput.$element.val().trim();\n\t};\n\n\tuw.deed.OwnWork.prototype.setAuthorInputValue = function ( value ) {\n\t\tthis.authorInput.$element.val( value );\n\t};\n\n\t/**\n\t * @return {Object}\n\t */\n\tuw.deed.OwnWork.prototype.getSerialized = function () {\n\t\tvar serialized = $.extend(\n\t\t\tuw.deed.Abstract.prototype.getSerialized.call( this ),\n\t\t\t{ author: this.getAuthorInputValue() }\n\t\t);\n\n\t\tserialized.origin = this.originRadio.findSelectedItem() && this.originRadio.findSelectedItem().getData();\n\t\tserialized.originOthers = this.originOthersRadio.findSelectedItem() && this.originOthersRadio.findSelectedItem().getData();\n\t\tserialized.ai = this.aiTextInput.getValue();\n\t\tserialized.license = this.licenseInput.getSerialized();\n\t\tserialized.purpose = this.purposeRadio.findSelectedItem() && this.purposeRadio.findSelectedItem().getData();\n\n\t\treturn serialized;\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.setAuthorInputValue( serialized.author );\n\t\t}\n\t\tif ( serialized.origin ) {\n\t\t\tthis.originRadio.selectItemByData( serialized.origin );\n\t\t}\n\t\tif ( serialized.originOthers ) {\n\t\t\tthis.originOthersRadio.selectItemByData( serialized.originOthers );\n\t\t}\n\t\tif ( serialized.ai ) {\n\t\t\tthis.aiTextInput.setValue( serialized.ai );\n\t\t}\n\t\tthis.licenseInput.setSerialized( serialized.license );\n\t\tif ( serialized.purpose ) {\n\t\t\tthis.purposeRadio.selectItemByData( serialized.purpose );\n\t\t}\n\t};\n\n\tuw.deed.OwnWork.prototype.getDefaultLicense = function () {\n\t\tvar license;\n\t\tif (\n\t\t\tthis.config.licensing.defaultType === 'ownwork' ||\n\t\t\tthis.config.licensing.defaultType === 'choice'\n\t\t) {\n\t\t\tlicense = this.config.licensing.ownWork.defaults;\n\t\t\treturn license instanceof Array ? license[ 0 ] : license;\n\t\t}\n\t};\n\n\t/**\n\t * @param {OO.ui.RadioSelectWidget} originRadio\n\t * @param {OO.ui.RadioSelectWidget} originOthersRadio\n\t * @param {OO.ui.TextInputWidget} aiTextInput\n\t * @param {boolean} thorough\n\t * @return {Array<string>}\n\t */\n\tuw.deed.OwnWork.prototype.getOwnWorkErrors = function (\n\t\toriginRadio, originOthersRadio, aiTextInput, thorough\n\t) {\n\t\tvar aiInputValue,\n\t\t\terrors = [];\n\n\t\tif ( thorough !== true ) {\n\t\t\t// `thorough` is the strict checks executed on submit, but we don't want errors\n\t\t\t// to change/display every change event\n\t\t\treturn [];\n\t\t}\n\n\t\tif ( originRadio.findSelectedItem() === null ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-deeds-require-selection' ) );\n\t\t} else if (\n\t\t\toriginRadio.findSelectedItem().getData() === 'others' &&\n\t\t\toriginOthersRadio.findSelectedItem() === null\n\t\t) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-deeds-require-selection' ) );\n\t\t} else if ( originRadio.findSelectedItem().getData() === 'ai' ) {\n\t\t\taiInputValue = aiTextInput.getValue().trim();\n\n\t\t\tif ( aiInputValue === '' ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-question-blank' ) );\n\t\t\t} else if ( aiInputValue.length < this.config.minAiInputLength ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-too-short', this.config.minAiInputLength ) );\n\t\t\t} else if ( aiInputValue.length > this.config.maxAiInputLength ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-too-long', this.config.maxAiInputLength ) );\n\t\t\t}\n\t\t}\n\n\t\treturn errors;\n\t};\n\n\t/**\n\t * @return {jQuery.Promise}\n\t */\n\tuw.deed.OwnWork.prototype.getOwnWorkWarnings = function () {\n\t\treturn $.Deferred().resolve( [] ).promise();\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\tvar\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( 'mwe-upwiz-error-signature-blank' ) );\n\t\t} else if ( text.length < minLength ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-signature-too-short', minLength ) );\n\t\t} else if ( text.length > maxLength ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-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\t/**\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @return {uw.PatentDialog}\n\t */\n\tuw.deed.OwnWork.prototype.getPatentDialog = function ( uploads ) {\n\t\tvar config = { panels: [ 'warranty', 'license-ownership', 'license-grant' ] };\n\n\t\t// Only show filename list when in \"details\" step & we're showing the dialog for individual files\n\t\tif ( uploads[ 0 ] && uploads[ 0 ].state === 'details' ) {\n\t\t\tconfig.panels.unshift( 'filelist' );\n\t\t}\n\n\t\treturn new uw.PatentDialog( config, this.config, uploads );\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":"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":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":321,"column":6,"nodeType":"CallExpression","endLine":323,"endColumn":7}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  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\tvar deed = this;\n\n\t\tuw.deed.Abstract.call( this, 'thirdparty', config, uploads );\n\n\t\tthis.uploadCount = uploads.length;\n\t\tthis.threeDCount = uploads.filter( this.needsPatentAgreement.bind( this ) ).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 ( thorough ) {\n\t\t\tvar\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 ( thorough !== true ) {\n\t\t\t\t// `thorough` is the strict checks executed on submit, but we don't want errors\n\t\t\t\t// to change/display every change event\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif ( text === '' ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-question-blank' ) );\n\t\t\t} else if ( text.length < minLength ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-too-short', minLength ) );\n\t\t\t} else if ( text.length > maxLength ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-too-long', maxLength ) );\n\t\t\t}\n\n\t\t\treturn errors;\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: $( '<li>' )\n\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t.msg( 'mwe-upwiz-source-text', this.uploadCount, mw.user ),\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\tthis.authorInput.getErrors = function ( thorough ) {\n\t\t\tvar\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 ( thorough !== true ) {\n\t\t\t\t// `thorough` is the strict checks executed on submit, but we don't want errors\n\t\t\t\t// to change/display every change event\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif ( this.isDisabled() ) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif ( text === '' ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-question-blank' ) );\n\t\t\t} else if ( text.length < minLength ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-too-short', minLength ) );\n\t\t\t} else if ( text.length > maxLength ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-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: $( '<li>' )\n\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t.msg( 'mwe-upwiz-author-text', this.uploadCount, mw.user ),\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( 'mwe-upwiz-deed-license-groups' );\n\t\tthis.licenseInput.setDefaultValues();\n\t\tthis.licenseInputField = new uw.FieldLayout( this.licenseInput, {\n\t\t\tlabel: $( '<div>' ).append(\n\t\t\t\t$( '<li>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t\t.append( mw.message( 'mwe-upwiz-source-thirdparty-cases-text', this.uploadCount, mw.user ).parseDom() ),\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra' )\n\t\t\t\t\t.text( mw.message( 'mwe-upwiz-tooltip-thirdparty-license', this.uploadCount, mw.user ).text() )\n\t\t\t),\n\t\t\trequired: true\n\t\t} );\n\n\t\tthis.complianceCheck = new OO.ui.CheckboxMultiselectWidget( {\n\t\t\titems: [\n\t\t\t\tnew OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-source-thirdparty-compliance-option-copyright', this.uploadCount, mw.user ).text(),\n\t\t\t\t\tdata: 'copyright'\n\t\t\t\t} )\n\t\t\t],\n\t\t\tclasses: [ 'mwe-upwiz-deed-compliance' ]\n\t\t} );\n\t\tthis.complianceCheck.getErrors = function ( thorough ) {\n\t\t\tvar allSelected = deed.complianceCheck.getItems().reduce( function ( result, item ) {\n\t\t\t\treturn result && item.isSelected();\n\t\t\t}, true );\n\n\t\t\tif ( thorough !== true ) {\n\t\t\t\t// `thorough` is the strict checks executed on submit, but we don't want errors\n\t\t\t\t// to change/display every change event\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif ( !allSelected ) {\n\t\t\t\treturn [ mw.message( 'mwe-upwiz-deeds-require-selection' ) ];\n\t\t\t}\n\n\t\t\treturn [];\n\t\t};\n\t\tthis.complianceCheck.getWarnings = function () {\n\t\t\t// just here for completeness; there is no warning ATM\n\t\t\treturn [];\n\t\t};\n\t\tthis.complianceField = new uw.FieldLayout( this.complianceCheck, {\n\t\t\tlabel: $( '<div>' ).append(\n\t\t\t\t$( '<li>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t\t.append( mw.message( 'mwe-upwiz-source-thirdparty-compliance-label', this.uploadCount, mw.user ).parseDom() )\n\t\t\t),\n\t\t\trequired: true\n\t\t} );\n\n\t\tif ( this.threeDCount > 0 ) {\n\t\t\tthis.patentAgreementField = this.getPatentAgreementField( uploads );\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\tvar fields = [\n\t\t\tthis.authorInputField,\n\t\t\tthis.sourceInputField,\n\t\t\tthis.licenseInputField,\n\t\t\tthis.complianceField\n\t\t];\n\t\tif ( this.threeDCount > 0 ) {\n\t\t\tfields.push( this.patentAgreementField );\n\t\t}\n\t\treturn fields;\n\t};\n\n\tuw.deed.ThirdParty.prototype.setFormFields = function ( $selector ) {\n\t\tvar $formFields = $( '<div>' ).addClass( 'mwe-upwiz-deed-form-internal' ), self = this;\n\n\t\tthis.$form = $( '<form>' );\n\n\t\t$formFields.append(\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'mwe-upwiz-source-thirdparty-explain' )\n\t\t\t\t.msg( 'mwe-upwiz-source-thirdparty-explain' )\n\t\t);\n\n\t\tif ( this.uploadCount > 1 ) {\n\t\t\t$formFields.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-source-thirdparty-custom-multiple-intro' )\n\t\t\t\t\t.msg( 'mwe-upwiz-source-thirdparty-custom-multiple-intro' )\n\t\t\t);\n\t\t}\n\n\t\t$formFields.append(\n\t\t\t$( '<ol>' ).append(\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-thirdparty-license' )\n\t\t\t\t\t.append( this.licenseInputField.$element ),\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-thirdparty-fields' )\n\t\t\t\t\t.append( this.sourceInputField.$element ),\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-thirdparty-fields' )\n\t\t\t\t\t.append( this.authorInputField.$element ),\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-thirdparty-fields' )\n\t\t\t\t\t.append( this.complianceField.$element )\n\t\t\t)\n\t\t);\n\n\t\tif ( this.templateOptions.aiGenerated ) {\n\t\t\t// add the element inside sourceInputField so any error msgs will be displayed for\n\t\t\t// the field (containing the text input and checkbox) rather than just the text input\n\t\t\tthis.sourceInput.$element.after(\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-thirdparty-checkbox' )\n\t\t\t\t\t.append( this.templateOptions.aiGenerated.field.$element )\n\t\t\t);\n\t\t\tthis.templateOptions.aiGenerated.input.$element.on( 'change', function () {\n\t\t\t\tself.updateAuthorFieldForAI();\n\t\t\t} );\n\n\t\t\t// Set up ai-relevant help text for the author input field that can be shown\n\t\t\t// whenever the checkbox is selected\n\t\t\tthis.authorInputField.help = new OO.ui.LabelWidget( {\n\t\t\t\tlabel: $( '<div>' ).msg( 'mwe-upwiz-author-text-ai-help' )\n\t\t\t} );\n\t\t\tthis.authorInput.$element.after(\n\t\t\t\tthis.authorInputField.help.$element.addClass( 'mwe-upwiz-details-help' )\n\t\t\t);\n\t\t\tthis.authorInputField.help.$element.hide();\n\t\t}\n\t\tif ( this.templateOptions.authorUnknown ) {\n\t\t\t// add the element inside authorInputField so any error msgs will be displayed for\n\t\t\t// the field (containing the text input and checkbox) rather than just the text input\n\t\t\tif ( this.templateOptions.aiGenerated ) {\n\t\t\t\tthis.authorInputField.help.$element.after(\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-thirdparty-checkbox' )\n\t\t\t\t\t\t.append( this.templateOptions.authorUnknown.field.$element )\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.authorInput.$element.after(\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-thirdparty-checkbox' )\n\t\t\t\t\t\t.append( this.templateOptions.authorUnknown.field.$element )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.templateOptions.authorUnknown.input.$element.on( 'change', function () {\n\t\t\t\tif ( self.templateOptions.authorUnknown.input.isSelected() ) {\n\t\t\t\t\tself.authorInput.setDisabled( true );\n\t\t\t\t\tself.authorInput.setValue( '' );\n\t\t\t\t\tself.authorInputField.checkValidity( false );\n\t\t\t\t} else {\n\t\t\t\t\tself.authorInput.setDisabled( false );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tif ( this.threeDCount > 0 ) {\n\t\t\t$formFields.append( this.patentAgreementField.$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.updateAuthorFieldForAI = function () {\n\t\tif ( this.templateOptions.aiGenerated.input.isSelected() ) {\n\t\t\tthis.authorInputField.setLabel(\n\t\t\t\t$( '<li>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t\t.msg( 'mwe-upwiz-author-text-ai' )\n\t\t\t);\n\t\t\tthis.authorInputField.help.$element.show();\n\t\t\tif ( this.templateOptions.authorUnknown ) {\n\t\t\t\tthis.templateOptions.authorUnknown.field.setLabel(\n\t\t\t\t\tmw.message(\n\t\t\t\t\t\t'mwe-upwiz-author-not-known'\n\t\t\t\t\t).text()\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.authorInputField.setLabel(\n\t\t\t\t$( '<li>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-title' )\n\t\t\t\t\t.msg( 'mwe-upwiz-author-text' )\n\t\t\t);\n\t\t\tthis.authorInputField.help.$element.hide();\n\t\t\tif ( this.templateOptions.authorUnknown ) {\n\t\t\t\tthis.templateOptions.authorUnknown.field.setLabel(\n\t\t\t\t\tmw.message(\n\t\t\t\t\t\tthis.config.templateOptions.thirdparty.authorUnknown.label\n\t\t\t\t\t).text()\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.Abstract.prototype.getSourceWikiText = function () {\n\t\treturn this.sourceInput.getValue();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.Abstract.prototype.getAuthorWikiText = function () {\n\t\treturn this.authorInput.getValue() || '{{Unknown|author}}';\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.deed.Abstract.prototype.getLicenseWikiText = function ( upload ) {\n\t\tvar wikitext = this.licenseInput.getWikiText();\n\n\t\tif ( this.needsPatentAgreement( upload ) ) {\n\t\t\twikitext += '\\n{{' + this.config.patents.template + '}}';\n\t\t}\n\n\t\treturn wikitext;\n\t};\n\n\t/**\n\t * @return {Object}\n\t */\n\tuw.deed.ThirdParty.prototype.getSerialized = function () {\n\t\treturn $.extend( 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\tcompliance: this.complianceCheck.findSelectedItems().map( function ( item ) {\n\t\t\t\treturn item.getData();\n\t\t\t} )\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\tif ( serialized.compliance ) {\n\t\t\tthis.complianceCheck.selectItemsByData( serialized.compliance );\n\t\t}\n\n\t\tif ( this.templateOptions.authorUnknown ) {\n\t\t\tthis.authorInput.setDisabled(\n\t\t\t\t!!this.templateOptions.authorUnknown.input.isSelected()\n\t\t\t);\n\n\t\t\tif ( this.templateOptions.aiGenerated ) {\n\t\t\t\tthis.updateAuthorFieldForAI();\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":"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":"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.CampaignDetailsWidget.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":"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":[],"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":"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":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":147,"column":20,"nodeType":"CallExpression","endLine":147,"endColumn":100},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":173,"column":70,"nodeType":"CallExpression","endLine":173,"endColumn":107},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":176,"column":70,"nodeType":"CallExpression","endLine":176,"endColumn":108},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":179,"column":70,"nodeType":"CallExpression","endLine":179,"endColumn":112}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A date field 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 {mw.UploadWizardUpload} upload\n\t */\n\tuw.DateDetailsWidget = function UWDateDetailsWidget( config ) {\n\t\tuw.DateDetailsWidget.super.call( this );\n\n\t\tthis.upload = config.upload;\n\t\tthis.dateInputWidgetMode = null; // or: 'calendar', 'arbitrary'\n\t\tthis.dateInputWidgetToggler = new OO.ui.ButtonSelectWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-dateDetailsWidget-toggler' ],\n\t\t\titems: [\n\t\t\t\tnew OO.ui.ButtonOptionWidget( {\n\t\t\t\t\tdata: 'calendar',\n\t\t\t\t\ticon: 'calendar',\n\t\t\t\t\ttitle: mw.msg( 'mwe-upwiz-calendar-date' )\n\t\t\t\t} ),\n\t\t\t\tnew OO.ui.ButtonOptionWidget( {\n\t\t\t\t\tdata: 'arbitrary',\n\t\t\t\t\ticon: 'edit',\n\t\t\t\t\ttitle: mw.msg( 'mwe-upwiz-custom-date' )\n\t\t\t\t} )\n\t\t\t]\n\t\t} )\n\t\t\t.selectItemByData( 'calendar' )\n\t\t\t.on( 'choose', function ( selectedItem ) {\n\t\t\t\tthis.setupDateInput( selectedItem.getData() );\n\t\t\t\tthis.dateInputWidget.focus();\n\t\t\t}.bind( this ) );\n\n\t\tthis.$element.addClass( 'mwe-upwiz-dateDetailsWidget' );\n\t\tthis.$element.append(\n\t\t\tthis.dateInputWidgetToggler.$element\n\t\t\t// this.dateInputWidget.$element goes here after setupDateInput() runs\n\t\t);\n\t\tthis.setupDateInput();\n\t};\n\tOO.inheritClass( uw.DateDetailsWidget, uw.DetailsWidget );\n\n\t/**\n\t * Set up the date input field, or switch between 'calendar' and 'arbitrary' mode.\n\t *\n\t * @param {string} [mode] Mode to switch to, 'calendar' or 'arbitrary'\n\t * @private\n\t */\n\tuw.DateDetailsWidget.prototype.setupDateInput = function ( mode ) {\n\t\tvar\n\t\t\toldDateInputWidget = this.dateInputWidget;\n\n\t\tif ( mode === undefined ) {\n\t\t\tmode = this.dateInputWidgetMode === 'calendar' ? 'arbitrary' : 'calendar';\n\t\t}\n\t\tthis.dateInputWidgetMode = mode;\n\t\tthis.dateInputWidgetToggler.selectItemByData( mode );\n\n\t\tif ( mode === 'arbitrary' ) {\n\t\t\tthis.dateInputWidget = new OO.ui.TextInputWidget( {\n\t\t\t\tclasses: [ 'mwe-date', 'mwe-upwiz-dateDetailsWidget-date' ],\n\t\t\t\tplaceholder: mw.msg( 'mwe-upwiz-select-date' )\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.dateInputWidget = new mw.widgets.DateInputWidget( {\n\t\t\t\tclasses: [ 'mwe-date', 'mwe-upwiz-dateDetailsWidget-date' ],\n\t\t\t\tplaceholderLabel: mw.msg( 'mwe-upwiz-select-date' )\n\t\t\t} );\n\t\t\t// If the user types '{{', assume that they are trying to input template wikitext and switch\n\t\t\t// to 'arbitrary' mode. This might help confused power-users (T110026#1567714).\n\t\t\tthis.dateInputWidget.textInput.on( 'change', function ( value ) {\n\t\t\t\tif ( value === '{{' ) {\n\t\t\t\t\tthis.setupDateInput( 'arbitrary' );\n\t\t\t\t\tthis.dateInputWidget.setValue( '{{' );\n\t\t\t\t\tthis.dateInputWidget.moveCursorToEnd();\n\t\t\t\t}\n\t\t\t}.bind( this ) );\n\t\t}\n\n\t\tif ( oldDateInputWidget ) {\n\t\t\tthis.dateInputWidget.setValue( oldDateInputWidget.getValue() );\n\t\t\toldDateInputWidget.$element.replaceWith( this.dateInputWidget.$element );\n\t\t} else {\n\t\t\tthis.dateInputWidgetToggler.$element.after( this.dateInputWidget.$element );\n\t\t}\n\n\t\t// Aggregate 'change' event\n\t\tthis.dateInputWidget.connect( this, { change: [ 'emit', 'change' ] } );\n\n\t\t// Also emit if the value was changed to fit the new widget\n\t\tif ( oldDateInputWidget && oldDateInputWidget.getValue() !== this.dateInputWidget.getValue() ) {\n\t\t\tthis.emit( 'change' );\n\t\t}\n\t};\n\n\t/**\n\t * Gets the selected license(s). The returned value will be a license\n\t * key => license props map, as defined in UploadWizard.config.php.\n\t *\n\t * @return {Object}\n\t */\n\tuw.DateDetailsWidget.prototype.getLicenses = function () {\n\t\tif ( this.upload.deedChooser && this.upload.deedChooser.deed && this.upload.deedChooser.deed.licenseInput ) {\n\t\t\treturn this.upload.deedChooser.deed.licenseInput.getLicenses();\n\t\t}\n\n\t\t// no license has been selected yet\n\t\t// this could happen when uploading multiple files and selecting to\n\t\t// provide copyright information for each file individually\n\t\treturn {};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.DateDetailsWidget.prototype.getWarnings = function () {\n\t\tvar i,\n\t\t\tlicense,\n\t\t\tlicenseMsg,\n\t\t\twarnings = [],\n\t\t\tdateVal = Date.parse( this.dateInputWidget.getValue().trim() ),\n\t\t\tlicenses = this.getLicenses(),\n\t\t\t// licenses that likely mean the image date is some time in the past\n\t\t\twarnLicenses = [ 'pd-usgov', 'pd-usgov-nasa', 'pd-art' ],\n\t\t\tnow = new Date(),\n\t\t\tdate = new Date( this.dateInputWidget.getValue() );\n\n\t\t// We don't really know what timezone this datetime is in. It could be the user's timezone, or\n\t\t// it could be the camera's timezone for data imported from EXIF, and we don't know what\n\t\t// timezone that is. UTC+14 is the highest timezone that currently exists, so assume that to\n\t\t// avoid giving false warnings.\n\t\tif ( this.dateInputWidgetMode === 'calendar' &&\n\t\t\tdateVal > now.getTime() + 14 * 60 * 60 ) {\n\t\t\twarnings.push( mw.message( 'mwe-upwiz-warning-postdate' ) );\n\t\t}\n\n\t\t// doublecheck that we've actually selected a valid date\n\t\tif ( !isNaN( date.getTime() ) ) {\n\t\t\t// it's unlikely for public domain images to have been published today\n\t\t\tif ( now.toISOString().slice( 0, 10 ) === date.toISOString().slice( 0, 10 ) ) {\n\t\t\t\tfor ( i in warnLicenses ) {\n\t\t\t\t\tif ( warnLicenses[ i ] in licenses ) {\n\t\t\t\t\t\tlicense = licenses[ warnLicenses[ i ] ];\n\t\t\t\t\t\tlicenseMsg = mw.message( license.msg, 0, license.url ? license.url : '#missing license URL' );\n\t\t\t\t\t\twarnings.push( mw.message( 'mwe-upwiz-error-date-license-unlikely', licenseMsg.parseDom() ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $.Deferred().resolve( warnings ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.DateDetailsWidget.prototype.getErrors = function () {\n\t\tvar errors = [],\n\t\t\tlicenses = this.getLicenses(),\n\t\t\tnow = new Date(),\n\t\t\told = new Date( now.getFullYear() - 70, now.getMonth(), now.getDate() ),\n\t\t\told100 = new Date( now.getFullYear() - 100, now.getMonth(), now.getDate() ),\n\t\t\tdate = new Date( this.dateInputWidget.getValue() );\n\n\t\tif ( this.dateInputWidget.getValue().trim() === '' ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-blank' ) );\n\t\t} else if ( 'pd-us' in licenses && date.getFullYear() >= new Date().getFullYear() - 95 ) {\n\t\t\t// if the license stated the work is public domain, it must've been\n\t\t\t// created a really long time ago\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-date-license-mismatch', mw.message( licenses[ 'pd-us' ].msg ).parseDom() ) );\n\t\t} else if ( 'pd-old' in licenses && date > old ) {\n\t\t\t// if the author died 70 years ago, the timestamp should reflect that\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-date-license-mismatch', mw.message( licenses[ 'pd-old' ].msg ).parseDom() ) );\n\t\t} else if ( 'pd-old-100' in licenses && date > old100 ) {\n\t\t\t// if the author died 100 years ago, the timestamp should reflect that\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-date-license-mismatch', mw.message( licenses[ 'pd-old-100' ].msg ).parseDom() ) );\n\t\t}\n\n\t\treturn $.Deferred().resolve( errors ).promise();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.DateDetailsWidget.prototype.getWikiText = function () {\n\t\treturn this.dateInputWidget.getValue().trim();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.DateDetailsWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\tmode: this.dateInputWidgetMode,\n\t\t\tvalue: this.dateInputWidget.getValue()\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {string} serialized.mode Date input mode ('calendar' or 'arbitrary')\n\t * @param {string} serialized.value Date value for given mode\n\t */\n\tuw.DateDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\tthis.setupDateInput( serialized.mode );\n\t\tthis.dateInputWidget.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":"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":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":14,"column":53,"nodeType":"ObjectExpression","endLine":17,"endColumn":4}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A language dropdown within a description field in UploadWizard's \"Details\" step form.\n\t *\n\t * @constructor\n\t * @param {Object} [config]\n\t */\n\tuw.LanguageDropdownWidget = function UWLanguageDropdownWidget( config ) {\n\t\tconfig = config || {};\n\n\t\tuw.LanguageDropdownWidget.super.call( this );\n\n\t\tthis.languageDropdown = new OO.ui.DropdownWidget( {\n\t\t\tmenu: { items: this.getLanguageMenuOptionWidgets( config.languages ) },\n\t\t\tclasses: config.classes\n\t\t} );\n\t\tthis.languageDropdown.getMenu().connect( this, { select: [ 'emit', 'select' ] } );\n\t};\n\tOO.inheritClass( uw.LanguageDropdownWidget, OO.ui.Widget );\n\tOO.mixinClass( uw.LanguageDropdownWidget, OO.EventEmitter );\n\n\t/**\n\t * @param {Object} languages\n\t */\n\tuw.LanguageDropdownWidget.prototype.updateLanguages = function ( languages ) {\n\t\tvar menu = this.languageDropdown.getMenu(),\n\t\t\tcurrentMenuItems = menu.getItems(),\n\t\t\tcurrentValue = this.getValue();\n\n\t\t// remove all items except the one currently selected (don't want\n\t\t// to trigger another select by removing it)\n\t\tmenu.removeItems( currentMenuItems.filter( function ( item ) {\n\t\t\treturn !item.isSelected();\n\t\t} ) );\n\n\t\t// and add the rest of the languages back in there\n\t\tdelete languages[ currentValue ];\n\t\tmenu.addItems( this.getLanguageMenuOptionWidgets( languages ) );\n\t};\n\n\t/**\n\t * @param {string} value\n\t */\n\tuw.LanguageDropdownWidget.prototype.setValue = function ( value ) {\n\t\tthis.languageDropdown.getMenu().selectItemByData( value );\n\t};\n\n\t/**\n\t * @return {string}\n\t */\n\tuw.LanguageDropdownWidget.prototype.getValue = function () {\n\t\treturn this.languageDropdown.getMenu().findSelectedItem().getData();\n\t};\n\n\t/**\n\t * @return {OO.ui.DropdownWidget}\n\t */\n\tuw.LanguageDropdownWidget.prototype.getElement = function () {\n\t\treturn this.languageDropdown.$element;\n\t};\n\n\t/**\n\t * Get options for the dropdown list of all allowed languages.\n\t *\n\t * @private\n\t * @param {Object} languages\n\t * @return {OO.ui.MenuOptionWidget[]}\n\t */\n\tuw.LanguageDropdownWidget.prototype.getLanguageMenuOptionWidgets = function ( languages ) {\n\t\treturn Object.keys( languages ).map( function ( code ) {\n\t\t\treturn new OO.ui.MenuOptionWidget( {\n\t\t\t\tdata: code,\n\t\t\t\tlabel: languages[ code ]\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":"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":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":238,"column":28,"nodeType":"Literal","endLine":238,"endColumn":110}],"suppressedMessages":[],"errorCount":0,"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 {boolean} [showHeading=true] Whether to show the 'heading' field\n\t */\n\tuw.LocationDetailsWidget = function UWLocationDetailsWidget( config ) {\n\t\tthis.config = config || {};\n\n\t\tuw.LocationDetailsWidget.super.call( this );\n\n\t\tthis.$element.addClass( 'mwe-upwiz-locationDetailsWidget' );\n\n\t\tthis.latitudeInput = new OO.ui.TextInputWidget();\n\t\tthis.longitudeInput = new OO.ui.TextInputWidget();\n\t\tthis.headingInput = new OO.ui.TextInputWidget();\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( 'mwe-upwiz-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} );\n\n\t\tthis.$element.append(\n\t\t\tnew OO.ui.FieldLayout( this.latitudeInput, {\n\t\t\t\talign: 'top',\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-location-lat' ).text()\n\t\t\t} ).$element,\n\t\t\tnew OO.ui.FieldLayout( this.longitudeInput, {\n\t\t\t\talign: 'top',\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-location-lon' ).text()\n\t\t\t} ).$element\n\t\t);\n\n\t\tif ( this.config.showHeading ) {\n\t\t\tthis.$element.append(\n\t\t\t\tnew OO.ui.FieldLayout( this.headingInput, {\n\t\t\t\t\talign: 'top',\n\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-location-heading' ).text()\n\t\t\t\t} ).$element\n\t\t\t);\n\t\t}\n\n\t\tthis.mapButton.setDisabled( true );\n\t\tthis.$element.append( this.mapButton.$element );\n\n\t\t// Aggregate 'change' events\n\t\tthis.latitudeInput.connect( this, { change: [ 'emit', 'change' ] } );\n\t\tthis.longitudeInput.connect( this, { change: [ 'emit', 'change' ] } );\n\t\tthis.headingInput.connect( this, { change: [ 'emit', 'change' ] } );\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( function () {\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}.bind( this ) );\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\tvar widget = this;\n\t\tthis.getErrors().done( function ( 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\tvar latitude = this.normalizeCoordinate( this.latitudeInput.getValue() ),\n\t\t\tlongitude = this.normalizeCoordinate( this.longitudeInput.getValue() );\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: [ longitude, latitude ] }\n\t\t} );\n\t\tthis.map.setView( [ latitude, longitude ], 9 );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.LocationDetailsWidget.prototype.getErrors = function () {\n\t\tvar errors = [],\n\t\t\tlatInput = this.latitudeInput.getValue(),\n\t\t\tlonInput = this.longitudeInput.getValue(),\n\t\t\theadInput = this.headingInput.getValue(),\n\t\t\tlatNum = this.normalizeCoordinate( latInput ),\n\t\t\tlonNum = this.normalizeCoordinate( lonInput ),\n\t\t\theadNum = parseFloat( headInput );\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 ( latInput || lonInput ) {\n\t\t\tif ( latNum > 90 || latNum < -90 || ( latNum === 0 && latInput.indexOf( '0' ) < 0 ) || isNaN( latNum ) ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-latitude' ) );\n\t\t\t}\n\n\t\t\tif ( lonNum > 180 || lonNum < -180 || ( lonNum === 0 && lonInput.indexOf( '0' ) < 0 ) || isNaN( lonNum ) ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-longitude' ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( headInput !== '' && ( headInput > 360 || headInput < 0 || isNaN( headNum ) ) ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-heading' ) );\n\t\t}\n\n\t\treturn $.Deferred().resolve( errors );\n\t};\n\n\t/**\n\t * Set up the input fields.\n\t *\n\t * @param {string} [lat] Latitude value to set.\n\t * @param {string} [lon] Longitude value to set.\n\t * @param {string} [head] Heading value to set.\n\t * @private\n\t */\n\tuw.LocationDetailsWidget.prototype.setupInputs = function ( lat, lon, head ) {\n\t\tif ( lat !== undefined ) {\n\t\t\tthis.latitudeInput.setValue( lat );\n\t\t}\n\n\t\tif ( lon !== undefined ) {\n\t\t\tthis.longitudeInput.setValue( lon );\n\t\t}\n\n\t\tif ( head !== undefined ) {\n\t\t\tthis.headingInput.setValue( head );\n\t\t}\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.LocationDetailsWidget.prototype.getWikiText = function () {\n\t\tvar locationParts,\n\t\t\tlatInput = this.latitudeInput.getValue(),\n\t\t\tlonInput = this.longitudeInput.getValue(),\n\t\t\theadInput = this.headingInput.getValue(),\n\t\t\tlatNum = this.normalizeCoordinate( latInput ),\n\t\t\tlonNum = this.normalizeCoordinate( lonInput ),\n\t\t\theadNum = parseFloat( headInput );\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 ( latNum !== 0 || latInput.indexOf( '0' ) >= 0 || lonNum !== 0 || lonInput.indexOf( '0' ) >= 0 ) {\n\t\t\tlocationParts = [ '{{Location', latNum, lonNum ];\n\n\t\t\tif ( !isNaN( headNum ) ) {\n\t\t\t\tlocationParts.push( 'heading:' + headNum );\n\t\t\t}\n\n\t\t\treturn locationParts.join( '|' ) + '}}';\n\t\t}\n\n\t\treturn '';\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.LocationDetailsWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\tlatitude: this.latitudeInput.getValue(),\n\t\t\tlongitude: this.longitudeInput.getValue(),\n\t\t\theading: this.headingInput.getValue()\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {string} serialized.latitude Latitude value\n\t * @param {string} serialized.longitude Longitude value\n\t * @param {string} serialized.heading Heading value\n\t */\n\tuw.LocationDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\tthis.setupInputs( serialized.latitude, serialized.longitude, serialized.heading );\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 * This code is shared with the Kartographer extension. Please consider updating both when you\n\t * touch this.\n\t *\n\t * @param {string} input\n\t * @return {number|NaN} NaN when normalization was not possible\n\t */\n\tuw.LocationDetailsWidget.prototype.normalizeCoordinate = function ( input ) {\n\t\tvar sign = input.match( /[sw]/i ) ? -1 : 1;\n\n\t\t// fix commonly used character alternatives\n\t\tvar value = input.trim()\n\t\t\t.replace( /−/g, '-' )\n\t\t\t.replace( /\\s*[,.]\\s*/g, '.' );\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\tvar parts = value.match( /^\\D*(-?\\d{1,3}\\b[\\d.]*)[^\\d.]+(\\d{1,2}\\b[\\d.]*)(?:[^\\d.]+(\\d{1,2}\\b[\\d.]*))?\\D*$/ );\n\t\tif ( parts ) {\n\t\t\tvalue = parts[ 1 ] * 1 + parts[ 2 ] / 60 + ( parts[ 3 ] || 0 ) / 3600;\n\t\t} else {\n\t\t\tvalue = value.replace( /[^-\\d.]+/g, '' ) * 1;\n\t\t\tif ( Math.abs( value ) > 360 ) {\n\t\t\t\treturn NaN;\n\t\t\t}\n\t\t}\n\n\t\t// Round to 6 decimal places, this approx. corresponds to a precision of 0.1 meter or less\n\t\treturn Math.round( sign * value * 1000000 ) / 1000000;\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":"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":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":8,"column":1,"nodeType":"Block","endLine":8,"endColumn":1},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":181,"column":10,"nodeType":"CallExpression","endLine":181,"endColumn":45}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"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 * @mixins OO.ui.mixin.GroupElement\n\t * @constructor\n\t * @param {Object} [config]\n\t * @cfg {boolean} [required=true]\n\t * @cfg {mw.Message} [label] Text for label\n\t * @cfg {mw.Message} [placeholder] Placeholder text for input field\n\t * @cfg {mw.Message} [remove] Title text for remove icon\n\t * @cfg {mw.Message} [error] Error message\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 = $.extend( {\n\t\t\trequired: true,\n\t\t\tlabel: mw.message( '' ),\n\t\t\tlanguages: this.getLanguageOptions()\n\t\t}, config );\n\t\tuw.MultipleLanguageInputWidget.super.call( this );\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: [ 'mwe-upwiz-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( 'mwe-upwiz-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( $.extend( {}, 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\tvar 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 = $.extend( {}, languages, unusedLanguages );\n\t\t} else {\n\t\t\tlanguages = unusedLanguages;\n\t\t}\n\n\t\tconfig = $.extend( {}, config, { languages: languages } );\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\tvar 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 = $.extend( {}, 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\tvar allLanguages = this.config.languages,\n\t\t\titems = this.getItems();\n\n\t\treturn items.reduce( function ( obj, item ) {\n\t\t\tvar 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\tvar allLanguages = this.config.languages,\n\t\t\tusedLanguageCodes = Object.keys( this.getUsedLanguages() );\n\n\t\treturn Object.keys( allLanguages ).reduce( function ( remaining, language ) {\n\t\t\tif ( usedLanguageCodes.indexOf( language ) < 0 ) {\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\tvar 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\tvar text = '', msg;\n\t\tif ( this.config.label.exists() ) {\n\t\t\t// clone the original object: `.params` doesn't replace existing\n\t\t\t// params so follow-up calls here would otherwise just keep adding\n\t\t\t// to the params instead of setting a new value for the first param\n\t\t\tmsg = mw.message( this.config.label.key ).params( this.config.label.parameters );\n\t\t\ttext = msg.params( [ this.items.length ] ).text();\n\t\t}\n\n\t\treturn text;\n\t};\n\n\t/**\n\t * @return {Object}\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getLanguageOptions = function () {\n\t\tvar languages, code;\n\n\t\tlanguages = {};\n\t\tfor ( code in mw.UploadWizard.config.uwLanguages ) {\n\t\t\tif ( Object.prototype.hasOwnProperty.call( mw.UploadWizard.config.uwLanguages, code ) ) {\n\t\t\t\tlanguages[ code ] = mw.UploadWizard.config.uwLanguages[ code ];\n\t\t\t}\n\t\t}\n\t\treturn languages;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.MultipleLanguageInputWidget.prototype.getErrors = function () {\n\t\tvar self = this,\n\t\t\t// Gather errors from each item\n\t\t\terrorPromises = this.getItems().map( function ( item ) {\n\t\t\t\treturn item.getErrors();\n\t\t\t} );\n\n\t\treturn $.when.apply( $, errorPromises ).then( function () {\n\t\t\tvar errors = [];\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\tif ( [ ...arguments ].some( ( arg ) => arg.length ) ) {\n\t\t\t\t// One of the items has errors\n\t\t\t\terrors.push( self.config.error );\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( 'mwe-upwiz-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\tvar 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( function ( widget ) {\n\t\t\treturn widget.getWikiText();\n\t\t} ).filter( function ( wikiText ) {\n\t\t\treturn !!wikiText;\n\t\t} ).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\tvar inputs = this.getItems().map( function ( widget ) {\n\t\t\treturn widget.getSerialized();\n\t\t} );\n\t\treturn {\n\t\t\tinputs: inputs\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} 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\tvar config = this.config,\n\t\t\ti;\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 = $.extend( {}, config, { defaultLanguage: serialized.inputs[ i ].language } );\n\t\t\tthis.addLanguageInput( config, serialized.inputs[ i ].text );\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":"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.OtherDetailsWidget.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":"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":[],"suppressedMessages":[{"ruleId":"new-cap","severity":2,"message":"A constructor name should not start with a lowercase letter.","line":45,"column":36,"nodeType":"NewExpression","messageId":"lower","endLine":45,"endColumn":58,"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":"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":"security/detect-non-literal-regexp","severity":1,"message":"Found non-literal argument to RegExp Constructor","line":49,"column":23,"nodeType":"NewExpression","endLine":49,"endColumn":90},{"ruleId":"security/detect-non-literal-regexp","severity":1,"message":"Found non-literal argument to RegExp Constructor","line":86,"column":14,"nodeType":"NewExpression","endLine":86,"endColumn":61},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":134,"column":15,"nodeType":"CallExpression","endLine":134,"endColumn":65},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":193,"column":22,"nodeType":"CallExpression","endLine":193,"endColumn":75}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tvar 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.super.call( this );\n\n\t\tthis.config = config;\n\t\tthis.extension = config.extension;\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', 'mwe-upwiz-titleDetailsWidget-title' ],\n\t\t\tmaxLength: config.maxLength\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( 'mwe-upwiz-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\tvar\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\tvar value, extRegex, cleaned, title;\n\t\tvalue = this.titleInput.getValue().trim();\n\t\tif ( !value ) {\n\t\t\treturn null;\n\t\t}\n\t\textRegex = new RegExp( '\\\\.' + this.extension + '$', 'i' );\n\t\tcleaned = value.replace( extRegex, '' ).replace( /\\.+$/g, '' ).trim();\n\t\ttitle = uw.TitleDetailsWidget.static.makeTitleInFileNS( cleaned + '.' + this.extension );\n\t\treturn title;\n\t};\n\n\t/**\n\t * @return {jQuery.Promise}\n\t */\n\tuw.TitleDetailsWidget.prototype.getErrors = function () {\n\t\tvar\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 ( value === '' ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-blank' ) );\n\t\t\treturn $.Deferred().resolve( errors ).promise();\n\t\t}\n\n\t\tif ( this.config.minLength && length < this.config.minLength ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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( function ( result ) {\n\t\t\t\tvar 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( function ( errorCode ) {\n\t\t\t\t\t\t\t// Messages:\n\t\t\t\t\t\t\t// mwe-upwiz-error-title-invalid, mwe-upwiz-error-title-senselessimagename,\n\t\t\t\t\t\t\t// mwe-upwiz-error-title-thumbnail, mwe-upwiz-error-title-extension,\n\t\t\t\t\t\t\treturn mw.message( 'mwe-upwiz-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( function ( moreErrors ) {\n\t\t\t\treturn [].concat( errors, moreErrors );\n\t\t\t}, function () {\n\t\t\t\treturn $.Deferred().resolve( errors );\n\t\t\t} );\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\tvar 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( 'mwe-upwiz-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'mwe-upwiz-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( 'mwe-upwiz-fileexists-replace-no-link', titleString ) );\n\t\t\t}\n\t\t} else if ( result.unique.isProtected ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-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'mwe-upwiz-blacklisted-details',\n\t\t\t\ttitleString,\n\t\t\t\tfunction () {\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\t// feedback request for titleblacklist\n\t\t\tif ( mw.UploadWizard.config.blacklistIssuesPage !== undefined && mw.UploadWizard.config.blacklistIssuesPage !== '' ) {\n\t\t\t\tmessageParams[ 0 ] = 'mwe-upwiz-blacklisted-details-feedback';\n\t\t\t\tmessageParams.push( function () {\n\t\t\t\t\tvar feedback = new mw.Feedback( {\n\t\t\t\t\t\ttitle: new mw.Title( mw.UploadWizard.config.blacklistIssuesPage ),\n\t\t\t\t\t\tdialogTitleMessageKey: 'mwe-upwiz-feedback-title'\n\t\t\t\t\t} );\n\t\t\t\t\tfeedback.launch( {\n\t\t\t\t\t\tmessage: mw.message( 'mwe-upwiz-feedback-blacklist-line-intro', result.blacklist.blacklistLine ).text(),\n\t\t\t\t\t\tsubject: mw.message( 'mwe-upwiz-feedback-blacklist-subject', titleString ).text()\n\t\t\t\t\t} );\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":"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":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":30,"column":3,"nodeType":"CallExpression","endLine":30,"endColumn":43}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A ULS within a description field in UploadWizard's \"Details\" step form.\n\t *\n\t * @constructor\n\t * @param {Object} [config]\n\t * @cfg {Object} [languages] Keys are 2-letter language codes, values are language autonyms\n\t * @cfg {Array} [classes] Classes to apply to the ULS container div\n\t */\n\tuw.UlsWidget = function UWUlsWidget( config ) {\n\t\tuw.UlsWidget.super.call( this );\n\n\t\tthis.$element = $( '<div>' )\n\t\t\t.append(\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.attr( 'tabindex', 0 )\n\t\t\t\t\t.addClass( 'oo-ui-dropdownWidget-handle' )\n\t\t\t\t\t.addClass( 'oo-ui-widget' )\n\t\t\t\t\t.addClass( 'oo-ui-indicatorElement' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<span>' ).addClass( 'oo-ui-labelElement-label' ),\n\t\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t\t.addClass( 'oo-ui-indicatorElement-indicator' )\n\t\t\t\t\t\t\t.addClass( 'oo-ui-indicator-down' )\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.addClass( 'oo-ui-dropdownWidget' )\n\t\t\t.addClass( 'oo-ui-widget-enabled' );\n\t\tthis.$element.addClass( config.classes );\n\n\t\t// Show the ULS when a user tabs into the language selection field\n\t\tthis.$element.find( '.oo-ui-dropdownWidget-handle' ).on( 'keyup', function ( e ) {\n\t\t\tif ( e.key === 'Tab' ) {\n\t\t\t\t$( this ).trigger( 'click' );\n\t\t\t}\n\t\t} );\n\n\t\tif ( mw.loader.getState( 'ext.uls.mediawiki' ) === 'ready' ) {\n\t\t\tthis.initialiseUls( config.languages );\n\t\t}\n\t};\n\tOO.inheritClass( uw.UlsWidget, OO.ui.Widget );\n\tOO.mixinClass( uw.UlsWidget, OO.EventEmitter );\n\n\tuw.UlsWidget.prototype.initialiseUls = function ( languages ) {\n\t\tvar ulsWidget = this;\n\n\t\tthis.languages = languages;\n\n\t\tthis.uls = this.$element.uls( {\n\t\t\tonSelect: function ( language ) {\n\t\t\t\tulsWidget.setValue( language );\n\t\t\t\tulsWidget.$element.parent().find( '.oo-ui-inputWidget-input' ).trigger( 'focus' );\n\t\t\t},\n\t\t\tlanguages: languages,\n\t\t\tulsPurpose: 'upload-wizard-description',\n\t\t\tonVisible: function () {\n\t\t\t\t// Re-position the ULS *after* the widget has been rendered, so that we can be\n\t\t\t\t// sure it's in the right place\n\t\t\t\tvar offset = ulsWidget.$element.offset();\n\t\t\t\tif ( this.$menu.css( 'direction' ) === 'rtl' ) {\n\t\t\t\t\toffset.left =\n\t\t\t\t\t\toffset.left - parseInt( this.$menu.css( 'width' ) ) + ulsWidget.$element.width();\n\t\t\t\t}\n\t\t\t\tthis.$menu.css( offset );\n\t\t\t}\n\t\t} );\n\t};\n\n\t/**\n\t * @param {Object} languages\n\t */\n\tuw.UlsWidget.prototype.updateLanguages = function ( languages ) {\n\t\tthis.uls.off().removeData( 'uls' );\n\t\tthis.initialiseUls( languages );\n\t};\n\n\t/**\n\t * @param {string} value\n\t */\n\tuw.UlsWidget.prototype.setValue = function ( value ) {\n\t\tvar current = this.languageValue;\n\t\tthis.languageValue = value;\n\t\tthis.$element.find( '.oo-ui-labelElement-label' ).text( this.languages[ value ] );\n\t\tif ( current !== value ) {\n\t\t\tthis.emit( 'select' );\n\t\t}\n\t};\n\n\t/**\n\t * @return {string}\n\t */\n\tuw.UlsWidget.prototype.getValue = function () {\n\t\treturn this.languageValue;\n\t};\n\n\t/**\n\t * @return {uw.UlsWidget}\n\t */\n\tuw.UlsWidget.prototype.getElement = function () {\n\t\treturn this.$element;\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":"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":"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":[],"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":"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.ApiUploadPostHandler.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":"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":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":88,"column":1,"nodeType":"Block","endLine":88,"endColumn":1}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"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\tvar $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\tvar $previous,\n\t\t\t$steps = this.data( 'arrowSteps' );\n\t\t$steps.each( function () {\n\t\t\tvar $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 * @mixins jQuery.plugin.arrowSteps\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":"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":"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/metadata/uw.MetadataContent.js","messages":[{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'change' is undefined.","line":118,"column":1,"nodeType":"Block","endLine":118,"endColumn":1}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\t'use strict';\n\n\t/*\n\t * External dependencies (WikibaseMediaInfo, Wikibase datamodel & config vars) are a\n\t * soft dependency and may not be available here. We'll attempt to lazy-load them from\n\t * uw.MetadataContent constructor and will then populate these vars on success.\n\t */\n\tvar AddPropertyWidget,\n\t\tStatementWidget,\n\t\tdataTypesMap,\n\t\tpropertyDataValuesTypes,\n\t\tdefaultProperties,\n\t\tpropertyTypes,\n\t\twikibaseDatamodel;\n\n\t/**\n\t * @constructor\n\t * @param {mw.UploadWizardUpload} upload\n\t * @param {Object} [config] Configuration options\n\t */\n\tuw.MetadataContent = function UWMetadataContent( upload, config ) {\n\t\tvar $titleDiv,\n\t\t\t$filenameDiv,\n\t\t\t$thumbnailDiv,\n\t\t\tself = this;\n\n\t\tuw.MetadataContent.super.call(\n\t\t\tthis,\n\t\t\t$.extend( { classes: [ 'mwe-upwiz-metadata-content' ] }, config )\n\t\t);\n\n\t\t// Set up widget data\n\t\tthis.upload = upload;\n\t\tthis.entityId = undefined;\n\t\tthis.statementWidgets = {};\n\n\t\t// Build the UI\n\t\t$titleDiv = $( '<h2>' )\n\t\t\t.addClass( 'mwe-upwiz-metadata-content-caption' )\n\t\t\t.text( upload.details.getThumbnailCaption() );\n\t\t$filenameDiv = $( '<p>' )\n\t\t\t.addClass( 'mwe-upwiz-metadata-content-filename' )\n\t\t\t.text( upload.details.getTitle().getMain() );\n\t\t$thumbnailDiv = $( '<div>' )\n\t\t\t.addClass( 'mwe-upwiz-metadata-content-thumbnail' );\n\t\tthis.$statementsDiv = $( '<div>' )\n\t\t\t.addClass( 'mwe-upwiz-metadata-content-statements' );\n\n\t\t// Copy all button\n\t\tthis.copyAllStatementsButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-copy-statements-button' ).text(),\n\t\t\tdisabled: true,\n\t\t\tclasses: [ 'mwe-upwiz-metadata-content-copy-all' ]\n\t\t} );\n\n\t\tthis.copyAllStatementsButton.connect( this, { click: 'copyStatementsToAllFiles' } );\n\n\t\t// Load thumbnail and append elements to page once ready\n\t\tupload.getThumbnail( 630, 360 ).then( function ( thumb ) {\n\t\t\tmw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );\n\t\t\tself.$element.prepend(\n\t\t\t\t$titleDiv,\n\t\t\t\t$filenameDiv,\n\t\t\t\t$thumbnailDiv\n\t\t\t);\n\t\t} );\n\n\t\t// Call the setup method and append statementWidgets once ready\n\t\tthis.$element.append( this.$statementsDiv );\n\t\tmw.loader.using( [\n\t\t\t'wikibase.mediainfo.statements',\n\t\t\t'wikibase.datamodel'\n\t\t] ).then( function ( require ) {\n\t\t\tAddPropertyWidget = require( 'wikibase.mediainfo.statements' ).AddPropertyWidget;\n\t\t\tStatementWidget = require( 'wikibase.mediainfo.statements' ).StatementWidget;\n\t\t\twikibaseDatamodel = require( 'wikibase.datamodel' );\n\t\t\tdataTypesMap = mw.config.get( 'wbDataTypes' );\n\t\t\tdefaultProperties = mw.config.get( 'wbmiDefaultProperties' ) || [];\n\t\t\tpropertyTypes = mw.config.get( 'wbmiPropertyTypes' ) || {};\n\t\t\tpropertyDataValuesTypes = [];\n\n\t\t\tObject.keys( propertyTypes ).forEach( function ( propertyId ) {\n\t\t\t\tpropertyDataValuesTypes[ propertyId ] = dataTypesMap[ propertyTypes[ propertyId ] ].dataValueType;\n\t\t\t} );\n\n\t\t\t( mw.UploadWizard.config.defaults.statements || [] ).forEach( function ( data ) {\n\t\t\t\tif ( defaultProperties.indexOf( data.propertyId ) < 0 ) {\n\t\t\t\t\tdefaultProperties.push( data.propertyId );\n\t\t\t\t}\n\t\t\t\tpropertyDataValuesTypes[ data.propertyId ] = data.dataType;\n\t\t\t} );\n\n\t\t\tObject.freeze( defaultProperties );\n\t\t} ).then( self.setup() ).then( function () {\n\t\t\tObject.keys( self.statementWidgets ).forEach( function ( propertyId ) {\n\t\t\t\tvar statementWidget = self.statementWidgets[ propertyId ];\n\t\t\t\tself.$statementsDiv.append( statementWidget.$element );\n\t\t\t} );\n\n\t\t\tself.createAddPropertyWidgetIfNecessary();\n\n\t\t\tif ( config.allowCopy ) {\n\t\t\t\tself.$element.append( self.copyAllStatementsButton.$element );\n\t\t\t}\n\t\t} );\n\t};\n\n\tOO.inheritClass( uw.MetadataContent, OO.ui.Widget );\n\n\t/**\n\t * Setup method. Fetch the mediainfo ID of the relevant file and create\n\t * widgets for default statements. If default statements are added,\n\t * a \"change\" event is emitted so that the user can immediately publish\n\t * using the suggested data.\n\t *\n\t * @return {jQuery.Promise}\n\t * @fires change\n\t */\n\tuw.MetadataContent.prototype.setup = function () {\n\t\tvar self = this;\n\n\t\treturn this.upload.details.getMediaInfoEntityId().then( function ( entityId ) {\n\t\t\tself.entityId = entityId;\n\n\t\t\t// Create a statement widget for each default property and set its datatype\n\t\t\tdefaultProperties.forEach( function ( propertyId ) {\n\t\t\t\tvar defaultData = self.getDefaultDataForProperty( propertyId ),\n\t\t\t\t\twidget = self.createStatementWidget(\n\t\t\t\t\t\tpropertyId,\n\t\t\t\t\t\tpropertyDataValuesTypes[ propertyId ],\n\t\t\t\t\t\tdefaultData\n\t\t\t\t\t);\n\n\t\t\t\tself.$statementsDiv.append( widget.$element );\n\n\t\t\t\t// pre-populate statements with data if necessary (campaigns only);\n\t\t\t\t// default values are still considered \"changes\" to be published\n\t\t\t\tif ( !defaultData.isEmpty() ) {\n\t\t\t\t\tself.emit( 'change' );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t};\n\n\t/**\n\t * @param {string} propertyId\n\t * @return {wikibaseDatamodel.StatementList}\n\t */\n\tuw.MetadataContent.prototype.getDefaultDataForProperty = function ( propertyId ) {\n\t\tvar defaultStatements = mw.UploadWizard.config.defaults.statements,\n\t\t\tdefaultData;\n\n\t\tif ( !defaultStatements ) {\n\t\t\treturn new wikibaseDatamodel.StatementList();\n\t\t}\n\n\t\tdefaultData = defaultStatements.filter( function ( statement ) {\n\t\t\treturn statement.propertyId === propertyId && statement.values;\n\t\t} )[ 0 ];\n\n\t\tif ( !defaultData || !defaultData.values ) {\n\t\t\treturn new wikibaseDatamodel.StatementList();\n\t\t}\n\n\t\treturn new wikibaseDatamodel.StatementList(\n\t\t\tdefaultData.values.map( function ( itemId ) {\n\t\t\t\treturn new wikibaseDatamodel.Statement(\n\t\t\t\t\tnew wikibaseDatamodel.Claim(\n\t\t\t\t\t\tnew wikibaseDatamodel.PropertyValueSnak(\n\t\t\t\t\t\t\tpropertyId,\n\t\t\t\t\t\t\tnew wikibaseDatamodel.EntityId( itemId )\n\t\t\t\t\t\t),\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tnull\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} )\n\t\t);\n\t};\n\n\t/**\n\t * Creates and sets up the AddPropertyWidget if other statements are enabled.\n\t */\n\tuw.MetadataContent.prototype.createAddPropertyWidgetIfNecessary = function () {\n\t\t// let's always create the widget, that way we don't have to check for its\n\t\t// existence everywhere - but we won't add it to DOM if it's not wanted\n\t\tthis.addPropertyWidget = new AddPropertyWidget( {\n\t\t\tpropertyIds: Object.keys( this.statementWidgets )\n\t\t} );\n\n\t\tthis.addPropertyWidget.connect( this, { choose: 'onPropertyAdded' } );\n\n\t\tif ( mw.UploadWizard.config.wikibase.nonDefaultStatements !== false ) {\n\t\t\tthis.$element.append( this.addPropertyWidget.$element );\n\t\t}\n\t};\n\n\t/**\n\t * Creates and returns a new StatementWidget, with appropriate event handlers\n\t * attached. Also stashes the statement's property ID.\n\t *\n\t * @param {string} propId P123, etc.\n\t * @param {string} valueType 'wikibase-entityid', 'string', etc.\n\t * @param {wikibaseDatamodel.Statement} [data]\n\t * @return {Object} StatementWidget\n\t */\n\tuw.MetadataContent.prototype.createStatementWidget = function ( propId, valueType, data ) {\n\t\tvar self = this,\n\t\t\twidget;\n\n\t\tdata = data || new wikibaseDatamodel.StatementList();\n\n\t\twidget = new StatementWidget( {\n\t\t\tediting: true,\n\t\t\tentityId: this.entityId,\n\t\t\tpropertyId: propId,\n\t\t\tvalueType: valueType,\n\t\t\tisDefaultProperty: defaultProperties.indexOf( propId ) >= 0,\n\t\t\thelpUrls: mw.config.get( 'wbmiHelpUrls' ) || {}\n\t\t} );\n\n\t\t// don't start subscribing to events until statementwidget has been\n\t\t// pre-populated with initial data\n\t\twidget.setData( data ).then( function () {\n\t\t\twidget.connect( self, { widgetRemoved: 'onStatementWidgetRemoved' } );\n\t\t\twidget.connect( self, { change: 'enableCopyAllButton' } );\n\t\t\twidget.connect( self, { change: [ 'emit', 'change' ] } );\n\t\t} );\n\n\t\tthis.statementWidgets[ propId ] = widget;\n\t\treturn widget;\n\t};\n\n\t/**\n\t * @param {Object.<StatementWidget>} statementWidgets Map of { property id: StatementWidget }\n\t */\n\tuw.MetadataContent.prototype.applyCopiedStatements = function ( statementWidgets ) {\n\t\tvar self = this;\n\n\t\t// 1. remove all existing statementWidgets\n\t\tObject.keys( this.statementWidgets ).forEach( function ( propId ) {\n\t\t\tself.onStatementWidgetRemoved( propId );\n\t\t} );\n\n\t\t// 2. re-create statement widgets for each PID in the statementWidgets array\n\t\t// NOTE: this currently loses \"default-ness\"\n\t\tObject.keys( statementWidgets ).forEach( function ( propertyId ) {\n\t\t\tvar statementWidget = statementWidgets[ propertyId ],\n\t\t\t\tsourceData = statementWidget.getData(),\n\t\t\t\ttargetData,\n\t\t\t\tvalueType;\n\n\t\t\tif ( sourceData.isEmpty() ) {\n\t\t\t\t// skip empty widgets\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// construct a new StatementList which is a copy of the existing list,\n\t\t\t// just a new instance (like, different GUID)\n\t\t\ttargetData = new wikibaseDatamodel.StatementList(\n\t\t\t\tsourceData.toArray().map( function ( statement ) {\n\t\t\t\t\treturn new wikibaseDatamodel.Statement(\n\t\t\t\t\t\tnew wikibaseDatamodel.Claim(\n\t\t\t\t\t\t\tstatement.getClaim().getMainSnak(),\n\t\t\t\t\t\t\tstatement.getClaim().getQualifiers(),\n\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t),\n\t\t\t\t\t\tstatement.getReferences(),\n\t\t\t\t\t\tstatement.getRank()\n\t\t\t\t\t);\n\t\t\t\t} )\n\t\t\t);\n\n\t\t\tvalueType = sourceData.toArray()[ 0 ].getClaim().getMainSnak().getValue().getType();\n\n\t\t\tself.createStatementWidget( propertyId, valueType, targetData );\n\t\t} );\n\n\t\t// 3. Append newly-copied statementWidgets to the page\n\t\tObject.keys( this.statementWidgets ).forEach( function ( propertyId ) {\n\t\t\tvar statementWidget = self.statementWidgets[ propertyId ];\n\t\t\tself.$statementsDiv.append( statementWidget.$element );\n\t\t} );\n\t};\n\n\t/**\n\t * Handles the selection by user of a new property to add to page. Creates a\n\t * new appropriate StatementWidget, updates internal datatype map, and\n\t * appends widget to DOM.\n\t *\n\t * @param {Object} item\n\t * @param {Object} data\n\t */\n\tuw.MetadataContent.prototype.onPropertyAdded = function ( item, data ) {\n\t\tvar propertyId = data.id,\n\t\t\tstatementWidget;\n\n\t\tstatementWidget = this.createStatementWidget( propertyId, dataTypesMap[ data.datatype ].dataValueType );\n\t\tthis.addPropertyWidget.$element.before( statementWidget.$element );\n\t};\n\n\t/**\n\t * Handles the removal of StatementWidgets.\n\t * Also cleans up the propertyID and statementWidget arrays.\n\t *\n\t * @param {string} propertyId\n\t * @throws {Error} Raises error if any item to remove is not found\n\t */\n\tuw.MetadataContent.prototype.onStatementWidgetRemoved = function ( propertyId ) {\n\t\tvar removedWidget;\n\n\t\tif ( !( propertyId in this.statementWidgets ) ) {\n\t\t\tthrow new Error( 'Statement widget for property ' + propertyId + ' not found' );\n\t\t}\n\t\tremovedWidget = this.statementWidgets[ propertyId ];\n\n\t\tremovedWidget.$element.remove();\n\t\tdelete this.statementWidgets[ propertyId ];\n\t\tthis.addPropertyWidget.onStatementPanelRemoved( propertyId );\n\t};\n\n\tuw.MetadataContent.prototype.copyStatementsToAllFiles = function () {\n\t\tvar self = this;\n\n\t\tOO.ui.confirm(\n\t\t\tmw.msg( 'mwe-upwiz-copy-statements-dialog' ),\n\t\t\t{\n\t\t\t\tactions: [\n\t\t\t\t\t{\n\t\t\t\t\t\taction: 'accept',\n\t\t\t\t\t\tlabel: mw.msg( 'mwe-upwiz-copy-statements-dialog-accept' ),\n\t\t\t\t\t\tflags: [ 'primary', 'progressive' ]\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\taction: 'reject',\n\t\t\t\t\t\tlabel: mw.msg( 'ooui-dialog-message-reject' ),\n\t\t\t\t\t\tflags: 'safe'\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t).then( function ( confirmed ) {\n\t\t\tvar statements = self.getStatements();\n\t\t\tif ( confirmed ) {\n\t\t\t\tself.emit( 'copyToAll', statements, self.upload.file.name );\n\t\t\t\tself.disableCopyAllButton();\n\t\t\t}\n\t\t} );\n\t};\n\n\tuw.MetadataContent.prototype.enableCopyAllButton = function () {\n\t\tthis.copyAllStatementsButton.setLabel( mw.message( 'mwe-upwiz-copy-statements-button' ).text() );\n\t\tthis.copyAllStatementsButton.setDisabled( false );\n\t};\n\n\tuw.MetadataContent.prototype.disableCopyAllButton = function () {\n\t\tthis.copyAllStatementsButton.setLabel( mw.message( 'mwe-upwiz-copy-statements-button-done' ).text() );\n\t\tthis.copyAllStatementsButton.setDisabled( true );\n\t};\n\n\t/**\n\t * @return {Object.<StatementWidget>} Map of { property id: StatementWidget }\n\t */\n\tuw.MetadataContent.prototype.getStatements = function () {\n\t\treturn this.statementWidgets;\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":"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/metadata/uw.MetadataPage.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":"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":"jsdoc/require-returns","severity":1,"message":"Found more than one @return declaration.","line":11,"column":3,"nodeType":"Block","endLine":20,"endColumn":6},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"Found more than one @return declaration.","line":11,"column":3,"nodeType":"Block","endLine":20,"endColumn":6},{"ruleId":"jsdoc/require-returns","severity":1,"message":"Found more than one @return declaration.","line":34,"column":3,"nodeType":"Block","endLine":44,"endColumn":6},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"Found more than one @return declaration.","line":34,"column":3,"nodeType":"Block","endLine":44,"endColumn":6},{"ruleId":"jsdoc/require-returns","severity":1,"message":"Found more than one @return declaration.","line":85,"column":3,"nodeType":"Block","endLine":96,"endColumn":6},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"Found more than one @return declaration.","line":85,"column":3,"nodeType":"Block","endLine":96,"endColumn":6}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"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 * @return {Function} return.done\n\t\t * @return {string} return.done.title The title that was passed in\n\t\t * @return {Object|boolean} return.done.blacklist See #checkBlacklist\n\t\t * @return {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( function ( unique, blacklist ) {\n\t\t\t\treturn {\n\t\t\t\t\tunique: unique,\n\t\t\t\t\tblacklist: blacklist,\n\t\t\t\t\ttitle: title\n\t\t\t\t};\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 * @return {Function} return.done\n\t\t * @return {boolean} return.done.notBlacklisted\n\t\t * @return {string} [return.done.blacklistReason] See mw.Api#isBlacklisted\n\t\t * @return {string} [return.done.blacklistMessage] See mw.Api#isBlacklisted\n\t\t * @return {string} [return.done.blacklistLine] See mw.Api#isBlacklisted\n\t\t */\n\t\tcheckBlacklist: function ( title ) {\n\t\t\tvar 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\tvar 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( function () {\n\t\t\t\treturn checker.api.isBlacklisted( title ).then( blacklistResultProcessor );\n\t\t\t}, function () {\n\t\t\t\t// it's not blacklisted, because the API isn't even available\n\t\t\t\treturn $.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 * @return {Function} return.done\n\t\t * @return {boolean} return.done.isUnique\n\t\t * @return {boolean} [return.done.isProtected]\n\t\t * @return {Object} [return.done.img] Image info\n\t\t * @return {string} [return.done.href] URL to file description page\n\t\t */\n\t\tcheckUnique: function ( title ) {\n\t\t\tvar 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\tvar 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( function ( val ) {\n\t\t\t\t\t\t\t\tif ( mw.config.get( 'wgUserGroups' ).indexOf( val.level ) === -1 ) {\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( function ( exact, fuzzy ) {\n\t\t\t\tvar 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":"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":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":63,"column":13,"nodeType":"Literal","endLine":63,"endColumn":56},{"ruleId":"security/detect-non-literal-regexp","severity":1,"message":"Found non-literal argument to RegExp Constructor","line":121,"column":19,"nodeType":"NewExpression","endLine":121,"endColumn":74}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"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\tvar 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, function ( match ) {\n\t\t\t\treturn match.replace( /\\|/g, '%7C' );\n\t\t\t} );\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, $.extend( 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\tvar 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\tvar 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\tvar extracts = {};\n\n\t\t\twikitext = wikitext.replace( /\\[\\[.*?\\]\\]/g, function ( match ) {\n\t\t\t\tvar 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\tvar 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\tvar 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":"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.FlickrChecker.js","messages":[{"ruleId":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":73,"column":42,"nodeType":"Literal","endLine":73,"endColumn":98},{"ruleId":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":75,"column":49,"nodeType":"Literal","endLine":75,"endColumn":120},{"ruleId":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":76,"column":50,"nodeType":"Literal","endLine":76,"endColumn":98},{"ruleId":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":77,"column":44,"nodeType":"Literal","endLine":77,"endColumn":92},{"ruleId":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":78,"column":46,"nodeType":"Literal","endLine":78,"endColumn":113},{"ruleId":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":79,"column":48,"nodeType":"Literal","endLine":79,"endColumn":107},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'getPhotos' is undefined.","line":199,"column":1,"nodeType":"Block","endLine":199,"endColumn":1},{"ruleId":"no-shadow","severity":1,"message":"'data' is already declared in the upper scope on line 206 column 24.","line":213,"column":26,"nodeType":"Identifier","messageId":"noShadow","endLine":213,"endColumn":30},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'getCollection' is undefined.","line":237,"column":1,"nodeType":"Block","endLine":237,"endColumn":1},{"ruleId":"no-shadow","severity":1,"message":"'data' is already declared in the upper scope on line 285 column 24.","line":296,"column":57,"nodeType":"Identifier","messageId":"noShadow","endLine":296,"endColumn":61},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'getPhotos' is undefined.","line":308,"column":1,"nodeType":"Block","endLine":308,"endColumn":1},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'getPhotos' is undefined.","line":329,"column":1,"nodeType":"Block","endLine":329,"endColumn":1},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":580,"column":49,"nodeType":"MemberExpression","messageId":"forbidden","endLine":580,"endColumn":66},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":678,"column":4,"nodeType":"MemberExpression","messageId":"forbidden","endLine":678,"endColumn":22},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":697,"column":42,"nodeType":"MemberExpression","messageId":"forbidden","endLine":697,"endColumn":64}],"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":83,"column":3,"nodeType":"CallExpression","endLine":83,"endColumn":49,"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":92,"column":4,"nodeType":"CallExpression","endLine":92,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'api_key' is not in camel case.","line":158,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":158,"endColumn":11,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'user_id' is not in camel case.","line":187,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":187,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'group_id' is not in camel case.","line":216,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":216,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'user_id' is not in camel case.","line":217,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":217,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'group_id' is not in camel case.","line":224,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":224,"endColumn":13,"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":257,"column":7,"nodeType":"CallExpression","endLine":257,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photoset_id' is not in camel case.","line":260,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":260,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'user_id' is not in camel case.","line":289,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":289,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'collection_id' is not in camel case.","line":293,"column":9,"nodeType":"Identifier","messageId":"notCamelCase","endLine":293,"endColumn":22,"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":298,"column":5,"nodeType":"CallExpression","endLine":298,"endColumn":28,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'gallery_id' is not in camel case.","line":319,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":319,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photoset_id' is not in camel case.","line":334,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":334,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'per_page' is not in camel case.","line":354,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":354,"endColumn":12,"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":442,"column":4,"nodeType":"CallExpression","endLine":442,"endColumn":40,"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":460,"column":5,"nodeType":"CallExpression","endLine":460,"endColumn":51,"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":462,"column":5,"nodeType":"CallExpression","endLine":462,"endColumn":35,"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":464,"column":5,"nodeType":"CallExpression","endLine":464,"endColumn":51,"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":487,"column":5,"nodeType":"CallExpression","endLine":487,"endColumn":51,"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":490,"column":5,"nodeType":"CallExpression","endLine":490,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'skip_invisible' is not in camel case.","line":492,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":492,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photo_id' is not in camel case.","line":519,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":519,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_content'.","line":540,"column":48,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":540,"endColumn":68,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_content'.","line":554,"column":18,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":554,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_content'.","line":580,"column":49,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":580,"endColumn":75,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'path_alias' is not in camel case.","line":606,"column":34,"nodeType":"Identifier","messageId":"notCamelCase","endLine":606,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'path_alias' is not in camel case.","line":607,"column":3,"nodeType":"Identifier","messageId":"notCamelCase","endLine":607,"endColumn":13,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'path_alias' is not in camel case.","line":610,"column":34,"nodeType":"Identifier","messageId":"notCamelCase","endLine":610,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'path_alias' is not in camel case.","line":610,"column":48,"nodeType":"Identifier","messageId":"notCamelCase","endLine":610,"endColumn":58,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-support","severity":1,"message":"$.support is not allowed","line":655,"column":3,"nodeType":"MemberExpression","endLine":655,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photo_id' is not in camel case.","line":695,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":695,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_content'.","line":697,"column":42,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":697,"endColumn":73,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photo_id' is not in camel case.","line":715,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":715,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":15,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/* eslint-disable camelcase, no-underscore-dangle */\n\nmw.FlickrChecker = function ( ui, selectButton ) {\n\tthis.ui = ui;\n\tthis.imageUploads = [];\n\tthis.apiUrl = mw.UploadWizard.config.flickrApiUrl;\n\tthis.apiKey = mw.UploadWizard.config.flickrApiKey;\n\tthis.selectButton = selectButton;\n};\n\n/**\n * Static list of all Flickr upload filenames.\n * Used to avoid name conflicts. Filenames are not removed when an upload is cancelled, so this can\n * contain fakes. Since we only use the list to choose an ugly but more unique file format on conflict,\n * and never refuse an upload based on it, that is not really a problem.\n *\n * @type {Object}\n */\nmw.FlickrChecker.fileNames = {};\n\n/**\n * Cache for Flickr blacklist lookups.\n * Resolves to a hash whose keys are the blacklisted Flickr NSIDs.\n * Use `FlickrChecker.getBlacklist()` instead of accessing this directly.\n *\n * @type {jQuery.Promise}\n */\nmw.FlickrChecker.blacklist = null;\n\n/**\n * Cache for Flickr license lookups.\n *\n * @type {jQuery.Promise}\n */\nmw.FlickrChecker.licensePromise = null;\n\n/**\n * Flickr licenses.\n */\nmw.FlickrChecker.licenseList = [];\n\n// Map each Flickr license name to the equivalent templates.\n// These are the current Flickr license names as of April 26, 2011.\n// Live list at http://api.flickr.com/services/rest/?&method=flickr.photos.licenses.getInfo&api_key=...\nmw.FlickrChecker.licenseMaps = {\n\t'All Rights Reserved': 'invalid',\n\t'Attribution License': '{{cc-by-2.0}}{{flickrreview}}',\n\t'Attribution-NoDerivs License': 'invalid',\n\t'Attribution-NonCommercial-NoDerivs License': 'invalid',\n\t'Attribution-NonCommercial License': 'invalid',\n\t'Attribution-NonCommercial-ShareAlike License': 'invalid',\n\t'Attribution-ShareAlike License': '{{cc-by-sa-2.0}}{{flickrreview}}',\n\t'No known copyright restrictions': '{{Flickr-no known copyright restrictions}}{{flickrreview}}',\n\t'United States Government Work': '{{PD-USGov}}{{flickrreview}}',\n\t'Public Domain Dedication (CC0)': '{{cc-zero}}{{flickrreview}}',\n\t'Public Domain Mark': '{{cc-zero}}{{flickrreview}}'\n};\n\nmw.FlickrChecker.prototype = {\n\t/**\n\t * If a photo is from Flickr, retrieve its license. If the license is valid, display the license\n\t * to the user, hide the normal license selection interface, and set it as the deed for the upload.\n\t * If the license is not valid, alert the user with an error message. If no recognized license is\n\t * retrieved, do nothing. Note that the license look-up system is fragile on purpose. If Flickr\n\t * changes the name associated with a license ID, it's better for the lookup to fail than to use\n\t * an incorrect license.\n\t *\n\t * @param {string} flickrInputUrl The source URL to check\n\t */\n\tcheckFlickr: function ( flickrInputUrl ) {\n\t\tvar photoIdMatches, albumIdMatches, userCollectionMatches, userPhotostreamMatches, groupPoolMatches, userGalleryMatches, userFavoritesMatches;\n\n\t\tphotoIdMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/[^/]+\\/([0-9]+)/ );\n\t\talbumIdMatches = flickrInputUrl.match( /flickr\\.com\\/photos\\/[^/]+\\/(sets|albums)\\/([0-9]+)/ );\n\t\tuserCollectionMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/[^/]+\\/collections\\/?([0-9]+)?/ );\n\t\tuserPhotostreamMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/([^/]+)/ );\n\t\tgroupPoolMatches = flickrInputUrl.match( /flickr\\.com\\/groups\\/[^/]+(?:\\/pool\\/([^/]+))?/ );\n\t\tuserGalleryMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/[^/]+\\/galleries\\/([0-9]+)/ );\n\t\tuserFavoritesMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/([^/]+)\\/favorites/ );\n\n\t\tthis.$spinner = $.createSpinner( { size: 'large', type: 'block' } );\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( '#mwe-upwiz-flickr-select-list-container' ).after( this.$spinner );\n\n\t\tif ( photoIdMatches === null ) {\n\t\t\t// try static urls\n\t\t\tphotoIdMatches = flickrInputUrl.match( /static\\.?flickr\\.com\\/[^/]+\\/([0-9]+)_/ );\n\t\t}\n\t\tif ( albumIdMatches || photoIdMatches || userCollectionMatches || userPhotostreamMatches ||\n\t\t\tgroupPoolMatches || userGalleryMatches || userFavoritesMatches ) {\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( '#mwe-upwiz-upload-add-flickr-container' ).hide();\n\t\t\tthis.imageUploads = [];\n\t\t\tif ( albumIdMatches && albumIdMatches[ 2 ] > 0 ) {\n\t\t\t\tthis.getPhotoset( albumIdMatches, flickrInputUrl );\n\t\t\t} else if ( photoIdMatches && photoIdMatches[ 1 ] > 0 ) {\n\t\t\t\tthis.getPhoto( photoIdMatches, flickrInputUrl );\n\t\t\t} else if ( userCollectionMatches ) {\n\t\t\t\tthis.getCollection( userCollectionMatches, flickrInputUrl );\n\t\t\t} else if ( userFavoritesMatches && userFavoritesMatches[ 1 ] ) {\n\t\t\t\tthis.getPhotostream( 'favorites', userPhotostreamMatches, flickrInputUrl );\n\t\t\t} else if ( userGalleryMatches && userGalleryMatches[ 1 ] ) {\n\t\t\t\tthis.getGallery( flickrInputUrl );\n\t\t\t} else if ( userPhotostreamMatches && userPhotostreamMatches[ 1 ] ) {\n\t\t\t\tthis.getPhotostream( 'stream', flickrInputUrl );\n\t\t\t} else if ( groupPoolMatches ) {\n\t\t\t\tthis.getGroupPool( groupPoolMatches, flickrInputUrl );\n\t\t\t}\n\t\t} else {\n\t\t\t// XXX show user the message that the URL entered was not valid\n\t\t\tmw.errorDialog( mw.message( 'mwe-upwiz-url-invalid', 'Flickr' ).escaped() );\n\t\t\tthis.$spinner.remove();\n\t\t\tthis.ui.flickrInterfaceReset();\n\t\t}\n\t},\n\n\t/**\n\t * Returns a suggested filename for the image.\n\t * Usually the filename is just the Flickr title plus an extension, but in case of name conflicts\n\t * or empty title a unique filename is generated.\n\t *\n\t * @param {string} title image title on Flickr\n\t * @param {number} id image id on Flickr\n\t * @param {string} ownername owner name on Flickr\n\t * @return {string}\n\t */\n\tgetFilenameFromItem: function ( title, id, ownername ) {\n\t\tvar fileName;\n\n\t\tif ( title === '' ) {\n\t\t\tfileName = ownername + ' - ' + id + '.jpg';\n\t\t} else if ( mw.FlickrChecker.fileNames[ title + '.jpg' ] ) {\n\t\t\tfileName = title + ' - ' + id + '.jpg';\n\t\t} else {\n\t\t\tfileName = title + '.jpg';\n\t\t}\n\n\t\treturn fileName;\n\t},\n\n\t/**\n\t * Reserves a filename; used by `mw.FlickrChecker.getFileNameFromItem()` which tries to\n\t * avoid returning a filename which is already reserved.\n\t * This works even when the filename was reserved in a different FlickrChecker instance.\n\t *\n\t * @param {string} fileName\n\t */\n\treserveFileName: function ( fileName ) {\n\t\tmw.FlickrChecker.fileNames[ fileName ] = true;\n\t},\n\n\t/**\n\t * @param {Object} params\n\t * @return {jQuery.Promise} a promise with the response data\n\t */\n\tflickrRequest: function ( params ) {\n\t\tparams = $.extend( {\n\t\t\tapi_key: this.apiKey,\n\t\t\tformat: 'json',\n\t\t\tnojsoncallback: 1\n\t\t}, params );\n\t\treturn $.getJSON( this.apiUrl, params );\n\t},\n\n\t/*\n\t * Retrieves a list of photos in photostream and displays it.\n\t * @see {@link getPhotos}\n\t * @param {string} mode may be: 'favorites' - user's favorites are retrieved,\n\t * or 'stream' - user's photostream is retrieved\n\t * @param {string} url URL to get the user from.\n\t * @return {jQuery.Promise}\n\t */\n\tgetPhotostream: function ( mode, url ) {\n\t\tvar checker = this;\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.urls.lookupUser',\n\t\t\turl: url\n\t\t} ).then( function ( data ) {\n\t\t\tvar method;\n\t\t\tif ( mode === 'stream' ) {\n\t\t\t\tmethod = 'flickr.people.getPublicPhotos';\n\t\t\t} else if ( mode === 'favorites' ) {\n\t\t\t\tmethod = 'flickr.favorites.getPublicList';\n\t\t\t}\n\t\t\treturn checker.getPhotos( 'photos', {\n\t\t\t\tmethod: method,\n\t\t\t\tuser_id: data.user.id\n\t\t\t} );\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieves a list of photos in group pool and displays it.\n\t *\n\t * @param {Object} groupPoolMatches Groups in the input URL\n\t * @param {string} url The URL from which to get the group.\n\t * @see {@link getPhotos}\n\t * @return {jQuery.Promise}\n\t */\n\tgetGroupPool: function ( groupPoolMatches, url ) {\n\t\tvar checker = this;\n\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.urls.lookupGroup',\n\t\t\turl: url\n\t\t} ).then( function ( data ) {\n\t\t\tvar gid = data.group.id;\n\n\t\t\tif ( groupPoolMatches[ 1 ] ) { // URL contains a user ID\n\t\t\t\treturn checker.flickrRequest( {\n\t\t\t\t\tmethod: 'flickr.urls.lookupUser',\n\t\t\t\t\turl: 'http://www.flickr.com/photos/' + groupPoolMatches[ 1 ]\n\t\t\t\t} ).then( function ( data ) {\n\t\t\t\t\treturn checker.getPhotos( 'photos', {\n\t\t\t\t\t\tmethod: 'flickr.groups.pools.getPhotos',\n\t\t\t\t\t\tgroup_id: gid,\n\t\t\t\t\t\tuser_id: data.user.id\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn checker.getPhotos( 'photos', {\n\t\t\t\tmethod: 'flickr.groups.pools.getPhotos',\n\t\t\t\tgroup_id: gid\n\t\t\t} );\n\t\t} );\n\t},\n\n\t/**\n\t * Constructs an unordered list of sets in the collection.\n\t *\n\t * @param {boolean} appendId True if you want to append\n\t *  id=\"mwe-upwiz-files-collection-chooser\"; false otherwise\n\t * @param {Object} data The retrieved data\n\t * @see {@link getCollection}\n\t * @return {jQuery}\n\t */\n\tbuildCollectionLinks: function ( appendId, data ) {\n\t\tvar $elem = $( '<ul>' );\n\t\tif ( appendId ) {\n\t\t\t$elem.attr( 'id', 'mwe-upwiz-files-collection-chooser' );\n\t\t}\n\t\tvar checker = this;\n\t\tdata.collection.forEach( function ( value ) {\n\t\t\tvar $li = $( '<li>' );\n\t\t\t$li.append( value.title );\n\t\t\tif ( value.collection !== undefined ) {\n\t\t\t\t$li.append( checker.buildCollectionLinks( false, value ) );\n\t\t\t}\n\t\t\tif ( value.set !== undefined ) {\n\t\t\t\tvar $ul = $( '<ul>' );\n\t\t\t\tvalue.set.forEach( function ( value2 ) {\n\t\t\t\t\tvar $link = $( '<a>' ).attr( { href: '#', role: 'button', 'data-id': value2.id } );\n\t\t\t\t\t$link.append( value2.title );\n\t\t\t\t\t$link.on( 'click', function () {\n\t\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t\t$( '#mwe-upwiz-files-collection-chooser' ).remove();\n\t\t\t\t\t\tchecker.getPhotos( 'photoset', {\n\t\t\t\t\t\t\tmethod: 'flickr.photosets.getPhotos',\n\t\t\t\t\t\t\tphotoset_id: $link.data( 'id' )\n\t\t\t\t\t\t} );\n\t\t\t\t\t} );\n\t\t\t\t\t$ul.append( $( '<li>' ).append( $link ) );\n\t\t\t\t} );\n\t\t\t\t$li.append( $ul );\n\t\t\t}\n\t\t\t$elem.append( $li );\n\t\t} );\n\t\treturn $elem;\n\t},\n\n\t/**\n\t * Retrieves a list of sets in a collection and displays it.\n\t *\n\t * @param {Object} userCollectionMatches Result of this.url.match\n\t * @param {string} url URL with which to look up the user.\n\t * @return {jQuery.Promise}\n\t */\n\tgetCollection: function ( userCollectionMatches, url ) {\n\t\tvar checker = this;\n\n\t\treturn checker.flickrRequest( {\n\t\t\tmethod: 'flickr.urls.lookupUser',\n\t\t\turl: url\n\t\t} ).then( function ( data ) {\n\t\t\tvar req = {\n\t\t\t\tmethod: 'flickr.collections.getTree',\n\t\t\t\textras: 'license, url_sq, owner_name, original_format, date_taken, geo',\n\t\t\t\tuser_id: data.user.id\n\t\t\t};\n\n\t\t\tif ( userCollectionMatches[ 1 ] ) {\n\t\t\t\treq.collection_id = userCollectionMatches[ 1 ];\n\t\t\t}\n\n\t\t\treturn checker.flickrRequest( req ).then( function ( data ) {\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-files' ).append( checker.buildCollectionLinks( true, data.collections ) );\n\t\t\t} );\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieves a list of photos in gallery and displays it.\n\t *\n\t * @see {@link getPhotos}\n\t * @param {string} url URL with which to look up the gallery information.\n\t * @return {jQuery.Promise}\n\t */\n\tgetGallery: function ( url ) {\n\t\tvar checker = this;\n\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.urls.lookupGallery',\n\t\t\turl: url\n\t\t} ).then( function ( data ) {\n\t\t\treturn checker.getPhotos( 'photos', {\n\t\t\t\tmethod: 'flickr.galleries.getPhotos',\n\t\t\t\tgallery_id: data.gallery.id\n\t\t\t} );\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieves a list of photos in photoset and displays it.\n\t *\n\t * @see {@link getPhotos}\n\t * @param {Object} albumIdMatches Result of this.url.match\n\t * @return {jQuery.Promise}\n\t */\n\tgetPhotoset: function ( albumIdMatches ) {\n\t\treturn this.getPhotos( 'photoset', {\n\t\t\tmethod: 'flickr.photosets.getPhotos',\n\t\t\tphotoset_id: albumIdMatches[ 2 ]\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieves a list of photos and displays it.\n\t *\n\t * @param {string} mode may be: 'photoset' - for use with photosets,\n\t *  or 'photos' - for use with everything else (the parameter is used\n\t *  to determine how the properties in retrieved JSON are named)\n\t * @param {Object} options options to pass to the API call; especially API method\n\t *  and some \"***_id\"s (photoset_id, etc.)\n\t * @return {jQuery.Promise}\n\t */\n\tgetPhotos: function ( mode, options ) {\n\t\tthis.selectButton.setLabel( mw.message( 'mwe-upwiz-select-flickr' ).text() );\n\t\tthis.selectButton.setDisabled( true );\n\n\t\tvar req = $.extend( {}, options, {\n\t\t\textras: 'license, url_sq, owner_name, original_format, date_taken, geo, path_alias',\n\t\t\tper_page: '500'\n\t\t} );\n\n\t\tvar flickrPromise = this.flickrRequest( req ).then( function ( data ) {\n\t\t\tvar photoset;\n\t\t\tif ( mode === 'photoset' ) {\n\t\t\t\tphotoset = data.photoset;\n\t\t\t} else if ( mode === 'photos' ) {\n\t\t\t\tphotoset = data.photos;\n\t\t\t}\n\t\t\tif ( !photoset ) {\n\t\t\t\t$.Deferred().reject( mw.message( 'mwe-upwiz-url-invalid', 'Flickr' ).escaped() );\n\t\t\t}\n\t\t\treturn photoset;\n\t\t} );\n\t\tvar checker = this;\n\n\t\t// would be better to use isBlacklisted(), but didn't find a nice way of combining it with $.each\n\t\treturn $.when( flickrPromise, this.getBlacklist() ).then( function ( photoset, blacklist ) {\n\t\t\tvar sourceURL;\n\t\t\tvar checkboxes = [];\n\t\t\tvar checkboxesWidget = new OO.ui.CheckboxMultiselectWidget();\n\t\t\tvar x = 0;\n\n\t\t\tchecker.$spinner.remove();\n\n\t\t\tphotoset.photo.forEach( function ( item, i ) {\n\t\t\t\tvar license = checker.checkLicense( item.license );\n\t\t\t\tvar licenseValue = license.licenseValue;\n\t\t\t\tif ( licenseValue === 'invalid' ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar ownerId;\n\t\t\t\tif ( mode === 'photoset' ) {\n\t\t\t\t\townerId = photoset.owner;\n\t\t\t\t\tsourceURL = 'https://www.flickr.com/photos/' + photoset.owner + '/' + item.id + '/';\n\t\t\t\t} else if ( mode === 'photos' ) {\n\t\t\t\t\townerId = item.owner;\n\t\t\t\t\tsourceURL = 'https://www.flickr.com/photos/' + item.owner + '/' + item.id + '/';\n\t\t\t\t}\n\n\t\t\t\tif ( ownerId in blacklist || item.pathalias in blacklist ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Limit to maximum of 500 valid images\n\t\t\t\t// (Flickr's API returns a maximum of 500 images anyway.)\n\t\t\t\tif ( x++ >= 500 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tvar fileName = checker.getFilenameFromItem( item.title, item.id, item.ownername );\n\n\t\t\t\tvar flickrUpload = {\n\t\t\t\t\tname: fileName,\n\t\t\t\t\turl: '',\n\t\t\t\t\ttype: 'JPEG',\n\t\t\t\t\tfromURL: true,\n\t\t\t\t\tsource: 'flickr',\n\t\t\t\t\tlicenseValue: licenseValue,\n\t\t\t\t\tlicenseMessage: license.licenseMessage,\n\t\t\t\t\tlicenseName: license.licenseName,\n\t\t\t\t\tphotoId: item.id,\n\t\t\t\t\tlocation: {\n\t\t\t\t\t\tlatitude: item.latitude,\n\t\t\t\t\t\tlongitude: item.longitude\n\t\t\t\t\t},\n\t\t\t\t\tauthor: item.ownername,\n\t\t\t\t\tdate: item.datetaken,\n\t\t\t\t\toriginalFormat: item.originalformat,\n\t\t\t\t\tsourceURL: sourceURL,\n\t\t\t\t\tindex: i\n\t\t\t\t};\n\t\t\t\t// Adding all the Photoset files which have a valid license with the required info to an array so that they can be referenced later\n\t\t\t\tchecker.imageUploads[ i ] = flickrUpload;\n\t\t\t\tchecker.reserveFileName( fileName );\n\n\t\t\t\t// setting up the thumbnail previews in the Selection list\n\t\t\t\tif ( item.url_sq ) {\n\t\t\t\t\tcheckboxes.push( new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\t\t\tdata: i,\n\t\t\t\t\t\tlabel: $( '<img class=\"lazy-thumbnail\" data-original=\"' + item.url_sq + '\">' )\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t} );\n\t\t\tcheckboxesWidget.addItems( checkboxes );\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( '#mwe-upwiz-flickr-select-list' ).append( checkboxesWidget.$element );\n\t\t\t// Set up checkboxes\n\t\t\tcheckboxesWidget.on( 'select', function () {\n\t\t\t\tvar selectedCount = checkboxesWidget.findSelectedItems().length;\n\t\t\t\t// If at least one item is selected, activate the upload button\n\t\t\t\tchecker.selectButton.setDisabled( selectedCount === 0 );\n\t\t\t\t// Limit the number of selectable images\n\t\t\t\tcheckboxesWidget.getItems().forEach( function ( checkbox ) {\n\t\t\t\t\tif ( !checkbox.isSelected() ) {\n\t\t\t\t\t\tcheckbox.setDisabled( selectedCount >= mw.UploadWizard.config.maxFlickrUploads );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\t\t// Set up action for 'Upload selected images' button\n\t\t\tchecker.selectButton.on( 'click', function () {\n\t\t\t\tvar uploads = [];\n\t\t\t\tchecker.$spinner = $.createSpinner( { size: 'large', type: 'block' } );\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-flickr-select-list-container' ).hide();\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-upload-ctrls' ).show();\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-flickr-select-list-container' ).after( checker.$spinner );\n\t\t\t\t$.when.apply( $, checkboxesWidget.findSelectedItemsData().map( function ( image ) {\n\t\t\t\t\tuploads.push( checker.imageUploads[ image ] );\n\t\t\t\t\t// For each image, load the description and URL to upload from\n\t\t\t\t\treturn $.when(\n\t\t\t\t\t\tchecker.setUploadDescription( checker.imageUploads[ image ] ),\n\t\t\t\t\t\tchecker.setImageURL( image )\n\t\t\t\t\t);\n\t\t\t\t} ) ).done( function () {\n\t\t\t\t\tchecker.ui.emit( 'files-added', uploads );\n\t\t\t\t} ).always( function () {\n\t\t\t\t\t// We'll only bind this once, since that selectButton could be\n\t\t\t\t\t// reused later, with a different flickr set (it is not destroyed)\n\t\t\t\t\tchecker.selectButton.off( 'click' );\n\t\t\t\t\tchecker.$spinner.remove();\n\t\t\t\t\tchecker.ui.flickrInterfaceDestroy();\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\tif ( checker.imageUploads.length === 0 ) {\n\t\t\t\treturn $.Deferred().reject( mw.message( 'mwe-upwiz-license-photoset-invalid' ).escaped() );\n\t\t\t} else {\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-flickr-select-list-container' ).show();\n\t\t\t\t// Lazy-load images\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( 'img.lazy-thumbnail' ).lazyload( {\n\t\t\t\t\t// jQuery considers all images without 'src' to not be ':visible'\n\t\t\t\t\tskip_invisible: false\n\t\t\t\t} );\n\t\t\t\t// Trigger initial update (HACK)\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t$( window ).triggerHandler( 'resize' );\n\t\t\t\t} );\n\t\t\t}\n\t\t} ).fail( function ( message ) {\n\t\t\tmw.errorDialog( message, mw.msg( 'mwe-upwiz-license-photoset-invalid-title' ) );\n\t\t\tchecker.$spinner.remove();\n\t\t\tchecker.ui.flickrInterfaceReset();\n\t\t} );\n\t},\n\n\t/**\n\t * Get a single photo from Flickr.\n\t *\n\t * @param {Object} photoIdMatches Result of matching input URL against a regex\n\t *   for photo IDs.\n\t * @return {jQuery.Promise}\n\t */\n\tgetPhoto: function ( photoIdMatches ) {\n\t\tvar checker = this;\n\t\tvar photoId = photoIdMatches[ 1 ];\n\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.photos.getInfo',\n\t\t\tphoto_id: photoId\n\t\t} ).then( function ( data ) {\n\t\t\tif ( !data.photo ) {\n\t\t\t\treturn $.Deferred().reject( mw.message( 'mwe-upwiz-url-invalid', 'Flickr' ).escaped() );\n\t\t\t}\n\t\t\treturn data.photo;\n\t\t} ).then( function ( photo ) {\n\t\t\tvar isBlacklistedPromise = checker.isBlacklisted( photo.owner.nsid, photo.owner.path_alias );\n\t\t\treturn isBlacklistedPromise.then( function ( isBlacklisted ) {\n\t\t\t\tif ( isBlacklisted ) {\n\t\t\t\t\treturn $.Deferred().reject( mw.message( 'mwe-upwiz-user-blacklisted', 'Flickr' ).escaped() );\n\t\t\t\t} else {\n\t\t\t\t\treturn photo;\n\t\t\t\t}\n\t\t\t} );\n\t\t} ).then( function ( photo ) {\n\t\t\tvar license = checker.checkLicense( photo.license );\n\t\t\tif ( license.licenseValue === 'invalid' ) {\n\t\t\t\treturn $.Deferred().reject( license.licenseMessage );\n\t\t\t}\n\n\t\t\tvar fileName = checker.getFilenameFromItem( photo.title._content, photo.id,\n\t\t\t\tphoto.owner.username );\n\n\t\t\t// if owner doesn't have a real name, use username\n\t\t\tvar photoAuthor;\n\t\t\tif ( photo.owner.realname !== '' ) {\n\t\t\t\tphotoAuthor = photo.owner.realname;\n\t\t\t} else {\n\t\t\t\tphotoAuthor = photo.owner.username;\n\t\t\t}\n\t\t\t// get the URL of the photo page\n\t\t\tvar sourceURL;\n\t\t\tphoto.urls.url.forEach( function ( url ) {\n\t\t\t\tif ( url.type === 'photopage' ) {\n\t\t\t\t\tsourceURL = url._content;\n\t\t\t\t\t// break each loop\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tvar flickrUpload = {\n\t\t\t\tname: fileName,\n\t\t\t\turl: '',\n\t\t\t\ttype: 'JPEG',\n\t\t\t\tfromURL: true,\n\t\t\t\tsource: 'flickr',\n\t\t\t\tlicenseValue: license.licenseValue,\n\t\t\t\tlicenseMessage: license.licenseMessage,\n\t\t\t\tlicenseName: license.licenseName,\n\t\t\t\tauthor: photoAuthor,\n\t\t\t\toriginalFormat: photo.originalformat,\n\t\t\t\tdate: photo.dates.taken,\n\t\t\t\tlocation: photo.location,\n\t\t\t\tphotoId: photo.id,\n\t\t\t\tsourceURL: sourceURL\n\t\t\t};\n\n\t\t\tchecker.imageUploads.push( flickrUpload );\n\t\t\tchecker.reserveFileName( fileName );\n\n\t\t\t$.when(\n\t\t\t\tchecker.setUploadDescription( flickrUpload, photo.description._content ),\n\t\t\t\tchecker.setImageURL( 0 )\n\t\t\t).done( function () {\n\t\t\t\tchecker.ui.emit( 'files-added', [ flickrUpload ] );\n\t\t\t} ).always( function () {\n\t\t\t\tchecker.$spinner.remove();\n\t\t\t\tchecker.ui.flickrInterfaceDestroy();\n\t\t\t} );\n\t\t} ).fail( function ( message ) {\n\t\t\tmw.errorDialog( message, mw.msg( 'mwe-upwiz-license-external-invalid-title' ) );\n\t\t\tchecker.$spinner.remove();\n\t\t\tchecker.ui.flickrInterfaceReset();\n\t\t} );\n\t},\n\n\t/**\n\t * Checks a user against the blacklist. Both the NSID and the path_alias (if it exists) MUST be\n\t * supplied, as the blacklist will probably only contain one of them. (Users don't have a\n\t * path_alias in the beginning, and must set it manually; if it does not exist, it can be left\n\t * undefined, or an empty string can be supplied (which is what the Flickr API usually returns\n\t * as the path_alias for such users).\n\t *\n\t * @param {string} nsid Flickr NSID of the author\n\t * @param {string} [path_alias] Flickr username of the author (the unchangeable one, in the URL)\n\t * @return {jQuery.Promise} a promise which resolves to a boolean - true if the user is blacklisted\n\t */\n\tisBlacklisted: function ( nsid, path_alias ) {\n\t\tpath_alias = String( path_alias );\n\t\treturn this.getBlacklist().then( function ( blacklist ) {\n\t\t\t// the blacklist should never contain the empty string, but better safe then sorry\n\t\t\treturn ( nsid in blacklist || path_alias && path_alias in blacklist );\n\t\t} );\n\t},\n\n\t/**\n\t * Returns a promise for the Flickr user blacklist.\n\t * The promise resolves to a hash with the blacklisted NSIDs/path_alias-es as its keys.\n\t * (path_alias is the username that appears in the URL.)\n\t * The blacklist will usually contain the path_alias or the NSID of the user, but not both;\n\t * it is the caller's responsibility to check against both of them.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tgetBlacklist: function () {\n\t\tvar api = new mw.Api();\n\t\tif ( !mw.FlickrChecker.blacklist ) {\n\t\t\tmw.FlickrChecker.blacklist = api.get( {\n\t\t\t\taction: 'flickrblacklist',\n\t\t\t\tlist: 1,\n\t\t\t\tformat: 'json'\n\t\t\t} ).then( function ( data ) {\n\t\t\t\tvar blacklist = {};\n\t\t\t\tif ( data.flickrblacklist && data.flickrblacklist.list ) {\n\t\t\t\t\tdata.flickrblacklist.list.forEach( function ( username ) {\n\t\t\t\t\t\tblacklist[ username ] = true;\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\treturn blacklist;\n\t\t\t} );\n\t\t}\n\t\treturn mw.FlickrChecker.blacklist;\n\t},\n\n\t/**\n\t * Retrieve the list of all current Flickr licenses and store it in an array (`mw.FlickrChecker.licenseList`)\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tgetLicenses: function () {\n\t\tif ( mw.FlickrChecker.licensePromise ) {\n\t\t\treturn mw.FlickrChecker.licensePromise;\n\t\t}\n\n\t\t// Workaround for http://bugs.jquery.com/ticket/8283\n\t\t// eslint-disable-next-line no-jquery/no-support\n\t\t$.support.cors = true;\n\t\tmw.FlickrChecker.licensePromise = this.flickrRequest( {\n\t\t\tmethod: 'flickr.photos.licenses.getInfo'\n\t\t} ).then( function ( data ) {\n\t\t\tif ( typeof data.licenses !== 'undefined' ) {\n\t\t\t\tdata.licenses.license.forEach( function ( value ) {\n\t\t\t\t\tmw.FlickrChecker.licenseList[ value.id ] = value.name;\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\treturn mw.FlickrChecker.licensePromise;\n\t},\n\n\t/**\n\t * @param {Object} upload\n\t * @param {string} description\n\t * @return {jQuery.Promise}\n\t */\n\tsetUploadDescription: function ( upload, description ) {\n\t\tif ( description !== undefined ) {\n\t\t\t// If a Flickr description has a | character in it, it will\n\t\t\t// mess up the MediaWiki description. Escape them.\n\t\t\tupload.description = description.replace( /\\|/g, '&#124;' );\n\t\t\treturn $.Deferred().resolve();\n\t\t} else {\n\t\t\treturn this.setImageDescription( upload );\n\t\t}\n\t},\n\n\t/**\n\t * @param {Object} upload\n\t * @return {jQuery.Promise}\n\t */\n\tsetImageDescription: function ( upload ) {\n\t\tvar checker = this;\n\t\tvar photoId = upload.photoId;\n\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.photos.getInfo',\n\t\t\tphoto_id: photoId\n\t\t} ).then( function ( data ) {\n\t\t\tchecker.setUploadDescription( upload, data.photo.description._content );\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieve the URL of the largest version available on Flickr and set that\n\t * as the upload URL.\n\t *\n\t * @param {number} index Index of the image for which we need to set the URL\n\t * @return {jQuery.Promise}\n\t */\n\tsetImageURL: function ( index ) {\n\t\tvar upload = this.imageUploads[ index ];\n\t\tvar photoId = upload.photoId;\n\t\tvar checker = this;\n\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.photos.getSizes',\n\t\t\tphoto_id: photoId\n\t\t} ).then( function ( data ) {\n\t\t\tvar nameParts;\n\n\t\t\tif (\n\t\t\t\ttypeof data.sizes !== 'undefined' &&\n\t\t\t\ttypeof data.sizes.size !== 'undefined' &&\n\t\t\t\tdata.sizes.size.length > 0\n\t\t\t) {\n\t\t\t\t// Flickr always returns the largest version as the final size.\n\t\t\t\t// TODO: Make this less fragile by actually comparing sizes.\n\t\t\t\tvar largestSize = data.sizes.size.pop();\n\t\t\t\t// Flickr provides the original format for images coming from pro users, hence we need to change the default JPEG to this format\n\t\t\t\tif ( largestSize.label === 'Original' ) {\n\t\t\t\t\tupload.type = upload.originalFormat;\n\n\t\t\t\t\tnameParts = upload.name.split( '.' );\n\t\t\t\t\tif ( nameParts.length > 1 ) {\n\t\t\t\t\t\tnameParts.pop();\n\t\t\t\t\t}\n\t\t\t\t\tupload.name = nameParts.join( '.' ) + '.' + upload.originalFormat;\n\t\t\t\t}\n\t\t\t\tupload.url = largestSize.source;\n\t\t\t} else {\n\t\t\t\tmw.errorDialog( mw.message( 'mwe-upwiz-error-no-image-retrieved', 'Flickr' ).escaped() );\n\t\t\t\tchecker.$spinner.remove();\n\t\t\t\tchecker.ui.flickrInterfaceReset();\n\t\t\t\treturn $.Deferred().reject();\n\t\t\t}\n\t\t} );\n\t},\n\n\tcheckLicense: function ( licenseId ) {\n\t\t// The returned data.photo.license is just an ID that we use to look up the license name\n\t\tvar licenseName = mw.FlickrChecker.licenseList[ licenseId ];\n\t\t// Use the license name to retrieve the template values\n\t\tvar licenseValue = mw.FlickrChecker.licenseMaps[ licenseName ];\n\n\t\t// Set the license message to show the user.\n\t\tvar licenseMessage;\n\t\tif ( licenseValue === 'invalid' ) {\n\t\t\tlicenseMessage = mw.msg( 'mwe-upwiz-license-external-invalid', 'Flickr', licenseName );\n\t\t} else {\n\t\t\tlicenseMessage = mw.msg( 'mwe-upwiz-license-external', 'Flickr', licenseName );\n\t\t}\n\n\t\treturn {\n\t\t\tlicenseName: licenseName,\n\t\t\tlicenseMessage: licenseMessage,\n\t\t\tlicenseValue: licenseValue\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":"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":[],"suppressedMessages":[{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeIn","line":52,"column":4,"nodeType":"CallExpression","endLine":52,"endColumn":70,"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":71,"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":"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":"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":"no-shadow","severity":1,"message":"'steps' is already declared in the upper scope on line 60 column 5.","line":83,"column":23,"nodeType":"Identifier","messageId":"noShadow","endLine":83,"endColumn":28},{"ruleId":"no-shadow","severity":1,"message":"'steps' is already declared in the upper scope on line 60 column 5.","line":113,"column":25,"nodeType":"Identifier","messageId":"noShadow","endLine":113,"endColumn":30}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Object that represents the entire multi-step Upload Wizard\n *\n * @param uw\n */\n( function ( uw ) {\n\n\tmw.UploadWizard = function ( config ) {\n\t\tvar 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\tconfig.maxSimultaneousConnections = Math.max( 1, maxSimPref );\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( function ( steps ) {\n\t\t\t\t// \"select\" the first step - highlight, make it visible, hide all others\n\t\t\t\tsteps.tutorial.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\tvar self = this,\n\t\t\t\tsteps = {};\n\n\t\t\tsteps.tutorial = new uw.controller.Tutorial( this.api, this.config );\n\t\t\tsteps.file = new uw.controller.Upload( this.api, this.config );\n\t\t\tsteps.deeds = new uw.controller.Deed( this.api, this.config );\n\t\t\tsteps.details = new uw.controller.Details( this.api, this.config );\n\t\t\tsteps.thanks = new uw.controller.Thanks( this.api, this.config );\n\n\t\t\tsteps.tutorial.setNextStep( steps.file );\n\n\t\t\tsteps.file.setPreviousStep( steps.tutorial );\n\t\t\tsteps.file.setNextStep( steps.deeds );\n\n\t\t\tsteps.deeds.setPreviousStep( steps.file );\n\t\t\tsteps.deeds.setNextStep( steps.details );\n\n\t\t\tsteps.details.setPreviousStep( steps.deeds );\n\t\t\tsteps.details.setNextStep( steps.thanks );\n\n\t\t\t// thanks doesn't need a \"previous\" step, there's no undoing uploads!\n\t\t\tsteps.thanks.setNextStep( steps.file );\n\n\t\t\treturn $.Deferred().resolve( steps ).promise()\n\t\t\t\t.then( function ( steps ) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tself.config.wikibase.enabled &&\n\t\t\t\t\t\t// .depicts is for backward compatibility - this config\n\t\t\t\t\t\t// var used to be called differently...\n\t\t\t\t\t\t( self.config.wikibase.statements || self.config.wikibase.depicts )\n\t\t\t\t\t) {\n\t\t\t\t\t\t// mediainfo has a couple of widgets that we'll be using, but they're not\n\t\t\t\t\t\t// necessarily a hard dependency for UploadWizard\n\t\t\t\t\t\t// let's just attempt to load it - if it's not available, we just won't\n\t\t\t\t\t\t// have that extra step then...\n\t\t\t\t\t\treturn mw.loader.using( [ 'wikibase', 'wikibase.mediainfo.statements' ] ).then(\n\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\t// interject metadata step in between details & thanks\n\t\t\t\t\t\t\t\tsteps.metadata = new uw.controller.Metadata( self.api, self.config );\n\n\t\t\t\t\t\t\t\tsteps.details.setNextStep( steps.metadata );\n\t\t\t\t\t\t\t\t// metadata has no \"previous\" step - the file\n\t\t\t\t\t\t\t\t// has already been uploaded at this point\n\t\t\t\t\t\t\t\tsteps.metadata.setNextStep( steps.thanks );\n\n\t\t\t\t\t\t\t\treturn steps;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\treturn steps; /* just move on without metadata... */\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn steps;\n\t\t\t\t} )\n\t\t\t\t.always( function ( steps ) {\n\t\t\t\t\tself.steps = steps;\n\t\t\t\t\tself.ui.initialiseSteps( steps );\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\tvar api = new mw.Api( options );\n\n\t\t\tapi.ajax = function ( parameters, ajaxOptions ) {\n\t\t\t\tvar original, override;\n\n\t\t\t\t$.extend( 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\tfunction ( code, result ) { // fail handler\n\t\t\t\t\t\tvar 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( '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 * 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( 'mwe-upwiz-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( 'mwe-upwiz-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":"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":[{"ruleId":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":7,"column":1,"nodeType":"Block","endLine":7,"endColumn":1},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":36,"column":42,"nodeType":"ObjectExpression","endLine":36,"endColumn":89},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":40,"column":6,"nodeType":"CallExpression","endLine":43,"endColumn":7},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":48,"column":8,"nodeType":"CallExpression","endLine":51,"endColumn":9},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":60,"column":17,"nodeType":"CallExpression","endLine":60,"endColumn":86}],"suppressedMessages":[{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":141,"column":3,"nodeType":"CallExpression","endLine":141,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":169,"column":3,"nodeType":"CallExpression","endLine":169,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\n\t/**\n\t * Interface widget to choose among various deeds -- for instance, if own work, or not own work, or other such cases.\n\t *\n\t * @class\n\t * @mixins OO.EventEmitter\n\t * @param {Object} config The UW config\n\t * @param {Object} deeds Keyed object of UploadWizardDeed items\n\t * @param {mw.UploadWizardUpload[]} uploads Uploads that this applies to (this is just to make deleting and plurals work)\n\t */\n\tmw.UploadWizardDeedChooser = function ( config, deeds, uploads ) {\n\t\tvar chooser = this,\n\t\t\t$radioContainer,\n\t\t\t$formContainer;\n\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.uploads = uploads;\n\t\tthis.deeds = deeds;\n\n\t\t// Name for radio button set\n\t\tmw.UploadWizardDeedChooser.prototype.widgetCount++;\n\t\tthis.name = 'deedChooser' + mw.UploadWizardDeedChooser.prototype.widgetCount.toString();\n\n\t\tthis.onLayoutReady = function () {};\n\n\t\t$radioContainer = $( '<div>' ).addClass( 'mwe-upwiz-deed-radios' );\n\t\t$formContainer = $( '<div>' ).addClass( 'mwe-upwiz-deed-forms' );\n\t\tthis.$element = $( '<div>' ).addClass( 'mwe-upwiz-deeds-container' ).append(\n\t\t\t$radioContainer, $formContainer\n\t\t);\n\n\t\tObject.keys( this.deeds ).forEach( function ( name ) {\n\t\t\tvar deed = chooser.deeds[ name ],\n\t\t\t\tradio = new OO.ui.RadioSelectWidget( { classes: [ 'mwe-upwiz-deed-radio-' + name ] } ),\n\t\t\t\toption = new OO.ui.RadioOptionWidget(),\n\t\t\t\t$label = $( '<span>' ).append(\n\t\t\t\t\t// label text\n\t\t\t\t\tmw.message(\n\t\t\t\t\t\t'mwe-upwiz-source-' + deed.name + '-label',\n\t\t\t\t\t\tchooser.uploads.length\n\t\t\t\t\t).text(),\n\t\t\t\t\t// label description\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra mwe-upwiz-label-explainer' )\n\t\t\t\t\t\t.text(\n\t\t\t\t\t\t\tmw.message(\n\t\t\t\t\t\t\t\t'mwe-upwiz-source-' + deed.name + '-description',\n\t\t\t\t\t\t\t\tchooser.uploads.length\n\t\t\t\t\t\t\t).text()\n\t\t\t\t\t\t)\n\t\t\t\t).contents(),\n\t\t\t\t// Separate the radio option from its form\n\t\t\t\t$deedRadio = $( '<div>' ).addClass( 'mwe-upwiz-deed-option-title' ).append(\n\t\t\t\t\t$( '<span>' ).addClass( 'mwe-upwiz-deed-header' ).append(\n\t\t\t\t\t\tradio.$element\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\t$deedForm = $( '<div>' ).addClass( 'mwe-upwiz-deed mwe-upwiz-deed-' + deed.name ).append(\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-deed-form' )\n\t\t\t\t).hide();\n\n\t\t\toption.setLabel( $label );\n\n\t\t\tradio.addItems( [ option ] );\n\n\t\t\t// Set the name attribute manually. We can't use RadioInputWidget which has\n\t\t\t// a name config because they don't emit change events. Ideally we would use\n\t\t\t// one RadioSelectWidget and not have to set this property.\n\t\t\tradio.items[ 0 ].radio.$input.attr( 'name', chooser.name );\n\n\t\t\t// Append intermediate containers\n\t\t\t$radioContainer.append( $deedRadio );\n\t\t\t$formContainer.append( $deedForm );\n\n\t\t\tdeed.setFormFields( $deedForm.find( '.mwe-upwiz-deed-form' ) );\n\n\t\t\tif ( Object.keys( chooser.deeds ).length === 1 ) {\n\t\t\t\tchooser.onLayoutReady = chooser.selectDeed.bind( chooser, deed );\n\t\t\t} else {\n\t\t\t\tif ( config.licensing.defaultType === deed.name ) {\n\t\t\t\t\tchooser.onLayoutReady = chooser.selectDeed.bind( chooser, deed );\n\t\t\t\t}\n\t\t\t\tradio.on( 'choose', function () {\n\t\t\t\t\tchooser.selectDeed( deed );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t// Deselect all deeds\n\t\tObject.keys( this.deeds ).forEach( function ( name ) {\n\t\t\tchooser.deselectDeedInterface( name );\n\t\t} );\n\t};\n\tOO.mixinClass( mw.UploadWizardDeedChooser, OO.EventEmitter );\n\n\t/**\n\t * How many deed choosers there are (important for creating unique ids, element names)\n\t */\n\tmw.UploadWizardDeedChooser.prototype.widgetCount = 0;\n\n\t/**\n\t * Check if this form is filled out correctly.\n\t *\n\t * @return {boolean} true if valid, false if not\n\t */\n\tmw.UploadWizardDeedChooser.prototype.valid = function () {\n\t\treturn !!this.deed;\n\t};\n\n\t/**\n\t * Uploads this deed controls\n\t */\n\tmw.UploadWizardDeedChooser.prototype.uploads = [];\n\n\tmw.UploadWizardDeedChooser.prototype.selectDeed = function ( deed ) {\n\t\tthis.choose( deed );\n\t\tthis.selectDeedInterface( deed.name );\n\t};\n\n\tmw.UploadWizardDeedChooser.prototype.choose = function ( deed ) {\n\t\tthis.deed = deed;\n\t\tthis.emit( 'choose' );\n\t};\n\n\t/**\n\t * From the deed choices, make a choice fade to the background a bit, hide the extended form\n\t *\n\t * @param {string} deedName\n\t */\n\tmw.UploadWizardDeedChooser.prototype.deselectDeedInterface = function ( deedName ) {\n\t\tvar $deedRadio = this.$element.find( '.mwe-upwiz-deed-radio-' + deedName + ' input' ),\n\t\t\t$deedForm = this.$element.find( '.mwe-upwiz-deed.mwe-upwiz-deed-' + deedName );\n\n\t\t$deedRadio.prop( 'checked', false );\n\t\t$deedForm.removeClass( 'selected' );\n\t\t// Prevent validation of deselected deeds by disabling all form inputs\n\t\t// TODO: Use a tag selector\n\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t$deedForm.find( ':input' ).prop( 'disabled', true );\n\n\t\t$deedForm.hide();\n\t};\n\n\t/**\n\t * From the deed choice page, show a particular deed\n\t *\n\t * @param {string} deedName\n\t */\n\tmw.UploadWizardDeedChooser.prototype.selectDeedInterface = function ( deedName ) {\n\t\tvar self = this,\n\t\t\t$deedRadio = this.$element.find( '.mwe-upwiz-deed-radio-' + deedName + ' input' ),\n\t\t\t$deedForm = this.$element.find( '.mwe-upwiz-deed.mwe-upwiz-deed-' + deedName );\n\n\t\t// deselect all other deeds\n\t\tObject.keys( this.deeds ).forEach( function ( name ) {\n\t\t\tif ( name === deedName ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tself.deselectDeedInterface( name );\n\t\t} );\n\n\t\t$deedRadio.prop( 'checked', true );\n\t\t$deedForm.addClass( 'selected' );\n\t\t// (Re-)enable all form inputs\n\t\t// TODO: Use a tag selector\n\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t$deedForm.find( ':input' ).prop( 'disabled', false );\n\n\t\t$deedForm.show();\n\t};\n\n\tmw.UploadWizardDeedChooser.prototype.remove = function () {\n\t\tvar self = this;\n\n\t\tObject.keys( this.deeds ).forEach( function ( name ) {\n\t\t\tself.deeds[ name ].unload();\n\t\t} );\n\n\t\tthis.$element.remove();\n\t};\n\n\t/**\n\t * @return {Object}\n\t */\n\tmw.UploadWizardDeedChooser.prototype.getSerialized = function () {\n\t\treturn this.valid() ? this.deed.getSerialized() : {};\n\t};\n\n\t/**\n\t * @param {Object} serialized\n\t */\n\tmw.UploadWizardDeedChooser.prototype.setSerialized = function ( serialized ) {\n\t\tvar deed;\n\n\t\tif ( serialized.name && serialized.name in this.deeds ) {\n\t\t\tdeed = this.deeds[ serialized.name ];\n\t\t\tdeed.setSerialized( serialized );\n\t\t\tthis.selectDeed( deed );\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":"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":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":260,"column":9,"nodeType":"MemberExpression","messageId":"forbidden","endLine":260,"endColumn":36},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":264,"column":14,"nodeType":"MemberExpression","messageId":"forbidden","endLine":264,"endColumn":41},{"ruleId":"no-shadow","severity":1,"message":"'matches' is already declared in the upper scope on line 439 column 42.","line":462,"column":10,"nodeType":"Identifier","messageId":"noShadow","endLine":462,"endColumn":17},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":554,"column":16,"nodeType":"MemberExpression","messageId":"forbidden","endLine":554,"endColumn":44},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"JSDoc @return declaration present but return expression not available in function.","line":644,"column":3,"nodeType":"Block","endLine":652,"endColumn":6},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":712,"column":9,"nodeType":"MemberExpression","messageId":"forbidden","endLine":712,"endColumn":31},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":713,"column":45,"nodeType":"MemberExpression","messageId":"forbidden","endLine":713,"endColumn":67},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":763,"column":4,"nodeType":"MemberExpression","messageId":"forbidden","endLine":763,"endColumn":27},{"ruleId":"es-x/no-symbol-prototype-description","severity":1,"message":"ES2019 'Symbol.prototype.description' property is forbidden.","line":766,"column":5,"nodeType":"MemberExpression","messageId":"forbidden","endLine":766,"endColumn":28}],"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":901,"column":6,"nodeType":"CallExpression","endLine":901,"endColumn":45,"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":903,"column":6,"nodeType":"CallExpression","endLine":903,"endColumn":37,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":9,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tvar 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.mainFields = [];\n\n\t\tthis.captionSubmissionErrors = {};\n\n\t\tthis.$div = $( '<div>' ).addClass( 'mwe-upwiz-info-file filled' );\n\t};\n\n\tmw.UploadWizardDetails.prototype = {\n\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\tvar descriptionRequired, uri,\n\t\t\t\t$moreDetailsWrapperDiv, $moreDetailsDiv,\n\t\t\t\tdetails = this,\n\t\t\t\tconfig = mw.UploadWizard.config;\n\n\t\t\tthis.$thumbnailDiv = $( '<div>' ).addClass( 'mwe-upwiz-thumbnail' );\n\n\t\t\tthis.$dataDiv = $( '<div>' ).addClass( 'mwe-upwiz-data' );\n\n\t\t\tthis.titleDetails = new uw.TitleDetailsWidget( {\n\t\t\t\t// Normalize file extension, e.g. 'JPEG' to 'jpg'\n\t\t\t\textension: mw.Title.normalizeExtension( this.upload.title.getExtension() ),\n\t\t\t\tminLength: config.minTitleLength,\n\t\t\t\tmaxLength: config.maxTitleLength\n\t\t\t} );\n\t\t\tthis.titleDetailsField = new uw.FieldLayout( this.titleDetails, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-title' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-title' ).text(),\n\t\t\t\trequired: true\n\t\t\t} );\n\t\t\tthis.mainFields.push( this.titleDetailsField );\n\n\t\t\tthis.captionsDetails = new uw.MultipleLanguageInputWidget( {\n\t\t\t\tinputWidgetConstructor: OO.ui.TextInputWidget.bind( null, {\n\t\t\t\t\tclasses: [ 'mwe-upwiz-singleLanguageInputWidget-text' ]\n\t\t\t\t} ),\n\t\t\t\trequired: false,\n\t\t\t\t// Messages: mwe-upwiz-caption-add-0, mwe-upwiz-caption-add-n\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-caption-add' ),\n\t\t\t\terror: mw.message( 'mwe-upwiz-error-bad-captions' ),\n\t\t\t\tremove: mw.message( 'mwe-upwiz-remove-caption' ),\n\t\t\t\tminLength: config.minCaptionLength,\n\t\t\t\tmaxLength: config.maxCaptionLength\n\t\t\t} );\n\t\t\tthis.captionsDetailsField = new uw.FieldLayout( this.captionsDetails, {\n\t\t\t\trequired: false,\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-caption' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-caption' ).text()\n\t\t\t} );\n\t\t\tif ( config.wikibase.enabled && config.wikibase.captions ) {\n\t\t\t\tthis.mainFields.push( this.captionsDetailsField );\n\t\t\t}\n\n\t\t\t// descriptions\n\t\t\t// Description is not required if a campaign provides alternative wikitext fields,\n\t\t\t// which are assumed to function like a description\n\t\t\tdescriptionRequired = !(\n\t\t\t\tconfig.fields &&\n\t\t\t\tconfig.fields.length &&\n\t\t\t\tconfig.fields[ 0 ].wikitext\n\t\t\t);\n\t\t\tthis.descriptionsDetails = new uw.MultipleLanguageInputWidget( {\n\t\t\t\trequired: descriptionRequired,\n\t\t\t\t// Messages: mwe-upwiz-desc-add-0, mwe-upwiz-desc-add-n\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-desc-add' ),\n\t\t\t\terror: mw.message( 'mwe-upwiz-error-bad-descriptions' ),\n\t\t\t\tremove: mw.message( 'mwe-upwiz-remove-description' ),\n\t\t\t\tminLength: config.minDescriptionLength,\n\t\t\t\tmaxLength: config.maxDescriptionLength\n\t\t\t} );\n\t\t\tthis.descriptionsDetailsField = new uw.FieldLayout( this.descriptionsDetails, {\n\t\t\t\trequired: descriptionRequired,\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-desc' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-description' ).text()\n\t\t\t} );\n\t\t\tthis.mainFields.push( this.descriptionsDetailsField );\n\n\t\t\tthis.categoriesDetails = new uw.CategoriesDetailsWidget();\n\t\t\tthis.categoriesDetailsField = new uw.FieldLayout( this.categoriesDetails, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-categories' ).text(),\n\t\t\t\thelp: new OO.ui.HtmlSnippet(\n\t\t\t\t\tmw.message( 'mwe-upwiz-tooltip-categories', $( '<a>' ).attr( {\n\t\t\t\t\t\ttarget: '_blank',\n\t\t\t\t\t\thref: config.allCategoriesLink\n\t\t\t\t\t} ) ).parse()\n\t\t\t\t)\n\t\t\t} );\n\t\t\tthis.mainFields.push( this.categoriesDetailsField );\n\n\t\t\tthis.dateDetails = new uw.DateDetailsWidget( { upload: this.upload } );\n\t\t\tthis.dateDetailsField = new uw.FieldLayout( this.dateDetails, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-date-created' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-date' ).text(),\n\t\t\t\trequired: true\n\t\t\t} );\n\t\t\tthis.mainFields.push( this.dateDetailsField );\n\n\t\t\tthis.otherDetails = new uw.OtherDetailsWidget();\n\t\t\tthis.otherDetailsField = new uw.FieldLayout( this.otherDetails, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-other' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-other' ).text()\n\t\t\t} );\n\t\t\tthis.mainFields.push( this.otherDetailsField );\n\n\t\t\tthis.locationInput = new uw.LocationDetailsWidget( { showHeading: true } );\n\t\t\tthis.locationInputField = new uw.FieldLayout( this.locationInput, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-location' ).text()\n\t\t\t} );\n\t\t\tthis.mainFields.push( this.locationInputField );\n\n\t\t\t/* Build the form for the file upload */\n\t\t\tthis.$form = $( '<form id=\"mwe-upwiz-detailsform' + this.upload.index + '\"></form>' ).addClass( 'detailsForm' );\n\t\t\tthis.$form.append(\n\t\t\t\tthis.titleDetailsField.$element,\n\t\t\t\tconfig.wikibase.enabled && config.wikibase.captions ? this.captionsDetailsField.$element : null,\n\t\t\t\tthis.descriptionsDetailsField.$element,\n\t\t\t\tthis.dateDetailsField.$element,\n\t\t\t\tthis.categoriesDetailsField.$element\n\t\t\t);\n\n\t\t\tthis.$form.on( 'submit', function ( 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.campaignDetailsFields = [];\n\t\t\tconfig.fields.forEach( function ( field ) {\n\t\t\t\tvar customDetails, customDetailsField;\n\n\t\t\t\tif ( field.wikitext ) {\n\t\t\t\t\tcustomDetails = new uw.CampaignDetailsWidget( field );\n\t\t\t\t\tcustomDetailsField = new uw.FieldLayout( customDetails, {\n\t\t\t\t\t\tlabel: $( $.parseHTML( field.label ) ),\n\t\t\t\t\t\trequired: !!field.required\n\t\t\t\t\t} );\n\n\t\t\t\t\tif ( field.initialValue ) {\n\t\t\t\t\t\tcustomDetails.setSerialized( { value: field.initialValue } );\n\t\t\t\t\t}\n\n\t\t\t\t\tdetails.$form.append( customDetailsField.$element );\n\t\t\t\t\tdetails.campaignDetailsFields.push( customDetailsField );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\t$moreDetailsWrapperDiv = $( '<div>' ).addClass( 'mwe-more-details' );\n\t\t\t$moreDetailsDiv = $( '<div>' );\n\n\t\t\t$moreDetailsDiv.append(\n\t\t\t\tthis.locationInputField.$element,\n\t\t\t\tthis.otherDetailsField.$element\n\t\t\t);\n\n\t\t\t$moreDetailsWrapperDiv\n\t\t\t\t.append(\n\t\t\t\t\t$( '<a>' ).text( mw.msg( 'mwe-upwiz-more-options' ) )\n\t\t\t\t\t\t.addClass( 'mwe-upwiz-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\t// Expand collapsed sections if the fields within were changed (e.g. by metadata copier)\n\t\t\tthis.locationInput.on( 'change', function () {\n\t\t\t\t$moreDetailsWrapperDiv.data( 'mw-collapsible' ).expand();\n\t\t\t} );\n\t\t\tthis.otherDetails.on( 'change', function () {\n\t\t\t\t$moreDetailsWrapperDiv.data( 'mw-collapsible' ).expand();\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( 'mwe-upwiz-remove' ).text(),\n\t\t\t\ttitle: mw.message( 'mwe-upwiz-remove-upload' ).text(),\n\t\t\t\tclasses: [ 'mwe-upwiz-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', function () {\n\t\t\t\tOO.ui.confirm( mw.message( 'mwe-upwiz-license-confirm-remove' ).text(), {\n\t\t\t\t\ttitle: mw.message( 'mwe-upwiz-license-confirm-remove-title' ).text()\n\t\t\t\t} ).done( function ( 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( 'mwe-upwiz-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( 'mwe-upwiz-submitting' )\n\t\t\t\t.append(\n\t\t\t\t\tthis.$indicator,\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-details-texts' ).append(\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-visible-file-filename-text' ),\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-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\turi = new mw.Uri( location.href, { overrideKeys: true } );\n\t\t\tif ( config.defaults.caption || uri.query.captionlang ) {\n\t\t\t\tthis.captionsDetails.setSerialized( {\n\t\t\t\t\tinputs: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: config.defaults.caption || ''\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t} );\n\t\t\t\tthis.captionsDetails.getItems()[ 0 ].setLanguage(\n\t\t\t\t\turi.query.captionlang ?\n\t\t\t\t\t\tthis.captionsDetails.getItems()[ 0 ].getClosestAllowedLanguage( uri.query.captionlang ) :\n\t\t\t\t\t\tthis.captionsDetails.getItems()[ 0 ].getDefaultLanguage()\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( config.defaults.description || uri.query.descriptionlang ) {\n\t\t\t\tthis.descriptionsDetails.setSerialized( {\n\t\t\t\t\tinputs: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: config.defaults.description || ''\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t} );\n\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].setLanguage(\n\t\t\t\t\turi.query.descriptionlang ?\n\t\t\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].getClosestAllowedLanguage( uri.query.descriptionlang ) :\n\t\t\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].getDefaultLanguage()\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.populate();\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\tvar $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\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.titleDetails.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\t// TODO This should give immediate response, not only when submitting the form\n\t\t\tthis.titleDetailsField.setErrors( [ mw.message( 'mwe-upwiz-error-title-duplicate' ) ] );\n\t\t\treturn this;\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.mainFields,\n\t\t\t\tthis.upload.deedChooser.deed ? this.upload.deedChooser.deed.getFields() : [],\n\t\t\t\tthis.campaignDetailsFields\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( function ( fieldLayout ) {\n\t\t\t\treturn fieldLayout.fieldWidget.getErrors();\n\t\t\t} ) );\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( function ( fieldLayout ) {\n\t\t\t\treturn fieldLayout.fieldWidget.getWarnings();\n\t\t\t} ) );\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\tvar fields = this.getAllFields();\n\n\t\t\treturn $.when.apply( $, fields.map( function ( fieldLayout ) {\n\t\t\t\t// Update any error/warning messages\n\t\t\t\treturn 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\tvar captions = [];\n\t\t\tif ( mw.UploadWizard.config.wikibase.enabled && mw.UploadWizard.config.wikibase.captions ) {\n\t\t\t\tcaptions = this.captionsDetails.getSerialized().inputs;\n\t\t\t} else {\n\t\t\t\tcaptions = this.descriptionsDetails.getSerialized().inputs;\n\t\t\t}\n\n\t\t\tif ( captions.length > 0 ) {\n\t\t\t\treturn mw.Escaper.escapeForTemplate( captions[ 0 ].text.trim() );\n\t\t\t} else {\n\t\t\t\treturn '';\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Pull some info into the form ( for instance, extracted from EXIF, desired filename )\n\t\t */\n\t\tpopulate: function () {\n\t\t\tvar $thumbnailDiv = this.$thumbnailDiv;\n\t\t\t// This must match the CSS dimensions of .mwe-upwiz-thumbnail\n\t\t\tthis.upload.getThumbnail( 230 ).done( function ( thumb ) {\n\t\t\t\tmw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );\n\t\t\t} );\n\t\t\tthis.prefillDate();\n\t\t\tthis.prefillTitle();\n\t\t\tthis.prefillDescription();\n\t\t\tthis.prefillLocation();\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\tprefillDate: function () {\n\t\t\tvar dateObj, metadata, dateTimeRegex, matches, 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\tvar 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( function ( propName ) {\n\t\t\t\t\tvar 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 lets try other sources - Flickr\n\t\t\tif ( dateObj === undefined && this.upload.file !== undefined && this.upload.file.date !== undefined ) {\n\t\t\t\tdateTimeRegex = /^\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d/;\n\t\t\t\tmatches = this.upload.file.date.match( dateTimeRegex );\n\t\t\t\tif ( matches ) {\n\t\t\t\t\tthis.dateDetails.setSerialized( {\n\t\t\t\t\t\tmode: dateMode,\n\t\t\t\t\t\tvalue: this.upload.file.date\n\t\t\t\t\t} );\n\t\t\t\t\treturn;\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;\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\tthis.dateDetails.setSerialized( {\n\t\t\t\tmode: dateMode,\n\t\t\t\tvalue: dateStr\n\t\t\t} );\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\tprefillTitle: function () {\n\t\t\tthis.titleDetails.setSerialized( {\n\t\t\t\ttitle: this.upload.title.getNameText()\n\t\t\t} );\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 (e.g. Flickr transfer)\n\t\t * or from the metadata.\n\t\t */\n\t\tprefillDescription: function () {\n\t\t\tvar m, descText;\n\n\t\t\tif (\n\t\t\t\tthis.descriptionsDetails.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\t// strip out any HTML tags\n\t\t\t\t\tdescText = descText.replace( /<[^>]+>/g, '' );\n\t\t\t\t\t// & and \" are escaped by Flickr, so we need to unescape\n\t\t\t\t\tdescText = descText.replace( /&amp;/g, '&' ).replace( /&quot;/g, '\"' );\n\n\t\t\t\t\tthis.descriptionsDetails.setSerialized( {\n\t\t\t\t\t\tinputs: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttext: descText.trim()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t} );\n\t\t\t\t\t// The language is probably wrong in many cases...\n\t\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].setLanguage(\n\t\t\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].getClosestAllowedLanguage( mw.config.get( 'wgContentLanguage' ) )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\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\tprefillLocation: function () {\n\t\t\tvar 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 ( mw.UploadWizard.config.defaults.lat ) {\n\t\t\t\tvalues.latitude = mw.UploadWizard.config.defaults.lat;\n\t\t\t\tmodified = true;\n\t\t\t}\n\t\t\tif ( mw.UploadWizard.config.defaults.lon ) {\n\t\t\t\tvalues.longitude = mw.UploadWizard.config.defaults.lon;\n\t\t\t\tmodified = true;\n\t\t\t}\n\t\t\tif ( mw.UploadWizard.config.defaults.heading ) {\n\t\t\t\tvalues.heading = mw.UploadWizard.config.defaults.heading;\n\t\t\t\tmodified = true;\n\t\t\t}\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 ( /^\\d+\\/\\d+$/.test( dir ) ) {\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\tthis.locationInput.setSerialized( values );\n\n\t\t\tif ( modified ) {\n\t\t\t\tthis.$form.find( '.mwe-more-details' )\n\t\t\t\t\t.data( 'mw-collapsible' ).expand();\n\t\t\t}\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\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\treturn {\n\t\t\t\ttitle: this.titleDetails.getSerialized(),\n\t\t\t\tcaption: this.captionsDetails.getSerialized(),\n\t\t\t\tdescription: this.descriptionsDetails.getSerialized(),\n\t\t\t\tdate: this.dateDetails.getSerialized(),\n\t\t\t\tcategories: this.categoriesDetails.getSerialized(),\n\t\t\t\tlocation: this.locationInput.getSerialized(),\n\t\t\t\tother: this.otherDetails.getSerialized(),\n\t\t\t\tcampaigns: this.campaignDetailsFields.map( function ( field ) {\n\t\t\t\t\treturn field.fieldWidget.getSerialized();\n\t\t\t\t} )\n\t\t\t};\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\tvar i;\n\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\tif ( serialized.title ) {\n\t\t\t\tthis.titleDetails.setSerialized( serialized.title );\n\t\t\t}\n\t\t\tif ( serialized.caption ) {\n\t\t\t\tthis.captionsDetails.setSerialized( serialized.caption );\n\t\t\t}\n\t\t\tif ( serialized.description ) {\n\t\t\t\tthis.descriptionsDetails.setSerialized( serialized.description );\n\t\t\t}\n\t\t\tif ( serialized.date ) {\n\t\t\t\tthis.dateDetails.setSerialized( serialized.date );\n\t\t\t}\n\t\t\tif ( serialized.categories ) {\n\t\t\t\tthis.categoriesDetails.setSerialized( serialized.categories );\n\t\t\t}\n\t\t\tif ( serialized.location ) {\n\t\t\t\tthis.locationInput.setSerialized( serialized.location );\n\t\t\t}\n\t\t\tif ( serialized.other ) {\n\t\t\t\tthis.otherDetails.setSerialized( serialized.other );\n\t\t\t}\n\t\t\tif ( serialized.campaigns ) {\n\t\t\t\tfor ( i = 0; i < this.campaignDetailsFields.length; i++ ) {\n\t\t\t\t\tthis.campaignDetailsFields[ i ].fieldWidget.setSerialized( serialized.campaigns[ i ] );\n\t\t\t\t}\n\t\t\t}\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\tvar deed, info, key,\n\t\t\t\tinformation,\n\t\t\t\twikiText = '';\n\n\t\t\t// https://commons.wikimedia.org/wiki/Template:Information\n\t\t\t// can we be more slick and do this with maps, applys, joins?\n\t\t\tinformation = {\n\t\t\t\t// {{lang|description in lang}}* (required)\n\t\t\t\tdescription: '',\n\t\t\t\t// YYYY, YYYY-MM, or YYYY-MM-DD (required) use jquery but allow editing, then double check for sane date.\n\t\t\t\tdate: '',\n\t\t\t\t// {{own}} or wikitext (optional)\n\t\t\t\tsource: '',\n\t\t\t\t// any wikitext, but particularly {{Creator:Name Surname}} (required)\n\t\t\t\tauthor: '',\n\t\t\t\t// leave blank unless OTRS pending; by default will be \"see below\" (optional)\n\t\t\t\tpermission: '',\n\t\t\t\t// pipe separated list, other versions (optional)\n\t\t\t\t'other versions': ''\n\t\t\t};\n\n\t\t\tinformation.description = this.descriptionsDetails.getWikiText();\n\n\t\t\tthis.campaignDetailsFields.forEach( function ( layout ) {\n\t\t\t\tinformation.description += layout.fieldWidget.getWikiText();\n\t\t\t} );\n\n\t\t\tinformation.date = this.dateDetails.getWikiText();\n\n\t\t\tdeed = this.upload.deedChooser.deed;\n\n\t\t\tinformation.source = deed.getSourceWikiText( this.upload );\n\n\t\t\tinformation.author = deed.getAuthorWikiText( this.upload );\n\n\t\t\tinfo = '';\n\n\t\t\tfor ( key in information ) {\n\t\t\t\tif ( Object.prototype.hasOwnProperty.call( information, key ) ) {\n\t\t\t\t\tinfo += '|' + key.replace( /:/g, '_' );\n\t\t\t\t\tinfo += '=' + mw.Escaper.escapeForTemplate( information[ key ] ) + '\\n';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twikiText += '=={{int:filedesc}}==\\n';\n\t\t\twikiText += '{{Information\\n' + info + '}}\\n';\n\n\t\t\twikiText += this.locationInput.getWikiText() + '\\n';\n\n\t\t\t// add an \"anything else\" template if needed\n\t\t\twikiText += this.otherDetails.getWikiText() + '\\n\\n';\n\n\t\t\t// add licensing information\n\t\t\twikiText += '\\n=={{int:license-header}}==\\n';\n\t\t\twikiText += deed.getLicenseWikiText( this.upload ) + '\\n\\n';\n\n\t\t\tif ( mw.UploadWizard.config.autoAdd.wikitext !== undefined ) {\n\t\t\t\twikiText += mw.UploadWizard.config.autoAdd.wikitext + '\\n';\n\t\t\t}\n\n\t\t\t// add parameters for list callback bot\n\t\t\t// this cue will be used to supplement a wiki page with an image thumbnail\n\t\t\tif ( $( '#imgPicker' + this.upload.index ).prop( 'checked' ) ) {\n\t\t\t\twikiText += '\\n<!-- WIKIPAGE_UPDATE_PARAMS ' +\n\t\t\t\t\tmw.UploadWizard.config.defaults.objref +\n\t\t\t\t\t' -->\\n';\n\t\t\t}\n\n\t\t\t// templates for other options\n\t\t\twikiText += deed.getTemplateOptionsWikiText() + '\\n\\n';\n\n\t\t\t// categories\n\t\t\twikiText += '\\n' + this.categoriesDetails.getWikiText();\n\n\t\t\t// sanitize wikitext if TextCleaner is defined (MediaWiki:TextCleaner.js)\n\t\t\tif ( typeof window.TextCleaner !== 'undefined' && typeof window.TextCleaner.sanitizeWikiText === 'function' ) {\n\t\t\t\twikiText = window.TextCleaner.sanitizeWikiText( wikiText, true );\n\t\t\t}\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\tvar details = this,\n\t\t\t\twikitext, captions, promise, languageCodes, allLanguages, errorString;\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( 'mwe-upwiz-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\tcaptions = this.captionsDetails.getValues();\n\t\t\tif (\n\t\t\t\tmw.UploadWizard.config.wikibase.enabled &&\n\t\t\t\tmw.UploadWizard.config.wikibase.captions &&\n\t\t\t\tObject.keys( captions ).length > 0\n\t\t\t) {\n\t\t\t\tpromise = promise\n\t\t\t\t\t.then( function () {\n\t\t\t\t\t\t// just work out the mediainfo entity id from the page id\n\t\t\t\t\t\t// @todo FIXME clean this up\n\t\t\t\t\t\tvar status = mw.message( 'mwe-upwiz-submitting-captions', Object.keys( captions ).length );\n\t\t\t\t\t\tdetails.setStatus( status.text() );\n\t\t\t\t\t\treturn details.getMediaInfoEntityId(); // (T208545)\n\t\t\t\t\t} )\n\t\t\t\t\t// submit captions to wikibase\n\t\t\t\t\t.then( this.submitCaptions.bind( this, captions ) );\n\t\t\t}\n\n\t\t\treturn promise.then( function () {\n\t\t\t\tif ( Object.keys( details.captionSubmissionErrors ).length > 0 ) {\n\t\t\t\t\tlanguageCodes = Object.keys( captions );\n\t\t\t\t\tallLanguages = mw.UploadWizard.config.uwLanguages;\n\n\t\t\t\t\terrorString = '<strong>' + mw.message(\n\t\t\t\t\t\t'mwe-upwiz-error-submit-captions',\n\t\t\t\t\t\tlanguageCodes.length\n\t\t\t\t\t).parse() + '</strong>';\n\n\t\t\t\t\tObject.keys( details.captionSubmissionErrors ).forEach( function ( langCode ) {\n\t\t\t\t\t\tvar msgs = [],\n\t\t\t\t\t\t\terror = details.captionSubmissionErrors[ langCode ];\n\t\t\t\t\t\terror.result.errors.forEach( function ( errorObject ) {\n\t\t\t\t\t\t\tvar newMsg = '<p>' + errorObject.html + '</p>';\n\t\t\t\t\t\t\tif ( msgs.indexOf( newMsg ) === -1 ) {\n\t\t\t\t\t\t\t\tmsgs.push( newMsg );\n\t\t\t\t\t\t\t\terrorString += newMsg;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t\terrorString += '<dl>' +\n\t\t\t\t\t\t\t'<dt>' + allLanguages[ langCode ] + '</dt>' +\n\t\t\t\t\t\t\t'<dd>' + captions[ langCode ] + '</dd>' +\n\t\t\t\t\t\t\t'</dl>';\n\t\t\t\t\t} );\n\n\t\t\t\t\terrorString += '<strong>' + mw.message(\n\t\t\t\t\t\t'mwe-upwiz-error-submit-captions-remedy',\n\t\t\t\t\t\tdetails.upload.imageinfo.canonicaltitle\n\t\t\t\t\t).parse() + '</strong>';\n\n\t\t\t\t\tdetails.upload.state = 'sdc-api-error';\n\t\t\t\t\tdetails.showError(\n\t\t\t\t\t\t'caption-fail',\n\t\t\t\t\t\terrorString\n\t\t\t\t\t);\n\t\t\t\t\t// If there is a captions error, then details for how to deal with it are\n\t\t\t\t\t// in the errorString above, no need to show anything else\n\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t$( '#mwe-upwiz-details-warning-count' ).hide();\n\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t$( '.mwe-upwiz-remove-upload' ).hide();\n\t\t\t\t\t// Remove the beforeunload warning, as the image is now as uploaded\n\t\t\t\t\t// as it's going to get\n\t\t\t\t\t$( window ).off( 'beforeunload' );\n\t\t\t\t} else {\n\t\t\t\t\tdetails.showIndicator( 'success' );\n\t\t\t\t\tdetails.setStatus( mw.message( 'mwe-upwiz-published' ).text() );\n\t\t\t\t}\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tgetMediaInfoEntityId: function () {\n\t\t\tvar self = this;\n\n\t\t\tif ( this.mediaInfoEntityId !== undefined ) {\n\t\t\t\treturn $.Deferred().resolve( this.mediaInfoEntityId ).promise();\n\t\t\t}\n\n\t\t\treturn this.upload.api.get( {\n\t\t\t\taction: 'query',\n\t\t\t\tprop: 'info',\n\t\t\t\ttitles: this.getTitle().getPrefixedDb()\n\t\t\t} ).then( function ( result ) {\n\t\t\t\tvar message;\n\n\t\t\t\tif ( result.query.pages[ 0 ].missing ) {\n\t\t\t\t\t// page doesn't exist (yet)\n\t\t\t\t\tmessage = mw.message( 'mwe-upwiz-error-pageprops-missing-page' ).parse();\n\t\t\t\t\treturn $.Deferred().reject( 'pageprops-missing-page', { errors: [ { html: message } ] } ).promise();\n\t\t\t\t}\n\n\t\t\t\t// FIXME: This just fetches the pageid and then hard-codes knowing that M+pageid is what we need\n\t\t\t\tself.mediaInfoEntityId = 'M' + result.query.pages[ 0 ].pageid;\n\t\t\t\treturn self.mediaInfoEntityId;\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\tvar 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'mwe-upwiz-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'mwe-upwiz-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 * @param {Object} captions {<languagecode>: <caption text>} map\n\t\t * @param {string} entityId\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmitCaptions: function ( captions, entityId ) {\n\t\t\tvar self = this,\n\t\t\t\tlanguages = Object.keys( captions ),\n\t\t\t\tpromise = $.Deferred().resolve().promise(),\n\t\t\t\tcallable = function ( language, result ) {\n\t\t\t\t\tvar text = captions[ language ],\n\t\t\t\t\t\tbaseRevId = result && result.entity && result.entity.lastrevid || null;\n\t\t\t\t\treturn self.submitCaption( entityId, baseRevId, language, text );\n\t\t\t\t},\n\t\t\t\ti;\n\n\t\t\tfor ( i = 0; i < languages.length; i++ ) {\n\t\t\t\tpromise = promise.then( callable.bind( promise, languages[ i ] ) );\n\t\t\t}\n\n\t\t\treturn promise;\n\t\t},\n\n\t\t/**\n\t\t * @param {string} id\n\t\t * @param {number|null} baseRevId\n\t\t * @param {string} language\n\t\t * @param {string} value\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmitCaption: function ( id, baseRevId, language, value ) {\n\t\t\tvar self = this,\n\t\t\t\tconfig = mw.UploadWizard.config,\n\t\t\t\tparams = {\n\t\t\t\t\taction: 'wbsetlabel',\n\t\t\t\t\tid: id,\n\t\t\t\t\tlanguage: language,\n\t\t\t\t\tvalue: value,\n\t\t\t\t\t// baserevid is intentionally left blank: captions can be submitted\n\t\t\t\t\t// without baserevid just fine, it just won't prevent all edit conflicts\n\t\t\t\t\t// (though it still somewhat prevent against it)\n\t\t\t\t\t// if we were to set the correct baserevid, we might fail to submit\n\t\t\t\t\t// some captions because of bots making edits immediately after upload\n\t\t\t\t\t// (e.g. https://phabricator.wikimedia.org/T219677)\n\t\t\t\t\t// this is a brand new upload, this is *supposed* to be the very\n\t\t\t\t\t// first content, entered at time of upload; the only edit conflict\n\t\t\t\t\t// that could happen would be caused by bots...\n\t\t\t\t\tbaserevid: undefined\n\t\t\t\t},\n\t\t\t\tajaxOptions = { url: config.wikibase.api };\n\n\t\t\tif ( !config.wikibase.enabled && config.wikibase.captions ) {\n\t\t\t\treturn $.Deferred().reject().promise();\n\t\t\t}\n\n\t\t\treturn this.upload.api.postWithEditToken(\n\t\t\t\tparams, ajaxOptions\n\t\t\t)\n\t\t\t\t.catch( function ( code, result ) {\n\t\t\t\t\tself.captionSubmissionErrors[ language ] = {\n\t\t\t\t\t\tcode: code,\n\t\t\t\t\t\tresult: result\n\t\t\t\t\t};\n\t\t\t\t} );\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\tvar 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( function ( 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( function ( 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\tvar 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// * mwe-upwiz-queued\n\t\t\t\t\t\t// * mwe-upwiz-publish\n\t\t\t\t\t\t// * mwe-upwiz-assembling\n\t\t\t\t\t\tthis.setStatus( mw.message( 'mwe-upwiz-' + result.upload.stage ).text() );\n\t\t\t\t\t\tsetTimeout( function () {\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( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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( '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\tthis.upload.state = 'recoverable-error';\n\t\t\tthis.$dataDiv.morphCrossfade( '.detailsForm' );\n\t\t\tthis.titleDetailsField.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\tvar 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.indexOf( code ) > -1 ) {\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( '.mwe-upwiz-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\tvar progress = status === 'progress';\n\t\t\tthis.$spinner.toggle( progress );\n\t\t\tthis.statusMessage.toggle( status && !progress ).setType( status );\n\t\t\tthis.$indicator.toggleClass( 'mwe-upwiz-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( '.mwe-upwiz-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":"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":"no-shadow","severity":1,"message":"'group' is already declared in the upper scope on line 38 column 7.","line":51,"column":41,"nodeType":"Identifier","messageId":"noShadow","endLine":51,"endColumn":46},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":55,"column":20,"nodeType":"CallExpression","endLine":55,"endColumn":98},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":64,"column":43,"nodeType":"ObjectExpression","endLine":67,"endColumn":6},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":69,"column":51,"nodeType":"ObjectExpression","endLine":72,"endColumn":6},{"ruleId":"no-shadow","severity":1,"message":"'group' is already declared in the upper scope on line 38 column 7.","line":96,"column":31,"nodeType":"Identifier","messageId":"noShadow","endLine":96,"endColumn":36},{"ruleId":"no-shadow","severity":1,"message":"'errors' is already declared in the upper scope on line 291 column 7.","line":293,"column":37,"nodeType":"Identifier","messageId":"noShadow","endLine":293,"endColumn":43},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":294,"column":18,"nodeType":"CallExpression","endLine":294,"endColumn":39},{"ruleId":"no-shadow","severity":1,"message":"'errors' is already declared in the upper scope on line 291 column 7.","line":334,"column":26,"nodeType":"Identifier","messageId":"noShadow","endLine":334,"endColumn":32}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":8,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Create a group of radio buttons for licenses. N.B. the licenses are named after the templates they invoke.\n * Note that this is very anti-MVC. The values are held only in the actual form elements themselves.\n *\n * @extends OO.ui.Widget\n * @param {Object} config Configuration. Must have following properties:\n * @param {string} config.type Whether inclusive or exclusive license allowed (\"and\"|\"or\")\n * @param {string[]} config.licenses Template string names (matching keys in mw.UploadWizard.config.licenses)\n * @param {Object[]} [config.licenseGroups] Groups of licenses, with more explanation\n * @param {string} [config.special] Indicates, don't put licenses here, instead use a special widget\n * @param {number} count Number of the things we are licensing (it matters to some texts)\n * @param {mw.Api} api API object, used for wikitext previews\n */\nmw.UploadWizardLicenseInput = function ( config, count, api ) {\n\tmw.UploadWizardLicenseInput.super.call( this );\n\tOO.ui.mixin.GroupElement.call( this );\n\n\tthis.count = count;\n\tthis.api = api;\n\n\tif (\n\t\tconfig.type === undefined ||\n\t\t( config.licenses === undefined && config.licenseGroups === undefined )\n\t) {\n\t\tthrow new Error( 'improper initialization' );\n\t}\n\n\tthis.type = config.type === 'or' ? 'radio' : 'checkbox';\n\n\tthis.defaults = [];\n\tif ( config.defaults ) {\n\t\tthis.defaults = config.defaults instanceof Array ? config.defaults : [ config.defaults ];\n\t}\n\n\t// create inputs and licenses from config\n\tvar groups = [];\n\tif ( config.licenseGroups === undefined ) {\n\t\tvar group = new mw.uploadWizard.LicenseGroup( config, this.type, this.api, this.count );\n\t\tgroups.push( group );\n\t\tthis.$element.append( this.$group );\n\t} else {\n\t\tvar input = this,\n\t\t\t$container = $( '<div>' ).addClass( 'mwe-upwiz-deed-license-group-container' );\n\n\t\tthis.widget = this.type === 'radio' ? new OO.ui.RadioSelectWidget() : new OO.ui.CheckboxMultiselectWidget();\n\n\t\tthis.$element.append( $container );\n\n\t\tconfig.licenseGroups.forEach( function ( groupConfig ) {\n\t\t\tvar classes = [ 'mwe-upwiz-deed-license-group-head', 'mwe-upwiz-deed-license-group-' + groupConfig.head ],\n\t\t\t\t$icons, label, labelParams, option, group;\n\n\t\t\t$icons = $( '<span>' );\n\t\t\t( groupConfig.icons || [] ).forEach( function ( icon ) {\n\t\t\t\t$icons.append( $( '<span>' ).addClass( 'mwe-upwiz-license-icon mwe-upwiz-' + icon + '-icon' ) );\n\t\t\t} );\n\n\t\t\t// 'url' can be either a single (string) url, or an array of (string) urls;\n\t\t\t// hence this convoluted variable-length parameters assembly...\n\t\t\tlabelParams = [ groupConfig.head, input.count ].concat( groupConfig.url ).concat( $icons );\n\t\t\tlabel = groupConfig.head && mw.message.apply( mw.message, labelParams ).parse() || '';\n\n\t\t\tif ( input.type === 'radio' ) {\n\t\t\t\toption = new OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: new OO.ui.HtmlSnippet( label ),\n\t\t\t\t\tclasses: classes\n\t\t\t\t} );\n\t\t\t} else if ( input.type === 'checkbox' ) {\n\t\t\t\toption = new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\t\tlabel: new OO.ui.HtmlSnippet( label ),\n\t\t\t\t\tclasses: classes\n\t\t\t\t} );\n\t\t\t}\n\t\t\tinput.widget.addItems( [ option ] );\n\n\t\t\tgroup = new mw.uploadWizard.LicenseGroup(\n\t\t\t\t$.extend( {}, groupConfig, { option: option } ),\n\t\t\t\t// group config can override overall type; e.g. a single group can be \"and\", while\n\t\t\t\t// the rest of the config can be \"or\"\n\t\t\t\t( groupConfig.type || config.type ) === 'or' ? 'radio' : 'checkbox',\n\t\t\t\tinput.api,\n\t\t\t\tinput.count\n\t\t\t);\n\t\t\tgroup.$element.addClass( 'mwe-upwiz-deed-subgroup' );\n\t\t\tgroups.push( group );\n\t\t} );\n\t\t$container.append( input.widget.$element );\n\n\t\tthis.widget.on( 'select', function ( selectedOption, isSelected ) {\n\t\t\t// radios don't have a second 'selected' arg; they're always true\n\t\t\tisSelected = isSelected || true;\n\n\t\t\t// radio groups won't fire events for group that got deselected\n\t\t\t// (as a results of a new one being selected), so we'll iterate\n\t\t\t// all groups to remove no-longer-active ones\n\t\t\tgroups.forEach( function ( group ) {\n\t\t\t\tvar option = group.config.option,\n\t\t\t\t\tdefaultLicenses = ( group.config.defaults || [] ).reduce( function ( defaults, license ) {\n\t\t\t\t\t\tdefaults[ license ] = true;\n\t\t\t\t\t\treturn defaults;\n\t\t\t\t\t}, {} );\n\n\t\t\t\tif ( !option.isSelected() ) {\n\t\t\t\t\t// collapse & nix any inputs that may have been selected in groups that\n\t\t\t\t\t// are no longer active/selected\n\t\t\t\t\tgroup.$element.detach();\n\t\t\t\t\tgroup.setValue( {} );\n\t\t\t\t} else {\n\t\t\t\t\t// attach group license selector\n\t\t\t\t\toption.$element.after( group.$element );\n\n\t\t\t\t\t// check the defaults (insofar they exist) for newly selected groups;\n\t\t\t\t\t// ignore groups that had already been selected to ensure existing\n\t\t\t\t\t// user input is not tampered with\n\t\t\t\t\tif (\n\t\t\t\t\t\tisSelected &&\n\t\t\t\t\t\toption === selectedOption &&\n\t\t\t\t\t\tObject.keys( group.getValue() ).length <= 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tgroup.setValue( defaultLicenses );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\tthis.addItems( groups );\n\tthis.aggregate( { change: 'change' } );\n\n\t// [wikitext => list of templates used in wikitext] map, used in\n\t// getUsedTemplates to reduce amount of API calls\n\tthis.templateCache = {};\n};\nOO.inheritClass( mw.UploadWizardLicenseInput, OO.ui.Widget );\nOO.mixinClass( mw.UploadWizardLicenseInput, OO.ui.mixin.GroupElement );\n\n$.extend( mw.UploadWizardLicenseInput.prototype, {\n\tunload: function () {\n\t\tthis.getItems().forEach( function ( group ) {\n\t\t\tgroup.unload();\n\t\t} );\n\t},\n\n\t/**\n\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 * cases we are now letting license inputs create multiple templates.\n\t *\n\t * @param {Object} values License-key to boolean values, e.g. { 'cc_by_sa_30': true, gfdl: true, 'flickrreview|cc_by_sa_30': false }\n\t * @param {string} [groupName] Name of group, when values are only relevant to this group\n\t */\n\tsetValues: function ( values, groupName ) {\n\t\tvar selectedGroups = [];\n\n\t\tvar input = this;\n\t\tthis.getItems().forEach( function ( group ) {\n\t\t\tif ( groupName === undefined || group.getGroup() === groupName ) {\n\t\t\t\tgroup.setValue( values );\n\t\t\t\tif ( Object.keys( group.getValue() ).length > 0 ) {\n\t\t\t\t\tselectedGroups.push( group );\n\t\t\t\t}\n\t\t\t} else if ( input.type === 'radio' ) {\n\t\t\t\t// when we're dealing with radio buttons and there are changes in another\n\t\t\t\t// group, then we'll need to clear out this group...\n\t\t\t\tgroup.setValue( {} );\n\t\t\t}\n\t\t} );\n\n\t\tif ( selectedGroups.length > 1 && this.type === 'radio' ) {\n\t\t\t// leave the last one alone - that one can remain selected\n\t\t\tselectedGroups.pop();\n\n\t\t\t// if we've selected things in multiple groups (= when the group was not defined,\n\t\t\t// which is basically only when dealing with defaults, from config or user\n\t\t\t// preferences), we need to make sure we're left with only 1 selected radio in\n\t\t\t// 1 group\n\t\t\t// in that case, we're only going to select the *last* occurrence, which is what\n\t\t\t// a browser would do when trying to find/select a radio that occurs twice\n\t\t\tselectedGroups.forEach( function ( group ) {\n\t\t\t\tgroup.setValue( {} );\n\t\t\t} );\n\t\t}\n\n\t\t// in the case of multiple option groups (with a parent radio/check to expand/collapse),\n\t\t// we need to make sure the parent option and expanded state match the state of the\n\t\t// group - when the group has things that are selected, it must be active\n\t\tthis.getItems().forEach( function ( group ) {\n\t\t\tvar option = group.config.option,\n\t\t\t\tselected = Object.keys( group.getValue() ).length > 0;\n\n\t\t\tif ( !option ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\toption.setSelected( selected );\n\t\t\tif ( selected ) {\n\t\t\t\toption.$element.append( group.$element );\n\t\t\t\t// there's an event listener bound to respond to changes when an option\n\t\t\t\t// is selected, but that in only triggered by manual (user) selection;\n\t\t\t\t// we're programmatically updating values here, and need to make sure\n\t\t\t\t// it also responds to these\n\t\t\t\tinput.widget.emit( 'select', option, true );\n\t\t\t} else {\n\t\t\t\tgroup.$element.detach();\n\t\t\t}\n\t\t} );\n\t},\n\n\t/**\n\t * Set the default configured licenses\n\t */\n\tsetDefaultValues: function () {\n\t\tvar values = {};\n\t\tthis.defaults.forEach( function ( license ) {\n\t\t\tvalues[ license ] = true;\n\t\t} );\n\t\tthis.setValues( values );\n\t},\n\n\t/**\n\t * Gets the selected license(s). The returned value will be a license\n\t * key => license props map, as defined in UploadWizard.config.php.\n\t *\n\t * @return {Object}\n\t */\n\tgetLicenses: function () {\n\t\tvar licenses = {};\n\n\t\tthis.getItems().forEach( function ( group ) {\n\t\t\tvar licenseNames = Object.keys( group.getValue() );\n\t\t\tlicenseNames.forEach( function ( name ) {\n\t\t\t\tlicenses[ name ] = mw.UploadWizard.config.licenses[ name ] || {};\n\t\t\t} );\n\t\t} );\n\n\t\treturn licenses;\n\t},\n\n\t/**\n\t * Gets the wikitext associated with all selected inputs. Some inputs also have associated textareas so we append their contents too.\n\t *\n\t * @return {string} of wikitext (empty string if no inputs set)\n\t */\n\tgetWikiText: function () {\n\t\treturn this.getItems().map( function ( group ) {\n\t\t\treturn group.getWikiText();\n\t\t} ).join( '' ).trim();\n\t},\n\n\t/**\n\t * Returns a list of templates used & transcluded in given wikitext\n\t *\n\t * @param {string} wikitext\n\t * @return {jQuery.Promise} Promise that resolves with an array of template names\n\t */\n\tgetUsedTemplates: function ( wikitext ) {\n\t\tif ( wikitext in this.templateCache ) {\n\t\t\treturn $.Deferred().resolve( this.templateCache[ wikitext ] ).promise();\n\t\t}\n\n\t\tvar input = this;\n\t\treturn this.api.get( {\n\t\t\taction: 'parse',\n\t\t\tpst: true,\n\t\t\tprop: 'templates',\n\t\t\ttitle: 'File:UploadWizard license verification.png',\n\t\t\ttext: wikitext\n\t\t} ).then( function ( result ) {\n\t\t\tvar templates = [];\n\t\t\tfor ( var i = 0; i < result.parse.templates.length; i++ ) {\n\t\t\t\tvar template = result.parse.templates[ i ];\n\n\t\t\t\t// normalize templates to mw.Title.getPrefixedDb() format\n\t\t\t\tvar title = new mw.Title( template.title, template.ns );\n\t\t\t\ttemplates.push( title.getPrefixedDb() );\n\t\t\t}\n\n\t\t\t// cache result so we won't have to fire another API request\n\t\t\t// for the same content\n\t\t\tinput.templateCache[ wikitext ] = templates;\n\n\t\t\treturn templates;\n\t\t} );\n\t},\n\n\t/**\n\t * See mw.uploadWizard.DetailsWidget\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tgetErrors: function () {\n\t\tvar errors = $.Deferred().resolve( [] ).promise();\n\t\tvar addError = function ( message ) {\n\t\t\terrors = errors.then( function ( errors ) {\n\t\t\t\terrors.push( mw.message( message ) );\n\t\t\t\treturn errors;\n\t\t\t} );\n\t\t};\n\t\tvar selectedInputs = this.getSerialized();\n\n\t\tif ( Object.keys( selectedInputs ).length === 0 ) {\n\t\t\taddError( 'mwe-upwiz-deeds-require-selection' );\n\t\t} else {\n\t\t\tvar input = this;\n\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// But also check that associated text inputs are filled for if the input is selected, and that\n\t\t\t// they are the appropriate size.\n\t\t\tObject.keys( selectedInputs ).forEach( function ( name ) {\n\t\t\t\tvar licenseMap = selectedInputs[ name ];\n\n\t\t\t\tObject.keys( licenseMap ).forEach( function ( license ) {\n\t\t\t\t\tvar licenseValue = licenseMap[ license ];\n\t\t\t\t\tif ( typeof licenseValue !== 'string' ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar wikitext = licenseValue.trim();\n\n\t\t\t\t\tif ( wikitext === '' ) {\n\t\t\t\t\t\taddError( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-error-license-wikitext-too-long' );\n\t\t\t\t\t} else if ( !/\\{\\{(.+?)\\}\\}/g.test( wikitext ) ) {\n\t\t\t\t\t\t// if text doesn't contain a template, we don't even\n\t\t\t\t\t\t// need to validate it any further...\n\t\t\t\t\t\taddError( 'mwe-upwiz-error-license-wikitext-missing-template' );\n\t\t\t\t\t} else if ( mw.UploadWizard.config.customLicenseTemplate !== false ) {\n\t\t\t\t\t\t// now do a thorough test to see if the text actually\n\t\t\t\t\t\t// includes a license template\n\t\t\t\t\t\terrors = $.when(\n\t\t\t\t\t\t\terrors, // array of existing errors\n\t\t\t\t\t\t\tinput.getUsedTemplates( wikitext )\n\t\t\t\t\t\t).then( function ( errors, usedTemplates ) {\n\t\t\t\t\t\t\tif ( usedTemplates.indexOf( mw.UploadWizard.config.customLicenseTemplate ) < 0 ) {\n\t\t\t\t\t\t\t\t// no license template found, add another error\n\t\t\t\t\t\t\t\terrors.push( mw.message( 'mwe-upwiz-error-license-wikitext-missing-template' ) );\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn errors;\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\t}\n\n\t\treturn errors;\n\t},\n\n\t/**\n\t * See mw.uploadWizard.DetailsWidget\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tgetWarnings: function () {\n\t\treturn $.Deferred().resolve( [] ).promise();\n\t},\n\n\t/**\n\t * @return {Object}\n\t */\n\tgetSerialized: function () {\n\t\tvar values = {};\n\n\t\tthis.getItems().forEach( function ( group ) {\n\t\t\tvar groupName = group.getGroup();\n\t\t\tvar value = group.getValue();\n\n\t\t\tif ( Object.keys( value ).length > 0 ) {\n\t\t\t\t// $.extend just in case there are multiple groups with the same name...\n\t\t\t\tvalues[ groupName ] = $.extend( {}, values[ groupName ] || {}, value );\n\t\t\t}\n\t\t} );\n\n\t\treturn values;\n\t},\n\n\t/**\n\t * @param {Object} serialized\n\t */\n\tsetSerialized: function ( serialized ) {\n\t\tvar input = this;\n\n\t\tObject.keys( serialized ).forEach( function ( groupName ) {\n\t\t\tinput.setValues( serialized[ groupName ], groupName );\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":"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":[],"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":31,"column":3,"nodeType":"CallExpression","endLine":31,"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":34,"column":8,"nodeType":"CallExpression","endLine":34,"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":42,"column":4,"nodeType":"CallExpression","endLine":42,"endColumn":33,"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":"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":2,"message":"'uw' is defined but never used.","line":10,"column":14,"nodeType":"Identifier","messageId":"unusedVar","endLine":10,"endColumn":16},{"ruleId":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":22,"column":1,"nodeType":"Block","endLine":22,"endColumn":1},{"ruleId":"es-x/no-typed-arrays","severity":1,"message":"ES2015 'Uint8Array' is forbidden.","line":226,"column":16,"nodeType":"Identifier","messageId":"forbidden","endLine":226,"endColumn":26}],"suppressedMessages":[{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_binary_data'.","line":236,"column":6,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":236,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier '_binary_data' is not in camel case.","line":236,"column":11,"nodeType":"Identifier","messageId":"notCamelCase","endLine":236,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":1,"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( 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 * @mixins OO.EventEmitter\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\n\t\tif ( file.licenseName ) {\n\t\t\tthis.ui.setLicenseText( file.licenseName );\n\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( 'mwe-upwiz-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\tvar 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\tvar 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\tvar 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\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\tvar 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\tvar 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( function ( 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\tvar 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.indexOf( 'url' ) === -1 ) {\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\tvar requestedTitle, params;\n\n\t\tfunction ok( data ) {\n\t\t\tvar 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( function ( pageId ) {\n\t\t\t\t\tvar 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.indexOf( 'url' ) === -1 ) {\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|mw.ApiUploadPostHandler} upload handler object\n\t */\n\tmw.UploadWizardUpload.prototype.getUploadHandler = function () {\n\t\tvar 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\tif ( mw.UploadWizard.config.debug ) {\n\t\t\t\tmw.log( 'mw.UploadWizard::getUploadHandler> ' + constructor );\n\t\t\t}\n\t\t\tif ( this.file.fromURL ) {\n\t\t\t\tconstructor = 'ApiUploadPostHandler';\n\t\t\t}\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\tvar 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( function ( thumb ) {\n\t\t\t\t\tvar 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', function () {\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', function () {\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( function () {\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\tvar 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\tvar scaling = 1;\n\t\tObject.keys( constraints ).forEach( function ( dim ) {\n\t\t\tvar 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\tvar 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\tvar 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\tvar 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\tvar 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( 'mwe-upwiz-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( function () {\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', function () {\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\tvar 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', function () {\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', function () {\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( function () {\n\t\t\t\t\t\t\tvar 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( function () {\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\tvar 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\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":"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":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":6,"column":1,"nodeType":"Block","endLine":6,"endColumn":1},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":113,"column":3,"nodeType":"CallExpression","endLine":113,"endColumn":36}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"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 * @mixins OO.EventEmitter\n\t * @constructor\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tmw.UploadWizardUploadInterface = function MWUploadWizardUploadInterface( upload ) {\n\t\tvar 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( 'mwe-upwiz-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( 'mwe-upwiz-file-indicator' ).append(\n\t\t\tthis.$spinner,\n\t\t\tthis.statusMessage.$element\n\t\t);\n\n\t\tthis.$visibleFilenameDiv = $( '<div>' ).addClass( 'mwe-upwiz-visible-file' ).append(\n\t\t\tthis.$indicator,\n\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-visible-file-filename' ).append(\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-preview' ),\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-texts' ).append(\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-visible-file-filename-text' ),\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-license' ),\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-status-line' ).append(\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-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( 'mwe-upwiz-remove' ).text(),\n\t\t\ttitle: mw.message( 'mwe-upwiz-remove-upload' ).text(),\n\t\t\tflags: 'destructive',\n\t\t\ticon: 'trash',\n\t\t\tframed: false\n\t\t} ).on( 'click', function () {\n\t\t\tui.emit( 'upload-removed' );\n\t\t} );\n\n\t\tif ( mw.UploadWizard.config.defaults && mw.UploadWizard.config.defaults.objref !== '' ) {\n\t\t\tthis.$imagePicker = this.createImagePickerField(\n\t\t\t\tthis.upload.index,\n\t\t\t\tmw.UploadWizard.config.defaults.updateList === ''\n\t\t\t);\n\t\t\tthis.$visibleFilenameDiv.find( '.mwe-upwiz-file-status-line' )\n\t\t\t\t.append( this.$imagePicker );\n\t\t}\n\n\t\tthis.$visibleFilenameDiv.find( '.mwe-upwiz-file-status-line' )\n\t\t\t.append( this.removeCtrl.$element );\n\n\t\tthis.$form = $( '<form>' )\n\t\t\t.addClass( 'mwe-upwiz-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', function () {\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\tvar progress = status === 'progress';\n\t\tthis.$spinner.toggle( progress );\n\t\tthis.statusMessage.toggle( status && !progress ).setType( status );\n\t\tthis.$indicator.toggleClass( 'mwe-upwiz-file-indicator-visible', !!status );\n\t};\n\n\t/**\n\t * @param {string} license License text\n\t */\n\tmw.UploadWizardUploadInterface.prototype.setLicenseText = function ( license ) {\n\t\tthis.$div.find( '.mwe-upwiz-file-license' ).text( license );\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\tvar $status = this.$div.find( '.mwe-upwiz-file-status' );\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( '.mwe-upwiz-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( '.mwe-upwiz-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( '.mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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\tvar 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\tvar $preview = this.$div.find( '.mwe-upwiz-file-preview' ),\n\t\t\tdeferred = $.Deferred();\n\t\t// This must match the CSS dimensions of .mwe-upwiz-file-preview\n\t\tthis.upload.getThumbnail( 120, 120 ).done( function ( 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\tvar path = this.upload.getFilename();\n\n\t\t// visible filename\n\t\tthis.$form.find( '.mwe-upwiz-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\t/**\n\t * Create a checkbox to process the object reference parameter\n\t *\n\t * @param {number} index Number of the file for which the field is being created\n\t * @param {boolean} setDisabled Disable in case there already is an image in the referring list\n\t * @return {jQuery} A `div` containing a checkbox, label, and optional notice\n\t */\n\tmw.UploadWizardUploadInterface.prototype.createImagePickerField = function ( index, setDisabled ) {\n\t\tvar $fieldContainer = $( '<div>' ).addClass( 'mwe-upwiz-objref-pick-image' ),\n\t\t\tattributes = {\n\t\t\t\ttype: 'checkbox',\n\t\t\t\tclass: 'imgPicker',\n\t\t\t\tid: 'imgPicker' + index,\n\t\t\t\tdisabled: false,\n\t\t\t\tchecked: false\n\t\t\t};\n\n\t\tif ( setDisabled ) {\n\t\t\tattributes.disabled = 'disabled';\n\t\t} else if ( index === 0 ) {\n\t\t\tattributes.checked = 'checked';\n\t\t}\n\n\t\t$fieldContainer.append(\n\t\t\t$( '<input>' ).attr( attributes ).on( 'click', function () {\n\t\t\t\t$( this )\n\t\t\t\t\t.prop( 'checked', true )\n\t\t\t\t\t.closest( '.mwe-upwiz-file' )\n\t\t\t\t\t.siblings()\n\t\t\t\t\t.find( '.imgPicker' )\n\t\t\t\t\t.prop( 'checked', false );\n\t\t\t} ),\n\n\t\t\t$( '<label>' ).attr( {\n\t\t\t\tfor: 'imgPicker' + index\n\t\t\t} ).text( this.getPickImageLabel() )\n\t\t);\n\n\t\tif ( setDisabled ) {\n\t\t\t$fieldContainer.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-objref-notice-existing-image' )\n\t\t\t\t\t.text( this.getExistingImageNotice() )\n\t\t\t);\n\t\t}\n\n\t\treturn $fieldContainer;\n\t};\n\n\tmw.UploadWizardUploadInterface.prototype.getExistingImageNotice = function () {\n\t\tif ( mw.UploadWizard.config && mw.UploadWizard.config.display && mw.UploadWizard.config.display.noticeExistingImage ) {\n\t\t\treturn mw.UploadWizard.config.display.noticeExistingImage;\n\t\t} else {\n\t\t\treturn mw.message( 'mwe-upwiz-objref-notice-existing-image' ).text();\n\t\t}\n\t};\n\n\tmw.UploadWizardUploadInterface.prototype.getPickImageLabel = function () {\n\t\tif ( mw.UploadWizard.config && mw.UploadWizard.config.display && mw.UploadWizard.config.display.labelPickImage ) {\n\t\t\treturn mw.UploadWizard.config.display.labelPickImage;\n\t\t} else {\n\t\t\treturn mw.message( 'mwe-upwiz-objref-pick-image' ).text();\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":"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":"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":"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":"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":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":7,"column":1,"nodeType":"Block","endLine":7,"endColumn":1},{"ruleId":"no-shadow","severity":1,"message":"'offset' is already declared in the upper scope on line 155 column 4.","line":165,"column":17,"nodeType":"Identifier","messageId":"noShadow","endLine":165,"endColumn":23}],"suppressedMessages":[{"ruleId":"no-loop-func","severity":2,"message":"Function declared in a loop contains unsafe references to variable(s) 'prevPromise', 'prevPromise'.","line":165,"column":6,"nodeType":"FunctionExpression","messageId":"unsafeRefs","endLine":181,"endColumn":5,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"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 * @mixins OO.EventEmitter\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\tvar 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\tvar xhr = $.ajaxSettings.xhr();\n\t\t\t\txhr.upload.addEventListener( 'progress', function ( evt ) {\n\t\t\t\t\tvar 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\tvar params = OO.cloneObject( this.formData );\n\n\t\t$.extend( 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\tvar 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, 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\tvar\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 ( offset ) {\n\t\t\t\tvar\n\t\t\t\t\tnewPromise = $.Deferred(),\n\t\t\t\t\tisLastChunk = offset + chunkSize >= fileSize,\n\t\t\t\t\tthisChunkSize = isLastChunk ? ( fileSize % chunkSize ) : chunkSize;\n\t\t\t\tprevPromise.done( function () {\n\t\t\t\t\ttransport.uploadChunk( file, offset )\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( function ( 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( ( offset + 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\tvar 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( '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( function ( 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}, function ( 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\tvar\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\tvar 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( '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\n\t\tthis.request = this.api.post( params );\n\n\t\treturn this.request.then(\n\t\t\tfunction ( 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},\n\t\t\tfunction ( code, result ) {\n\t\t\t\treturn $.Deferred().reject( code, result );\n\t\t\t}\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":"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":[],"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":"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":[],"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":213,"column":4,"nodeType":"CallExpression","endLine":213,"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":221,"column":4,"nodeType":"CallExpression","endLine":221,"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":252,"column":4,"nodeType":"CallExpression","endLine":252,"endColumn":21,"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":"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.Metadata.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":"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":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":165,"column":4,"nodeType":"CallExpression","endLine":165,"endColumn":94}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  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\tvar $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', 'mwe-upwiz-thanks' )\n\t\t);\n\n\t\tif ( this.isObjectReferenceGiven() ) {\n\t\t\tthis.getDelayNotice().prependTo( this.$div );\n\t\t}\n\n\t\t$( '<p>' )\n\t\t\t.addClass( 'mwe-upwiz-thanks-explain' )\n\t\t\t.msg( 'mwe-upwiz-thanks-explain' )\n\t\t\t.prependTo( this.$div );\n\n\t\t$header = $( '<h3>' )\n\t\t\t.addClass( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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 || ( beginButtonTarget === 'dropObjref' && !this.isObjectReferenceGiven() ) ) {\n\t\t\tthis.beginButton.on( 'click', function () {\n\t\t\t\tthanks.emit( 'next-step' );\n\t\t\t} );\n\t\t} else {\n\t\t\tif ( beginButtonTarget === 'dropObjref' ) {\n\t\t\t\tbeginButtonTarget = this.dropParameterFromURL( location.href, 'updateList' );\n\t\t\t}\n\t\t\tthis.beginButton.setHref( beginButtonTarget );\n\t\t}\n\t\tthis.beginButton.on( 'click', function () {\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\tvar 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( 'mwe-upwiz-thanks ui-helper-clearfix' );\n\t\t$thumbnailWrapDiv = $( '<div>' )\n\t\t\t.addClass( 'mwe-upwiz-thumbnail-side' )\n\t\t\t.appendTo( $thanksDiv );\n\t\t$thumbnailDiv = $( '<div>' )\n\t\t\t.addClass( 'mwe-upwiz-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( 'mwe-upwiz-data' )\n\t\t\t.appendTo( $thanksDiv )\n\t\t\t.append(\n\t\t\t\tthis.makeReadOnlyInput( thumbWikiText, mw.message( 'mwe-upwiz-thanks-wikitext' ).text(), true ),\n\t\t\t\tthis.makeReadOnlyInput( upload.imageinfo.descriptionurl, mw.message( 'mwe-upwiz-thanks-url' ).text() )\n\t\t\t);\n\n\t\t// This must match the CSS dimensions of .mwe-upwiz-thumbnail\n\t\tupload.getThumbnail( 120, 120 ).done( function ( 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( '.mwe-upwiz-thumbnail-link' ) ).attr( {\n\t\t\thref: upload.imageinfo.descriptionurl,\n\t\t\ttarget: '_blank'\n\t\t} );\n\n\t\tthis.$div.find( '.mwe-upwiz-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\tvar 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\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\t/**\n\t * Drops a parameter from the given url\n\t *\n\t * @param {string} url URL from which to drop a parameter\n\t * @param {string} paramName parameter to be dropped\n\t * @return {string}\n\t * @private\n\t */\n\tuw.ui.Thanks.prototype.dropParameterFromURL = function ( url, paramName ) {\n\t\tvar newUrl = new mw.Uri( url );\n\t\tif ( newUrl.query ) {\n\t\t\tdelete newUrl.query[ paramName ];\n\t\t\tdelete newUrl.query[ paramName + '[]' ];\n\t\t}\n\t\treturn newUrl.toString();\n\t};\n\n\tuw.ui.Thanks.prototype.getDelayNotice = function () {\n\t\tvar $delayNotice = $( '<p>' )\n\t\t\t.addClass( 'mwe-upwiz-thanks-update-delay' )\n\t\t\t.msg( 'mwe-upwiz-objref-notice-update-delay' );\n\n\t\tif ( this.config.display && this.config.display.noticeUpdateDelay ) {\n\t\t\t$delayNotice.html( this.config.display.noticeUpdateDelay );\n\t\t}\n\t\treturn $delayNotice;\n\t};\n\n\tuw.ui.Thanks.prototype.isObjectReferenceGiven = function () {\n\t\treturn this.config.defaults && this.config.defaults.objref !== '';\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":"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":[],"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":55,"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":91,"column":3,"nodeType":"CallExpression","endLine":91,"endColumn":38,"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":"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":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":266,"column":39,"nodeType":"CallExpression","endLine":266,"endColumn":56},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":271,"column":33,"nodeType":"CallExpression","endLine":271,"endColumn":51}],"suppressedMessages":[{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":231,"column":4,"nodeType":"CallExpression","endLine":231,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":233,"column":4,"nodeType":"CallExpression","endLine":233,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  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\tvar 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', 'mwe-upwiz-add-file-container' )\n\t\t\t.addClass( 'mwe-upwiz-add-files-0' );\n\n\t\tthis.$uploadCtrl = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-upload-ctrls' )\n\t\t\t.addClass( 'mwe-upwiz-file ui-helper-clearfix' )\n\t\t\t.append( this.$addFileContainer );\n\n\t\tthis.addFile = new OO.ui.SelectFileWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-add-file' ],\n\t\t\tmultiple: true,\n\t\t\tshowDropTarget: true,\n\t\t\tbutton: {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-add-file-0-free' ).text(),\n\t\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t\t}\n\t\t} );\n\t\tthis.addFile.on( 'change', function ( files ) {\n\t\t\tupload.emit( 'files-added', files );\n\t\t\tupload.addFile.setValue( null );\n\t\t} );\n\n\t\tthis.$addFileContainer.append( this.addFile.$element );\n\n\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\tthis.$flickrAddFileContainer = $( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-upload-ctrl-flickr-container' );\n\n\t\t\tthis.$uploadCenterDivide = $( '<p>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-upload-ctr-divide' )\n\t\t\t\t.text( mw.message( 'mwe-upwiz-add-flickr-or' ).text() );\n\n\t\t\tthis.addFlickrFile = new OO.ui.ButtonWidget( {\n\t\t\t\tid: 'mwe-upwiz-add-flickr-file',\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-add-file-flickr' ).text(),\n\t\t\t\tflags: 'progressive'\n\t\t\t} ).on( 'click', function () {\n\t\t\t\tupload.flickrInterfaceInit();\n\t\t\t} );\n\n\t\t\tthis.$flickrAddFileContainer.append(\n\t\t\t\tthis.$uploadCenterDivide,\n\t\t\t\tthis.addFlickrFile.$element\n\t\t\t);\n\n\t\t\tthis.$addFileContainer\n\t\t\t\t.append( this.$flickrAddFileContainer );\n\n\t\t\tthis.$flickrSelectList = $( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-flickr-select-list' );\n\n\t\t\tthis.$flickrSelectListContainer = $( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-flickr-select-list-container' )\n\t\t\t\t.addClass( 'ui-corner-all' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.text( mw.message(\n\t\t\t\t\t\t\t'mwe-upwiz-multi-file-select2',\n\t\t\t\t\t\t\tconfig.maxFlickrUploads\n\t\t\t\t\t\t) ),\n\t\t\t\t\tthis.$flickrSelectList\n\t\t\t\t);\n\n\t\t\t// Button to move on & upload the files that were selected\n\t\t\tthis.flickrSelectButton = new OO.ui.ButtonWidget( {\n\t\t\t\tid: 'mwe-upwiz-select-flickr',\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-add-file-0-free' ).text(),\n\t\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t\t} );\n\t\t\tthis.$flickrSelectListContainer.append( this.flickrSelectButton.$element );\n\n\t\t\t// A container holding a form\n\t\t\tthis.$flickrContainer = $( '<div>' ).attr( 'id', 'mwe-upwiz-upload-add-flickr-container' );\n\n\t\t\t// Form whose submit event will be listened to and prevented\n\t\t\tthis.$flickrForm = $( '<form>' ).attr( 'id', 'mwe-upwiz-flickr-url-form' )\n\t\t\t\t.appendTo( this.$flickrContainer )\n\t\t\t\t.on( 'submit', function () {\n\t\t\t\t\tvar checker = new mw.FlickrChecker( upload, upload.flickrSelectButton );\n\t\t\t\t\tupload.flickrButton.setDisabled( true );\n\t\t\t\t\tupload.flickrChecker( checker );\n\t\t\t\t\t// TODO Any particular reason to stopPropagation ?\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\n\t\t\t// The input that will hold a flickr URL entered by the user; will be appended to a form\n\t\t\tthis.flickrInput = new OO.ui.TextInputWidget( {\n\t\t\t\tplaceholder: mw.message( 'mwe-upwiz-flickr-input-placeholder' ).text()\n\t\t\t} );\n\n\t\t\tthis.flickrButton = new OO.ui.ButtonInputWidget( {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-add-flickr' ).text(),\n\t\t\t\tflags: [ 'progressive', 'primary' ],\n\t\t\t\ttype: 'submit'\n\t\t\t} );\n\n\t\t\tthis.flickrField = new OO.ui.ActionFieldLayout(\n\t\t\t\tthis.flickrInput, this.flickrButton, {\n\t\t\t\t\talign: 'top',\n\t\t\t\t\tclasses: [ 'mwe-upwiz-flickr-field' ]\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tthis.$flickrForm.append( this.flickrField.$element );\n\n\t\t\t// Add disclaimer\n\t\t\t$( '<div>' ).attr( 'id', 'mwe-upwiz-flickr-disclaimer' )\n\t\t\t\t.append(\n\t\t\t\t\tmw.message( 'mwe-upwiz-flickr-disclaimer1' ).parseDom(),\n\t\t\t\t\t$( '<br>' ), mw.message( 'mwe-upwiz-flickr-disclaimer2' ).parseDom()\n\t\t\t\t)\n\t\t\t\t.appendTo( this.$flickrContainer );\n\t\t}\n\n\t\tthis.nextStepButtonAllOk = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-next-file' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', function () {\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( 'mwe-upwiz-file-retry' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', function () {\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( 'mwe-upwiz-next-file-despite-failures' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', function () {\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( 'mwe-upwiz-file-retry' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', function () {\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', 'mwe-upwiz-filelist' )\n\t\t\t.addClass( 'ui-corner-all' );\n\n\t\tthis.$progress = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-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( 'mwe-upwiz-filled-filelist', haveUploads );\n\t\tthis.$addFileContainer.toggleClass( 'mwe-upwiz-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\tif ( this.isFlickrImportEnabled() ) {\n\t\t\t\tthis.$uploadCenterDivide.hide();\n\t\t\t}\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( '.mwe-upwiz-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\t\t\tthis.showNoticeForImageMetadata( true );\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\tthis.showNoticeForImageMetadata( false );\n\n\t\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\t\tthis.$uploadCenterDivide.show();\n\t\t\t}\n\t\t}\n\n\t\tthis.addFile.setDisabled( !fewerThanMax );\n\n\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\tthis.addFlickrFile.setDisabled( !fewerThanMax );\n\t\t}\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\tvar msg = 'mwe-upwiz-add-file-',\n\t\t\tfmsg = 'mwe-upwiz-add-file-flickr';\n\n\t\tif ( more ) {\n\t\t\tmsg += 'n';\n\t\t\tfmsg += '-n';\n\t\t} else {\n\t\t\tmsg += '0-free';\n\t\t}\n\n\t\tthis.addFile.selectButton.setLabel( mw.message( msg ).text() );\n\n\t\t// if Flickr uploading is available to this user, show the \"add more files from flickr\" button\n\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\t// changes the flickr add button to \"add more files from flickr\" if necessary.\n\t\t\tthis.addFlickrFile.setLabel( mw.message( fmsg ).text() );\n\t\t\t// jQuery likes to restore the wrong 'display' value when doing .show()\n\t\t\tthis.$flickrAddFileContainer.css( 'display', '' );\n\t\t}\n\t};\n\n\tuw.ui.Upload.prototype.load = function ( uploads ) {\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tif ( uploads.length === 0 ) {\n\t\t\tthis.$fileList.removeClass( 'mwe-upwiz-filled-filelist' );\n\t\t}\n\n\t\tvar $noticeMessage = $( '<span>' )\n\t\t\t.append(\n\t\t\t\t$( '<strong>' ).text( mw.message( 'mwe-upwiz-metadata-notice-header' ).text() ),\n\t\t\t\t$( '<br>' ),\n\t\t\t\tmw.message( 'mwe-upwiz-metadata-notice-description' ).parseDom()\n\t\t\t);\n\n\t\tthis.notice = new OO.ui.MessageWidget( {\n\t\t\ttype: 'notice',\n\t\t\ticon: 'pageSettings',\n\t\t\tclasses: [ 'mwe-upwiz-metadata-notice' ],\n\t\t\tlabel: $noticeMessage\n\t\t} );\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-files' )\n\t\t\t\t.append(\n\t\t\t\t\tthis.$flickrSelectListContainer,\n\t\t\t\t\tthis.$fileList,\n\t\t\t\t\tthis.$uploadCtrl,\n\t\t\t\t\tthis.notice.$element\n\t\t\t\t)\n\t\t);\n\n\t\tthis.displayUploads( uploads );\n\t};\n\n\tuw.ui.Upload.prototype.displayUploads = function ( uploads ) {\n\t\tvar thumbPromise,\n\t\t\t$uploadInterfaceDivs = $( [] );\n\n\t\tuploads.forEach( function ( 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( function ( upload ) {\n\t\t\tthumbPromise = thumbPromise.then( function () {\n\t\t\t\tvar 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( function () {\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\tvar ui = this;\n\n\t\tthis.nextButtonPromise.done( function () {\n\t\t\tui.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-file-next-all-ok mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-file-next-some-failed mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-file-next-all-failed mwe-upwiz-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( 'mwe-upwiz-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( '.mwe-upwiz-buttons .mwe-upwiz-file-endchoice' )\n\t\t\t.hide();\n\t};\n\n\t/**\n\t * @param {boolean} show\n\t */\n\tuw.ui.Upload.prototype.showNoticeForImageMetadata = function ( show ) {\n\t\tthis.$div.find( '.mwe-upwiz-metadata-notice' ).toggle( show );\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'mwe-upwiz-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( 'mwe-upwiz-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'mwe-upwiz-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( 'mwe-upwiz-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\tvar $errorMessage = $( '<p>' ).msg( 'mwe-upwiz-upload-error-bad-filename-extension', extension );\n\t\tthis.showFilenameError( $errorMessage );\n\t};\n\n\tuw.ui.Upload.prototype.showMissingExtensionError = function () {\n\t\tvar $errorMessage = $( '<p>' ).msg( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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\t/**\n\t * Checks whether flickr import is enabled and the current user has the rights to use it\n\t *\n\t * @return {boolean}\n\t */\n\tuw.ui.Upload.prototype.isFlickrImportEnabled = function () {\n\t\treturn this.config.UploadFromUrl && this.config.flickrApiKey !== '';\n\t};\n\n\t/**\n\t * Initiates the Interface to upload media from Flickr.\n\t * Called when the user clicks on the 'Add images from Flickr' button.\n\t */\n\tuw.ui.Upload.prototype.flickrInterfaceInit = function () {\n\t\t// Hide containers for selecting files, and show the flickr interface instead\n\t\tthis.$addFileContainer.hide();\n\t\tthis.$flickrAddFileContainer.hide();\n\t\tthis.$flickrContainer.show();\n\t\tthis.flickrSelectButton.$element.show();\n\t\tthis.flickrButton.setDisabled( false );\n\n\t\t// Insert form into the page\n\t\tthis.$div.find( '#mwe-upwiz-files' ).prepend( this.$flickrContainer );\n\n\t\tthis.flickrInput.focus();\n\t};\n\n\t/**\n\t * Responsible for fetching license of the provided media.\n\t *\n\t * @param {mw.FlickrChecker} checker\n\t */\n\tuw.ui.Upload.prototype.flickrChecker = function ( checker ) {\n\t\tvar flickrInputUrl = this.flickrInput.getValue();\n\n\t\tchecker.getLicenses().done( function () {\n\t\t\tchecker.checkFlickr( flickrInputUrl );\n\t\t} );\n\t};\n\n\t/**\n\t * Reset the interface if there is a problem while fetching the images from\n\t * the URL entered by the user.\n\t */\n\tuw.ui.Upload.prototype.flickrInterfaceReset = function () {\n\t\t// first destroy it completely, then reshow the add button\n\t\tthis.flickrInterfaceDestroy();\n\t\tthis.flickrButton.setDisabled( false );\n\t\tthis.$flickrContainer.show();\n\t\tthis.flickrSelectButton.$element.show();\n\t};\n\n\t/**\n\t * Removes the flickr interface.\n\t */\n\tuw.ui.Upload.prototype.flickrInterfaceDestroy = function () {\n\t\tthis.flickrInput.setValue( '' );\n\t\tthis.$flickrSelectList.empty();\n\t\tthis.$flickrSelectListContainer.off().hide();\n\t\tthis.$flickrContainer.hide();\n\t\tthis.flickrButton.setDisabled( true );\n\t\tthis.flickrSelectButton.$element.hide();\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":"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":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":23,"column":1,"nodeType":"Block","endLine":23,"endColumn":1}],"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":40,"column":3,"nodeType":"CallExpression","endLine":40,"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":57,"column":16,"nodeType":"CallExpression","endLine":57,"endColumn":25,"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":65,"column":3,"nodeType":"CallExpression","endLine":65,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  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 * @mixins OO.EventEmitter\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( 'mwe-upwiz-buttons' );\n\n\t\tthis.$div = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-stepdiv-' + this.name )\n\t\t\t.addClass( 'mwe-upwiz-stepdiv' )\n\t\t\t.hide();\n\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( '#mwe-upwiz-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\tvar 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\tvar ui = this;\n\n\t\tthis.nextButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-button-next' ],\n\t\t\tlabel: mw.message( 'mwe-upwiz-next' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', function () {\n\t\t\tui.emit( 'next-step' );\n\t\t} );\n\n\t\tthis.nextButtonPromise.done( function () {\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\tvar ui = this;\n\n\t\tthis.previousButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-button-previous' ],\n\t\t\tlabel: mw.message( 'mwe-upwiz-previous' ).text()\n\t\t} ).on( 'click', function () {\n\t\t\tui.emit( 'previous-step' );\n\t\t} );\n\n\t\tthis.previousButtonPromise.done( function () {\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":"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":[{"ruleId":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":23,"column":1,"nodeType":"Block","endLine":23,"endColumn":1},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":144,"column":25,"nodeType":"CallExpression","endLine":144,"endColumn":72},{"ruleId":"no-shadow","severity":1,"message":"'$arrow' is already declared in the upper scope on line 141 column 8.","line":149,"column":32,"nodeType":"Identifier","messageId":"noShadow","endLine":149,"endColumn":38}],"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":51,"column":18,"nodeType":"CallExpression","endLine":51,"endColumn":36,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":87,"column":3,"nodeType":"CallExpression","endLine":87,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard 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 * UploadWizard 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 UploadWizard.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard.\n\t *\n\t * @class uw.ui.Wizard\n\t * @mixins OO.EventEmitter\n\t * @constructor\n\t * @param {string} selector Where to put all of the wizard interface.\n\t */\n\tuw.ui.Wizard = function UWUIWizard( selector ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.$div = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-content' );\n\n\t\t$( selector ).append(\n\t\t\tthis.$div,\n\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-clearing' )\n\t\t);\n\n\t\tthis.initHeader( mw.UploadWizard.config );\n\t};\n\n\tOO.mixinClass( uw.ui.Wizard, OO.EventEmitter );\n\n\t/**\n\t * Initializes the static stuff above the wizard.\n\t *\n\t * @param {Object} config\n\t */\n\tuw.ui.Wizard.prototype.initHeader = function ( config ) {\n\t\tvar feedbackLink,\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$contentSub = $( '#contentSub' );\n\n\t\tif ( config.feedbackLink ) {\n\t\t\t// Preferred. Send user to bug tracker (defaults to UW's own\n\t\t\t// Phabricator project)\n\t\t\tfeedbackLink = config.feedbackLink;\n\t\t} else if ( config.feedbackPage ) {\n\t\t\t// Backwards compatibility...send user to talk page to give\n\t\t\t// feedback.\n\t\t\tfeedbackLink = mw.util.getUrl( config.feedbackPage );\n\t\t}\n\n\t\tif ( feedbackLink ) {\n\t\t\tthis.$feedbackLink = $( '<a>' )\n\t\t\t\t.addClass( 'contentSubLink' )\n\t\t\t\t.prop( 'href', feedbackLink )\n\t\t\t\t.msg( 'mwe-upwiz-feedback-prompt' );\n\n\t\t\t$contentSub.append( this.$feedbackLink );\n\t\t}\n\n\t\tif ( config.alternativeUploadToolsPage ) {\n\t\t\tthis.$alternativeUploads = $( '<a>' )\n\t\t\t\t.addClass( 'contentSubLink' )\n\t\t\t\t.prop( 'href', new mw.Title( config.alternativeUploadToolsPage ).getUrl() )\n\t\t\t\t.msg( 'mwe-upwiz-subhead-alternatives' );\n\n\t\t\t$contentSub.append( this.$alternativeUploads );\n\t\t}\n\n\t\tif ( config.altUploadForm ) {\n\t\t\tthis.initAltUploadForm( config.altUploadForm );\n\t\t}\n\n\t\t// Separate each link in the header with a dot.\n\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t$contentSub.find( '.contentSubLink:not(:last)' ).after( '&nbsp;&middot;&nbsp;' );\n\t};\n\n\t/**\n\t * Initializes a link to the alternate upload form, if any.\n\t *\n\t * @param {Object|string} configAltUploadForm A link or map of languages to links, pointing at an alternate form.\n\t */\n\tuw.ui.Wizard.prototype.initAltUploadForm = function ( configAltUploadForm ) {\n\t\tvar altUploadForm, userLanguage, title;\n\n\t\tif ( typeof configAltUploadForm === 'object' ) {\n\t\t\tuserLanguage = mw.config.get( 'wgUserLanguage' );\n\n\t\t\tif ( configAltUploadForm[ userLanguage ] ) {\n\t\t\t\taltUploadForm = configAltUploadForm[ userLanguage ];\n\t\t\t} else if ( configAltUploadForm.default ) {\n\t\t\t\taltUploadForm = configAltUploadForm.default;\n\t\t\t}\n\t\t} else {\n\t\t\taltUploadForm = configAltUploadForm;\n\t\t}\n\n\t\t// altUploadForm is expected to be a page title like 'Commons:Upload', so convert to URL\n\t\tif ( typeof altUploadForm === 'string' && altUploadForm.length > 0 ) {\n\t\t\ttry {\n\t\t\t\ttitle = new mw.Title( altUploadForm );\n\n\t\t\t\t$( '<a>' )\n\t\t\t\t\t.msg( 'mwe-upwiz-subhead-alt-upload' )\n\t\t\t\t\t.addClass( 'contentSubLink' )\n\t\t\t\t\t.attr( 'href', title.getUrl() )\n\t\t\t\t\t.appendTo( '#contentSub' );\n\t\t\t} catch ( e ) {\n\t\t\t\t// page was empty, or impossible on this wiki (missing namespace or some other issue). Give up.\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Initializes the arrow steps above the wizard.\n\t *\n\t * @param {Object.<uw.controller.Step>} steps\n\t */\n\tuw.ui.Wizard.prototype.initialiseSteps = function ( steps ) {\n\t\tvar $steps = $( '<ul>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-steps' )\n\t\t\t\t.addClass( 'ui-helper-clearfix' )\n\t\t\t\t.insertBefore( '#mwe-upwiz-content' ),\n\t\t\tsortedSteps = this.sortSteps( Object.keys( steps ).map( function ( key ) {\n\t\t\t\treturn steps[ key ];\n\t\t\t} ) );\n\n\t\tsortedSteps.forEach( function ( step ) {\n\t\t\tvar $arrow = $( '<li>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-step-' + step.stepName )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<div>' ).text( mw.message( 'mwe-upwiz-step-' + step.stepName ).text() )\n\t\t\t\t);\n\t\t\t$steps.append( $arrow );\n\n\t\t\t// once a (new) step loads, highlight it\n\t\t\tstep.on( 'load', function ( $arrow ) {\n\t\t\t\t$steps.arrowStepsHighlight( $arrow );\n\t\t\t}.bind( step, $arrow ) );\n\t\t} );\n\n\t\t$steps.arrowSteps();\n\t};\n\n\t/**\n\t * Sorts the steps in the order they'll actually be used.\n\t *\n\t * @param {uw.controller.Step[]} steps\n\t * @return {uw.controller.Step[]}\n\t */\n\tuw.ui.Wizard.prototype.sortSteps = function ( steps ) {\n\t\tvar first = steps[ 0 ],\n\t\t\tsorted,\n\t\t\ti;\n\n\t\t// find the very first step (element at position [0] is not guaranteed\n\t\t// to be first (it was just added first)\n\t\t// The actual internal relationship is defined in previousStep & nextStep\n\t\t// properties ...)\n\t\twhile ( first.previousStep !== null ) {\n\t\t\tfirst = first.previousStep;\n\t\t}\n\n\t\tsorted = [ first ];\n\t\tfor ( i = 1; i < steps.length; i++ ) {\n\t\t\tsorted.push( sorted[ i - 1 ].nextStep );\n\t\t}\n\n\t\treturn sorted;\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":"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":"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":"jsdoc/check-tag-names","severity":1,"message":"Invalid JSDoc tag name \"mixins\".","line":10,"column":1,"nodeType":"Block","endLine":10,"endColumn":1}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"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 * @mixins OO.EventEmitter\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\tvar 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\tvar 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\tvar 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\tvar 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":"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":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":30,"column":23,"nodeType":"CallExpression","endLine":30,"endColumn":69},{"ruleId":"security/detect-unsafe-regex","severity":1,"message":"Unsafe Regular Expression","line":181,"column":31,"nodeType":"Literal","endLine":181,"endColumn":56}],"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":"FunctionExpression","messageId":"unsafeRefs","endLine":200,"endColumn":7,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"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\tvar metadataType, defaultStatus, copyMetadataMsg,\n\t\t\tcheckboxes = [],\n\t\t\t$copyMetadataWrapperDiv = $( '<div>' ),\n\t\t\t$copyMetadataDiv = $( '<div>' );\n\n\t\tuw.CopyMetadataWidget.super.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// mwe-upwiz-copy-title, mwe-upwiz-copy-caption, mwe-upwiz-copy-description,\n\t\t\t\t// mwe-upwiz-copy-date, mwe-upwiz-copy-categories, mwe-upwiz-copy-location,\n\t\t\t\t// mwe-upwiz-copy-other\n\t\t\t\tcopyMetadataMsg = mw.message( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-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( 'mwe-upwiz-copy-metadata' ) )\n\t\t\t\t\t.addClass( 'mwe-upwiz-details-copy-metadata mw-collapsible-toggle mw-collapsible-arrow' ),\n\t\t\t\t$copyMetadataDiv.addClass( 'mw-collapsible-content' )\n\t\t\t)\n\t\t\t.addClass( 'mwe-upwiz-data' )\n\t\t\t.makeCollapsible( { collapsed: true } );\n\n\t\tthis.$element\n\t\t\t.addClass( 'mwe-upwiz-info-file filled mwe-upwiz-copyMetadataWidget' )\n\t\t\t.append(\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-thumbnail' ),\n\t\t\t\t$copyMetadataWrapperDiv\n\t\t\t);\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\tcaption: 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\tvar 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( 'mwe-upwiz-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( 'mwe-upwiz-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\tvar 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( function ( 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\tfunction ( str, m1, m2, m3 ) {\n\t\t\t\t\t\tvar 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\tvar 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":"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":"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":[],"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":"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":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":140,"column":39,"nodeType":"ObjectExpression","endLine":140,"endColumn":75},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":175,"column":47,"nodeType":"ObjectExpression","endLine":175,"endColumn":83},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":362,"column":20,"nodeType":"CallExpression","endLine":362,"endColumn":98},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":366,"column":12,"nodeType":"CallExpression","endLine":367,"endColumn":61},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":381,"column":5,"nodeType":"CallExpression","endLine":382,"endColumn":73}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":5,"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.template] Filter templates. If 'filterTemplate' was 'filter',\n\t *   then  [ 'fooLicense', 'barLicense' ] -> {{filter|fooLicense|barLicense}}\n\t * @param {Array} [config.prependTemplates] Array of templates to prepend. If prependTemplates\n\t *   were [ 'pre', 'pended' ], then [ 'fooLicense' ] -> \"{{pre}}{{pended}}{{fooLicense}}\"\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\tvar self = this;\n\n\t\tuw.LicenseGroup.super.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' ].indexOf( type ) < 0 ) {\n\t\t\tthrow new Error( 'Invalid type: ' + type );\n\t\t}\n\n\t\tthis.config = config;\n\t\tthis.type = type;\n\t\tthis.api = api;\n\t\tthis.count = count;\n\t\tthis.customInputs = {};\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( [ 'mwe-upwiz-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( [ 'mwe-upwiz-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 input, we'll immediately focus it\n\t\tthis.on( 'change', function ( 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( function () {\n\t\t\t\t\tvar name = item.getData();\n\t\t\t\t\tif ( self.customInputs[ name ] ) {\n\t\t\t\t\t\tself.customInputs[ 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\tvar fieldset = new OO.ui.FieldsetLayout( {\n\t\t\t\titems: [ group ],\n\t\t\t\tclasses: [ 'mwe-upwiz-deed-license-group' ]\n\t\t\t} ),\n\t\t\tlabelParams, $subhead;\n\n\t\tif ( this.config.subhead ) {\n\t\t\t// 'url' can be either a single (string) url, or an array of (string) urls;\n\t\t\t// hence this convoluted variable-length parameters assembly...\n\t\t\tlabelParams = [ this.config.subhead, this.count ].concat( this.config.url );\n\t\t\t$subhead = $( '<div>' )\n\t\t\t\t.addClass( 'mwe-upwiz-deed-license-group-subhead mwe-upwiz-deed-title' )\n\t\t\t\t.append( mw.message.apply( mw.message, labelParams ).parseDom() );\n\n\t\t\tfieldset.addItems(\n\t\t\t\t[\n\t\t\t\t\tnew OO.ui.FieldLayout(\n\t\t\t\t\t\tnew OO.ui.Widget( { content: [] } ),\n\t\t\t\t\t\t{ label: $subhead, align: 'top' }\n\t\t\t\t\t)\n\t\t\t\t],\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\tvar self = this,\n\t\t\toptions = [];\n\n\t\tthis.config.licenses.forEach( function ( licenseName ) {\n\t\t\tvar 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.customInputs[ licenseName ] ) {\n\t\t\t\tself.customInputs[ licenseName ].on( 'focus', function () {\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\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\tvar self = this,\n\t\t\toptions = [];\n\n\t\tthis.config.licenses.forEach( function ( licenseName ) {\n\t\t\tvar 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 input fields changes, we should make sure this element is selected when\n\t\t\t// there is content, or deselected when empty\n\t\t\tif ( self.customInputs[ licenseName ] ) {\n\t\t\t\tself.customInputs[ licenseName ].on( 'focus', function () {\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\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\tvar wikiTexts,\n\t\t\tself = this,\n\t\t\tvalues = this.getValue();\n\n\t\twikiTexts = Object.keys( values ).map( function ( name ) {\n\t\t\tvar wikiText = self.getLicenceWikiText( 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;\n\t\t} );\n\n\t\treturn wikiTexts.join( '' ).trim();\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 {string}\n\t */\n\tuw.LicenseGroup.prototype.getData = function () {\n\t\treturn this.getGroup();\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\tvar 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.customInputs[ name ] || this.customInputs[ 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( function ( item ) {\n\t\t\t\tname = item.getData();\n\t\t\t\tresult[ name ] = !self.customInputs[ name ] || self.customInputs[ 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\tvar self = this,\n\t\t\tselectArray = [];\n\n\t\tObject.keys( values ).forEach( function ( name ) {\n\t\t\tvar value = values[ name ];\n\t\t\tif ( typeof value === 'string' && self.customInputs[ name ] ) {\n\t\t\t\tself.customInputs[ 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} else if ( this.type === 'checkbox' ) {\n\t\t\tthis.group.selectItemsByData( selectArray );\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 * @private\n\t * @param {string} name\n\t * @return {string[]}\n\t */\n\tuw.LicenseGroup.prototype.getTemplates = function ( name ) {\n\t\tvar licenseInfo = this.getLicenseInfo( name );\n\t\treturn licenseInfo.props.templates === undefined ?\n\t\t\t[ licenseInfo.name ] :\n\t\t\tlicenseInfo.props.templates.slice( 0 );\n\t};\n\n\t/**\n\t * License templates are these abstract ideas like cc-by-sa. In general they map directly to a license template.\n\t * However, configuration for a particular option can add other templates or transform the templates,\n\t * such as wrapping templates in an outer \"self\" template for own-work\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.getLicenceWikiText = function ( name ) {\n\t\tvar templates = this.getTemplates( name ),\n\t\t\twikiTexts;\n\n\t\tif ( this.config.prependTemplates !== undefined ) {\n\t\t\tthis.config.prependTemplates.forEach( function ( template ) {\n\t\t\t\ttemplates.unshift( template );\n\t\t\t} );\n\t\t}\n\n\t\tif ( this.config.template !== undefined ) {\n\t\t\ttemplates.unshift( this.config.template );\n\t\t\ttemplates = [ templates.join( '|' ) ];\n\t\t}\n\n\t\twikiTexts = templates.map( function ( t ) {\n\t\t\treturn '{{' + t + '}}';\n\t\t} );\n\t\treturn wikiTexts.join( '' );\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\tvar 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\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 (\n\t\t\tlicenseInfo.props.languageCodePrefix !== undefined &&\n\t\t\tlicenseInfo.props.availableLanguages !== undefined\n\t\t) {\n\t\t\tvar i,\n\t\t\t\ttargetLanguageCode = 'en', // final fallback\n\t\t\t\tfallbackChain = mw.language.getFallbackLanguageChain();\n\t\t\tfor ( i = 0; i < fallbackChain.length; i++ ) {\n\t\t\t\tif ( licenseInfo.props.availableLanguages.indexOf( fallbackChain[ i ] ) !== -1 ) {\n\t\t\t\t\ttargetLanguageCode = fallbackChain[ i ];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlicenseURL += licenseInfo.props.languageCodePrefix + targetLanguageCode;\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( function ( icon ) {\n\t\t\t\t$icons.append( $( '<span>' ).addClass( 'mwe-upwiz-license-icon mwe-upwiz-' + icon + '-icon' ) );\n\t\t\t} );\n\t\t}\n\n\t\t$label = $( '<label>' )\n\t\t\t.msg( messageKey, this.count || 0, $licenseLink, $icons )\n\t\t\t.addClass( 'mwe-upwiz-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\t$label.append(\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.msg( 'mwe-upwiz-license-custom-explain', this.count || 0, $licenseLink )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra' )\n\t\t\t);\n\t\t}\n\n\t\tif ( licenseInfo.props.msgExplain !== undefined ) {\n\t\t\t$label.append(\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.msg( licenseInfo.props.msgExplain, this.count || 0, $licenseLink )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra mwe-upwiz-label-explainer' )\n\t\t\t);\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\tvar self = this,\n\t\t\tbutton;\n\n\t\tthis.customInputs[ name ] = new OO.ui.TextInputWidget( {\n\t\t\tvalue: defaultText\n\t\t} );\n\n\t\t// Update displayed errors as the user is typing\n\t\tthis.customInputs[ 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( 'mwe-upwiz-license-custom-preview' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', function () {\n\t\t\tself.showPreview( self.customInputs[ name ].getValue() );\n\t\t} );\n\n\t\treturn $( '<div>' ).addClass( 'mwe-upwiz-license-custom' ).append(\n\t\t\tthis.customInputs[ name ].$element,\n\t\t\tbutton.$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\tvar 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\tvar 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":"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":"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":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":90,"column":15,"nodeType":"CallExpression","endLine":91,"endColumn":61}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"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( 'mwe-upwiz-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\tvar 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( function ( 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( function () {\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\tvar 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$listItem = OO.ui.FieldLayout.prototype.makeMessage.call( this, kind, $content )\n\t\t\t.addClass( 'mwe-upwiz-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":"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":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":21,"column":11,"nodeType":"CallExpression","endLine":21,"endColumn":73}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tvar scaleMsgKeys = [ 'size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes' ];\n\n\tuw.units = {\n\t\t/**\n\t\t * Format a size in bytes for output, using an appropriate\n\t\t * unit (bytes, K, MB, GB, or TB) according to the magnitude in question\n\t\t *\n\t\t * Units above K get 2 fixed decimal places.\n\t\t *\n\t\t * @param {number} size Number of bytes\n\t\t * @return {string} formatted size\n\t\t */\n\t\tbytes: function ( size ) {\n\t\t\tvar i = 0;\n\t\t\twhile ( size >= 1024 && i < scaleMsgKeys.length - 1 ) {\n\t\t\t\tsize /= 1024.0;\n\t\t\t\ti++;\n\t\t\t}\n\t\t\treturn mw.message( scaleMsgKeys[ i ], size.toFixed( i > 1 ? 2 : 0 ) ).text();\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":"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/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":"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/sql/abstractSchemaChanges/patch-uw_campaigns-cleanup.json","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":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","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":"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":"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":[],"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":"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":"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":"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":[],"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":"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":"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/details/uw.LocationDetailsWidget.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":"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.FlickrChecker.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":"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":[],"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":"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":[],"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":"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":[],"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":"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":[],"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":"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":[],"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":"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":[],"suppressedMessages":[{"ruleId":"camelcase","severity":2,"message":"Identifier 'user_talk' is not in camel case.","line":67,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":67,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'wikipedia_talk' is not in camel case.","line":69,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":69,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'file_talk' is not in camel case.","line":71,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":71,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'mediawiki_talk' is not in camel case.","line":73,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":73,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'template_talk' is not in camel case.","line":75,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":75,"endColumn":18,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'help_talk' is not in camel case.","line":77,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":77,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'category_talk' is not in camel case.","line":79,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":79,"endColumn":18,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'image_talk' is not in camel case.","line":81,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":81,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'project_talk' is not in camel case.","line":83,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":83,"endColumn":17,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'antarctic_waterfowl' is not in camel case.","line":86,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":86,"endColumn":24,"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":"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 ---
$ /usr/bin/npm ci
--- stderr ---
npm WARN deprecated stylelint-stylistic@0.4.3: This package has been deprecated in favor of @stylistic/stylelint-plugin
--- stdout ---

added 468 packages, and audited 469 packages in 5s

99 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.Details.js
  244:51  warning  'i' is already declared in the upper scope on line 234 column 7          no-shadow
  244:54  warning  'warnings' is already declared in the upper scope on line 233 column 66  no-shadow

/src/repo/resources/controller/uw.controller.Step.js
  23:1  warning  Invalid JSDoc tag name "mixins"  jsdoc/check-tag-names

/src/repo/resources/deed/dialog/uw.deed.dialog.PatentDialog.js
  116:1  warning  Missing JSDoc @param "ownership" type  jsdoc/require-param-type
  117:1  warning  Missing JSDoc @param "grant" type      jsdoc/require-param-type

/src/repo/resources/deed/uw.deed.Abstract.js
   46:14  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  220:1   warning  Missing JSDoc @return type                                                           jsdoc/require-returns-type

/src/repo/resources/deed/uw.deed.OwnWork.js
  464:1  warning  Missing JSDoc @return type  jsdoc/require-returns-type

/src/repo/resources/deed/uw.deed.ThirdParty.js
  321:6  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/details/uw.DateDetailsWidget.js
  147:20  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  173:70  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  176:70  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  179:70  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/details/uw.LanguageDropdownWidget.js
  14:53  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details  mediawiki/class-doc

/src/repo/resources/details/uw.LocationDetailsWidget.js
  238:28  warning  Unsafe Regular Expression  security/detect-unsafe-regex

/src/repo/resources/details/uw.MultipleLanguageInputWidget.js
    8:1   warning  Invalid JSDoc tag name "mixins"                                                      jsdoc/check-tag-names
  181:10  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/details/uw.TitleDetailsWidget.js
   49:23  warning  Found non-literal argument to RegExp Constructor                                     security/detect-non-literal-regexp
   86:14  warning  Found non-literal argument to RegExp Constructor                                     security/detect-non-literal-regexp
  134:15  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  193:22  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/details/uw.UlsWidget.js
  30:3  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details  mediawiki/class-doc

/src/repo/resources/jquery.arrowSteps/jquery.arrowSteps.js
  88:1  warning  Invalid JSDoc tag name "mixins"  jsdoc/check-tag-names

/src/repo/resources/metadata/uw.MetadataContent.js
  118:1  warning  The type 'change' is undefined  jsdoc/no-undefined-types

/src/repo/resources/mw.DestinationChecker.js
  11:3  warning  Found more than one @return declaration  jsdoc/require-returns
  11:3  warning  Found more than one @return declaration  jsdoc/require-returns-check
  34:3  warning  Found more than one @return declaration  jsdoc/require-returns
  34:3  warning  Found more than one @return declaration  jsdoc/require-returns-check
  85:3  warning  Found more than one @return declaration  jsdoc/require-returns
  85:3  warning  Found more than one @return declaration  jsdoc/require-returns-check

/src/repo/resources/mw.Escaper.js
   63:13  warning  Unsafe Regular Expression                         security/detect-unsafe-regex
  121:19  warning  Found non-literal argument to RegExp Constructor  security/detect-non-literal-regexp

/src/repo/resources/mw.FlickrChecker.js
   73:42  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   75:49  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   76:50  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   77:44  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   78:46  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
   79:48  warning  Unsafe Regular Expression                                            security/detect-unsafe-regex
  199:1   warning  The type 'getPhotos' is undefined                                    jsdoc/no-undefined-types
  213:26  warning  'data' is already declared in the upper scope on line 206 column 24  no-shadow
  237:1   warning  The type 'getCollection' is undefined                                jsdoc/no-undefined-types
  296:57  warning  'data' is already declared in the upper scope on line 285 column 24  no-shadow
  308:1   warning  The type 'getPhotos' is undefined                                    jsdoc/no-undefined-types
  329:1   warning  The type 'getPhotos' is undefined                                    jsdoc/no-undefined-types
  580:49  warning  ES2019 'Symbol.prototype.description' property is forbidden          es-x/no-symbol-prototype-description
  678:4   warning  ES2019 'Symbol.prototype.description' property is forbidden          es-x/no-symbol-prototype-description
  697:42  warning  ES2019 'Symbol.prototype.description' property is forbidden          es-x/no-symbol-prototype-description

/src/repo/resources/mw.UploadWizard.js
    4:1   warning  Missing JSDoc @param "uw" type                                      jsdoc/require-param-type
   83:23  warning  'steps' is already declared in the upper scope on line 60 column 5  no-shadow
  113:25  warning  'steps' is already declared in the upper scope on line 60 column 5  no-shadow

/src/repo/resources/mw.UploadWizardDeedChooser.js
   7:1   warning  Invalid JSDoc tag name "mixins"                                                      jsdoc/check-tag-names
  36:42  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
  40:6   warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  48:8   warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  60:17  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc

/src/repo/resources/mw.UploadWizardDetails.js
  260:9   warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  264:14  warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  462:10  warning  'matches' is already declared in the upper scope on line 439 column 42             no-shadow
  554:16  warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  644:3   warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  712:9   warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  713:45  warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  763:4   warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description
  766:5   warning  ES2019 'Symbol.prototype.description' property is forbidden                        es-x/no-symbol-prototype-description

/src/repo/resources/mw.UploadWizardLicenseInput.js
   51:41  warning  'group' is already declared in the upper scope on line 38 column 7                   no-shadow
   55:20  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
   64:43  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
   69:51  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
   96:31  warning  'group' is already declared in the upper scope on line 38 column 7                   no-shadow
  293:37  warning  'errors' is already declared in the upper scope on line 291 column 7                 no-shadow
  294:18  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  334:26  warning  'errors' is already declared in the upper scope on line 291 column 7                 no-shadow

/src/repo/resources/mw.UploadWizardUpload.js
    8:1   warning  Missing JSDoc @param "uw" type    jsdoc/require-param-type
   10:14  error    'uw' is defined but never used    no-unused-vars
   22:1   warning  Invalid JSDoc tag name "mixins"   jsdoc/check-tag-names
  226:16  warning  ES2015 'Uint8Array' is forbidden  es-x/no-typed-arrays

/src/repo/resources/mw.UploadWizardUploadInterface.js
    6:1  warning  Invalid JSDoc tag name "mixins"                                                      jsdoc/check-tag-names
  113:3  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/transports/mw.FormDataTransport.js
    7:1   warning  Invalid JSDoc tag name "mixins"                                       jsdoc/check-tag-names
  165:17  warning  'offset' is already declared in the upper scope on line 155 column 4  no-shadow

/src/repo/resources/ui/steps/uw.ui.Thanks.js
  165:4  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details  mediawiki/class-doc

/src/repo/resources/ui/steps/uw.ui.Upload.js
  266:39  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  271:33  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/ui/uw.ui.Step.js
  23:1  warning  Invalid JSDoc tag name "mixins"  jsdoc/check-tag-names

/src/repo/resources/ui/uw.ui.Wizard.js
   23:1   warning  Invalid JSDoc tag name "mixins"                                                      jsdoc/check-tag-names
  144:25  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  149:32  warning  '$arrow' is already declared in the upper scope on line 141 column 8                 no-shadow

/src/repo/resources/uw.ConcurrentQueue.js
  10:1  warning  Invalid JSDoc tag name "mixins"  jsdoc/check-tag-names

/src/repo/resources/uw.CopyMetadataWidget.js
   30:23  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  181:31  warning  Unsafe Regular Expression                                                            security/detect-unsafe-regex

/src/repo/resources/uw.LicenseGroup.js
  140:39  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
  175:47  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
  362:20  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details    mediawiki/class-doc
  366:12  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc
  381:5   warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

/src/repo/resources/uw.ValidationMessageElement.js
  39:2   warning  JSDoc @return declaration present but return expression not available in function  jsdoc/require-returns-check
  90:15  warning  All possible CSS classes should be documented. See https://w.wiki/PS2 for details  mediawiki/class-doc

/src/repo/resources/uw.units.js
  21:11  warning  All possible message keys should be documented. See https://w.wiki/4r9a for details  mediawiki/msg-doc

✖ 98 problems (1 error, 97 warnings)

Warning: Task "eslint:all" failed. Use --force to continue.

Aborted due to warnings.

--- end ---
Traceback (most recent call last):
  File "/venv/lib/python3.11/site-packages/runner-0.1.0-py3.11.egg/runner/__init__.py", line 1534, in main
    libup.run(args.repo, args.output, args.branch)
  File "/venv/lib/python3.11/site-packages/runner-0.1.0-py3.11.egg/runner/__init__.py", line 1472, in run
    self.npm_upgrade(plan)
  File "/venv/lib/python3.11/site-packages/runner-0.1.0-py3.11.egg/runner/__init__.py", line 1057, in npm_upgrade
    self.npm_test()
  File "/venv/lib/python3.11/site-packages/runner-0.1.0-py3.11.egg/runner/__init__.py", line 297, in npm_test
    self.check_call(['npm', 'test'])
  File "/venv/lib/python3.11/site-packages/runner-0.1.0-py3.11.egg/runner/shell2.py", line 54, in check_call
    res.check_returncode()
  File "/usr/lib/python3.11/subprocess.py", line 502, in check_returncode
    raise CalledProcessError(self.returncode, self.args, self.stdout,
subprocess.CalledProcessError: Command '['/usr/bin/npm', 'test']' returned non-zero exit status 3.
Source code is licensed under the AGPL.