diff --git a/.eslintrc.js b/.eslintrc.js index ab6094823..ba8d87e78 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,244 +1,274 @@ +var appConfig = { + env: { + browser: true, + es6: true, + node: true, + }, + plugins: [ + '@typescript-eslint', + 'header', + 'jsdoc', + 'prefer-arrow', + 'promise', + ], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier', + 'prettier/@typescript-eslint', + 'plugin:@angular-eslint/recommended', + 'plugin:promise/recommended', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + sourceType: 'module', + }, + reportUnusedDisableDirectives: true, + rules: { + '@angular-eslint/component-class-suffix': ['error', { suffixes: ['Component', 'Page'] }], + '@typescript-eslint/adjacent-overload-signatures': 'error', + '@typescript-eslint/ban-types': [ + 'error', + { + types: { + Boolean: { + message: 'Use \'boolean\' instead.', + }, + Number: { + message: 'Use \'number\' instead.', + }, + String: { + message: 'Use \'string\' instead.', + }, + Object: { + message: 'Use {} instead.', + }, + }, + }, + ], + '@typescript-eslint/explicit-member-accessibility': [ + 'error', + { + accessibility: 'no-public', + }, + ], + '@typescript-eslint/explicit-module-boundary-types': [ + 'error', + { + allowArgumentsExplicitlyTypedAsAny: true, + }, + ], + '@typescript-eslint/indent': [ + 'error', + 4, + { + SwitchCase: 1, + ignoredNodes: [ + 'ClassProperty *', + ], + }, + ], + '@typescript-eslint/lines-between-class-members': [ + 'error', + 'always', + { + exceptAfterSingleLine: true, + }, + ], + '@typescript-eslint/member-delimiter-style': [ + 'error', + { + multiline: { + delimiter: 'semi', + requireLast: true, + }, + singleline: { + delimiter: 'semi', + requireLast: false, + }, + }, + ], + '@typescript-eslint/member-ordering': 'error', + '@typescript-eslint/naming-convention': [ + 'error', + { + selector: 'property', + modifiers: ['readonly'], + format: ['UPPER_CASE'], + }, + { + selector: 'property', + format: ['camelCase'], + }, + ], + '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-empty-interface': 'off', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-inferrable-types': [ + 'error', + { + ignoreParameters: true, + }, + ], + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-this-alias': 'error', + '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/quotes': [ + 'error', + 'single', + ], + '@typescript-eslint/semi': [ + 'error', + 'always', + ], + '@typescript-eslint/type-annotation-spacing': 'error', + '@typescript-eslint/unified-signatures': 'error', + 'header/header': [ + 2, + 'line', + [ + ' (C) Copyright 2015 Moodle Pty Ltd.', + '', + ' Licensed under the Apache License, Version 2.0 (the "License");', + ' you may not use this file except in compliance with the License.', + ' You may obtain a copy of the License at', + '', + ' http://www.apache.org/licenses/LICENSE-2.0', + '', + ' Unless required by applicable law or agreed to in writing, software', + ' distributed under the License is distributed on an "AS IS" BASIS,', + ' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.', + ' See the License for the specific language governing permissions and', + ' limitations under the License.', + ], + 1, + ], + 'promise/catch-or-return': [ + 'warn', + { + allowFinally: true, + }, + ], + 'arrow-body-style': ['error', 'as-needed'], + 'array-bracket-spacing': ['error', 'never'], + 'comma-dangle': ['error', 'always-multiline'], + 'constructor-super': 'error', + 'curly': 'error', + 'eol-last': 'error', + 'function-call-argument-newline': ['error', 'consistent'], + 'function-paren-newline': ['error', 'multiline-arguments'], + 'id-blacklist': [ + 'error', + 'any', + 'Number', + 'number', + 'String', + 'string', + 'Boolean', + 'boolean', + 'Undefined', + 'undefined', + ], + 'id-match': 'error', + 'jsdoc/check-alignment': 'error', + 'jsdoc/check-indentation': [ + 'error', + { + excludeTags: ['param'], + }, + ], + 'jsdoc/newline-after-description': 'error', + 'linebreak-style': [ + 'error', + 'unix', + ], + 'max-len': [ + 'error', + { + code: 132, + }, + ], + 'new-parens': 'error', + 'no-bitwise': 'error', + 'no-cond-assign': 'error', + 'no-console': 'error', + 'no-debugger': 'error', + 'no-duplicate-case': 'error', + 'no-duplicate-imports': 'error', + 'no-empty': 'error', + 'no-eval': 'error', + 'no-invalid-this': 'error', + 'no-irregular-whitespace': 'error', + 'no-multiple-empty-lines': 'error', + 'no-new-wrappers': 'error', + 'no-redeclare': 'error', + 'no-sequences': 'error', + 'no-trailing-spaces': 'error', + 'no-underscore-dangle': 'error', + 'no-unused-labels': 'error', + 'no-var': 'error', + 'object-curly-spacing': ['error', 'always'], + 'one-var': ['error', 'never'], + 'padded-blocks': [ + 'error', + { + classes: 'always', + blocks: 'never', + switches: 'never', + }, + ], + 'padding-line-between-statements': [ + 'error', + { + blankLine: 'always', + prev: '*', + next: 'return', + }, + ], + 'prefer-arrow/prefer-arrow-functions': [ + 'error', + { + singleReturnOnly: true, + allowStandaloneDeclarations: true, + }, + ], + 'prefer-const': 'error', + 'prefer-spread': 'off', + 'quote-props': [ + 'error', + 'consistent-as-needed', + ], + 'spaced-comment': [ + 'error', + 'always', + { + markers: [ + '/', + ], + }, + ], + 'use-isnan': 'error', + 'yoda': 'error', + }, +}; + +var testsConfig = Object.assign({}, appConfig); +testsConfig['rules']['padded-blocks'] = [ + 'error', + { + classes: 'always', + switches: 'never', + }, +]; +testsConfig['plugins'].push('jest'); +testsConfig['extends'].push('plugin:jest/recommended'); + module.exports = { root: true, overrides: [ - { - files: ['*.ts'], - env: { - browser: true, - es6: true, - node: true, - }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier', - 'prettier/@typescript-eslint', - 'plugin:jest/recommended', - 'plugin:@angular-eslint/recommended', - ], - parser: '@typescript-eslint/parser', - parserOptions: { - project: 'tsconfig.json', - sourceType: 'module', - }, - plugins: [ - 'eslint-plugin-prefer-arrow', - 'eslint-plugin-jsdoc', - '@typescript-eslint', - 'header', - 'jest', - ], - rules: { - '@angular-eslint/component-class-suffix': ['error', { suffixes: ['Component', 'Page'] }], - '@typescript-eslint/adjacent-overload-signatures': 'error', - '@typescript-eslint/ban-types': [ - 'error', - { - types: { - Boolean: { - message: 'Use \'boolean\' instead.', - }, - Number: { - message: 'Use \'number\' instead.', - }, - String: { - message: 'Use \'string\' instead.', - }, - Object: { - message: 'Use {} instead.', - }, - }, - }, - ], - '@typescript-eslint/explicit-member-accessibility': [ - 'error', - { - accessibility: 'no-public', - }, - ], - '@typescript-eslint/indent': 'error', - '@typescript-eslint/member-delimiter-style': [ - 'error', - { - multiline: { - delimiter: 'semi', - requireLast: true, - }, - singleline: { - delimiter: 'semi', - requireLast: false, - }, - }, - ], - '@typescript-eslint/member-ordering': 'error', - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: 'property', - modifiers: ['readonly'], - format: ['UPPER_CASE'], - }, - { - selector: 'property', - format: ['camelCase'], - }, - ], - '@typescript-eslint/no-empty-function': 'error', - '@typescript-eslint/no-empty-interface': 'off', - '@typescript-eslint/no-explicit-any': [ - 'warn', - { - fixToUnknown: true, - }, - ], - '@typescript-eslint/no-inferrable-types': [ - 'error', - { - ignoreParameters: true, - }, - ], - '@typescript-eslint/no-non-null-assertion': 'error', - '@typescript-eslint/no-this-alias': 'error', - '@typescript-eslint/no-unused-vars': 'error', - '@typescript-eslint/quotes': [ - 'error', - 'single', - ], - '@typescript-eslint/semi': [ - 'error', - 'always', - ], - '@typescript-eslint/type-annotation-spacing': 'error', - '@typescript-eslint/typedef': [ - 'error', - { - arrayDestructuring: false, - arrowParameter: false, - memberVariableDeclaration: true, - objectDestructuring: false, - parameter: true, - propertyDeclaration: true, - variableDeclaration: false, - }, - ], - '@typescript-eslint/unified-signatures': 'error', - 'header/header': [ - 2, - 'line', - [ - ' (C) Copyright 2015 Moodle Pty Ltd.', - '', - ' Licensed under the Apache License, Version 2.0 (the "License");', - ' you may not use this file except in compliance with the License.', - ' You may obtain a copy of the License at', - '', - ' http://www.apache.org/licenses/LICENSE-2.0', - '', - ' Unless required by applicable law or agreed to in writing, software', - ' distributed under the License is distributed on an "AS IS" BASIS,', - ' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.', - ' See the License for the specific language governing permissions and', - ' limitations under the License.', - ], - 1, - ], - 'arrow-body-style': ['error', 'as-needed'], - 'array-bracket-spacing': ['error', 'never'], - 'comma-dangle': ['error', 'always-multiline'], - 'constructor-super': 'error', - 'curly': 'error', - 'default-case': 'error', - 'eol-last': 'error', - 'id-blacklist': [ - 'error', - 'any', - 'Number', - 'number', - 'String', - 'string', - 'Boolean', - 'boolean', - 'Undefined', - 'undefined', - ], - 'id-match': 'error', - 'jsdoc/check-alignment': 'error', - 'jsdoc/check-indentation': 'error', - 'jsdoc/newline-after-description': 'error', - 'linebreak-style': [ - 'error', - 'unix', - ], - 'lines-between-class-members': ['error', 'always'], - 'max-len': [ - 'error', - { - code: 132, - }, - ], - 'new-parens': 'error', - 'no-bitwise': 'error', - 'no-cond-assign': 'error', - 'no-console': 'error', - 'no-debugger': 'error', - 'no-duplicate-case': 'error', - 'no-duplicate-imports': 'error', - 'no-empty': 'error', - 'no-eval': 'error', - 'no-invalid-this': 'error', - 'no-irregular-whitespace': 'error', - 'no-multiple-empty-lines': 'error', - 'no-new-wrappers': 'error', - 'no-redeclare': 'error', - 'no-sequences': 'error', - 'no-trailing-spaces': 'error', - 'no-underscore-dangle': 'error', - 'no-unused-labels': 'error', - 'no-var': 'error', - 'object-curly-spacing': ['error', 'always'], - 'one-var': ['error', 'never'], - 'padded-blocks': [ - 'error', - { - classes: 'always', - blocks: 'never', - switches: 'never', - }, - ], - 'padding-line-between-statements': [ - 'error', - { - blankLine: 'always', - prev: '*', - next: 'return', - }, - ], - 'prefer-arrow/prefer-arrow-functions': [ - 'error', - { - singleReturnOnly: true, - allowStandaloneDeclarations: true, - }, - ], - 'prefer-const': 'error', - 'prefer-spread': 'off', - 'quote-props': [ - 'error', - 'consistent-as-needed', - ], - 'spaced-comment': [ - 'error', - 'always', - { - markers: [ - '/', - ], - }, - ], - 'use-isnan': 'error', - 'yoda': 'error', - }, - }, + Object.assign({ files: ['*.ts'] }, appConfig), + Object.assign({ files: ['*.test.ts'] }, testsConfig), { files: ['*.html'], extends: ['plugin:@angular-eslint/template/recommended'], diff --git a/.gitignore b/.gitignore index 416fc4c1f..ebdd7f113 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ npm-debug.log* /.sass-cache /.sourcemaps /.versions -/.vscode /coverage /dist /node_modules diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..b2467c4d7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Jest All", + "program": "${workspaceFolder}/node_modules/.bin/jest", + "args": ["--runInBand"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "windows": { + "program": "${workspaceFolder}/node_modules/jest/bin/jest", + } + }, + { + "type": "node", + "request": "launch", + "name": "Jest Current File", + "program": "${workspaceFolder}/node_modules/.bin/jest", + "args": [ + "${fileBasenameNoExtension}", + "--config", + "jest.config.js" + ], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "windows": { + "program": "${workspaceFolder}/node_modules/jest/bin/jest", + } + } + ] +} diff --git a/package-lock.json b/package-lock.json index aa7eda930..a336a9a04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3849,12 +3849,6 @@ "picomatch": "^2.0.4" } }, - "app-root-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", - "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==", - "dev": true - }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -3876,16 +3870,6 @@ "sprintf-js": "~1.0.2" } }, - "aria-query": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", - "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", - "dev": true, - "requires": { - "ast-types-flow": "0.0.7", - "commander": "^2.11.0" - } - }, "arity-n": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", @@ -4059,12 +4043,6 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", - "dev": true - }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -4184,15 +4162,6 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==" }, - "axobject-query": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", - "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", - "dev": true, - "requires": { - "ast-types-flow": "0.0.7" - } - }, "babel-jest": { "version": "26.5.2", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.5.2.tgz", @@ -5291,60 +5260,6 @@ } } }, - "codelyzer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.1.tgz", - "integrity": "sha512-cOyGQgMdhnRYtW2xrJUNrNYDjEgwQ+BrE2y93Bwz3h4DJ6vJRLfupemU5N3pbYsUlBHJf0u1j1UGk+NLW4d97g==", - "dev": true, - "requires": { - "@angular/compiler": "9.0.0", - "@angular/core": "9.0.0", - "app-root-path": "^3.0.0", - "aria-query": "^3.0.0", - "axobject-query": "2.0.2", - "css-selector-tokenizer": "^0.7.1", - "cssauron": "^1.4.0", - "damerau-levenshtein": "^1.0.4", - "rxjs": "^6.5.3", - "semver-dsl": "^1.0.1", - "source-map": "^0.5.7", - "sprintf-js": "^1.1.2", - "tslib": "^1.10.0", - "zone.js": "~0.10.3" - }, - "dependencies": { - "@angular/compiler": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", - "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==", - "dev": true - }, - "@angular/core": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", - "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", - "dev": true - }, - "tslib": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz", - "integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw==", - "dev": true - } - } - }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -6559,16 +6474,6 @@ "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", "dev": true }, - "css-selector-tokenizer": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", - "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, "css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -6593,15 +6498,6 @@ "integrity": "sha512-wHOppVDKl4vTAOWzJt5Ek37Sgd9qq1Bmj/T1OjvicWbU5W7ru7Pqbn0Jdqii3Drx/h+dixHKXNhZYx7blthL7g==", "dev": true }, - "cssauron": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", - "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", - "dev": true, - "requires": { - "through": "X.X.X" - } - }, "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -6765,12 +6661,6 @@ "type": "^1.0.1" } }, - "damerau-levenshtein": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", - "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", - "dev": true - }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -7936,6 +7826,12 @@ "integrity": "sha512-C8YMhL+r8RMeMdYAw/rQtE6xNdMulj+zGWud/qIGnlmomiPRaLDGLMeskZ3alN6uMBojmooRimtdrXebLN4svQ==", "dev": true }, + "eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -8329,6 +8225,12 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz", "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=" }, + "faker": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.1.0.tgz", + "integrity": "sha512-RrWKFSSA/aNLP0g3o2WW1Zez7/MnMr7xkiZmoCfAGZmdkDQZ6l2KtuXHN5XjdvpRjDl8+3vf+Rrtl06Z352+Mw==", + "dev": true + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8363,12 +8265,6 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", - "dev": true - }, "fastq": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", @@ -15642,23 +15538,6 @@ } } }, - "semver-dsl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", - "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", - "dev": true, - "requires": { - "semver": "^5.3.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "semver-intersect": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", diff --git a/package.json b/package.json index b999cd2c8..f92313d7e 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,6 @@ "@angular/language-service": "~10.0.0", "@ionic/angular-toolkit": "^2.3.0", "@types/node": "^12.12.64", - "codelyzer": "^6.0.0", "@typescript-eslint/eslint-plugin": "4.3.0", "@typescript-eslint/parser": "4.3.0", "eslint": "^7.6.0", @@ -131,6 +130,8 @@ "eslint-plugin-jest": "^24.1.0", "eslint-plugin-jsdoc": "^30.6.3", "eslint-plugin-prefer-arrow": "^1.2.2", + "eslint-plugin-promise": "^4.2.1", + "faker": "^5.1.0", "jest": "^26.5.0", "jest-preset-angular": "^8.3.1", "ts-jest": "^26.4.1", diff --git a/src/app/classes/error.test.ts b/src/app/classes/error.test.ts new file mode 100644 index 000000000..133f5bd01 --- /dev/null +++ b/src/app/classes/error.test.ts @@ -0,0 +1,75 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import Faker from 'faker'; + +import { CoreError } from './error'; + +describe('CoreError', () => { + + it('behaves like an error', () => { + // Arrange + const message = Faker.lorem.sentence(); + + let error: CoreError | null = null; + + // Act + try { + throw new CoreError(message); + } catch (e) { + error = e; + } + + // Assert + expect(error).not.toBeNull(); + expect(error).toBeInstanceOf(Error); + expect(error).toBeInstanceOf(CoreError); + expect(error!.name).toEqual('CoreError'); + expect(error!.message).toEqual(message); + expect(error!.stack).not.toBeNull(); + expect(error!.stack).toContain('src/app/classes/error.test.ts'); + }); + + it('can be subclassed', () => { + // Arrange + class CustomCoreError extends CoreError { + + constructor(m: string) { + super(`Custom message: ${m}`); + } + + } + + const message = Faker.lorem.sentence(); + + let error: CustomCoreError | null = null; + + // Act + try { + throw new CustomCoreError(message); + } catch (e) { + error = e; + } + + // Assert + expect(error).not.toBeNull(); + expect(error).toBeInstanceOf(Error); + expect(error).toBeInstanceOf(CoreError); + expect(error).toBeInstanceOf(CustomCoreError); + expect(error!.name).toEqual('CustomCoreError'); + expect(error!.message).toEqual(`Custom message: ${message}`); + expect(error!.stack).not.toBeNull(); + expect(error!.stack).toContain('src/app/classes/error.test.ts'); + }); + +}); diff --git a/src/app/services/utils/iframe.ts b/src/app/services/utils/iframe.ts index 33c0094b9..3dae9ab13 100644 --- a/src/app/services/utils/iframe.ts +++ b/src/app/services/utils/iframe.ts @@ -13,9 +13,10 @@ // limitations under the License. import { Injectable } from '@angular/core'; +import { NavController } from '@ionic/angular'; import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript'; -import { CoreApp, CoreAppProvider } from '@services/app'; +import { CoreApp } from '@services/app'; import { CoreFile } from '@services/file'; import { CoreFileHelper } from '@services/file-helper'; import { CoreSites } from '@services/sites'; @@ -24,42 +25,35 @@ import { CoreTextUtils } from '@services/utils/text'; import { CoreUrlUtils } from '@services/utils/url'; import { CoreUtils } from '@services/utils/utils'; -import { makeSingleton, Translate, Network, Platform, NgZone } from '@singletons/core.singletons'; +import { makeSingleton, Network, Platform, NgZone } from '@singletons/core.singletons'; import { CoreLogger } from '@singletons/logger'; import { CoreUrl } from '@singletons/url'; import { CoreWindow } from '@singletons/window'; +/** + * Possible types of frame elements. + */ +type CoreFrameElement = (HTMLIFrameElement | HTMLFrameElement | HTMLObjectElement | HTMLEmbedElement) & { + window?: Window; + getWindow?(): Window; +}; + /* * "Utils" service with helper functions for iframes, embed and similar. */ @Injectable() export class CoreIframeUtilsProvider { - static FRAME_TAGS = ['iframe', 'frame', 'object', 'embed']; + + static readonly FRAME_TAGS = ['iframe', 'frame', 'object', 'embed']; protected logger: CoreLogger; constructor() { this.logger = CoreLogger.getInstance('CoreUtilsProvider'); - const win = window; - - if (CoreApp.instance.isIOS() && win.WKUserScript) { - Platform.instance.ready().then(() => { - // Inject code to the iframes because we cannot access the online ones. - const wwwPath = CoreFile.instance.getWWWAbsolutePath(); - const linksPath = CoreTextUtils.instance.concatenatePaths(wwwPath, 'assets/js/iframe-treat-links.js'); - const recaptchaPath = CoreTextUtils.instance.concatenatePaths(wwwPath, 'assets/js/iframe-recaptcha.js'); - - win.WKUserScript.addScript({id: 'CoreIframeUtilsLinksScript', file: linksPath}); - win.WKUserScript.addScript({ - id: 'CoreIframeUtilsRecaptchaScript', - file: recaptchaPath, - injectionTime: WKUserScriptInjectionTime.END, - }); - - // Handle post messages received by iframes. - window.addEventListener('message', this.handleIframeMessage.bind(this)); - }); + if (CoreApp.instance.isIOS() && 'WKUserScript' in window) { + // eslint-disable-next-line promise/catch-or-return + Platform.instance.ready().then(() => this.injectiOSScripts(window)); } } @@ -70,8 +64,8 @@ export class CoreIframeUtilsProvider { * @param isSubframe Whether it's a frame inside another frame. * @return True if frame is online and the app is offline, false otherwise. */ - checkOnlineFrameInOffline(element: any, isSubframe?: boolean): boolean { - const src = element.src || element.data; + checkOnlineFrameInOffline(element: CoreFrameElement, isSubframe?: boolean): boolean { + const src = 'src' in element ? element.src : element.data; if (src && src != 'about:blank' && !CoreUrlUtils.instance.isLocalFileUrl(src) && !CoreApp.instance.isOnline()) { if (element.classList.contains('core-iframe-offline-disabled')) { @@ -86,8 +80,6 @@ export class CoreIframeUtilsProvider { div.setAttribute('padding', ''); div.classList.add('core-iframe-offline-warning'); - const site = CoreSites.instance.getCurrentSite(); - const username = site ? site.getInfo().username : undefined; // @todo Handle link // Add a class to specify that the iframe is hidden. @@ -112,8 +104,13 @@ export class CoreIframeUtilsProvider { return true; } else if (element.classList.contains('core-iframe-offline-disabled')) { // Reload the frame. - element.src = element.src; - element.data = element.data; + if ('src' in element) { + // eslint-disable-next-line no-self-assign + element.src = element.src; + } else { + // eslint-disable-next-line no-self-assign + element.data = element.data; + } // Remove the warning and show the iframe CoreDomUtils.instance.removeElement(element.parentElement, 'div.core-iframe-offline-warning'); @@ -134,12 +131,14 @@ export class CoreIframeUtilsProvider { * @param element Element to treat (iframe, embed, ...). * @return Window and Document. */ - getContentWindowAndDocument(element: any): { window: Window, document: Document } { - let contentWindow: Window = element.contentWindow; + getContentWindowAndDocument(element: CoreFrameElement): { window: Window; document: Document } { + let contentWindow: Window = 'contentWindow' in element ? element.contentWindow : undefined; let contentDocument: Document; try { - contentDocument = element.contentDocument || (contentWindow && contentWindow.document); + contentDocument = 'contentDocument' in element && element.contentDocument + ? element.contentDocument + : contentWindow && contentWindow.document; } catch (ex) { // Ignore errors. } @@ -149,7 +148,7 @@ export class CoreIframeUtilsProvider { contentWindow = contentDocument.defaultView; } - if (!contentWindow && element.getSVGDocument) { + if (!contentWindow && 'getSVGDocument' in element) { // It's probably an . Try to get the window and the document. try { contentDocument = element.getSVGDocument(); @@ -187,9 +186,6 @@ export class CoreIframeUtilsProvider { case 'link_clicked': this.linkClicked(event.data.link); break; - - default: - break; } } @@ -202,10 +198,15 @@ export class CoreIframeUtilsProvider { * @param contentDocument The document of the element contents. * @param navCtrl NavController to use if a link can be opened in the app. */ - redefineWindowOpen(element: any, contentWindow: Window, contentDocument: Document, navCtrl?: any): void { + redefineWindowOpen( + element: CoreFrameElement, + contentWindow: Window, + contentDocument: Document, + navCtrl?: NavController, + ): void { if (contentWindow) { // Intercept window.open. - ( contentWindow).open = (url: string, name: string): Window => { + contentWindow.open = (url: string, name: string) => { this.windowOpen(url, name, element, navCtrl); return null; @@ -216,7 +217,7 @@ export class CoreIframeUtilsProvider { // Search sub frames. CoreIframeUtilsProvider.FRAME_TAGS.forEach((tag) => { const elements = Array.from(contentDocument.querySelectorAll(tag)); - elements.forEach((subElement) => { + elements.forEach((subElement: CoreFrameElement) => { this.treatFrame(subElement, true, navCtrl); }); }); @@ -231,7 +232,7 @@ export class CoreIframeUtilsProvider { * @param isSubframe Whether it's a frame inside another frame. * @param navCtrl NavController to use if a link can be opened in the app. */ - treatFrame(element: any, isSubframe?: boolean, navCtrl?: any): void { + treatFrame(element: CoreFrameElement, isSubframe?: boolean, navCtrl?: NavController): void { if (element) { this.checkOnlineFrameInOffline(element, isSubframe); @@ -266,7 +267,7 @@ export class CoreIframeUtilsProvider { * @param element Element to treat (iframe, embed, ...). * @param contentDocument The document of the element contents. */ - treatFrameLinks(element: any, contentDocument: Document): void { + treatFrameLinks(element: CoreFrameElement, contentDocument: Document): void { if (!contentDocument) { return; } @@ -292,7 +293,7 @@ export class CoreIframeUtilsProvider { link.treated = true; link.addEventListener('click', this.linkClicked.bind(this, link, element)); }, { - capture: true // Use capture to fix this listener not called if the element clicked is too deep in the DOM. + capture: true, // Use capture to fix this listener not called if the element clicked is too deep in the DOM. }); } @@ -305,11 +306,13 @@ export class CoreIframeUtilsProvider { * @param navCtrl NavController to use if a link can be opened in the app. * @return Promise resolved when done. */ - protected async windowOpen(url: string, name: string, element?: any, navCtrl?: any): Promise { + protected async windowOpen(url: string, name: string, element?: CoreFrameElement, navCtrl?: NavController): Promise { const scheme = CoreUrlUtils.instance.getUrlScheme(url); if (!scheme) { // It's a relative URL, use the frame src to create the full URL. - const src = element && (element.src || element.data); + const src = element + ? ('src' in element ? element.src : element.data) + : null; if (src) { const dirAndFile = CoreFile.instance.getFileAndDirectoryFromPath(src); if (dirAndFile.directory) { @@ -372,8 +375,11 @@ export class CoreIframeUtilsProvider { * @param event Click event. * @return Promise resolved when done. */ - protected async linkClicked(link: {href: string, target?: string}, element?: HTMLFrameElement | HTMLObjectElement, - event?: Event): Promise { + protected async linkClicked( + link: {href: string; target?: string}, + element?: HTMLFrameElement | HTMLObjectElement, + event?: Event, + ): Promise { if (event && event.defaultPrevented) { // Event already prevented by some other code. return; @@ -438,6 +444,28 @@ export class CoreIframeUtilsProvider { } } } + + /** + * Inject code to the iframes because we cannot access the online ones. + * + * @param userScriptWindow Window. + */ + private injectiOSScripts(userScriptWindow: WKUserScriptWindow) { + const wwwPath = CoreFile.instance.getWWWAbsolutePath(); + const linksPath = CoreTextUtils.instance.concatenatePaths(wwwPath, 'assets/js/iframe-treat-links.js'); + const recaptchaPath = CoreTextUtils.instance.concatenatePaths(wwwPath, 'assets/js/iframe-recaptcha.js'); + + userScriptWindow.WKUserScript.addScript({ id: 'CoreIframeUtilsLinksScript', file: linksPath }); + userScriptWindow.WKUserScript.addScript({ + id: 'CoreIframeUtilsRecaptchaScript', + file: recaptchaPath, + injectionTime: WKUserScriptInjectionTime.END, + }); + + // Handle post messages received by iframes. + window.addEventListener('message', this.handleIframeMessage.bind(this)); + } + } export class CoreIframeUtils extends makeSingleton(CoreIframeUtilsProvider) {} diff --git a/src/app/services/utils/mimetype.ts b/src/app/services/utils/mimetype.ts index 9437ce74d..06588c49e 100644 --- a/src/app/services/utils/mimetype.ts +++ b/src/app/services/utils/mimetype.ts @@ -13,36 +13,55 @@ // limitations under the License. import { Injectable } from '@angular/core'; +import { FileEntry } from '@ionic-native/file'; import { CoreFile } from '@services/file'; import { CoreTextUtils } from '@services/utils/text'; import { makeSingleton, Translate, Http } from '@singletons/core.singletons'; import { CoreLogger } from '@singletons/logger'; +import { CoreWSExternalFile } from '@services/ws'; +import { CoreUtils } from '@services/utils/utils'; + +interface MimeTypeInfo { + type: string; + icon?: string; + groups?: string[]; + + // eslint-disable-next-line id-blacklist + string?: string; +} + +interface MimeTypeGroupInfo { + mimetypes: string[]; + extensions: string[]; +} + +const EXTENSION_REGEX = /^[a-z0-9]+$/; /* * "Utils" service with helper functions for mimetypes and extensions. */ @Injectable() export class CoreMimetypeUtilsProvider { + protected logger: CoreLogger; - protected extToMime = {}; // Object to map extensions -> mimetypes. - protected mimeToExt = {}; // Object to map mimetypes -> extensions. - protected groupsMimeInfo = {}; // Object to hold extensions and mimetypes that belong to a certain "group" (audio, video, ...). - protected extensionRegex = /^[a-z0-9]+$/; + protected extToMime: Record = {}; + protected mimeToExt: Record = {}; + protected groupsMimeInfo: Record = {}; constructor() { this.logger = CoreLogger.getInstance('CoreMimetypeUtilsProvider'); - Http.instance.get('assets/exttomime.json').subscribe((result) => { + Http.instance.get('assets/exttomime.json').subscribe((result: Record) => { this.extToMime = result; - }, (err) => { + }, () => { // Error, shouldn't happen. }); - Http.instance.get('assets/mimetoext.json').subscribe((result) => { + Http.instance.get('assets/mimetoext.json').subscribe((result: Record) => { this.mimeToExt = result; - }, (err) => { - // Error, shouldn't happen. + }, () => { + // Error, shouldn't happen }); } @@ -148,31 +167,38 @@ export class CoreMimetypeUtilsProvider { * Set the embed type to display an embedded file and mimetype if not found. * * @param file File object. - * @paran path Alternative path that will override fileurl from file object. + * @param path Alternative path that will override fileurl from file object. */ - getEmbeddedHtml(file: any, path?: string): string { - let ext; - const filename = file.filename || file.name; + getEmbeddedHtml(file: CoreWSExternalFile | FileEntry, path?: string): string { + const filename = CoreUtils.instance.isFileEntry(file) ? (file as FileEntry).name : file.filename; + const extension = !CoreUtils.instance.isFileEntry(file) && file.mimetype + ? this.getExtension(file.mimetype) + : this.getFileExtension(filename); + const mimeType = !CoreUtils.instance.isFileEntry(file) && file.mimetype ? file.mimetype : this.getMimeType(extension); - if (file.mimetype) { - ext = this.getExtension(file.mimetype); - } else { - ext = this.getFileExtension(filename); - file.mimetype = this.getMimeType(ext); - } + // @todo linting: See if this can be removed + (file as CoreWSExternalFile).mimetype = mimeType; - if (this.canBeEmbedded(ext)) { - file.embedType = this.getExtensionType(ext); + if (this.canBeEmbedded(extension)) { + const embedType = this.getExtensionType(extension); - path = CoreFile.instance.convertFileSrc(path || file.fileurl || file.url || (file.toURL && file.toURL())); + // @todo linting: See if this can be removed + (file as { embedType: string }).embedType = embedType; - if (file.embedType == 'image') { - return ''; - } - if (file.embedType == 'audio' || file.embedType == 'video') { - return '<' + file.embedType + ' controls title="' + filename + '" src="' + path + '">' + - '' + - ''; + path = CoreFile.instance.convertFileSrc(path ?? (CoreUtils.instance.isFileEntry(file) ? file.toURL() : file.fileurl)); + + switch (embedType) { + case 'image': + return ``; + case 'audio': + case 'video': + return [ + `<${embedType} controls title="${filename}" src="${path}">`, + ``, + ``, + ].join(''); + default: + return ''; } } @@ -290,7 +316,7 @@ export class CoreMimetypeUtilsProvider { candidate = candidate.substr(0, position); } - if (this.extensionRegex.test(candidate)) { + if (EXTENSION_REGEX.test(candidate)) { extension = candidate; } } @@ -338,7 +364,7 @@ export class CoreMimetypeUtilsProvider { * @param field The field to get. If not supplied, all the info will be returned. * @return Info for the group. */ - getGroupMimeInfo(group: string, field?: string): any { + getGroupMimeInfo(group: string, field?: string): MimeTypeGroupInfo { if (typeof this.groupsMimeInfo[group] == 'undefined') { this.fillGroupMimeInfo(group); } @@ -372,13 +398,13 @@ export class CoreMimetypeUtilsProvider { * @param capitalise If true, capitalises first character of result. * @return Type description. */ - getMimetypeDescription(obj: any, capitalise?: boolean): string { + getMimetypeDescription(obj: FileEntry | { filename: string; mimetype: string } | string, capitalise?: boolean): string { const langPrefix = 'assets.mimetypes.'; let filename = ''; let mimetype = ''; let extension = ''; - if (typeof obj == 'object' && typeof obj.file == 'function') { + if (typeof obj == 'object' && CoreUtils.instance.isFileEntry(obj)) { // It's a FileEntry. Don't use the file function because it's asynchronous and the type isn't reliable. filename = obj.name; } else if (typeof obj == 'object') { @@ -548,6 +574,7 @@ export class CoreMimetypeUtilsProvider { return path; } + } export class CoreMimetypeUtils extends makeSingleton(CoreMimetypeUtilsProvider) {} diff --git a/src/app/services/utils/text.ts b/src/app/services/utils/text.ts index e6b6745ce..30ce8fb26 100644 --- a/src/app/services/utils/text.ts +++ b/src/app/services/utils/text.ts @@ -18,6 +18,8 @@ import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; import { CoreApp } from '@services/app'; import { CoreLang } from '@services/lang'; import { makeSingleton, Translate } from '@singletons/core.singletons'; +import { CoreWSExternalFile } from '@services/ws'; +import { Locutus } from '@singletons/locutus'; /** * Different type of errors the app can treat. @@ -36,53 +38,53 @@ export type CoreTextErrorObject = { export class CoreTextUtilsProvider { // List of regular expressions to convert the old nomenclature to new nomenclature for disabled features. - protected DISABLED_FEATURES_COMPAT_REGEXPS = [ - {old: /\$mmLoginEmailSignup/g, new: 'CoreLoginEmailSignup'}, - {old: /\$mmSideMenuDelegate/g, new: 'CoreMainMenuDelegate'}, - {old: /\$mmCoursesDelegate/g, new: 'CoreCourseOptionsDelegate'}, - {old: /\$mmUserDelegate/g, new: 'CoreUserDelegate'}, - {old: /\$mmCourseDelegate/g, new: 'CoreCourseModuleDelegate'}, - {old: /_mmCourses/g, new: '_CoreCourses'}, - {old: /_mmaFrontpage/g, new: '_CoreSiteHome'}, - {old: /_mmaGrades/g, new: '_CoreGrades'}, - {old: /_mmaCompetency/g, new: '_AddonCompetency'}, - {old: /_mmaNotifications/g, new: '_AddonNotifications'}, - {old: /_mmaMessages/g, new: '_AddonMessages'}, - {old: /_mmaCalendar/g, new: '_AddonCalendar'}, - {old: /_mmaFiles/g, new: '_AddonFiles'}, - {old: /_mmaParticipants/g, new: '_CoreUserParticipants'}, - {old: /_mmaCourseCompletion/g, new: '_AddonCourseCompletion'}, - {old: /_mmaNotes/g, new: '_AddonNotes'}, - {old: /_mmaBadges/g, new: '_AddonBadges'}, - {old: /files_privatefiles/g, new: 'AddonFilesPrivateFiles'}, - {old: /files_sitefiles/g, new: 'AddonFilesSiteFiles'}, - {old: /files_upload/g, new: 'AddonFilesUpload'}, - {old: /_mmaModAssign/g, new: '_AddonModAssign'}, - {old: /_mmaModBook/g, new: '_AddonModBook'}, - {old: /_mmaModChat/g, new: '_AddonModChat'}, - {old: /_mmaModChoice/g, new: '_AddonModChoice'}, - {old: /_mmaModData/g, new: '_AddonModData'}, - {old: /_mmaModFeedback/g, new: '_AddonModFeedback'}, - {old: /_mmaModFolder/g, new: '_AddonModFolder'}, - {old: /_mmaModForum/g, new: '_AddonModForum'}, - {old: /_mmaModGlossary/g, new: '_AddonModGlossary'}, - {old: /_mmaModH5pactivity/g, new: '_AddonModH5PActivity'}, - {old: /_mmaModImscp/g, new: '_AddonModImscp'}, - {old: /_mmaModLabel/g, new: '_AddonModLabel'}, - {old: /_mmaModLesson/g, new: '_AddonModLesson'}, - {old: /_mmaModLti/g, new: '_AddonModLti'}, - {old: /_mmaModPage/g, new: '_AddonModPage'}, - {old: /_mmaModQuiz/g, new: '_AddonModQuiz'}, - {old: /_mmaModResource/g, new: '_AddonModResource'}, - {old: /_mmaModScorm/g, new: '_AddonModScorm'}, - {old: /_mmaModSurvey/g, new: '_AddonModSurvey'}, - {old: /_mmaModUrl/g, new: '_AddonModUrl'}, - {old: /_mmaModWiki/g, new: '_AddonModWiki'}, - {old: /_mmaModWorkshop/g, new: '_AddonModWorkshop'}, - {old: /remoteAddOn_/g, new: 'sitePlugin_'}, + protected readonly DISABLED_FEATURES_COMPAT_REGEXPS: { old: RegExp; new: string }[] = [ + { old: /\$mmLoginEmailSignup/g, new: 'CoreLoginEmailSignup' }, + { old: /\$mmSideMenuDelegate/g, new: 'CoreMainMenuDelegate' }, + { old: /\$mmCoursesDelegate/g, new: 'CoreCourseOptionsDelegate' }, + { old: /\$mmUserDelegate/g, new: 'CoreUserDelegate' }, + { old: /\$mmCourseDelegate/g, new: 'CoreCourseModuleDelegate' }, + { old: /_mmCourses/g, new: '_CoreCourses' }, + { old: /_mmaFrontpage/g, new: '_CoreSiteHome' }, + { old: /_mmaGrades/g, new: '_CoreGrades' }, + { old: /_mmaCompetency/g, new: '_AddonCompetency' }, + { old: /_mmaNotifications/g, new: '_AddonNotifications' }, + { old: /_mmaMessages/g, new: '_AddonMessages' }, + { old: /_mmaCalendar/g, new: '_AddonCalendar' }, + { old: /_mmaFiles/g, new: '_AddonFiles' }, + { old: /_mmaParticipants/g, new: '_CoreUserParticipants' }, + { old: /_mmaCourseCompletion/g, new: '_AddonCourseCompletion' }, + { old: /_mmaNotes/g, new: '_AddonNotes' }, + { old: /_mmaBadges/g, new: '_AddonBadges' }, + { old: /files_privatefiles/g, new: 'AddonFilesPrivateFiles' }, + { old: /files_sitefiles/g, new: 'AddonFilesSiteFiles' }, + { old: /files_upload/g, new: 'AddonFilesUpload' }, + { old: /_mmaModAssign/g, new: '_AddonModAssign' }, + { old: /_mmaModBook/g, new: '_AddonModBook' }, + { old: /_mmaModChat/g, new: '_AddonModChat' }, + { old: /_mmaModChoice/g, new: '_AddonModChoice' }, + { old: /_mmaModData/g, new: '_AddonModData' }, + { old: /_mmaModFeedback/g, new: '_AddonModFeedback' }, + { old: /_mmaModFolder/g, new: '_AddonModFolder' }, + { old: /_mmaModForum/g, new: '_AddonModForum' }, + { old: /_mmaModGlossary/g, new: '_AddonModGlossary' }, + { old: /_mmaModH5pactivity/g, new: '_AddonModH5PActivity' }, + { old: /_mmaModImscp/g, new: '_AddonModImscp' }, + { old: /_mmaModLabel/g, new: '_AddonModLabel' }, + { old: /_mmaModLesson/g, new: '_AddonModLesson' }, + { old: /_mmaModLti/g, new: '_AddonModLti' }, + { old: /_mmaModPage/g, new: '_AddonModPage' }, + { old: /_mmaModQuiz/g, new: '_AddonModQuiz' }, + { old: /_mmaModResource/g, new: '_AddonModResource' }, + { old: /_mmaModScorm/g, new: '_AddonModScorm' }, + { old: /_mmaModSurvey/g, new: '_AddonModSurvey' }, + { old: /_mmaModUrl/g, new: '_AddonModUrl' }, + { old: /_mmaModWiki/g, new: '_AddonModWiki' }, + { old: /_mmaModWorkshop/g, new: '_AddonModWorkshop' }, + { old: /remoteAddOn_/g, new: 'sitePlugin_' }, ]; - protected template = document.createElement('template'); // A template element to convert HTML to element. + protected template: HTMLTemplateElement = document.createElement('template'); // A template element to convert HTML to element. constructor(private sanitizer: DomSanitizer) { } @@ -200,7 +202,6 @@ export class CoreTextUtilsProvider { * @return Size in human readable format. */ bytesToSize(bytes: number, precision: number = 2): string { - if (typeof bytes == 'undefined' || bytes === null || bytes < 0) { return Translate.instance.instant('core.notapplicable'); } @@ -449,9 +450,17 @@ export class CoreTextUtilsProvider { * @param courseId Course ID the text belongs to. It can be used to improve performance with filters. * @deprecated since 3.8.3. Please use viewText instead. */ - expandText(title: string, text: string, component?: string, componentId?: string | number, files?: any[], - filter?: boolean, contextLevel?: string, instanceId?: number, courseId?: number): void { - + expandText( + title: string, + text: string, + component?: string, + componentId?: string | number, + files?: CoreWSExternalFile[], + filter?: boolean, + contextLevel?: string, + instanceId?: number, + courseId?: number, + ): void { return this.viewText(title, text, { component, componentId, @@ -531,12 +540,12 @@ export class CoreTextUtilsProvider { * @param files Files to extract the URL from. They need to have the URL in a 'url' or 'fileurl' attribute. * @return Pluginfile URL, undefined if no files found. */ - getTextPluginfileUrl(files: any[]): string { + getTextPluginfileUrl(files: CoreWSExternalFile[]): string { if (files && files.length) { - const fileURL = files[0].url || files[0].fileurl; + const url = files[0].fileurl; // Remove text after last slash (encoded or not). - return fileURL.substr(0, Math.max(fileURL.lastIndexOf('/'), fileURL.lastIndexOf('%2F'))); + return url.substr(0, Math.max(url.lastIndexOf('/'), url.lastIndexOf('%2F'))); } return undefined; @@ -610,13 +619,17 @@ export class CoreTextUtilsProvider { * @param data Object to be checked. * @return If the data has any long Unicode char on it. */ - hasUnicodeData(data: object): boolean { + hasUnicodeData(data: Record): boolean { for (const el in data) { if (typeof data[el] == 'object') { - if (this.hasUnicodeData(data[el])) { + if (this.hasUnicodeData(data[el] as Record)) { return true; } - } else if (typeof data[el] == 'string' && this.hasUnicode(data[el])) { + + continue; + } + + if (typeof data[el] == 'string' && this.hasUnicode(data[el] as string)) { return true; } } @@ -628,17 +641,17 @@ export class CoreTextUtilsProvider { * Same as Javascript's JSON.parse, but it will handle errors. * * @param json JSON text. - * @param defaultValue Default value t oreturn if the parse fails. Defaults to the original value. + * @param defaultValue Default value to return if the parse fails. Defaults to the original value. * @param logErrorFn An error to call with the exception to log the error. If not supplied, no error. * @return JSON parsed as object or what it gets. */ - parseJSON(json: string, defaultValue?: any, logErrorFn?: (error?: any) => void): any { + parseJSON(json: string, defaultValue?: T, logErrorFn?: (error?: Error) => void): T | string { try { return JSON.parse(json); - } catch (ex) { + } catch (error) { // Error, log the error if needed. if (logErrorFn) { - logErrorFn(ex); + logErrorFn(error); } } @@ -675,7 +688,7 @@ export class CoreTextUtilsProvider { return ''; } - return text.replace(/[#:\/\?\\]+/g, '_'); + return text.replace(/[#:/?\\]+/g, '_'); } /** @@ -700,7 +713,7 @@ export class CoreTextUtilsProvider { * @param files Files to extract the pluginfile URL from. They need to have the URL in a url or fileurl attribute. * @return Treated text. */ - replacePluginfileUrls(text: string, files: any[]): string { + replacePluginfileUrls(text: string, files: CoreWSExternalFile[]): string { if (text && typeof text == 'string') { const fileURL = this.getTextPluginfileUrl(files); if (fileURL) { @@ -718,7 +731,7 @@ export class CoreTextUtilsProvider { * @param files Files to extract the pluginfile URL from. They need to have the URL in a url or fileurl attribute. * @return Treated text. */ - restorePluginfileUrls(text: string, files: any[]): string { + restorePluginfileUrls(text: string, files: CoreWSExternalFile[]): string { if (text && typeof text == 'string') { const fileURL = this.getTextPluginfileUrl(files); if (fileURL) { @@ -804,7 +817,6 @@ export class CoreTextUtilsProvider { /** * Replace text within a portion of a string. Equivalent to PHP's substr_replace. - * Credits to http://locutus.io/php/strings/substr_replace/ * * @param str The string to treat. * @param replace The value to put inside the string. @@ -814,22 +826,7 @@ export class CoreTextUtilsProvider { * @return Treated string. */ substrReplace(str: string, replace: string, start: number, length?: number): string { - length = typeof length != 'undefined' ? length : str.length; - - if (start < 0) { - start = start + str.length; - } - - if (length < 0) { - length = length + str.length - start; - } - - return [ - str.slice(0, start), - replace.substr(0, length), - replace.slice(length), - str.slice(start + length) - ].join(''); + return Locutus.substrReplace(str, replace, start, length); } /** @@ -867,14 +864,14 @@ export class CoreTextUtilsProvider { return CoreLang.instance.getCurrentLanguage().then((language) => { // Match the current language. const anyLangRegEx = /<(?:lang|span)[^>]+lang="[a-zA-Z0-9_-]+"[^>]*>(.*?)<\/(?:lang|span)>/g; - let currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)<\/(?:lang|span)>', 'g'); + let currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)', 'g'); if (!text.match(currentLangRegEx)) { // Current lang not found. Try to find the first language. const matches = text.match(anyLangRegEx); if (matches && matches[0]) { language = matches[0].match(/lang="([a-zA-Z0-9_-]+)"/)[1]; - currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)<\/(?:lang|span)>', 'g'); + currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)', 'g'); } else { // No multi-lang tag found, stop. return text; @@ -915,221 +912,12 @@ export class CoreTextUtilsProvider { /** * Unserialize Array from PHP. - * Taken from: https://github.com/kvz/locutus/blob/master/src/php/var/unserialize.js * * @param data String to unserialize. - * @param logErrorFn An error to call with the exception to log the error. If not supplied, no error. * @return Unserialized data. */ - unserialize(data: string, logErrorFn?: (error?: string) => void): any { - // Discuss at: http://locutus.io/php/unserialize/ - // Original by: Arpad Ray (mailto:arpad@php.net) - // Improved by: Pedro Tainha (http://www.pedrotainha.com) - // Improved by: Kevin van Zonneveld (http://kvz.io) - // Improved by: Kevin van Zonneveld (http://kvz.io) - // Improved by: Chris - // Improved by: James - // Improved by: Le Torbi - // Improved by: Eli Skeggs - // Bugfixed by: dptr1988 - // Bugfixed by: Kevin van Zonneveld (http://kvz.io) - // Bugfixed by: Brett Zamir (http://brett-zamir.me) - // Bugfixed by: philippsimon (https://github.com/philippsimon/) - // Revised by: d3x - // Input by: Brett Zamir (http://brett-zamir.me) - // Input by: Martin (http://www.erlenwiese.de/) - // Input by: kilops - // Input by: Jaroslaw Czarniak - // Input by: lovasoa (https://github.com/lovasoa/) - // Note 1: We feel the main purpose of this function should be - // Note 1: to ease the transport of data between php & js - // Note 1: Aiming for PHP-compatibility, we have to translate objects to arrays - // Example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}') - // Returns 1: ['Kevin', 'van', 'Zonneveld'] - // Example 2: unserialize('a:2:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";}') - // Returns 2: {firstName: 'Kevin', midName: 'van'} - // Example 3: unserialize('a:3:{s:2:"ü";s:2:"ü";s:3:"四";s:3:"四";s:4:"𠜎";s:4:"𠜎";}') - // Returns 3: {'ü': 'ü', '四': '四', '𠜎': '𠜎'} - - const utf8Overhead = (str: string): number => { - let s = str.length; - - for (let i = str.length - 1; i >= 0; i--) { - const code = str.charCodeAt(i); - if (code > 0x7f && code <= 0x7ff) { - s++; - } else if (code > 0x7ff && code <= 0xffff) { - s += 2; - } - // Trail surrogate. - if (code >= 0xDC00 && code <= 0xDFFF) { - i--; - } - } - - return s - 1; - }; - - const error = (type: string, msg: string): void => { - if (logErrorFn) { - logErrorFn(type + msg); - } - }; - - const readUntil = (data: string, offset: number, stopchr: string): Array => { - let i = 2; - const buf = []; - let chr = data.slice(offset, offset + 1); - - while (chr !== stopchr) { - if ((i + offset) > data.length) { - error('Error', 'Invalid'); - } - buf.push(chr); - chr = data.slice(offset + (i - 1), offset + i); - i += 1; - } - - return [buf.length, buf.join('')]; - }; - - const readChrs = (data: string, offset: number, length: number): Array => { - let chr; - const buf = []; - - for (let i = 0; i < length; i++) { - chr = data.slice(offset + (i - 1), offset + i); - buf.push(chr); - length -= utf8Overhead(chr); - } - - return [buf.length, buf.join('')]; - }; - - const _unserialize = (data: string, offset: number): any => { - let dtype, - dataoffset, - keyandchrs, - keys, - contig, - length, - array, - readdata, - readData, - ccount, - stringlength, - i, - key, - kprops, - kchrs, - vprops, - vchrs, - value, - chrs = 0, - typeconvert = (x: any): any => { - return x; - }; - - if (!offset) { - offset = 0; - } - dtype = (data.slice(offset, offset + 1)).toLowerCase(); - - dataoffset = offset + 2; - - switch (dtype) { - case 'i': - typeconvert = (x: any): number => { - return parseInt(x, 10); - }; - readData = readUntil(data, dataoffset, ';'); - chrs = readData[0]; - readdata = readData[1]; - dataoffset += chrs + 1; - break; - case 'b': - typeconvert = (x: any): boolean => { - return parseInt(x, 10) !== 0; - }; - readData = readUntil(data, dataoffset, ';'); - chrs = readData[0]; - readdata = readData[1]; - dataoffset += chrs + 1; - break; - case 'd': - typeconvert = (x: any): number => { - return parseFloat(x); - }; - readData = readUntil(data, dataoffset, ';'); - chrs = readData[0]; - readdata = readData[1]; - dataoffset += chrs + 1; - break; - case 'n': - readdata = null; - break; - case 's': - ccount = readUntil(data, dataoffset, ':'); - chrs = ccount[0]; - stringlength = ccount[1]; - dataoffset += chrs + 2; - - readData = readChrs(data, dataoffset + 1, parseInt(stringlength, 10)); - chrs = readData[0]; - readdata = readData[1]; - dataoffset += chrs + 2; - if (chrs !== parseInt(stringlength, 10) && chrs !== readdata.length) { - error('SyntaxError', 'String length mismatch'); - } - break; - case 'a': - readdata = {}; - - keyandchrs = readUntil(data, dataoffset, ':'); - chrs = keyandchrs[0]; - keys = keyandchrs[1]; - dataoffset += chrs + 2; - - length = parseInt(keys, 10); - contig = true; - - for (let i = 0; i < length; i++) { - kprops = _unserialize(data, dataoffset); - kchrs = kprops[1]; - key = kprops[2]; - dataoffset += kchrs; - - vprops = _unserialize(data, dataoffset); - vchrs = vprops[1]; - value = vprops[2]; - dataoffset += vchrs; - - if (key !== i) { - contig = false; - } - - readdata[key] = value; - } - - if (contig) { - array = new Array(length); - for (i = 0; i < length; i++) { - array[i] = readdata[i]; - } - readdata = array; - } - - dataoffset += 1; - break; - default: - error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype); - break; - } - - return [dtype, dataoffset - offset, typeconvert(readdata)]; - }; - - return _unserialize((data + ''), 0)[2]; + unserialize(data: string): T { + return Locutus.unserialize(data); } /** @@ -1138,16 +926,13 @@ export class CoreTextUtilsProvider { * @param title Title of the new state. * @param text Content of the text to be expanded. * @param component Component to link the embedded files to. - * @param componentId An ID to use in conjunction with the component. - * @param files List of files to display along with the text. - * @param filter Whether the text should be filtered. - * @param contextLevel The context level. - * @param instanceId The instance ID related to the context. - * @param courseId Course ID the text belongs to. It can be used to improve performance with filters. + * @param options Options. */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars viewText(title: string, text: string, options?: CoreTextUtilsViewTextOptions): void { // @todo } + } /** @@ -1156,7 +941,7 @@ export class CoreTextUtilsProvider { export type CoreTextUtilsViewTextOptions = { component?: string; // Component to link the embedded files to. componentId?: string | number; // An ID to use in conjunction with the component. - files?: any[]; // List of files to display along with the text. + files?: CoreWSExternalFile[]; // List of files to display along with the text. filter?: boolean; // Whether the text should be filtered. contextLevel?: string; // The context level. instanceId?: number; // The instance ID related to the context. diff --git a/src/app/services/utils/utils.ts b/src/app/services/utils/utils.ts index b59b8d3b1..c61f367b4 100644 --- a/src/app/services/utils/utils.ts +++ b/src/app/services/utils/utils.ts @@ -13,44 +13,43 @@ // limitations under the License. import { Injectable, NgZone } from '@angular/core'; -import { InAppBrowserObject } from '@ionic-native/in-app-browser'; +import { InAppBrowserObject, InAppBrowserOptions } from '@ionic-native/in-app-browser'; +import { FileEntry } from '@ionic-native/file'; import { Subscription } from 'rxjs'; import { CoreApp } from '@services/app'; import { CoreEvents, CoreEventsProvider } from '@services/events'; import { CoreFile } from '@services/file'; import { CoreLang } from '@services/lang'; -import { CoreWS, CoreWSError } from '@services/ws'; +import { CoreWS, CoreWSError, CoreWSExternalFile } from '@services/ws'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreTextUtils } from '@services/utils/text'; import { - makeSingleton, Clipboard, InAppBrowser, Platform, FileOpener, WebIntent, QRScanner, Translate + makeSingleton, Clipboard, InAppBrowser, Platform, FileOpener, WebIntent, QRScanner, Translate, } from '@singletons/core.singletons'; import { CoreLogger } from '@singletons/logger'; +type TreeNode = T & { children: TreeNode[] }; + /* * "Utils" service with helper functions. */ @Injectable() export class CoreUtilsProvider { - protected DONT_CLONE = ['[object FileEntry]', '[object DirectoryEntry]', '[object DOMFileSystem]']; + + protected readonly DONT_CLONE = ['[object FileEntry]', '[object DirectoryEntry]', '[object DOMFileSystem]']; + protected logger: CoreLogger; protected iabInstance: InAppBrowserObject; protected uniqueIds: {[name: string]: number} = {}; - protected qrScanData: {deferred: PromiseDefer, observable: Subscription}; + protected qrScanData: {deferred: PromiseDefer; observable: Subscription}; constructor(protected zone: NgZone) { this.logger = CoreLogger.getInstance('CoreUtilsProvider'); - Platform.instance.ready().then(() => { - const win = window; - - if (win.cordova && win.cordova.InAppBrowser) { - // Override the default window.open with the InAppBrowser one. - win.open = win.cordova.InAppBrowser.open; - } - }); + // eslint-disable-next-line promise/catch-or-return + Platform.instance.ready().then(() => this.overrideWindowOpen()); } /** @@ -60,7 +59,7 @@ export class CoreUtilsProvider { * @param defaultError Message to show if the error is not a string. * @return New error message. */ - addDataNotDownloadedError(error: any, defaultError?: string): string { + addDataNotDownloadedError(error: Error | string, defaultError?: string): string { let errorMessage = error; if (error && typeof error != 'string') { @@ -73,7 +72,7 @@ export class CoreUtilsProvider { if (!this.isWebServiceError(error)) { // Local error. Add an extra warning. - errorMessage += '

' + Translate.instance.instant('core.errorsomedatanotdownloaded'); + errorMessage += '

' + Translate.instance.instant('core.errorsomedatanotdownloaded'); } return errorMessage; @@ -85,35 +84,25 @@ export class CoreUtilsProvider { * @param promises Promises. * @return Promise resolved if all promises are resolved and rejected if at least 1 promise fails. */ - allPromises(promises: Promise[]): Promise { + async allPromises(promises: Promise[]): Promise { if (!promises || !promises.length) { return Promise.resolve(); } - return new Promise((resolve, reject): void => { - const total = promises.length; - let count = 0; - let hasFailed = false; - let error; + const getPromiseError = async (promise): Promise => { + try { + await promise; + } catch (error) { + return error; + } + }; - promises.forEach((promise) => { - promise.catch((err) => { - hasFailed = true; - error = err; - }).finally(() => { - count++; + const errors = await Promise.all(promises.map(getPromiseError)); + const error = errors.find(error => !!error); - if (count === total) { - // All promises have finished, reject/resolve. - if (hasFailed) { - reject(error); - } else { - resolve(); - } - } - }); - }); - }); + if (error) { + throw error; + } } /** @@ -126,7 +115,7 @@ export class CoreUtilsProvider { * @param result Object where to put the properties. If not defined, a new object will be created. * @return The object. */ - arrayToObject(array: any[], propertyName?: string, result?: any): any { + arrayToObject(array: unknown[], propertyName?: string, result?: unknown): unknown { result = result || {}; array.forEach((entry) => { const key = propertyName ? entry[propertyName] : entry; @@ -148,7 +137,13 @@ export class CoreUtilsProvider { * @param undefinedIsNull True if undefined is equal to null. Defaults to true. * @return Whether both items are equal. */ - basicLeftCompare(itemA: any, itemB: any, maxLevels: number = 0, level: number = 0, undefinedIsNull: boolean = true): boolean { + basicLeftCompare( + itemA: any, // eslint-disable-line @typescript-eslint/no-explicit-any + itemB: any, // eslint-disable-line @typescript-eslint/no-explicit-any + maxLevels: number = 0, + level: number = 0, + undefinedIsNull: boolean = true, + ): boolean { if (typeof itemA == 'function' || typeof itemB == 'function') { return true; // Don't compare functions. } else if (typeof itemA == 'object' && typeof itemB == 'object') { @@ -190,6 +185,7 @@ export class CoreUtilsProvider { /** * Blocks leaving a view. + * * @deprecated, use ionViewCanLeave instead. */ blockLeaveView(): void { @@ -202,35 +198,33 @@ export class CoreUtilsProvider { * @param url The URL to check. * @return Promise resolved with boolean_ whether there is a redirect. */ - checkRedirect(url: string): Promise { - if (window.fetch) { - const win = window; // Convert to to be able to use AbortController (not supported by our TS version). - const initOptions: any = { - redirect: 'follow', - }; - let controller; + async checkRedirect(url: string): Promise { + if (!window.fetch) { + // Cannot check if there is a redirect, assume it's false. + return false; + } - // Some browsers implement fetch but no AbortController. - if (win.AbortController) { - controller = new win.AbortController(); - initOptions.signal = controller.signal; + const initOptions: RequestInit = { redirect: 'follow' }; + + // Some browsers implement fetch but no AbortController. + const controller = AbortController ? new AbortController() : false; + + if (controller) { + initOptions.signal = controller.signal; + } + + try { + const response = await this.timeoutPromise(window.fetch(url, initOptions), CoreWS.instance.getRequestTimeout()); + + return response.redirected; + } catch (error) { + if (error.timeout && controller) { + // Timeout, abort the request. + controller.abort(); } - return this.timeoutPromise(window.fetch(url, initOptions), CoreWS.instance.getRequestTimeout()) - .then((response: Response) => { - return response.redirected; - }).catch((error) => { - if (error.timeout && controller) { - // Timeout, abort the request. - controller.abort(); - } - - // There was a timeout, cannot determine if there's a redirect. Assume it's false. - return false; - }); - } else { - // Cannot check if there is a redirect, assume it's false. - return Promise.resolve(false); + // There was a timeout, cannot determine if there's a redirect. Assume it's false. + return false; } } @@ -255,7 +249,7 @@ export class CoreUtilsProvider { * @param level Depth we are right now inside a cloned object. It's used to prevent reaching max call stack size. * @return Cloned variable. */ - clone(source: any, level: number = 0): any { + clone(source: T, level: number = 0): T { if (level >= 20) { // Max 20 levels. this.logger.error('Max depth reached when cloning object.', source); @@ -265,7 +259,7 @@ export class CoreUtilsProvider { if (Array.isArray(source)) { // Clone the array and all the entries. - const newArray = []; + const newArray = [] as unknown as T; for (let i = 0; i < source.length; i++) { newArray[i] = this.clone(source[i], level + 1); } @@ -279,7 +273,7 @@ export class CoreUtilsProvider { } // Clone the object and all the subproperties. - const newObject = {}; + const newObject = {} as T; for (const name in source) { newObject[name] = this.clone(source[name], level + 1); } @@ -298,7 +292,7 @@ export class CoreUtilsProvider { * @param to Object where to store the properties. * @param clone Whether the properties should be cloned (so they are different instances). */ - copyProperties(from: any, to: any, clone: boolean = true): void { + copyProperties(from: Record, to: Record, clone: boolean = true): void { for (const name in from) { if (clone) { to[name] = this.clone(from[name]); @@ -314,13 +308,15 @@ export class CoreUtilsProvider { * @param text Text to be copied * @return Promise resolved when text is copied. */ - copyToClipboard(text: string): Promise { - return Clipboard.instance.copy(text).then(() => { + async copyToClipboard(text: string): Promise { + try { + await Clipboard.instance.copy(text); + // Show toast using ionicLoading. - return CoreDomUtils.instance.showToast('core.copiedtoclipboard', true); - }).catch(() => { + CoreDomUtils.instance.showToast('core.copiedtoclipboard', true); + } catch { // Ignore errors. - }); + } } /** @@ -339,7 +335,7 @@ export class CoreUtilsProvider { * * @param array Array to empty. */ - emptyArray(array: any[]): void { + emptyArray(array: unknown[]): void { array.length = 0; // Empty array without losing its reference. } @@ -348,9 +344,9 @@ export class CoreUtilsProvider { * * @param object Object to remove the properties. */ - emptyObject(object: object): void { + emptyObject(object: Record): void { for (const key in object) { - if (object.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(object, key)) { delete object[key]; } } @@ -373,10 +369,8 @@ export class CoreUtilsProvider { // Execute all the processes in order. for (const i in orderedPromisesData) { const data = orderedPromisesData[i]; - let promise; - // Add the process to the dependency stack. - promise = dependency.finally(() => { + const promise = dependency.finally(() => { try { return data.function(); } catch (e) { @@ -406,19 +400,19 @@ export class CoreUtilsProvider { * @param useDotNotation Whether to use dot notation '.' or square brackets '['. * @return Flattened object. */ - flattenObject(obj: object, useDotNotation?: boolean): object { + flattenObject(obj: Record, useDotNotation?: boolean): Record { const toReturn = {}; for (const name in obj) { - if (!obj.hasOwnProperty(name)) { + if (!Object.prototype.hasOwnProperty.call(obj, name)) { continue; } const value = obj[name]; if (typeof value == 'object' && !Array.isArray(value)) { - const flatObject = this.flattenObject(value); + const flatObject = this.flattenObject(value as Record); for (const subName in flatObject) { - if (!flatObject.hasOwnProperty(subName)) { + if (!Object.prototype.hasOwnProperty.call(flatObject, subName)) { continue; } @@ -463,19 +457,24 @@ export class CoreUtilsProvider { * @param ...args All the params sent after checkAll will be passed to isEnabledFn. * @return Promise resolved with the list of enabled sites. */ - filterEnabledSites(siteIds: string[], isEnabledFn: (siteId, ...args: any[]) => boolean | Promise, checkAll?: boolean, - ...args: any[]): Promise { + filterEnabledSites

( + siteIds: string[], + isEnabledFn: (siteId, ...args: P) => boolean | Promise, + checkAll?: boolean, + ...args: P + ): Promise { const promises = []; const enabledSites = []; for (const i in siteIds) { const siteId = siteIds[i]; + const pushIfEnabled = enabled => enabled && enabledSites.push(siteId); if (checkAll || !promises.length) { - promises.push(Promise.resolve(isEnabledFn.apply(isEnabledFn, [siteId].concat(args))).then((enabled) => { - if (enabled) { - enabledSites.push(siteId); - } - })); + promises.push( + Promise + .resolve(isEnabledFn(siteId, ...args)) + .then(pushIfEnabled), + ); } } @@ -498,7 +497,7 @@ export class CoreUtilsProvider { * @param float The float to print. * @return Locale float. */ - formatFloat(float: any): string { + formatFloat(float: unknown): string { if (typeof float == 'undefined' || float === null || typeof float == 'boolean') { return ''; } @@ -506,9 +505,9 @@ export class CoreUtilsProvider { const localeSeparator = Translate.instance.instant('core.decsep'); // Convert float to string. - float += ''; + const floatString = float + ''; - return float.replace('.', localeSeparator); + return floatString.replace('.', localeSeparator); } /** @@ -523,17 +522,20 @@ export class CoreUtilsProvider { * @param maxDepth Max Depth to convert to tree. Children found will be in the last level of depth. * @return Array with the formatted tree, children will be on each node under children field. */ - formatTree(list: any[], parentFieldName: string = 'parent', idFieldName: string = 'id', rootParentId: number = 0, - maxDepth: number = 5): any[] { + formatTree( + list: T[], + parentFieldName: string = 'parent', + idFieldName: string = 'id', + rootParentId: number = 0, + maxDepth: number = 5, + ): TreeNode[] { const map = {}; const mapDepth = {}; - const tree = []; - let parent; - let id; + const tree: TreeNode[] = []; - list.forEach((node, index): void => { - id = node[idFieldName]; - parent = node[parentFieldName]; + list.forEach((node: TreeNode, index): void => { + const id = node[idFieldName]; + const parent = node[parentFieldName]; node.children = []; if (!id || !parent) { @@ -543,7 +545,7 @@ export class CoreUtilsProvider { // Use map to look-up the parents. map[id] = index; if (parent != rootParentId) { - const parentNode = list[map[parent]]; + const parentNode = list[map[parent]] as TreeNode; if (parentNode) { if (mapDepth[parent] == maxDepth) { // Reached max level of depth. Proceed with flat order. Find parent object of the current node. @@ -551,11 +553,11 @@ export class CoreUtilsProvider { if (parentOfParent) { // This element will be the child of the node that is two levels up the hierarchy // (i.e. the child of node.parent.parent). - list[map[parentOfParent]].children.push(node); + (list[map[parentOfParent]] as TreeNode).children.push(node); // Assign depth level to the same depth as the parent (i.e. max depth level). mapDepth[id] = mapDepth[parent]; // Change the parent to be the one that is two levels up the hierarchy. - node.parent = parentOfParent; + node[parentFieldName] = parentOfParent; } else { this.logger.error(`Node parent of parent:${parentOfParent} not found on formatTree`); } @@ -596,7 +598,7 @@ export class CoreUtilsProvider { * * @return Promise resolved with the list of countries. */ - getCountryList(): Promise { + getCountryList(): Promise> { // Get the keys of the countries. return this.getCountryKeysList().then((keys) => { // Now get the code and the translated name. @@ -618,14 +620,14 @@ export class CoreUtilsProvider { * * @return Promise resolved with the list of countries. */ - getCountryListSorted(): Promise { + getCountryListSorted(): Promise<{ code: string; name: string }[]> { // Get the keys of the countries. return this.getCountryList().then((countries) => { // Sort translations. const sortedCountries = []; Object.keys(countries).sort((a, b) => countries[a].localeCompare(countries[b])).forEach((key) => { - sortedCountries.push({code: key, name: countries[key]}); + sortedCountries.push({ code: key, name: countries[key] }); }); return sortedCountries; @@ -647,7 +649,7 @@ export class CoreUtilsProvider { if (fallbackLang === defaultLang) { // Same language, just reject. - return Promise.reject('Countries not found.'); + throw new Error('Countries not found.'); } return this.getCountryKeysListForLanguage(fallbackLang); @@ -660,25 +662,25 @@ export class CoreUtilsProvider { * @param lang Language to check. * @return Promise resolved with the countries list. Rejected if not translated. */ - protected getCountryKeysListForLanguage(lang: string): Promise { + protected async getCountryKeysListForLanguage(lang: string): Promise { // Get the translation table for the language. - return CoreLang.instance.getTranslationTable(lang).then((table): any => { - // Gather all the keys for countries, - const keys = []; + const table = await CoreLang.instance.getTranslationTable(lang); - for (const name in table) { - if (name.indexOf('assets.countries.') === 0) { - keys.push(name); - } + // Gather all the keys for countries, + const keys = []; + + for (const name in table) { + if (name.indexOf('assets.countries.') === 0) { + keys.push(name); } + } - if (keys.length === 0) { - // Not translated, reject. - return Promise.reject('Countries not found.'); - } + if (keys.length === 0) { + // Not translated, reject. + throw new Error('Countries not found.'); + } - return keys; - }); + return keys; } /** @@ -699,9 +701,7 @@ export class CoreUtilsProvider { } // Can't be guessed, get the remote mimetype. - return CoreWS.instance.getRemoteFileMimeType(url).then((mimetype) => { - return mimetype || ''; - }); + return CoreWS.instance.getRemoteFileMimeType(url).then(mimetype => mimetype || ''); } /** @@ -718,13 +718,23 @@ export class CoreUtilsProvider { return ++this.uniqueIds[name]; } + /** + * Check if a file is a FileEntry + * + * @param file File. + * @return Type guard indicating if the file is a FileEntry. + */ + isFileEntry(file: FileEntry | CoreWSExternalFile): file is FileEntry { + return 'isFile' in file; + } + /** * Given a list of files, check if there are repeated names. * * @param files List of files. * @return String with error message if repeated, false if no repeated. */ - hasRepeatedFilenames(files: any[]): string | boolean { + hasRepeatedFilenames(files: (FileEntry | CoreWSExternalFile)[]): string | false { if (!files || !files.length) { return false; } @@ -733,12 +743,14 @@ export class CoreUtilsProvider { // Check if there are 2 files with the same name. for (let i = 0; i < files.length; i++) { - const name = files[i].filename || files[i].name; + const file = files[i]; + const name = this.isFileEntry(file) ? file.name : file.filename; + if (names.indexOf(name) > -1) { return Translate.instance.instant('core.filenameexist', { $a: name }); - } else { - names.push(name); } + + names.push(name); } return false; @@ -774,6 +786,7 @@ export class CoreUtilsProvider { * @param value Value to check. * @return Whether the value is false, 0 or "0". */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any isFalseOrZero(value: any): boolean { return typeof value != 'undefined' && (value === false || value === 'false' || parseInt(value, 10) === 0); } @@ -784,6 +797,7 @@ export class CoreUtilsProvider { * @param value Value to check. * @return Whether the value is true, 1 or "1". */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any isTrueOrOne(value: any): boolean { return typeof value != 'undefined' && (value === true || value === 'true' || parseInt(value, 10) === 1); } @@ -794,6 +808,7 @@ export class CoreUtilsProvider { * @param error Error to check. * @return Whether the error was returned by the WebService. */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any isWebServiceError(error: any): boolean { return error && (typeof error.warningcode != 'undefined' || (typeof error.errorcode != 'undefined' && error.errorcode != 'invalidtoken' && error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' && @@ -812,19 +827,22 @@ export class CoreUtilsProvider { * @param defaultValue Element that will become default option value. Default 0. * @return The now assembled array */ - makeMenuFromList(list: string, defaultLabel?: string, separator: string = ',', defaultValue?: any): any[] { + makeMenuFromList( + list: string, + defaultLabel?: string, + separator: string = ',', + defaultValue?: T, + ): { label: string; value: T | number }[] { // Split and format the list. - const split = list.split(separator).map((label, index) => { - return { - label: label.trim(), - value: index + 1 - }; - }); + const split = list.split(separator).map((label, index) => ({ + label: label.trim(), + value: index + 1, + })) as { label: string; value: T | number }[]; if (defaultLabel) { split.unshift({ label: defaultLabel, - value: defaultValue || 0 + value: defaultValue || 0, }); } @@ -839,8 +857,8 @@ export class CoreUtilsProvider { * @param [key] Key of the property that must be unique. If not specified, the whole entry. * @return Merged array. */ - mergeArraysWithoutDuplicates(array1: any[], array2: any[], key?: string): any[] { - return this.uniqueArray(array1.concat(array2), key); + mergeArraysWithoutDuplicates(array1: T[], array2: T[], key?: string): T[] { + return this.uniqueArray(array1.concat(array2), key) as T[]; } /** @@ -849,6 +867,7 @@ export class CoreUtilsProvider { * @param value Value to check. * @return True if not null and not undefined. */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any notNullOrUndefined(value: any): boolean { return typeof value != 'undefined' && value !== null; } @@ -888,12 +907,10 @@ export class CoreUtilsProvider { if (!extension || extension.indexOf('/') > -1 || extension.indexOf('\\') > -1) { // Extension not found. - error = Translate.instance.instant('core.erroropenfilenoextension'); - } else { - error = Translate.instance.instant('core.erroropenfilenoapp'); + throw new Error(Translate.instance.instant('core.erroropenfilenoextension')); } - throw error; + throw new Error(Translate.instance.instant('core.erroropenfilenoapp')); } } @@ -905,7 +922,7 @@ export class CoreUtilsProvider { * @param options Override default options passed to InAppBrowser. * @return The opened window. */ - openInApp(url: string, options?: any): InAppBrowserObject { + openInApp(url: string, options?: InAppBrowserOptions): InAppBrowserObject { if (!url) { return; } @@ -995,36 +1012,32 @@ export class CoreUtilsProvider { * @param url The URL of the file. * @return Promise resolved when opened. */ - openOnlineFile(url: string): Promise { + async openOnlineFile(url: string): Promise { if (CoreApp.instance.isAndroid()) { // In Android we need the mimetype to open it. - return this.getMimeTypeFromUrl(url).catch(() => { - // Error getting mimetype, return undefined. - }).then((mimetype) => { - if (!mimetype) { - // Couldn't retrieve mimetype. Return error. - return Promise.reject(Translate.instance.instant('core.erroropenfilenoextension')); - } + const mimetype = await this.ignoreErrors(this.getMimeTypeFromUrl(url)); - const options = { - action: WebIntent.instance.ACTION_VIEW, - url, - type: mimetype - }; + if (!mimetype) { + // Couldn't retrieve mimetype. Return error. + throw new Error(Translate.instance.instant('core.erroropenfilenoextension')); + } - return WebIntent.instance.startActivity(options).catch((error) => { - this.logger.error('Error opening online file ' + url + ' with mimetype ' + mimetype); - this.logger.error('Error: ', JSON.stringify(error)); + const options = { + action: WebIntent.instance.ACTION_VIEW, + url, + type: mimetype, + }; - return Promise.reject(Translate.instance.instant('core.erroropenfilenoapp')); - }); + return WebIntent.instance.startActivity(options).catch((error) => { + this.logger.error('Error opening online file ' + url + ' with mimetype ' + mimetype); + this.logger.error('Error: ', JSON.stringify(error)); + + throw new Error(Translate.instance.instant('core.erroropenfilenoapp')); }); } // In the rest of platforms we need to open them in InAppBrowser. this.openInApp(url); - - return Promise.resolve(); } /** @@ -1033,10 +1046,8 @@ export class CoreUtilsProvider { * @param obj Object to convert. * @return Array with the values of the object but losing the keys. */ - objectToArray(obj: object): any[] { - return Object.keys(obj).map((key) => { - return obj[key]; - }); + objectToArray(obj: Record): T[] { + return Object.keys(obj).map((key) => obj[key]); } /** @@ -1051,9 +1062,15 @@ export class CoreUtilsProvider { * @param sortByValue True to sort values alphabetically, false otherwise. * @return Array of objects with the name & value of each property. */ - objectToArrayOfObjects(obj: object, keyName: string, valueName: string, sortByKey?: boolean, sortByValue?: boolean): any[] { + objectToArrayOfObjects( + obj: Record, + keyName: string, + valueName: string, + sortByKey?: boolean, + sortByValue?: boolean, + ): Record[] { // Get the entries from an object or primitive value. - const getEntries = (elKey, value): any[] | any => { + const getEntries = (elKey: string, value: unknown): Record[] | unknown => { if (typeof value == 'undefined' || value == null) { // Filter undefined and null values. return; @@ -1087,7 +1104,7 @@ export class CoreUtilsProvider { } // "obj" will always be an object, so "entries" will always be an array. - const entries = getEntries('', obj); + const entries = getEntries('', obj) as Record[]; if (sortByKey || sortByValue) { return entries.sort((a, b) => { if (sortByKey) { @@ -1111,7 +1128,12 @@ export class CoreUtilsProvider { * @param keyPrefix Key prefix if neededs to delete it. * @return Object. */ - objectToKeyValueMap(objects: object[], keyName: string, valueName: string, keyPrefix?: string): {[name: string]: any} { + objectToKeyValueMap( + objects: Record[], + keyName: string, + valueName: string, + keyPrefix?: string, + ): {[name: string]: unknown} { if (!objects) { return; } @@ -1119,7 +1141,8 @@ export class CoreUtilsProvider { const prefixSubstr = keyPrefix ? keyPrefix.length : 0; const mapped = {}; objects.forEach((item) => { - const key = prefixSubstr > 0 ? item[keyName].substr(prefixSubstr) : item[keyName]; + const keyValue = item[keyName] as string; + const key = prefixSubstr > 0 ? keyValue.substr(prefixSubstr) : keyValue; mapped[key] = item[valueName]; }); @@ -1133,7 +1156,7 @@ export class CoreUtilsProvider { * @param removeEmpty Whether to remove params whose value is null/undefined. * @return GET params. */ - objectToGetParams(object: any, removeEmpty: boolean = true): string { + objectToGetParams(object: Record, removeEmpty: boolean = true): string { // First of all, flatten the object so all properties are in the first level. const flattened = this.flattenObject(object); let result = ''; @@ -1164,7 +1187,7 @@ export class CoreUtilsProvider { * @param prefix Prefix to add. * @return Prefixed object. */ - prefixKeys(data: any, prefix: string): any { + prefixKeys(data: Record, prefix: string): Record { const newObj = {}; const keys = Object.keys(data); @@ -1196,12 +1219,14 @@ export class CoreUtilsProvider { * @param promise Promise to check * @return Promise resolved with boolean: true if the promise is rejected or false if it's resolved. */ - promiseFails(promise: Promise): Promise { - return promise.then(() => { + async promiseFails(promise: Promise): Promise { + try { + await promise; + return false; - }).catch(() => { + } catch { return true; - }); + } } /** @@ -1210,12 +1235,14 @@ export class CoreUtilsProvider { * @param promise Promise to check * @return Promise resolved with boolean: true if the promise it's resolved or false if it's rejected. */ - promiseWorks(promise: Promise): Promise { - return promise.then(() => { + async promiseWorks(promise: Promise): Promise { + try { + await promise; + return true; - }).catch(() => { + } catch { return false; - }); + } } /** @@ -1228,7 +1255,7 @@ export class CoreUtilsProvider { * @param key Key to check. * @return Whether the two objects/arrays have the same value (or lack of one) for a given key. */ - sameAtKeyMissingIsBlank(obj1: any, obj2: any, key: string): boolean { + sameAtKeyMissingIsBlank(obj1: unknown, obj2: unknown, key: string): boolean { let value1 = typeof obj1[key] != 'undefined' ? obj1[key] : ''; let value2 = typeof obj2[key] != 'undefined' ? obj2[key] : ''; @@ -1249,7 +1276,7 @@ export class CoreUtilsProvider { * @param obj Object to stringify. * @return Stringified object. */ - sortAndStringify(obj: object): string { + sortAndStringify(obj: Record): string { return JSON.stringify(this.sortProperties(obj)); } @@ -1259,7 +1286,7 @@ export class CoreUtilsProvider { * @param obj The object to sort. If it isn't an object, the original value will be returned. * @return Sorted object. */ - sortProperties(obj: object): object { + sortProperties(obj: T): T { if (obj != null && typeof obj == 'object' && !Array.isArray(obj)) { // It's an object, sort it. return Object.keys(obj).sort().reduce((accumulator, key) => { @@ -1267,7 +1294,7 @@ export class CoreUtilsProvider { accumulator[key] = this.sortProperties(obj[key]); return accumulator; - }, {}); + }, {} as T); } else { return obj; } @@ -1279,12 +1306,12 @@ export class CoreUtilsProvider { * @param obj The object to sort. If it isn't an object, the original value will be returned. * @return Sorted object. */ - sortValues(obj: object): object { + sortValues(obj: T): T { if (typeof obj == 'object' && !Array.isArray(obj)) { // It's an object, sort it. Convert it to an array to be able to sort it and then convert it back to object. - const array = this.objectToArrayOfObjects(obj, 'name', 'value', false, true); + const array = this.objectToArrayOfObjects(obj as Record, 'name', 'value', false, true); - return this.objectToKeyValueMap(array, 'name', 'value'); + return this.objectToKeyValueMap(array, 'name', 'value') as unknown as T; } else { return obj; } @@ -1297,10 +1324,10 @@ export class CoreUtilsProvider { * @return File size and a boolean to indicate if it is the total size or only partial. * @deprecated since 3.8.0. Use CorePluginFileDelegate.getFilesSize instead. */ - sumFileSizes(files: any[]): { size: number, total: boolean } { + sumFileSizes(files: CoreWSExternalFile[]): { size: number; total: boolean } { const result = { size: 0, - total: true + total: true, }; files.forEach((file) => { @@ -1325,13 +1352,25 @@ export class CoreUtilsProvider { */ timeoutPromise(promise: Promise, time: number): Promise { return new Promise((resolve, reject): void => { - const timeout = setTimeout(() => { - reject({timeout: true}); - }, time); + let timedOut = false; + const resolveBeforeTimeout = () => { + if (timedOut) { + return; + } + resolve(); + }; + const timeout = setTimeout( + () => { + reject({ timeout: true }); + timedOut = true; + }, + time, + ); - promise.then(resolve).catch(reject).finally(() => { - clearTimeout(timeout); - }); + promise + .then(resolveBeforeTimeout) + .catch(reject) + .finally(() => clearTimeout(timeout)); }); } @@ -1344,7 +1383,8 @@ export class CoreUtilsProvider { * @param strict If true, then check the input and return false if it is not a valid number. * @return False if bad format, empty string if empty value or the parsed float if not. */ - unformatFloat(localeFloat: any, strict?: boolean): any { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + unformatFloat(localeFloat: any, strict?: boolean): false | '' | number { // Bad format on input type number. if (typeof localeFloat == 'undefined') { return false; @@ -1383,7 +1423,7 @@ export class CoreUtilsProvider { * @param [key] Key of the property that must be unique. If not specified, the whole entry. * @return Array without duplicate values. */ - uniqueArray(array: any[], key?: string): any[] { + uniqueArray(array: T[], key?: string): T[] { const filtered = []; const unique = {}; // Use an object to make it faster to check if it's duplicate. @@ -1407,16 +1447,13 @@ export class CoreUtilsProvider { * @param delay Time that must pass until the function is called. * @return Debounced function. */ - debounce(fn: (...args: any[]) => any, delay: number): (...args: any[]) => void { - + debounce(fn: (...args: T) => unknown, delay: number): (...args: T) => void { let timeoutID: number; - const debounced = (...args: any[]): void => { + const debounced = (...args: unknown[]): void => { clearTimeout(timeoutID); - timeoutID = window.setTimeout(() => { - fn.apply(null, args); - }, delay); + timeoutID = window.setTimeout(() => fn.apply(null, args), delay); }; return debounced; @@ -1448,18 +1485,19 @@ export class CoreUtilsProvider { * * @return Promise resolved with the QR string, rejected if error or cancelled. */ - startScanQR(): Promise { + async startScanQR(): Promise { if (!CoreApp.instance.isMobile()) { return Promise.reject('QRScanner isn\'t available in desktop apps.'); } // Ask the user for permission to use the camera. // The scan method also does this, but since it returns an Observable we wouldn't be able to detect if the user denied. - return QRScanner.instance.prepare().then((status) => { + try { + const status = await QRScanner.instance.prepare(); if (!status.authorized) { // No access to the camera, reject. In android this shouldn't happen, denying access passes through catch. - return Promise.reject('The user denied camera access.'); + throw new Error('The user denied camera access.'); } if (this.qrScanData && this.qrScanData.deferred) { @@ -1470,29 +1508,29 @@ export class CoreUtilsProvider { // Start scanning. this.qrScanData = { deferred: this.promiseDefer(), - observable: QRScanner.instance.scan().subscribe((text) => { - // Text received, stop scanning and return the text. - this.stopScanQR(text, false); - }) + // When text is received, stop scanning and return the text. + observable: QRScanner.instance.scan().subscribe(text => this.stopScanQR(text, false)), }; // Show the camera. - return QRScanner.instance.show().then(() => { + try { + await QRScanner.instance.show(); + document.body.classList.add('core-scanning-qr'); return this.qrScanData.deferred.promise; - }, (err) => { - this.stopScanQR(err, true); + } catch (e) { + this.stopScanQR(e, true); - return Promise.reject(err); - }); + throw e; + } + } catch (error) { + // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/naming-convention + error.message = error.message || (error as { _message?: string })._message; - }).catch((err) => { - err.message = err.message || err._message; - - return Promise.reject(err); - }); + throw error; + } } /** @@ -1501,8 +1539,7 @@ export class CoreUtilsProvider { * @param data If success, the text of the QR code. If error, the error object or message. Undefined for cancelled. * @param error True if the data belongs to an error, false otherwise. */ - stopScanQR(data?: any, error?: boolean): void { - + stopScanQR(data?: string | Error, error?: boolean): void { if (!this.qrScanData) { // Not scanning. return; @@ -1518,7 +1555,7 @@ export class CoreUtilsProvider { if (error) { this.qrScanData.deferred.reject(data); } else if (typeof data != 'undefined') { - this.qrScanData.deferred.resolve(data); + this.qrScanData.deferred.resolve(data as string); } else { this.qrScanData.deferred.reject(CoreDomUtils.instance.createCanceledError()); } @@ -1549,10 +1586,20 @@ export class CoreUtilsProvider { * @return Promise resolved after the time has passed. */ wait(milliseconds: number): Promise { - return new Promise((resolve, reject): void => { - setTimeout(resolve, milliseconds); - }); + return new Promise(resolve => setTimeout(resolve, milliseconds)); } + + /** + * Override native window.open with InAppBrowser if available. + */ + private overrideWindowOpen() { + if (!window.cordova?.InAppBrowser) { + return; + } + + window.open = window.cordova.InAppBrowser.open; + } + } export class CoreUtils extends makeSingleton(CoreUtilsProvider) {} diff --git a/src/app/singletons/locutus.ts b/src/app/singletons/locutus.ts new file mode 100644 index 000000000..0cc32e5c7 --- /dev/null +++ b/src/app/singletons/locutus.ts @@ -0,0 +1,447 @@ +/* eslint-disable */ + +/** + * Original code taken from https://github.com/kvz/locutus + */ + +function initCache () { + const store = [] + // cache only first element, second is length to jump ahead for the parser + const cache = function cache (value) { + store.push(value[0]) + return value + } + + cache.get = (index) => { + if (index >= store.length) { + throw RangeError(`Can't resolve reference ${index + 1}`) + } + + return store[index] + } + + return cache +} + +function expectType (str, cache) { + const types = /^(?:N(?=;)|[bidsSaOCrR](?=:)|[^:]+(?=:))/g + const type = (types.exec(str) || [])[0] + + if (!type) { + throw SyntaxError('Invalid input: ' + str) + } + + switch (type) { + case 'N': + return cache([ null, 2 ]) + case 'b': + return cache(expectBool(str)) + case 'i': + return cache(expectInt(str)) + case 'd': + return cache(expectFloat(str)) + case 's': + return cache(expectString(str)) + case 'S': + return cache(expectEscapedString(str)) + case 'a': + return expectArray(str, cache) + case 'O': + return expectObject(str, cache) + case 'C': + return expectClass(str, cache) + case 'r': + case 'R': + return expectReference(str, cache) + default: + throw SyntaxError(`Invalid or unsupported data type: ${type}`) + } +} + +function expectBool (str) { + const reBool = /^b:([01]);/ + const [ match, boolMatch ] = reBool.exec(str) || [] + + if (!boolMatch) { + throw SyntaxError('Invalid bool value, expected 0 or 1') + } + + return [ boolMatch === '1', match.length ] +} + +function expectInt (str) { + const reInt = /^i:([+-]?\d+);/ + const [ match, intMatch ] = reInt.exec(str) || [] + + if (!intMatch) { + throw SyntaxError('Expected an integer value') + } + + return [ parseInt(intMatch, 10), match.length ] +} + +function expectFloat (str) { + const reFloat = /^d:(NAN|-?INF|(?:\d+\.\d*|\d*\.\d+|\d+)(?:[eE][+-]\d+)?);/ + const [ match, floatMatch ] = reFloat.exec(str) || [] + + if (!floatMatch) { + throw SyntaxError('Expected a float value') + } + + let floatValue + + switch (floatMatch) { + case 'NAN': + floatValue = Number.NaN + break + case '-INF': + floatValue = Number.NEGATIVE_INFINITY + break + case 'INF': + floatValue = Number.POSITIVE_INFINITY + break + default: + floatValue = parseFloat(floatMatch) + break + } + + return [ floatValue, match.length ] +} + +function readBytes (str, len, escapedString = false) { + let bytes = 0 + let out = '' + let c = 0 + const strLen = str.length + let wasHighSurrogate = false + let escapedChars = 0 + + while (bytes < len && c < strLen) { + let chr = str.charAt(c) + const code = chr.charCodeAt(0) + const isHighSurrogate = code >= 0xd800 && code <= 0xdbff + const isLowSurrogate = code >= 0xdc00 && code <= 0xdfff + + if (escapedString && chr === '\\') { + chr = String.fromCharCode(parseInt(str.substr(c + 1, 2), 16)) + escapedChars++ + + // each escaped sequence is 3 characters. Go 2 chars ahead. + // third character will be jumped over a few lines later + c += 2 + } + + c++ + + bytes += isHighSurrogate || (isLowSurrogate && wasHighSurrogate) + // if high surrogate, count 2 bytes, as expectation is to be followed by low surrogate + // if low surrogate preceded by high surrogate, add 2 bytes + ? 2 + : code > 0x7ff + // otherwise low surrogate falls into this part + ? 3 + : code > 0x7f + ? 2 + : 1 + + // if high surrogate is not followed by low surrogate, add 1 more byte + bytes += wasHighSurrogate && !isLowSurrogate ? 1 : 0 + + out += chr + wasHighSurrogate = isHighSurrogate + } + + return [ out, bytes, escapedChars ] +} + +function expectString (str) { + // PHP strings consist of one-byte characters. + // JS uses 2 bytes with possible surrogate pairs. + // Serialized length of 2 is still 1 JS string character + const reStrLength = /^s:(\d+):"/g // also match the opening " char + const [ match, byteLenMatch ] = reStrLength.exec(str) || [] + + if (!match) { + throw SyntaxError('Expected a string value') + } + + const len = parseInt(byteLenMatch, 10) + + str = str.substr(match.length) + + let [ strMatch, bytes ] = readBytes(str, len) + + if (bytes !== len) { + throw SyntaxError(`Expected string of ${len} bytes, but got ${bytes}`) + } + + str = str.substr((strMatch as string).length) + + // strict parsing, match closing "; chars + if (!str.startsWith('";')) { + throw SyntaxError('Expected ";') + } + + return [ strMatch, match.length + (strMatch as string).length + 2 ] // skip last "; +} + +function expectEscapedString (str) { + const reStrLength = /^S:(\d+):"/g // also match the opening " char + const [ match, strLenMatch ] = reStrLength.exec(str) || [] + + if (!match) { + throw SyntaxError('Expected an escaped string value') + } + + const len = parseInt(strLenMatch, 10) + + str = str.substr(match.length) + + let [ strMatch, bytes, escapedChars ] = readBytes(str, len, true) + + if (bytes !== len) { + throw SyntaxError(`Expected escaped string of ${len} bytes, but got ${bytes}`) + } + + str = str.substr((strMatch as string).length + (escapedChars as number) * 2) + + // strict parsing, match closing "; chars + if (!str.startsWith('";')) { + throw SyntaxError('Expected ";') + } + + return [ strMatch, match.length + (strMatch as string).length + 2 ] // skip last "; +} + +function expectKeyOrIndex (str) { + try { + return expectString(str) + } catch (err) {} + + try { + return expectEscapedString(str) + } catch (err) {} + + try { + return expectInt(str) + } catch (err) { + throw SyntaxError('Expected key or index') + } +} + +function expectObject (str, cache) { + // O::"class name"::{} + // O:8:"stdClass":2:{s:3:"foo";s:3:"bar";s:3:"bar";s:3:"baz";} + const reObjectLiteral = /^O:(\d+):"([^"]+)":(\d+):\{/ + const [ objectLiteralBeginMatch, /* classNameLengthMatch */, className, propCountMatch ] = reObjectLiteral.exec(str) || [] + + if (!objectLiteralBeginMatch) { + throw SyntaxError('Invalid input') + } + + if (className !== 'stdClass') { + throw SyntaxError(`Unsupported object type: ${className}`) + } + + let totalOffset = objectLiteralBeginMatch.length + + const propCount = parseInt(propCountMatch, 10) + const obj = {} + cache([obj]) + + str = str.substr(totalOffset) + + for (let i = 0; i < propCount; i++) { + const prop = expectKeyOrIndex(str) + str = str.substr(prop[1]) + totalOffset += prop[1] as number + + const value = expectType(str, cache) + str = str.substr(value[1]) + totalOffset += value[1] + + obj[prop[0]] = value[0] + } + + // strict parsing, expect } after object literal + if (str.charAt(0) !== '}') { + throw SyntaxError('Expected }') + } + + return [ obj, totalOffset + 1 ] // skip final } +} + +function expectClass (str, cache) { + // can't be well supported, because requires calling eval (or similar) + // in order to call serialized constructor name + // which is unsafe + // or assume that constructor is defined in global scope + // but this is too much limiting + throw Error('Not yet implemented') +} + +function expectReference (str, cache) { + const reRef = /^[rR]:([1-9]\d*);/ + const [ match, refIndex ] = reRef.exec(str) || [] + + if (!match) { + throw SyntaxError('Expected reference value') + } + + return [ cache.get(parseInt(refIndex, 10) - 1), match.length ] +} + +function expectArray (str, cache) { + const reArrayLength = /^a:(\d+):{/ + const [ arrayLiteralBeginMatch, arrayLengthMatch ] = reArrayLength.exec(str) || [] + + if (!arrayLengthMatch) { + throw SyntaxError('Expected array length annotation') + } + + str = str.substr(arrayLiteralBeginMatch.length) + + const array = expectArrayItems(str, parseInt(arrayLengthMatch, 10), cache) + + // strict parsing, expect closing } brace after array literal + if (str.charAt(array[1]) !== '}') { + throw SyntaxError('Expected }') + } + + return [ array[0], arrayLiteralBeginMatch.length + (array[1] as number) + 1 ] // jump over } +} + +function expectArrayItems (str, expectedItems = 0, cache) { + let key + let hasStringKeys = false + let item + let totalOffset = 0 + let items = [] + cache([items]) + + for (let i = 0; i < expectedItems; i++) { + key = expectKeyOrIndex(str) + + // this is for backward compatibility with previous implementation + if (!hasStringKeys) { + hasStringKeys = (typeof key[0] === 'string') + } + + str = str.substr(key[1]) + totalOffset += key[1] + + // references are resolved immediately, so if duplicate key overwrites previous array index + // the old value is anyway resolved + // fixme: but next time the same reference should point to the new value + item = expectType(str, cache) + str = str.substr(item[1]) + totalOffset += item[1] + + items[key[0]] = item[0] + } + + // this is for backward compatibility with previous implementation + if (hasStringKeys) { + items = Object.assign({}, items) + } + + return [ items, totalOffset ] +} + +function unserialize (str) { + // discuss at: https://locutus.io/php/unserialize/ + // original by: Arpad Ray (mailto:arpad@php.net) + // improved by: Pedro Tainha (https://www.pedrotainha.com) + // improved by: Kevin van Zonneveld (https://kvz.io) + // improved by: Kevin van Zonneveld (https://kvz.io) + // improved by: Chris + // improved by: James + // improved by: Le Torbi + // improved by: Eli Skeggs + // bugfixed by: dptr1988 + // bugfixed by: Kevin van Zonneveld (https://kvz.io) + // bugfixed by: Brett Zamir (https://brett-zamir.me) + // bugfixed by: philippsimon (https://github.com/philippsimon/) + // revised by: d3x + // input by: Brett Zamir (https://brett-zamir.me) + // input by: Martin (https://www.erlenwiese.de/) + // input by: kilops + // input by: Jaroslaw Czarniak + // input by: lovasoa (https://github.com/lovasoa/) + // improved by: Rafał Kukawski + // reimplemented by: Rafał Kukawski + // note 1: We feel the main purpose of this function should be + // note 1: to ease the transport of data between php & js + // note 1: Aiming for PHP-compatibility, we have to translate objects to arrays + // example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}') + // returns 1: ['Kevin', 'van', 'Zonneveld'] + // example 2: unserialize('a:2:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";}') + // returns 2: {firstName: 'Kevin', midName: 'van'} + // example 3: unserialize('a:3:{s:2:"ü";s:2:"ü";s:3:"四";s:3:"四";s:4:"𠜎";s:4:"𠜎";}') + // returns 3: {'ü': 'ü', '四': '四', '𠜎': '𠜎'} + // example 4: unserialize(undefined) + // returns 4: false + // example 5: unserialize('O:8:"stdClass":1:{s:3:"foo";b:1;}') + // returns 5: { foo: true } + // example 6: unserialize('a:2:{i:0;N;i:1;s:0:"";}') + // returns 6: [null, ""] + // example 7: unserialize('S:7:"\\65\\73\\63\\61\\70\\65\\64";') + // returns 7: 'escaped' + + try { + if (typeof str !== 'string') { + return false + } + + return expectType(str, initCache())[0] + } catch (err) { + console.error(err) + return false + } +} + +function substr_replace (str, replace, start, length) { // eslint-disable-line camelcase + // discuss at: https://locutus.io/php/substr_replace/ + // original by: Brett Zamir (https://brett-zamir.me) + // example 1: substr_replace('ABCDEFGH:/MNRPQR/', 'bob', 0) + // returns 1: 'bob' + // example 2: var $var = 'ABCDEFGH:/MNRPQR/' + // example 2: substr_replace($var, 'bob', 0, $var.length) + // returns 2: 'bob' + // example 3: substr_replace('ABCDEFGH:/MNRPQR/', 'bob', 0, 0) + // returns 3: 'bobABCDEFGH:/MNRPQR/' + // example 4: substr_replace('ABCDEFGH:/MNRPQR/', 'bob', 10, -1) + // returns 4: 'ABCDEFGH:/bob/' + // example 5: substr_replace('ABCDEFGH:/MNRPQR/', 'bob', -7, -1) + // returns 5: 'ABCDEFGH:/bob/' + // example 6: substr_replace('ABCDEFGH:/MNRPQR/', '', 10, -1) + // returns 6: 'ABCDEFGH://' + + if (start < 0) { + // start position in str + start = start + str.length + } + length = length !== undefined ? length : str.length + if (length < 0) { + length = length + str.length - start + } + + return [ + str.slice(0, start), + replace.substr(0, length), + replace.slice(length), + str.slice(start + length) + ].join('') +} + +export class Locutus { + + static unserialize(data: string): T { + return unserialize(data); + } + + static substrReplace(str: string, replace: string, start: number, length?: number): string { + return substr_replace(str, replace, start, length); + } + +}; diff --git a/src/assets/exttomime.json b/src/assets/exttomime.json new file mode 100644 index 000000000..2728d8b3d --- /dev/null +++ b/src/assets/exttomime.json @@ -0,0 +1,1272 @@ +{ +"123": {"type":"application/vnd.lotus-1-2-3"}, +"3dm": {"type":"x-world/x-3dmf"}, +"3dmf": {"type":"x-world/x-3dmf"}, +"3dml": {"type":"text/vnd.in3d.3dml"}, +"3ds": {"type":"image/x-3ds"}, +"3g2": {"type":"video/3gpp2"}, +"3gp": {"type":"video/quicktime","icon":"quicktime","string":"video","groups":["video"]}, +"7z": {"type":"application/x-7z-compressed","icon":"archive","string":"archive","groups":["archive"]}, +"a": {"type":"application/octet-stream"}, +"aab": {"type":"application/x-authorware-bin"}, +"aac": {"type":"audio/aac","icon":"audio","string":"audio","groups":["audio","html_audio","web_audio"]}, +"aam": {"type":"application/x-authorware-map"}, +"aas": {"type":"application/x-authorware-seg"}, +"abc": {"type":"text/vnd.abc"}, +"abw": {"type":"application/x-abiword"}, +"ac": {"type":"application/pkix-attr-cert"}, +"acc": {"type":"application/vnd.americandynamics.acc"}, +"accdb": {"type":"application/msaccess","icon":"base"}, +"ace": {"type":"application/x-ace-compressed","icon":"archive"}, +"acgi": {"type":"text/html"}, +"acu": {"type":"application/vnd.acucobol"}, +"acutc": {"type":"application/vnd.acucorp"}, +"adp": {"type":"audio/adpcm"}, +"aep": {"type":"application/vnd.audiograph"}, +"afl": {"type":"video/animaflex"}, +"afm": {"type":"application/x-font-type1"}, +"afp": {"type":"application/vnd.ibm.modcap"}, +"ahead": {"type":"application/vnd.ahead.space"}, +"ai": {"type":"application/postscript","icon":"eps","string":"image","groups":["image"]}, +"aif": {"type":"audio/x-aiff","icon":"audio","string":"audio","groups":["audio"]}, +"aifc": {"type":"audio/x-aiff","icon":"audio","string":"audio","groups":["audio"]}, +"aiff": {"type":"audio/x-aiff","icon":"audio","string":"audio","groups":["audio"]}, +"aim": {"type":"application/x-aim"}, +"aip": {"type":"text/x-audiosoft-intra"}, +"air": {"type":"application/vnd.adobe.air-application-installer-package+zip"}, +"ait": {"type":"application/vnd.dvb.ait"}, +"ami": {"type":"application/vnd.amiga.ami"}, +"amr": {"type":"audio/amr","icon":"audio","string":"audio","groups":["audio"]}, +"ani": {"type":"application/x-navi-animation"}, +"aos": {"type":"application/x-nokia-9000-communicator-add-on-software"}, +"apk": {"type":"application/vnd.android.package-archive"}, +"appcache": {"type":"text/cache-manifest"}, +"applescript": {"type":"text/plain","icon":"text"}, +"application": {"type":"application/x-ms-application"}, +"apr": {"type":"application/vnd.lotus-approach"}, +"aps": {"type":"application/mime"}, +"arc": {"type":"application/x-freearc"}, +"arj": {"type":"application/arj"}, +"art": {"type":"image/x-jg"}, +"asa": {"type":"text/plain"}, +"asax": {"type":"application/octet-stream"}, +"asc": {"type":"text/plain","icon":"sourcecode"}, +"ascx": {"type":"text/plain"}, +"asf": {"type":"video/x-ms-asf","icon":"wmv","string":"video","groups":["video"]}, +"ashx": {"type":"text/plain"}, +"asm": {"type":"text/plain","icon":"sourcecode"}, +"asmx": {"type":"text/plain"}, +"aso": {"type":"application/vnd.accpac.simply.aso"}, +"asp": {"type":"text/plain"}, +"aspx": {"type":"text/plain"}, +"asx": {"type":"video/x-ms-asf"}, +"atc": {"type":"application/vnd.acucorp"}, +"atom": {"type":"application/atom+xml","icon":"markup"}, +"atomcat": {"type":"application/atomcat+xml","icon":"markup"}, +"atomsvc": {"type":"application/atomsvc+xml","icon":"markup"}, +"atx": {"type":"application/vnd.antix.game-component"}, +"au": {"type":"audio/au","icon":"audio","string":"audio","groups":["audio"]}, +"avi": {"type":"video/x-ms-wm","icon":"avi","string":"video","groups":["video","web_video"]}, +"avs": {"type":"video/avs-video"}, +"aw": {"type":"application/applixware"}, +"axd": {"type":"text/plain"}, +"azf": {"type":"application/vnd.airzip.filesecure.azf","icon":"archive"}, +"azs": {"type":"application/vnd.airzip.filesecure.azs","icon":"archive"}, +"azw": {"type":"application/vnd.amazon.ebook"}, +"bat": {"type":"application/x-msdownload"}, +"bcpio": {"type":"application/x-bcpio"}, +"bdf": {"type":"application/x-font-bdf"}, +"bdm": {"type":"application/vnd.syncml.dm+wbxml"}, +"bdoc": {"type":"application/x-digidoc","icon":"document","groups":["archive"]}, +"bed": {"type":"application/vnd.realvnc.bed"}, +"bh2": {"type":"application/vnd.fujitsu.oasysprs"}, +"bin": {"type":"application/octet-stream"}, +"blb": {"type":"application/x-blorb"}, +"blorb": {"type":"application/x-blorb"}, +"bm": {"type":"image/bmp","icon":"bmp","string":"image","groups":["image","web_image"]}, +"bmi": {"type":"application/vnd.bmi"}, +"bmp": {"type":"image/bmp","icon":"bmp","string":"image","groups":["image","web_image"]}, +"boo": {"type":"application/book"}, +"book": {"type":"application/vnd.framemaker"}, +"box": {"type":"application/vnd.previewsystems.box"}, +"boz": {"type":"application/x-bzip2","icon":"archive"}, +"bpk": {"type":"application/octet-stream"}, +"bsh": {"type":"application/x-bsh"}, +"btif": {"type":"image/prs.btif"}, +"bz": {"type":"application/x-bzip","icon":"archive"}, +"bz2": {"type":"application/x-bzip2","icon":"archive"}, +"c": {"type":"text/plain","icon":"sourcecode"}, +"c++": {"type":"text/plain"}, +"c11amc": {"type":"application/vnd.cluetrust.cartomobile-config"}, +"c11amz": {"type":"application/vnd.cluetrust.cartomobile-config-pkg"}, +"c4d": {"type":"application/vnd.clonk.c4group"}, +"c4f": {"type":"application/vnd.clonk.c4group"}, +"c4g": {"type":"application/vnd.clonk.c4group"}, +"c4p": {"type":"application/vnd.clonk.c4group"}, +"c4u": {"type":"application/vnd.clonk.c4group"}, +"cab": {"type":"application/vnd.ms-cab-compressed","icon":"archive"}, +"caf": {"type":"audio/x-caf"}, +"cap": {"type":"application/vnd.tcpdump.pcap"}, +"car": {"type":"application/vnd.curl.car"}, +"cat": {"type":"application/vnd.ms-pki.seccat"}, +"cb7": {"type":"application/x-cbr"}, +"cba": {"type":"application/x-cbr"}, +"cbr": {"type":"application/x-cbr"}, +"cbt": {"type":"application/x-cbr"}, +"cbz": {"type":"application/x-cbr"}, +"cc": {"type":"text/x-c"}, +"ccad": {"type":"application/clariscad"}, +"cco": {"type":"application/x-cocoa"}, +"cct": {"type":"shockwave/director","icon":"flash"}, +"ccxml": {"type":"application/ccxml+xml"}, +"cdbcmsg": {"type":"application/vnd.contact.cmsg"}, +"cdf": {"type":"application/x-netcdf"}, +"cdkey": {"type":"application/vnd.mediastation.cdkey"}, +"cdmia": {"type":"application/cdmi-capability"}, +"cdmic": {"type":"application/cdmi-container"}, +"cdmid": {"type":"application/cdmi-domain"}, +"cdmio": {"type":"application/cdmi-object"}, +"cdmiq": {"type":"application/cdmi-queue"}, +"cdoc": {"type":"application/x-digidoc","icon":"document","groups":["archive"]}, +"cdx": {"type":"chemical/x-cdx"}, +"cdxml": {"type":"application/vnd.chemdraw+xml"}, +"cdy": {"type":"application/vnd.cinderella"}, +"cer": {"type":"application/pkix-cert"}, +"cfc": {"type":"application/x-coldfusion"}, +"cfm": {"type":"application/x-coldfusion"}, +"cfs": {"type":"application/x-cfs-compressed"}, +"cgm": {"type":"image/cgm"}, +"cha": {"type":"application/x-chat"}, +"chat": {"type":"application/x-chat"}, +"chm": {"type":"application/vnd.ms-htmlhelp"}, +"chrt": {"type":"application/vnd.kde.kchart","icon":"chart"}, +"cif": {"type":"chemical/x-cif"}, +"cii": {"type":"application/vnd.anser-web-certificate-issue-initiation"}, +"cil": {"type":"application/vnd.ms-artgalry"}, +"cla": {"type":"application/vnd.claymore"}, +"class": {"type":"application/java-vm"}, +"clkk": {"type":"application/vnd.crick.clicker.keyboard"}, +"clkp": {"type":"application/vnd.crick.clicker.palette"}, +"clkt": {"type":"application/vnd.crick.clicker.template"}, +"clkw": {"type":"application/vnd.crick.clicker.wordbank"}, +"clkx": {"type":"application/vnd.crick.clicker"}, +"clp": {"type":"application/x-msclip"}, +"cmc": {"type":"application/vnd.cosmocaller"}, +"cmdf": {"type":"chemical/x-cmdf"}, +"cml": {"type":"chemical/x-cml"}, +"cmp": {"type":"application/vnd.yellowriver-custom-menu"}, +"cmx": {"type":"image/x-cmx"}, +"cod": {"type":"application/vnd.rim.cod"}, +"com": {"type":"application/x-msdownload"}, +"conf": {"type":"text/plain"}, +"cpio": {"type":"application/x-cpio"}, +"cpp": {"type":"text/plain","icon":"sourcecode"}, +"cpt": {"type":"application/mac-compactpro"}, +"crd": {"type":"application/x-mscardfile"}, +"crl": {"type":"application/pkix-crl"}, +"crt": {"type":"application/x-x509-ca-cert"}, +"crx": {"type":"application/octet-stream"}, +"cryptonote": {"type":"application/vnd.rig.cryptonote"}, +"cs": {"type":"application/x-csh","icon":"sourcecode"}, +"csh": {"type":"application/x-csh"}, +"csml": {"type":"chemical/x-csml"}, +"csp": {"type":"application/vnd.commonspace"}, +"csr": {"type":"application/pkcs10"}, +"css": {"type":"text/css","icon":"text","groups":["web_file"]}, +"cst": {"type":"application/x-director"}, +"csv": {"type":"text/csv","icon":"spreadsheet","groups":["spreadsheet"]}, +"cu": {"type":"application/cu-seeme"}, +"curl": {"type":"text/vnd.curl"}, +"cww": {"type":"application/prs.cww"}, +"cxt": {"type":"application/x-director"}, +"cxx": {"type":"text/x-c"}, +"dae": {"type":"model/vnd.collada+xml"}, +"daf": {"type":"application/vnd.mobius.daf"}, +"dart": {"type":"application/vnd.dart"}, +"dataless": {"type":"application/vnd.fdsn.seed"}, +"davmount": {"type":"application/davmount+xml"}, +"dbk": {"type":"application/docbook+xml"}, +"dcr": {"type":"application/x-director","icon":"flash"}, +"dcurl": {"type":"text/vnd.curl.dcurl"}, +"dd2": {"type":"application/vnd.oma.dd2+xml"}, +"ddd": {"type":"application/vnd.fujixerox.ddd"}, +"ddoc": {"type":"application/x-digidoc","icon":"document","groups":["archive"]}, +"deb": {"type":"application/x-debian-package"}, +"deepv": {"type":"application/x-deepv"}, +"def": {"type":"text/plain"}, +"deploy": {"type":"application/octet-stream"}, +"der": {"type":"application/x-x509-ca-cert"}, +"dfac": {"type":"application/vnd.dreamfactory"}, +"dgc": {"type":"application/x-dgc-compressed"}, +"dic": {"type":"text/x-c"}, +"dif": {"type":"video/x-dv","icon":"quicktime","string":"video","groups":["video"]}, +"dir": {"type":"application/x-director","icon":"flash"}, +"dis": {"type":"application/vnd.mobius.dis"}, +"dist": {"type":"application/octet-stream"}, +"distz": {"type":"application/octet-stream"}, +"djv": {"type":"image/vnd.djvu"}, +"djvu": {"type":"image/vnd.djvu"}, +"dl": {"type":"video/dl"}, +"dll": {"type":"application/x-msdownload"}, +"dmg": {"type":"application/octet-stream","icon":"unknown"}, +"dmp": {"type":"application/vnd.tcpdump.pcap"}, +"dms": {"type":"application/octet-stream"}, +"dna": {"type":"application/vnd.dna"}, +"doc": {"type":"application/msword","icon":"document","groups":["document"]}, +"docm": {"type":"application/vnd.ms-word.document.macroenabled.12","icon":"document"}, +"docx": {"type":"application/vnd.openxmlformats-officedocument.wordprocessingml.document","icon":"document","groups":["document"]}, +"dot": {"type":"application/msword"}, +"dotm": {"type":"application/vnd.ms-word.template.macroenabled.12","icon":"document"}, +"dotx": {"type":"application/vnd.openxmlformats-officedocument.wordprocessingml.template","icon":"document"}, +"dp": {"type":"application/vnd.osgi.dp"}, +"dpg": {"type":"application/vnd.dpgraph"}, +"dra": {"type":"audio/vnd.dra"}, +"drw": {"type":"application/drafting"}, +"dsc": {"type":"text/prs.lines.tag"}, +"dssc": {"type":"application/dssc+der"}, +"dtb": {"type":"application/x-dtbook+xml"}, +"dtd": {"type":"application/xml-dtd"}, +"dts": {"type":"audio/vnd.dts"}, +"dtshd": {"type":"audio/vnd.dts.hd"}, +"dump": {"type":"application/octet-stream"}, +"dv": {"type":"video/x-dv","icon":"quicktime","string":"video","groups":["video"]}, +"dvb": {"type":"video/vnd.dvb.file"}, +"dvi": {"type":"application/x-dvi"}, +"dwf": {"type":"model/vnd.dwf"}, +"dwg": {"type":"image/vnd.dwg"}, +"dxf": {"type":"image/vnd.dxf"}, +"dxp": {"type":"application/vnd.spotfire.dxp"}, +"dxr": {"type":"application/x-director","icon":"flash"}, +"ecelp4800": {"type":"audio/vnd.nuera.ecelp4800"}, +"ecelp7470": {"type":"audio/vnd.nuera.ecelp7470"}, +"ecelp9600": {"type":"audio/vnd.nuera.ecelp9600"}, +"ecma": {"type":"application/ecmascript"}, +"edm": {"type":"application/vnd.novadigm.edm"}, +"edx": {"type":"application/vnd.novadigm.edx"}, +"efif": {"type":"application/vnd.picsel"}, +"ei6": {"type":"application/vnd.pg.osasli"}, +"el": {"type":"text/x-script.elisp"}, +"elc": {"type":"application/octet-stream"}, +"emf": {"type":"application/x-msmetafile"}, +"eml": {"type":"message/rfc822"}, +"emma": {"type":"application/emma+xml"}, +"emz": {"type":"application/x-msmetafile"}, +"env": {"type":"application/x-envoy"}, +"eol": {"type":"audio/vnd.digital-winds"}, +"eot": {"type":"application/vnd.ms-fontobject"}, +"eps": {"type":"application/postscript","icon":"eps"}, +"epub": {"type":"application/epub+zip","icon":"epub","groups":["document"]}, +"es": {"type":"application/x-esrehber"}, +"es3": {"type":"application/vnd.eszigno3+xml"}, +"esa": {"type":"application/vnd.osgi.subsystem"}, +"esf": {"type":"application/vnd.epson.esf"}, +"et3": {"type":"application/vnd.eszigno3+xml"}, +"etx": {"type":"text/x-setext"}, +"eva": {"type":"application/x-eva"}, +"evy": {"type":"application/x-envoy"}, +"exe": {"type":"application/x-msdownload"}, +"exi": {"type":"application/exi"}, +"ext": {"type":"application/vnd.novadigm.ext"}, +"ez": {"type":"application/andrew-inset"}, +"ez2": {"type":"application/vnd.ezpix-album"}, +"ez3": {"type":"application/vnd.ezpix-package"}, +"f": {"type":"text/x-fortran"}, +"f4v": {"type":"video/mp4","icon":"flash","string":"video","groups":["video","web_video"]}, +"f77": {"type":"text/x-fortran"}, +"f90": {"type":"text/x-fortran"}, +"fbs": {"type":"image/vnd.fastbidsheet"}, +"fcdt": {"type":"application/vnd.adobe.formscentral.fcdt"}, +"fcs": {"type":"application/vnd.isac.fcs"}, +"fdf": {"type":"application/vnd.fdf","icon":"pdf"}, +"fdk": {"type":"application/octet-stream"}, +"fe_launch": {"type":"application/vnd.denovo.fcselayout-link"}, +"fg5": {"type":"application/vnd.fujitsu.oasysgp"}, +"fgd": {"type":"application/x-director"}, +"fh": {"type":"image/x-freehand"}, +"fh4": {"type":"image/x-freehand"}, +"fh5": {"type":"image/x-freehand"}, +"fh7": {"type":"image/x-freehand"}, +"fhc": {"type":"image/x-freehand"}, +"fif": {"type":"application/fractals"}, +"fig": {"type":"application/x-xfig"}, +"flac": {"type":"audio/flac","icon":"audio","string":"audio","groups":["audio","html_audio","web_audio"]}, +"fli": {"type":"video/x-fli"}, +"flo": {"type":"application/vnd.micrografx.flo"}, +"flv": {"type":"video/x-flv","icon":"flash","string":"video","groups":["video","web_video"]}, +"flw": {"type":"application/vnd.kde.kivio"}, +"flx": {"type":"text/vnd.fmi.flexstor"}, +"fly": {"type":"text/vnd.fly"}, +"fm": {"type":"application/vnd.framemaker"}, +"fmf": {"type":"video/x-atomic3d-feature"}, +"fmp4": {"type":"video/mp4","icon":"mpeg","string":"video","groups":["html_video","video","web_video"]}, +"fnc": {"type":"application/vnd.frogans.fnc"}, +"for": {"type":"text/x-fortran"}, +"fpx": {"type":"image/vnd.fpx"}, +"frame": {"type":"application/vnd.framemaker"}, +"frl": {"type":"application/freeloader"}, +"fsc": {"type":"application/vnd.fsc.weblaunch"}, +"fst": {"type":"image/vnd.fst"}, +"ftc": {"type":"application/vnd.fluxtime.clip"}, +"fti": {"type":"application/vnd.anser-web-funds-transfer-initiation"}, +"funk": {"type":"audio/make"}, +"fvt": {"type":"video/vnd.fvt"}, +"fxp": {"type":"application/vnd.adobe.fxp"}, +"fxpl": {"type":"application/vnd.adobe.fxp"}, +"fzs": {"type":"application/vnd.fuzzysheet"}, +"g": {"type":"text/plain"}, +"g2w": {"type":"application/vnd.geoplan"}, +"g3": {"type":"image/g3fax"}, +"g3w": {"type":"application/vnd.geospace"}, +"gac": {"type":"application/vnd.groove-account"}, +"gallery": {"type":"application/x-smarttech-notebook","icon":"archive"}, +"gallerycollection": {"type":"application/x-smarttech-notebook","icon":"archive"}, +"galleryitem": {"type":"application/x-smarttech-notebook","icon":"archive"}, +"gam": {"type":"application/x-tads"}, +"gbr": {"type":"application/rpki-ghostbusters"}, +"gca": {"type":"application/x-gca-compressed"}, +"gdl": {"type":"model/vnd.gdl"}, +"gdoc": {"type":"application/vnd.google-apps.document","icon":"document","groups":["document"]}, +"gdraw": {"type":"application/vnd.google-apps.drawing","icon":"image","groups":["image"]}, +"geo": {"type":"application/vnd.dynageo"}, +"gex": {"type":"application/vnd.geometry-explorer"}, +"ggb": {"type":"application/vnd.geogebra.file","icon":"archive"}, +"ggt": {"type":"application/vnd.geogebra.tool","icon":"archive"}, +"ghf": {"type":"application/vnd.groove-help"}, +"gif": {"type":"image/gif","icon":"gif","string":"image","groups":["image","web_image"]}, +"gim": {"type":"application/vnd.groove-identity-message"}, +"gl": {"type":"video/gl"}, +"gml": {"type":"application/gml+xml"}, +"gmx": {"type":"application/vnd.gmx"}, +"gnumeric": {"type":"application/x-gnumeric","icon":"calc"}, +"gph": {"type":"application/vnd.flographit"}, +"gpx": {"type":"application/gpx+xml"}, +"gqf": {"type":"application/vnd.grafeq"}, +"gqs": {"type":"application/vnd.grafeq"}, +"gram": {"type":"application/srgs"}, +"gramps": {"type":"application/x-gramps-xml"}, +"gre": {"type":"application/vnd.geometry-explorer"}, +"grv": {"type":"application/vnd.groove-injector"}, +"grxml": {"type":"application/srgs+xml"}, +"gsd": {"type":"audio/x-gsm"}, +"gsf": {"type":"application/x-font-ghostscript"}, +"gsheet": {"type":"application/vnd.google-apps.spreadsheet","icon":"spreadsheet","groups":["spreadsheet"]}, +"gslides": {"type":"application/vnd.google-apps.presentation","icon":"powerpoint","groups":["presentation"]}, +"gsm": {"type":"audio/x-gsm"}, +"gsp": {"type":"application/x-gsp"}, +"gss": {"type":"application/x-gss"}, +"gtar": {"type":"application/x-gtar","icon":"archive","string":"archive","groups":["archive"]}, +"gtm": {"type":"application/vnd.groove-tool-message"}, +"gtw": {"type":"model/vnd.gtw"}, +"gv": {"type":"text/vnd.graphviz"}, +"gxf": {"type":"application/gxf"}, +"gxt": {"type":"application/vnd.geonext"}, +"gz": {"type":"application/g-zip","icon":"archive","string":"archive","groups":["archive"]}, +"gzip": {"type":"application/g-zip","icon":"archive","string":"archive","groups":["archive"]}, +"h": {"type":"text/plain","icon":"sourcecode"}, +"h261": {"type":"video/h261"}, +"h263": {"type":"video/h263"}, +"h264": {"type":"video/h264"}, +"h5p": {"type":"application/zip","icon":"h5p","string":"archive"}, +"hal": {"type":"application/vnd.hal+xml"}, +"hbci": {"type":"application/vnd.hbci"}, +"hdf": {"type":"application/x-hdf"}, +"help": {"type":"application/x-helpfile"}, +"hgl": {"type":"application/vnd.hp-hpgl"}, +"hh": {"type":"text/x-c"}, +"hlb": {"type":"text/x-script"}, +"hlp": {"type":"application/winhlp"}, +"hpg": {"type":"application/vnd.hp-hpgl"}, +"hpgl": {"type":"application/vnd.hp-hpgl"}, +"hpid": {"type":"application/vnd.hp-hpid"}, +"hpp": {"type":"text/plain","icon":"sourcecode"}, +"hps": {"type":"application/vnd.hp-hps"}, +"hqx": {"type":"application/mac-binhex40","icon":"archive","string":"archive","groups":["archive"]}, +"hta": {"type":"application/octet-stream"}, +"htc": {"type":"text/x-component","icon":"markup"}, +"htke": {"type":"application/vnd.kenameaapp"}, +"htm": {"type":"text/html","icon":"html","groups":["web_file"]}, +"html": {"type":"text/html","icon":"html","groups":["web_file"]}, +"htmls": {"type":"text/html"}, +"htt": {"type":"text/webviewhtml"}, +"htx": {"type":"text/html"}, +"hvd": {"type":"application/vnd.yamaha.hv-dic"}, +"hvp": {"type":"application/vnd.yamaha.hv-voice"}, +"hvs": {"type":"application/vnd.yamaha.hv-script"}, +"i2g": {"type":"application/vnd.intergeo"}, +"ibooks": {"type":"application/x-ibooks+zip","icon":"archive"}, +"icc": {"type":"application/vnd.iccprofile"}, +"ice": {"type":"x-conference/x-cooltalk"}, +"icm": {"type":"application/vnd.iccprofile"}, +"ico": {"type":"image/vnd.microsoft.icon","icon":"image","string":"image","groups":["image"]}, +"ics": {"type":"text/calendar","icon":"text"}, +"idc": {"type":"text/plain"}, +"ief": {"type":"image/ief"}, +"iefs": {"type":"image/ief"}, +"ifb": {"type":"text/calendar"}, +"ifm": {"type":"application/vnd.shana.informed.formdata"}, +"iges": {"type":"model/iges"}, +"igl": {"type":"application/vnd.igloader"}, +"igm": {"type":"application/vnd.insors.igm"}, +"igs": {"type":"model/iges"}, +"igx": {"type":"application/vnd.micrografx.igx"}, +"iif": {"type":"application/vnd.shana.informed.interchange"}, +"ima": {"type":"application/x-ima"}, +"imap": {"type":"application/x-httpd-imap"}, +"imp": {"type":"application/vnd.accpac.simply.imp"}, +"ims": {"type":"application/vnd.ms-ims"}, +"in": {"type":"text/plain"}, +"inf": {"type":"application/inf"}, +"ini": {"type":"text/plain"}, +"ink": {"type":"application/inkml+xml"}, +"inkml": {"type":"application/inkml+xml"}, +"ins": {"type":"application/x-internett-signup"}, +"install": {"type":"application/x-install-instructions"}, +"iota": {"type":"application/vnd.astraea-software.iota"}, +"ip": {"type":"application/x-ip2"}, +"ipa": {"type":"application/octet-stream"}, +"ipfix": {"type":"application/ipfix"}, +"ipk": {"type":"application/vnd.shana.informed.package"}, +"irm": {"type":"application/vnd.ibm.rights-management"}, +"irp": {"type":"application/vnd.irepository.package+xml"}, +"isf": {"type":"application/inspiration","icon":"isf"}, +"iso": {"type":"application/x-iso9660-image"}, +"ist": {"type":"application/inspiration.template","icon":"isf"}, +"isu": {"type":"video/x-isvideo"}, +"it": {"type":"audio/it"}, +"itp": {"type":"application/vnd.shana.informed.formtemplate"}, +"iv": {"type":"application/x-inventor"}, +"ivp": {"type":"application/vnd.immervision-ivp"}, +"ivr": {"type":"i-world/i-vrml"}, +"ivu": {"type":"application/vnd.immervision-ivu"}, +"ivy": {"type":"application/x-livescreen"}, +"jad": {"type":"text/vnd.sun.j2me.app-descriptor"}, +"jam": {"type":"application/vnd.jam"}, +"jar": {"type":"application/java-archive","icon":"archive"}, +"jav": {"type":"text/plain"}, +"java": {"type":"text/plain","icon":"sourcecode"}, +"jcb": {"type":"text/xml","icon":"markup"}, +"jcl": {"type":"text/xml","icon":"markup"}, +"jcm": {"type":"application/x-java-commerce"}, +"jcw": {"type":"text/xml","icon":"markup"}, +"jfif": {"type":"image/jpeg"}, +"jfif-tbnl": {"type":"image/jpeg"}, +"jisp": {"type":"application/vnd.jisp"}, +"jlt": {"type":"application/vnd.hp-jlyt"}, +"jmt": {"type":"text/xml","icon":"markup"}, +"jmx": {"type":"text/xml","icon":"markup"}, +"jnlp": {"type":"application/x-java-jnlp-file","icon":"markup"}, +"joda": {"type":"application/vnd.joost.joda-archive"}, +"jpe": {"type":"image/jpeg","icon":"jpeg","string":"image","groups":["image","web_image"]}, +"jpeg": {"type":"image/jpeg","icon":"jpeg","string":"image","groups":["image","web_image"]}, +"jpg": {"type":"image/jpeg","icon":"jpeg","string":"image","groups":["image","web_image"]}, +"jpgm": {"type":"video/jpm"}, +"jpgv": {"type":"video/jpeg"}, +"jpm": {"type":"video/jpm"}, +"jps": {"type":"image/x-jps"}, +"jqz": {"type":"text/xml","icon":"markup"}, +"js": {"type":"application/x-javascript","icon":"text","groups":["web_file"]}, +"json": {"type":"application/json","icon":"text"}, +"jsonml": {"type":"application/jsonml+json"}, +"jut": {"type":"image/jutvision"}, +"kar": {"type":"audio/midi"}, +"karbon": {"type":"application/vnd.kde.karbon"}, +"key": {"type":"application/pkcs8"}, +"kfo": {"type":"application/vnd.kde.kformula"}, +"kia": {"type":"application/vnd.kidspiration"}, +"kml": {"type":"application/vnd.google-earth.kml+xml"}, +"kmz": {"type":"application/vnd.google-earth.kmz"}, +"kne": {"type":"application/vnd.kinar"}, +"knp": {"type":"application/vnd.kinar"}, +"kon": {"type":"application/vnd.kde.kontour"}, +"kpr": {"type":"application/vnd.kde.kpresenter"}, +"kpt": {"type":"application/vnd.kde.kpresenter"}, +"kpxx": {"type":"application/vnd.ds-keypoint"}, +"ksh": {"type":"application/x-ksh"}, +"ksp": {"type":"application/vnd.kde.kspread"}, +"ktr": {"type":"application/vnd.kahootz"}, +"ktx": {"type":"image/ktx"}, +"ktz": {"type":"application/vnd.kahootz"}, +"kwd": {"type":"application/vnd.kde.kword"}, +"kwt": {"type":"application/vnd.kde.kword"}, +"la": {"type":"audio/nspaudio"}, +"lam": {"type":"audio/x-liveaudio"}, +"lasxml": {"type":"application/vnd.las.las+xml"}, +"latex": {"type":"application/x-latex","icon":"text"}, +"lbd": {"type":"application/vnd.llamagraphics.life-balance.desktop"}, +"lbe": {"type":"application/vnd.llamagraphics.life-balance.exchange+xml"}, +"les": {"type":"application/vnd.hhe.lesson-player"}, +"lha": {"type":"application/x-lzh-compressed"}, +"lhx": {"type":"application/octet-stream"}, +"link66": {"type":"application/vnd.route66.link66+xml"}, +"list": {"type":"text/plain"}, +"list3820": {"type":"application/vnd.ibm.modcap"}, +"listafp": {"type":"application/vnd.ibm.modcap"}, +"lma": {"type":"audio/nspaudio"}, +"lnk": {"type":"application/x-ms-shortcut"}, +"log": {"type":"text/plain"}, +"lostxml": {"type":"application/lost+xml"}, +"lrf": {"type":"application/octet-stream"}, +"lrm": {"type":"application/vnd.ms-lrm"}, +"lsp": {"type":"application/x-lisp"}, +"lst": {"type":"text/plain"}, +"lsx": {"type":"text/x-la-asf"}, +"ltf": {"type":"application/vnd.frogans.ltf"}, +"ltx": {"type":"application/x-latex"}, +"lvp": {"type":"audio/vnd.lucent.voice"}, +"lwp": {"type":"application/vnd.lotus-wordpro"}, +"lz": {"type":"application/x-lzip","icon":"archive"}, +"lzh": {"type":"application/x-lzh-compressed"}, +"lzma": {"type":"application/x-lzma"}, +"lzo": {"type":"application/x-lzop"}, +"lzx": {"type":"application/lzx"}, +"m": {"type":"text/plain","icon":"sourcecode"}, +"m13": {"type":"application/x-msmediaview"}, +"m14": {"type":"application/x-msmediaview"}, +"m1v": {"type":"video/mpeg"}, +"m21": {"type":"application/mp21"}, +"m2a": {"type":"audio/mpeg"}, +"m2v": {"type":"video/mpeg"}, +"m3a": {"type":"audio/mpeg"}, +"m3u": {"type":"audio/x-mpegurl","icon":"mp3","string":"audio","groups":["audio"]}, +"m3u8": {"type":"application/x-mpegURL","icon":"mpeg","groups":["media_source"]}, +"m4a": {"type":"audio/mp4","icon":"mp3","string":"audio","groups":["audio","html_audio","web_audio"]}, +"m4u": {"type":"video/vnd.mpegurl"}, +"m4v": {"type":"video/mp4","icon":"mpeg","string":"video","groups":["html_video","video","web_video"]}, +"ma": {"type":"application/mathematica","string":"math"}, +"mads": {"type":"application/mads+xml"}, +"mag": {"type":"application/vnd.ecowin.chart"}, +"maker": {"type":"application/vnd.framemaker"}, +"man": {"type":"text/troff"}, +"map": {"type":"application/x-navimap"}, +"mar": {"type":"application/octet-stream"}, +"mathml": {"type":"application/mathml+xml","string":"math"}, +"mb": {"type":"application/mathematica","string":"math"}, +"mbd": {"type":"application/mbedlet"}, +"mbk": {"type":"application/vnd.mobius.mbk"}, +"mbox": {"type":"application/mbox"}, +"mbz": {"type":"application/vnd.moodle.backup","icon":"moodle"}, +"mc$": {"type":"application/x-magic-cap-package-1.0"}, +"mc1": {"type":"application/vnd.medcalcdata"}, +"mcd": {"type":"application/vnd.mcd"}, +"mcf": {"type":"image/vasa"}, +"mcp": {"type":"application/netmc"}, +"mcurl": {"type":"text/vnd.curl.mcurl"}, +"mdb": {"type":"application/x-msaccess","icon":"base"}, +"mdi": {"type":"image/vnd.ms-modi"}, +"me": {"type":"text/troff"}, +"mesh": {"type":"model/mesh"}, +"meta4": {"type":"application/metalink4+xml"}, +"metalink": {"type":"application/metalink+xml"}, +"mets": {"type":"application/mets+xml"}, +"mfm": {"type":"application/vnd.mfmp"}, +"mft": {"type":"application/rpki-manifest"}, +"mgp": {"type":"application/vnd.osgeo.mapguide.package"}, +"mgz": {"type":"application/vnd.proteus.magazine"}, +"mht": {"type":"message/rfc822","icon":"archive"}, +"mhtml": {"type":"message/rfc822","icon":"archive"}, +"mid": {"type":"audio/midi"}, +"midi": {"type":"audio/midi"}, +"mie": {"type":"application/x-mie"}, +"mif": {"type":"application/vnd.mif"}, +"mime": {"type":"message/rfc822"}, +"mj2": {"type":"video/mj2"}, +"mjf": {"type":"audio/x-vnd.audioexplosion.mjuicemediafile"}, +"mjp2": {"type":"video/mj2"}, +"mjpg": {"type":"video/x-motion-jpeg"}, +"mk3d": {"type":"video/x-matroska"}, +"mka": {"type":"audio/x-matroska"}, +"mks": {"type":"video/x-matroska"}, +"mkv": {"type":"video/x-matroska"}, +"mlp": {"type":"application/vnd.dolby.mlp"}, +"mm": {"type":"application/base64"}, +"mmd": {"type":"application/vnd.chipnuts.karaoke-mmd"}, +"mme": {"type":"application/base64"}, +"mmf": {"type":"application/vnd.smaf"}, +"mmr": {"type":"image/vnd.fujixerox.edmics-mmr"}, +"mng": {"type":"video/x-mng"}, +"mny": {"type":"application/x-msmoney"}, +"mobi": {"type":"application/x-mobipocket-ebook"}, +"mod": {"type":"audio/mod"}, +"mods": {"type":"application/mods+xml"}, +"moov": {"type":"video/quicktime"}, +"mov": {"type":"video/quicktime","icon":"quicktime","string":"video","groups":["video","web_video","html_video"]}, +"movie": {"type":"video/x-sgi-movie","icon":"quicktime","string":"video","groups":["video"]}, +"mp2": {"type":"audio/mpeg"}, +"mp21": {"type":"application/mp21"}, +"mp2a": {"type":"audio/mpeg"}, +"mp3": {"type":"audio/mp3","icon":"mp3","string":"audio","groups":["audio","html_audio","web_audio"]}, +"mp4": {"type":"video/mp4","icon":"mpeg","string":"video","groups":["html_video","video","web_video"]}, +"mp4a": {"type":"audio/mp4","icon":"audio","string":"audio","groups":["audio","html_audio","web_audio"]}, +"mp4s": {"type":"application/mp4"}, +"mp4v": {"type":"video/mp4","icon":"mpeg","string":"video","groups":["video","web_video"]}, +"mpa": {"type":"audio/mpeg"}, +"mpc": {"type":"application/vnd.mophun.certificate"}, +"mpd": {"type":"application/dash+xml","icon":"mpeg","groups":["media_source"]}, +"mpe": {"type":"video/mpeg","icon":"mpeg","string":"video","groups":["video","web_video"]}, +"mpeg": {"type":"video/mpeg","icon":"mpeg","string":"video","groups":["video","web_video"]}, +"mpg": {"type":"video/mpeg","icon":"mpeg","string":"video","groups":["video","web_video"]}, +"mpg4": {"type":"video/mp4"}, +"mpga": {"type":"audio/mpeg"}, +"mpkg": {"type":"application/vnd.apple.installer+xml"}, +"mpm": {"type":"application/vnd.blueice.multipass"}, +"mpn": {"type":"application/vnd.mophun.application"}, +"mpp": {"type":"application/vnd.ms-project"}, +"mpr": {"type":"application/vnd.moodle.profiling","icon":"moodle"}, +"mpt": {"type":"application/vnd.ms-project"}, +"mpv": {"type":"application/x-project"}, +"mpx": {"type":"application/x-project"}, +"mpy": {"type":"application/vnd.ibm.minipay"}, +"mqy": {"type":"application/vnd.mobius.mqy"}, +"mrc": {"type":"application/marc"}, +"mrcx": {"type":"application/marcxml+xml"}, +"ms": {"type":"text/troff"}, +"mscml": {"type":"application/mediaservercontrol+xml"}, +"mseed": {"type":"application/vnd.fdsn.mseed"}, +"mseq": {"type":"application/vnd.mseq"}, +"msf": {"type":"application/vnd.epson.msf"}, +"msh": {"type":"model/mesh"}, +"msi": {"type":"application/x-msdownload"}, +"msl": {"type":"application/vnd.mobius.msl"}, +"msty": {"type":"application/vnd.muvee.style"}, +"mts": {"type":"model/vnd.mts"}, +"mus": {"type":"application/vnd.musician"}, +"musicxml": {"type":"application/vnd.recordare.musicxml+xml"}, +"mv": {"type":"video/x-sgi-movie"}, +"mvb": {"type":"application/x-msmediaview"}, +"mw": {"type":"application/maple","icon":"math"}, +"mwf": {"type":"application/vnd.mfer"}, +"mws": {"type":"application/maple","icon":"math"}, +"mxf": {"type":"application/mxf"}, +"mxl": {"type":"application/vnd.recordare.musicxml"}, +"mxml": {"type":"application/xv+xml"}, +"mxs": {"type":"application/vnd.triscape.mxs"}, +"mxu": {"type":"video/vnd.mpegurl"}, +"my": {"type":"audio/make"}, +"mzz": {"type":"application/x-vnd.audioexplosion.mzz"}, +"n-gage": {"type":"application/vnd.nokia.n-gage.symbian.install"}, +"n3": {"type":"text/n3"}, +"nap": {"type":"image/naplps"}, +"naplps": {"type":"image/naplps"}, +"nb": {"type":"application/mathematica","string":"math"}, +"nbk": {"type":"application/x-smarttech-notebook","icon":"archive"}, +"nbp": {"type":"application/vnd.wolfram.player"}, +"nc": {"type":"application/x-netcdf"}, +"ncm": {"type":"application/vnd.nokia.configuration-message"}, +"ncx": {"type":"application/x-dtbncx+xml"}, +"nfo": {"type":"text/x-nfo"}, +"ngdat": {"type":"application/vnd.nokia.n-gage.data"}, +"nif": {"type":"image/x-niff"}, +"niff": {"type":"image/x-niff"}, +"nitf": {"type":"application/vnd.nitf"}, +"nix": {"type":"application/x-mix-transfer"}, +"nlu": {"type":"application/vnd.neurolanguage.nlu"}, +"nml": {"type":"application/vnd.enliven"}, +"nnd": {"type":"application/vnd.noblenet-directory"}, +"nns": {"type":"application/vnd.noblenet-sealer"}, +"nnw": {"type":"application/vnd.noblenet-web"}, +"notebook": {"type":"application/x-smarttech-notebook","icon":"archive"}, +"npx": {"type":"image/vnd.net-fpx"}, +"nsc": {"type":"application/x-conference"}, +"nsf": {"type":"application/vnd.lotus-notes"}, +"ntf": {"type":"application/vnd.nitf"}, +"nvd": {"type":"application/x-navidoc"}, +"nzb": {"type":"application/x-nzb"}, +"o": {"type":"application/octet-stream"}, +"oa2": {"type":"application/vnd.fujitsu.oasys2"}, +"oa3": {"type":"application/vnd.fujitsu.oasys3"}, +"oas": {"type":"application/vnd.fujitsu.oasys"}, +"obd": {"type":"application/x-msbinder"}, +"obj": {"type":"application/x-tgif"}, +"oda": {"type":"application/oda"}, +"odb": {"type":"application/vnd.oasis.opendocument.database","icon":"base"}, +"odc": {"type":"application/vnd.oasis.opendocument.chart","icon":"chart"}, +"odf": {"type":"application/vnd.oasis.opendocument.formula","icon":"math"}, +"odft": {"type":"application/vnd.oasis.opendocument.formula-template","icon":"math"}, +"odg": {"type":"application/vnd.oasis.opendocument.graphics","icon":"draw"}, +"odi": {"type":"application/vnd.oasis.opendocument.image","icon":"draw"}, +"odm": {"type":"application/vnd.oasis.opendocument.text-master","icon":"writer"}, +"odp": {"type":"application/vnd.oasis.opendocument.presentation","icon":"impress","groups":["presentation"]}, +"ods": {"type":"application/vnd.oasis.opendocument.spreadsheet","icon":"calc","groups":["spreadsheet"]}, +"odt": {"type":"application/vnd.oasis.opendocument.text","icon":"writer","groups":["document"]}, +"oga": {"type":"audio/ogg","icon":"audio","string":"audio","groups":["audio","html_audio","web_audio"]}, +"ogg": {"type":"audio/ogg","icon":"audio","string":"audio","groups":["audio","html_audio","web_audio"]}, +"ogv": {"type":"video/ogg","icon":"video","string":"video","groups":["html_video","video","web_video"]}, +"ogx": {"type":"application/ogg"}, +"omc": {"type":"application/x-omc"}, +"omcd": {"type":"application/x-omcdatamaker"}, +"omcr": {"type":"application/x-omcregerator"}, +"omdoc": {"type":"application/omdoc+xml"}, +"onepkg": {"type":"application/onenote"}, +"onetmp": {"type":"application/onenote"}, +"onetoc": {"type":"application/onenote"}, +"onetoc2": {"type":"application/onenote"}, +"opf": {"type":"application/oebps-package+xml"}, +"opml": {"type":"text/x-opml"}, +"oprc": {"type":"application/vnd.palm"}, +"org": {"type":"application/vnd.lotus-organizer"}, +"osf": {"type":"application/vnd.yamaha.openscoreformat"}, +"osfpvg": {"type":"application/vnd.yamaha.openscoreformat.osfpvg+xml"}, +"otc": {"type":"application/vnd.oasis.opendocument.chart-template","icon":"chart"}, +"otf": {"type":"application/x-font-otf"}, +"otg": {"type":"application/vnd.oasis.opendocument.graphics-template","icon":"draw"}, +"oth": {"type":"application/vnd.oasis.opendocument.text-web","icon":"oth","groups":["document"]}, +"oti": {"type":"application/vnd.oasis.opendocument.image-template"}, +"otp": {"type":"application/vnd.oasis.opendocument.presentation-template","icon":"impress","groups":["presentation"]}, +"ots": {"type":"application/vnd.oasis.opendocument.spreadsheet-template","icon":"calc","groups":["spreadsheet"]}, +"ott": {"type":"application/vnd.oasis.opendocument.text-template","icon":"writer","groups":["document"]}, +"oxps": {"type":"application/oxps"}, +"oxt": {"type":"application/vnd.openofficeorg.extension"}, +"p": {"type":"text/x-pascal"}, +"p10": {"type":"application/pkcs10"}, +"p12": {"type":"application/x-pkcs12"}, +"p7a": {"type":"application/x-pkcs7-signature"}, +"p7b": {"type":"application/x-pkcs7-certificates"}, +"p7c": {"type":"application/pkcs7-mime"}, +"p7m": {"type":"application/pkcs7-mime"}, +"p7r": {"type":"application/x-pkcs7-certreqresp"}, +"p7s": {"type":"application/pkcs7-signature"}, +"p8": {"type":"application/pkcs8"}, +"part": {"type":"application/pro_eng"}, +"pas": {"type":"text/x-pascal"}, +"paw": {"type":"application/vnd.pawaafile"}, +"pbd": {"type":"application/vnd.powerbuilder6"}, +"pbm": {"type":"image/x-portable-bitmap"}, +"pcap": {"type":"application/vnd.tcpdump.pcap"}, +"pcf": {"type":"application/x-font-pcf"}, +"pcl": {"type":"application/vnd.hp-pcl"}, +"pclxl": {"type":"application/vnd.hp-pclxl"}, +"pct": {"type":"image/pict","icon":"image","string":"image","groups":["image"]}, +"pcurl": {"type":"application/vnd.curl.pcurl"}, +"pcx": {"type":"image/x-pcx"}, +"pdb": {"type":"application/vnd.palm"}, +"pdf": {"type":"application/pdf","icon":"pdf","groups":["document"]}, +"pem": {"type":"application/x-pem-file"}, +"pfa": {"type":"application/x-font-type1"}, +"pfb": {"type":"application/x-font-type1"}, +"pfm": {"type":"application/x-font-type1"}, +"pfr": {"type":"application/font-tdpfr"}, +"pfunk": {"type":"audio/make"}, +"pfx": {"type":"application/x-pkcs12"}, +"pgm": {"type":"image/x-portable-graymap"}, +"pgn": {"type":"application/x-chess-pgn"}, +"pgp": {"type":"application/pgp-encrypted"}, +"phar": {"type":"application/octet-stream"}, +"php": {"type":"text/plain","icon":"sourcecode"}, +"phps": {"type":"application/x-httpd-phps"}, +"pic": {"type":"image/pict","icon":"image","string":"image","groups":["image"]}, +"pict": {"type":"image/pict","icon":"image","string":"image","groups":["image"]}, +"pkg": {"type":"application/octet-stream"}, +"pki": {"type":"application/pkixcmp"}, +"pkipath": {"type":"application/pkix-pkipath"}, +"pko": {"type":"application/vnd.ms-pki.pko"}, +"pl": {"type":"text/plain"}, +"plb": {"type":"application/vnd.3gpp.pic-bw-large"}, +"plc": {"type":"application/vnd.mobius.plc"}, +"plf": {"type":"application/vnd.pocketlearn"}, +"plist": {"type":"application/x-plist"}, +"pls": {"type":"application/pls+xml"}, +"plx": {"type":"application/x-pixclscript"}, +"pm": {"type":"image/x-xpixmap"}, +"pm4": {"type":"application/x-pagemaker"}, +"pm5": {"type":"application/x-pagemaker"}, +"pml": {"type":"application/vnd.ctc-posml"}, +"png": {"type":"image/png","icon":"png","string":"image","groups":["image","web_image"]}, +"pnm": {"type":"image/x-portable-anymap"}, +"portpkg": {"type":"application/vnd.macports.portpkg"}, +"pot": {"type":"application/vnd.ms-powerpoint","icon":"powerpoint","groups":["presentation"]}, +"potm": {"type":"application/vnd.ms-powerpoint.template.macroenabled.12","icon":"powerpoint","groups":["presentation"]}, +"potx": {"type":"application/vnd.openxmlformats-officedocument.presentationml.template","icon":"powerpoint","groups":["presentation"]}, +"pov": {"type":"model/x-pov"}, +"ppa": {"type":"application/vnd.ms-powerpoint","icon":"powerpoint","groups":["presentation"]}, +"ppam": {"type":"application/vnd.ms-powerpoint.addin.macroenabled.12","icon":"powerpoint","groups":["presentation"]}, +"ppd": {"type":"application/vnd.cups-ppd"}, +"ppm": {"type":"image/x-portable-pixmap"}, +"pps": {"type":"application/vnd.ms-powerpoint","icon":"powerpoint","groups":["presentation"]}, +"ppsm": {"type":"application/vnd.ms-powerpoint.slideshow.macroenabled.12","icon":"powerpoint","groups":["presentation"]}, +"ppsx": {"type":"application/vnd.openxmlformats-officedocument.presentationml.slideshow","icon":"powerpoint","groups":["presentation"]}, +"ppt": {"type":"application/vnd.ms-powerpoint","icon":"powerpoint","groups":["presentation"]}, +"pptm": {"type":"application/vnd.ms-powerpoint.presentation.macroenabled.12","icon":"powerpoint","groups":["presentation"]}, +"pptx": {"type":"application/vnd.openxmlformats-officedocument.presentationml.presentation","icon":"powerpoint","groups":["presentation"]}, +"ppz": {"type":"application/mspowerpoint"}, +"pqa": {"type":"application/vnd.palm"}, +"prc": {"type":"application/x-mobipocket-ebook"}, +"pre": {"type":"application/vnd.lotus-freelance"}, +"prf": {"type":"application/pics-rules"}, +"prt": {"type":"application/pro_eng"}, +"ps": {"type":"application/postscript","icon":"pdf"}, +"psb": {"type":"application/vnd.3gpp.pic-bw-small"}, +"psd": {"type":"image/vnd.adobe.photoshop","icon":"psd"}, +"psf": {"type":"application/x-font-linux-psf"}, +"pskcxml": {"type":"application/pskc+xml"}, +"ptid": {"type":"application/vnd.pvi.ptid1"}, +"pub": {"type":"application/x-mspublisher","icon":"publisher","groups":["presentation"]}, +"pvb": {"type":"application/vnd.3gpp.pic-bw-var"}, +"pvu": {"type":"paleovu/x-pv"}, +"pwn": {"type":"application/vnd.3m.post-it-notes"}, +"pwz": {"type":"application/vnd.ms-powerpoint","icon":"powerpoint","groups":["presentation"]}, +"py": {"type":"text/x-script.phyton"}, +"pya": {"type":"audio/vnd.ms-playready.media.pya"}, +"pyc": {"type":"application/x-bytecode.python"}, +"pyv": {"type":"video/vnd.ms-playready.media.pyv"}, +"qam": {"type":"application/vnd.epson.quickanime"}, +"qbo": {"type":"application/vnd.intu.qbo"}, +"qcp": {"type":"audio/vnd.qcelp"}, +"qd3": {"type":"x-world/x-3dmf"}, +"qd3d": {"type":"x-world/x-3dmf"}, +"qfx": {"type":"application/vnd.intu.qfx"}, +"qif": {"type":"image/x-quicktime"}, +"qps": {"type":"application/vnd.publishare-delta-tree"}, +"qt": {"type":"video/quicktime","icon":"quicktime","string":"video","groups":["video","web_video"]}, +"qtc": {"type":"video/x-qtc"}, +"qti": {"type":"image/x-quicktime"}, +"qtif": {"type":"image/x-quicktime"}, +"qwd": {"type":"application/vnd.quark.quarkxpress"}, +"qwt": {"type":"application/vnd.quark.quarkxpress"}, +"qxb": {"type":"application/vnd.quark.quarkxpress"}, +"qxd": {"type":"application/vnd.quark.quarkxpress"}, +"qxl": {"type":"application/vnd.quark.quarkxpress"}, +"qxt": {"type":"application/vnd.quark.quarkxpress"}, +"ra": {"type":"audio/x-realaudio-plugin","icon":"audio","string":"audio","groups":["audio","web_audio"]}, +"ram": {"type":"audio/x-pn-realaudio-plugin","icon":"audio","string":"audio","groups":["audio"]}, +"rar": {"type":"application/x-rar-compressed","icon":"archive","string":"archive","groups":["archive"]}, +"ras": {"type":"image/x-cmu-raster"}, +"rast": {"type":"image/cmu-raster"}, +"rb": {"type":"text/plain"}, +"rcprofile": {"type":"application/vnd.ipunplugged.rcprofile"}, +"rdf": {"type":"application/rdf+xml"}, +"rdz": {"type":"application/vnd.data-vision.rdz"}, +"rep": {"type":"application/vnd.businessobjects"}, +"res": {"type":"application/x-dtbresource+xml"}, +"resx": {"type":"text/xml"}, +"rexx": {"type":"text/x-script.rexx"}, +"rf": {"type":"image/vnd.rn-realflash"}, +"rgb": {"type":"image/x-rgb"}, +"rhb": {"type":"text/xml","icon":"markup"}, +"rif": {"type":"application/reginfo+xml"}, +"rip": {"type":"audio/vnd.rip"}, +"ris": {"type":"application/x-research-info-systems"}, +"rl": {"type":"application/resource-lists+xml"}, +"rlc": {"type":"image/vnd.fujixerox.edmics-rlc"}, +"rld": {"type":"application/resource-lists-diff+xml"}, +"rm": {"type":"audio/x-pn-realaudio-plugin","icon":"audio","string":"audio","groups":["audio"]}, +"rmi": {"type":"audio/midi"}, +"rmm": {"type":"audio/x-pn-realaudio"}, +"rmp": {"type":"audio/x-pn-realaudio-plugin"}, +"rms": {"type":"application/vnd.jcp.javame.midlet-rms"}, +"rmvb": {"type":"application/vnd.rn-realmedia-vbr","icon":"video","string":"video","groups":["video"]}, +"rnc": {"type":"application/relax-ng-compact-syntax"}, +"rng": {"type":"application/ringing-tones"}, +"rnx": {"type":"application/vnd.rn-realplayer"}, +"roa": {"type":"application/rpki-roa"}, +"roff": {"type":"text/troff"}, +"rp": {"type":"image/vnd.rn-realpix"}, +"rp9": {"type":"application/vnd.cloanto.rp9"}, +"rpm": {"type":"application/x-rpm"}, +"rpss": {"type":"application/vnd.nokia.radio-presets"}, +"rpst": {"type":"application/vnd.nokia.radio-preset"}, +"rq": {"type":"application/sparql-query"}, +"rs": {"type":"application/rls-services+xml"}, +"rsd": {"type":"application/rsd+xml"}, +"rss": {"type":"application/rss+xml"}, +"rt": {"type":"text/richtext"}, +"rtf": {"type":"text/rtf","icon":"text","groups":["document"]}, +"rtx": {"type":"text/richtext","icon":"text"}, +"rv": {"type":"audio/x-pn-realaudio-plugin","icon":"audio","string":"video","groups":["video"]}, +"s": {"type":"text/x-asm"}, +"s3m": {"type":"audio/s3m"}, +"saf": {"type":"application/vnd.yamaha.smaf-audio"}, +"safariextz": {"type":"application/octet-stream"}, +"sass": {"type":"text/x-sass"}, +"saveme": {"type":"application/octet-stream"}, +"sbk": {"type":"application/x-tbook"}, +"sbml": {"type":"application/sbml+xml"}, +"sc": {"type":"application/vnd.ibm.secure-container"}, +"scd": {"type":"application/x-msschedule"}, +"scm": {"type":"application/vnd.lotus-screencam"}, +"scq": {"type":"application/scvp-cv-request"}, +"scs": {"type":"application/scvp-cv-response"}, +"scss": {"type":"text/x-scss","icon":"text","groups":["web_file"]}, +"scurl": {"type":"text/vnd.curl.scurl"}, +"sda": {"type":"application/vnd.stardivision.draw","icon":"draw"}, +"sdc": {"type":"application/vnd.stardivision.calc","icon":"calc"}, +"sdd": {"type":"application/vnd.stardivision.impress","icon":"impress"}, +"sdkd": {"type":"application/vnd.solent.sdkm+xml"}, +"sdkm": {"type":"application/vnd.solent.sdkm+xml"}, +"sdml": {"type":"text/plain"}, +"sdp": {"type":"application/sdp"}, +"sdr": {"type":"application/sounder"}, +"sdw": {"type":"application/vnd.stardivision.writer","icon":"writer"}, +"sea": {"type":"application/sea"}, +"see": {"type":"application/vnd.seemail"}, +"seed": {"type":"application/vnd.fdsn.seed"}, +"sema": {"type":"application/vnd.sema"}, +"semd": {"type":"application/vnd.semd"}, +"semf": {"type":"application/vnd.semf"}, +"ser": {"type":"application/java-serialized-object"}, +"set": {"type":"application/set"}, +"setpay": {"type":"application/set-payment-initiation"}, +"setreg": {"type":"application/set-registration-initiation"}, +"sfd-hdstx": {"type":"application/vnd.hydrostatix.sof-data"}, +"sfs": {"type":"application/vnd.spotfire.sfs"}, +"sfv": {"type":"text/x-sfv"}, +"sgi": {"type":"image/sgi"}, +"sgl": {"type":"application/vnd.stardivision.writer-global"}, +"sgm": {"type":"text/sgml"}, +"sgml": {"type":"text/sgml"}, +"sh": {"type":"application/x-sh","icon":"sourcecode"}, +"shar": {"type":"application/x-shar"}, +"shf": {"type":"application/shf+xml"}, +"shtml": {"type":"text/html"}, +"sid": {"type":"image/x-mrsid-image"}, +"sig": {"type":"application/pgp-signature"}, +"sil": {"type":"audio/silk"}, +"silo": {"type":"model/mesh"}, +"sis": {"type":"application/vnd.symbian.install"}, +"sisx": {"type":"application/vnd.symbian.install"}, +"sit": {"type":"application/x-stuffit","icon":"archive","string":"archive","groups":["archive"]}, +"sitx": {"type":"application/x-stuffitx"}, +"skd": {"type":"application/vnd.koan"}, +"skm": {"type":"application/vnd.koan"}, +"skp": {"type":"application/vnd.koan"}, +"skt": {"type":"application/vnd.koan"}, +"sl": {"type":"application/x-seelogo"}, +"sldm": {"type":"application/vnd.ms-powerpoint.slide.macroenabled.12","icon":"powerpoint","groups":["presentation"]}, +"sldx": {"type":"application/vnd.openxmlformats-officedocument.presentationml.slide"}, +"slt": {"type":"application/vnd.epson.salt"}, +"sm": {"type":"application/vnd.stepmania.stepchart"}, +"smf": {"type":"application/vnd.stardivision.math","icon":"math"}, +"smi": {"type":"application/smil","icon":"text"}, +"smil": {"type":"application/smil","icon":"text"}, +"smv": {"type":"video/x-smv"}, +"smzip": {"type":"application/vnd.stepmania.package"}, +"snd": {"type":"audio/basic"}, +"snf": {"type":"application/x-font-snf"}, +"so": {"type":"application/octet-stream"}, +"sol": {"type":"application/solids"}, +"spc": {"type":"application/x-pkcs7-certificates"}, +"spf": {"type":"application/vnd.yamaha.smaf-phrase"}, +"spl": {"type":"application/x-futuresplash"}, +"spot": {"type":"text/vnd.in3d.spot"}, +"spp": {"type":"application/scvp-vp-response"}, +"spq": {"type":"application/scvp-vp-request"}, +"spr": {"type":"application/x-sprite"}, +"sprite": {"type":"application/x-sprite"}, +"spx": {"type":"audio/ogg"}, +"sql": {"type":"application/x-sql"}, +"sqt": {"type":"text/xml","icon":"markup"}, +"src": {"type":"application/x-wais-source"}, +"srt": {"type":"application/x-subrip"}, +"sru": {"type":"application/sru+xml"}, +"srx": {"type":"application/sparql-results+xml"}, +"ssdl": {"type":"application/ssdl+xml"}, +"sse": {"type":"application/vnd.kodak-descriptor"}, +"ssf": {"type":"application/vnd.epson.ssf"}, +"ssi": {"type":"text/x-server-parsed-html"}, +"ssm": {"type":"application/streamingmedia"}, +"ssml": {"type":"application/ssml+xml"}, +"sst": {"type":"application/vnd.ms-pki.certstore"}, +"st": {"type":"application/vnd.sailingtracker.track"}, +"stc": {"type":"application/vnd.sun.xml.calc.template","icon":"calc"}, +"std": {"type":"application/vnd.sun.xml.draw.template","icon":"draw"}, +"step": {"type":"application/step"}, +"stf": {"type":"application/vnd.wt.stf"}, +"sti": {"type":"application/vnd.sun.xml.impress.template","icon":"impress","groups":["presentation"]}, +"stk": {"type":"application/hyperstudio"}, +"stl": {"type":"application/vnd.ms-pki.stl"}, +"stp": {"type":"application/step"}, +"str": {"type":"application/vnd.pg.format"}, +"stw": {"type":"application/vnd.sun.xml.writer.template","icon":"writer"}, +"styl": {"type":"text/x-styl"}, +"sub": {"type":"image/vnd.dvb.subtitle"}, +"sus": {"type":"application/vnd.sus-calendar"}, +"susp": {"type":"application/vnd.sus-calendar"}, +"sv4cpio": {"type":"application/x-sv4cpio"}, +"sv4crc": {"type":"application/x-sv4crc"}, +"svc": {"type":"application/vnd.dvb.service"}, +"svd": {"type":"application/vnd.svd"}, +"svf": {"type":"image/vnd.dwg"}, +"svg": {"type":"image/svg+xml","icon":"image","string":"image","groups":["image","web_image"]}, +"svgz": {"type":"image/svg+xml","icon":"image","string":"image","groups":["image","web_image"]}, +"svr": {"type":"application/x-world"}, +"swa": {"type":"application/x-director","icon":"flash"}, +"swf": {"type":"application/x-shockwave-flash","icon":"flash","groups":["video"]}, +"swfl": {"type":"application/x-shockwave-flash","icon":"flash","groups":["video"]}, +"swi": {"type":"application/vnd.aristanetworks.swi"}, +"sxc": {"type":"application/vnd.sun.xml.calc","icon":"calc"}, +"sxd": {"type":"application/vnd.sun.xml.draw","icon":"draw"}, +"sxg": {"type":"application/vnd.sun.xml.writer.global","icon":"writer"}, +"sxi": {"type":"application/vnd.sun.xml.impress","icon":"impress","groups":["presentation"]}, +"sxm": {"type":"application/vnd.sun.xml.math","icon":"math"}, +"sxw": {"type":"application/vnd.sun.xml.writer","icon":"writer"}, +"t": {"type":"text/troff"}, +"t3": {"type":"application/x-t3vm-image"}, +"taglet": {"type":"application/vnd.mynfc"}, +"talk": {"type":"text/x-speech"}, +"tao": {"type":"application/vnd.tao.intent-module-archive"}, +"tar": {"type":"application/x-tar","icon":"archive","string":"archive","groups":["archive"]}, +"tbk": {"type":"application/toolbook"}, +"tcap": {"type":"application/vnd.3gpp2.tcap"}, +"tcl": {"type":"application/x-tcl"}, +"tcsh": {"type":"text/x-script.tcsh"}, +"teacher": {"type":"application/vnd.smart.teacher"}, +"tei": {"type":"application/tei+xml"}, +"teicorpus": {"type":"application/tei+xml"}, +"tex": {"type":"application/x-tex","icon":"text"}, +"texi": {"type":"application/x-texinfo","icon":"text"}, +"texinfo": {"type":"application/x-texinfo","icon":"text"}, +"text": {"type":"text/plain"}, +"tfi": {"type":"application/thraud+xml"}, +"tfm": {"type":"application/x-tex-tfm"}, +"tga": {"type":"image/x-tga"}, +"tgz": {"type":"application/g-zip","icon":"archive","string":"archive","groups":["archive"]}, +"thmx": {"type":"application/vnd.ms-officetheme"}, +"tif": {"type":"image/tiff","icon":"tiff","string":"image","groups":["image"]}, +"tiff": {"type":"image/tiff","icon":"tiff","string":"image","groups":["image"]}, +"tmo": {"type":"application/vnd.tmobile-livetv"}, +"torrent": {"type":"application/x-bittorrent"}, +"tpl": {"type":"application/vnd.groove-tool-template"}, +"tpt": {"type":"application/vnd.trid.tpt"}, +"tr": {"type":"text/troff"}, +"tra": {"type":"application/vnd.trueapp"}, +"trm": {"type":"application/x-msterminal"}, +"ts": {"type":"video/MP2T","icon":"mpeg","string":"video","groups":["video","web_video"]}, +"tsd": {"type":"application/timestamped-data"}, +"tsi": {"type":"audio/tsp-audio"}, +"tsp": {"type":"application/dsptype"}, +"tsv": {"type":"text/tab-separated-values","icon":"text"}, +"ttc": {"type":"application/x-font-ttf"}, +"ttf": {"type":"application/x-font-ttf"}, +"ttl": {"type":"text/turtle"}, +"turbot": {"type":"image/florian"}, +"twd": {"type":"application/vnd.simtech-mindmapper"}, +"twds": {"type":"application/vnd.simtech-mindmapper"}, +"txd": {"type":"application/vnd.genomatix.tuxedo"}, +"txf": {"type":"application/vnd.mobius.txf"}, +"txt": {"type":"text/plain","icon":"text","defaulticon":true}, +"udeb": {"type":"application/x-debian-package"}, +"ufd": {"type":"application/vnd.ufdl"}, +"ufdl": {"type":"application/vnd.ufdl"}, +"uil": {"type":"text/x-uil"}, +"ulx": {"type":"application/x-glulx"}, +"umj": {"type":"application/vnd.umajin"}, +"uni": {"type":"text/uri-list"}, +"unis": {"type":"text/uri-list"}, +"unityweb": {"type":"application/vnd.unity"}, +"unv": {"type":"application/i-deas"}, +"uoml": {"type":"application/vnd.uoml+xml"}, +"uri": {"type":"text/uri-list"}, +"uris": {"type":"text/uri-list"}, +"urls": {"type":"text/uri-list"}, +"ustar": {"type":"application/x-ustar"}, +"utz": {"type":"application/vnd.uiq.theme"}, +"uu": {"type":"text/x-uuencode"}, +"uue": {"type":"text/x-uuencode"}, +"uva": {"type":"audio/vnd.dece.audio"}, +"uvd": {"type":"application/vnd.dece.data"}, +"uvf": {"type":"application/vnd.dece.data"}, +"uvg": {"type":"image/vnd.dece.graphic"}, +"uvh": {"type":"video/vnd.dece.hd"}, +"uvi": {"type":"image/vnd.dece.graphic"}, +"uvm": {"type":"video/vnd.dece.mobile"}, +"uvp": {"type":"video/vnd.dece.pd"}, +"uvs": {"type":"video/vnd.dece.sd"}, +"uvt": {"type":"application/vnd.dece.ttml+xml"}, +"uvu": {"type":"video/vnd.uvvu.mp4"}, +"uvv": {"type":"video/vnd.dece.video"}, +"uvva": {"type":"audio/vnd.dece.audio"}, +"uvvd": {"type":"application/vnd.dece.data"}, +"uvvf": {"type":"application/vnd.dece.data"}, +"uvvg": {"type":"image/vnd.dece.graphic"}, +"uvvh": {"type":"video/vnd.dece.hd"}, +"uvvi": {"type":"image/vnd.dece.graphic"}, +"uvvm": {"type":"video/vnd.dece.mobile"}, +"uvvp": {"type":"video/vnd.dece.pd"}, +"uvvs": {"type":"video/vnd.dece.sd"}, +"uvvt": {"type":"application/vnd.dece.ttml+xml"}, +"uvvu": {"type":"video/vnd.uvvu.mp4"}, +"uvvv": {"type":"video/vnd.dece.video"}, +"uvvx": {"type":"application/vnd.dece.unspecified"}, +"uvvz": {"type":"application/vnd.dece.zip"}, +"uvx": {"type":"application/vnd.dece.unspecified"}, +"uvz": {"type":"application/vnd.dece.zip"}, +"vcard": {"type":"text/vcard"}, +"vcd": {"type":"application/x-cdlink"}, +"vcf": {"type":"text/x-vcard"}, +"vcg": {"type":"application/vnd.groove-vcard"}, +"vcs": {"type":"text/x-vcalendar"}, +"vcx": {"type":"application/vnd.vcx"}, +"vda": {"type":"application/vda"}, +"vdo": {"type":"video/vdo"}, +"vew": {"type":"application/groupwise"}, +"vis": {"type":"application/vnd.visionary"}, +"viv": {"type":"video/vnd.vivo"}, +"vivo": {"type":"video/vivo"}, +"vmd": {"type":"application/vocaltec-media-desc"}, +"vmf": {"type":"application/vocaltec-media-file"}, +"vob": {"type":"video/x-ms-vob"}, +"voc": {"type":"audio/voc"}, +"vor": {"type":"application/vnd.stardivision.writer","icon":"writer"}, +"vos": {"type":"video/vosaic"}, +"vox": {"type":"audio/voxware"}, +"vqe": {"type":"audio/x-twinvq-plugin"}, +"vqf": {"type":"audio/x-twinvq"}, +"vql": {"type":"audio/x-twinvq-plugin"}, +"vrml": {"type":"model/vrml"}, +"vrt": {"type":"x-world/x-vrt"}, +"vsd": {"type":"application/vnd.visio"}, +"vsf": {"type":"application/vnd.vsf"}, +"vss": {"type":"application/vnd.visio"}, +"vst": {"type":"application/vnd.visio"}, +"vsw": {"type":"application/vnd.visio"}, +"vtt": {"type":"text/vtt","icon":"text","groups":["html_track"]}, +"vtu": {"type":"model/vnd.vtu"}, +"vxml": {"type":"application/voicexml+xml"}, +"w3d": {"type":"application/x-director"}, +"w60": {"type":"application/wordperfect6.0"}, +"w61": {"type":"application/wordperfect6.1"}, +"w6w": {"type":"application/msword"}, +"wad": {"type":"application/x-doom"}, +"wav": {"type":"audio/wav","icon":"wav","string":"audio","groups":["audio","html_audio","web_audio"]}, +"wax": {"type":"audio/x-ms-wax"}, +"wb1": {"type":"application/x-qpro"}, +"wbmp": {"type":"image/vnd.wap.wbmp"}, +"wbs": {"type":"application/vnd.criticaltools.wbs+xml"}, +"wbxml": {"type":"application/vnd.wap.wbxml"}, +"wcm": {"type":"application/vnd.ms-works"}, +"wdb": {"type":"application/vnd.ms-works"}, +"wdp": {"type":"image/vnd.ms-photo"}, +"web": {"type":"application/vnd.xara"}, +"weba": {"type":"audio/webm","icon":"audio","string":"audio","groups":["audio","html_audio","web_audio"]}, +"webm": {"type":"video/webm","icon":"video","string":"video","groups":["html_video","video","web_video"]}, +"webp": {"type":"image/webp"}, +"wg": {"type":"application/vnd.pmi.widget"}, +"wgt": {"type":"application/widget"}, +"wiz": {"type":"application/msword"}, +"wk1": {"type":"application/x-123"}, +"wks": {"type":"application/vnd.ms-works"}, +"wm": {"type":"video/x-ms-wm"}, +"wma": {"type":"audio/x-ms-wma","icon":"audio","string":"audio","groups":["audio"]}, +"wmd": {"type":"application/x-ms-wmd"}, +"wmf": {"type":"application/x-msmetafile"}, +"wml": {"type":"text/vnd.wap.wml"}, +"wmlc": {"type":"application/vnd.wap.wmlc"}, +"wmls": {"type":"text/vnd.wap.wmlscript"}, +"wmlsc": {"type":"application/vnd.wap.wmlscriptc"}, +"wmv": {"type":"video/x-ms-wmv","icon":"wmv","string":"video","groups":["video"]}, +"wmx": {"type":"video/x-ms-wmx"}, +"wmz": {"type":"application/x-ms-wmz"}, +"woff": {"type":"application/x-font-woff"}, +"word": {"type":"application/msword"}, +"wp": {"type":"application/wordperfect"}, +"wp5": {"type":"application/wordperfect"}, +"wp6": {"type":"application/wordperfect"}, +"wpd": {"type":"application/vnd.wordperfect"}, +"wpl": {"type":"application/vnd.ms-wpl"}, +"wps": {"type":"application/vnd.ms-works"}, +"wq1": {"type":"application/x-lotus"}, +"wqd": {"type":"application/vnd.wqd"}, +"wri": {"type":"application/x-mswrite"}, +"wrl": {"type":"model/vrml"}, +"wrz": {"type":"model/vrml"}, +"wsc": {"type":"text/scriplet"}, +"wsdl": {"type":"application/wsdl+xml"}, +"wspolicy": {"type":"application/wspolicy+xml"}, +"wsrc": {"type":"application/x-wais-source"}, +"wtb": {"type":"application/vnd.webturbo"}, +"wtk": {"type":"application/x-wintalk"}, +"wvx": {"type":"video/x-ms-wvx"}, +"x-png": {"type":"image/png","icon":"png","string":"image","groups":["image","web_image"]}, +"x3d": {"type":"model/x3d+xml"}, +"x3db": {"type":"model/x3d+binary"}, +"x3dbz": {"type":"model/x3d+binary"}, +"x3dv": {"type":"model/x3d+vrml"}, +"x3dvz": {"type":"model/x3d+vrml"}, +"x3dz": {"type":"model/x3d+xml"}, +"xaml": {"type":"application/xaml+xml"}, +"xap": {"type":"application/x-silverlight-app"}, +"xar": {"type":"application/vnd.xara"}, +"xbap": {"type":"application/x-ms-xbap"}, +"xbd": {"type":"application/vnd.fujixerox.docuworks.binder"}, +"xbk": {"type":"application/x-smarttech-notebook","icon":"archive"}, +"xbm": {"type":"image/x-xbitmap"}, +"xdf": {"type":"application/xcap-diff+xml"}, +"xdm": {"type":"application/vnd.syncml.dm+xml"}, +"xdp": {"type":"application/vnd.adobe.xdp+xml","icon":"pdf"}, +"xdr": {"type":"video/x-amt-demorun"}, +"xdssc": {"type":"application/dssc+xml"}, +"xdw": {"type":"application/vnd.fujixerox.docuworks"}, +"xenc": {"type":"application/xenc+xml"}, +"xer": {"type":"application/patch-ops-error+xml"}, +"xfd": {"type":"application/vnd.xfdl","icon":"pdf"}, +"xfdf": {"type":"application/vnd.adobe.xfdf","icon":"pdf"}, +"xfdl": {"type":"application/vnd.xfdl"}, +"xgz": {"type":"xgl/drawing"}, +"xht": {"type":"application/xhtml+xml"}, +"xhtml": {"type":"application/xhtml+xml","icon":"html","groups":["web_file"]}, +"xhvml": {"type":"application/xv+xml"}, +"xif": {"type":"image/vnd.xiff"}, +"xl": {"type":"application/excel"}, +"xla": {"type":"application/vnd.ms-excel","icon":"spreadsheet"}, +"xlam": {"type":"application/vnd.ms-excel.addin.macroenabled.12","icon":"spreadsheet"}, +"xlb": {"type":"application/excel"}, +"xlc": {"type":"application/vnd.ms-excel","icon":"spreadsheet"}, +"xld": {"type":"application/excel"}, +"xlf": {"type":"application/x-xliff+xml"}, +"xlk": {"type":"application/excel"}, +"xll": {"type":"application/excel"}, +"xlm": {"type":"application/vnd.ms-excel","icon":"spreadsheet"}, +"xls": {"type":"application/vnd.ms-excel","icon":"spreadsheet","groups":["spreadsheet"]}, +"xlsb": {"type":"application/vnd.ms-excel.sheet.binary.macroenabled.12","icon":"spreadsheet"}, +"xlsm": {"type":"application/vnd.ms-excel.sheet.macroenabled.12","icon":"spreadsheet","groups":["spreadsheet"]}, +"xlsx": {"type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","icon":"spreadsheet","groups":["spreadsheet"]}, +"xlt": {"type":"application/vnd.ms-excel","icon":"spreadsheet"}, +"xltm": {"type":"application/vnd.ms-excel.template.macroenabled.12","icon":"spreadsheet"}, +"xltx": {"type":"application/vnd.openxmlformats-officedocument.spreadsheetml.template","icon":"spreadsheet"}, +"xlv": {"type":"application/excel"}, +"xlw": {"type":"application/vnd.ms-excel","icon":"spreadsheet"}, +"xm": {"type":"audio/xm"}, +"xml": {"type":"application/xml","icon":"markup"}, +"xmz": {"type":"xgl/movie"}, +"xo": {"type":"application/vnd.olpc-sugar"}, +"xop": {"type":"application/xop+xml"}, +"xpi": {"type":"application/x-xpinstall"}, +"xpix": {"type":"application/x-vnd.ls-xpix"}, +"xpl": {"type":"application/xproc+xml"}, +"xpm": {"type":"image/x-xpixmap"}, +"xpr": {"type":"application/vnd.is-xpr"}, +"xps": {"type":"application/vnd.ms-xpsdocument"}, +"xpw": {"type":"application/vnd.intercon.formnet"}, +"xpx": {"type":"application/vnd.intercon.formnet"}, +"xsl": {"type":"text/xml","icon":"markup"}, +"xslt": {"type":"application/xslt+xml"}, +"xsm": {"type":"application/vnd.syncml+xml"}, +"xspf": {"type":"application/xspf+xml"}, +"xsr": {"type":"video/x-amt-showrun"}, +"xul": {"type":"application/vnd.mozilla.xul+xml"}, +"xvm": {"type":"application/xv+xml"}, +"xvml": {"type":"application/xv+xml"}, +"xwd": {"type":"image/x-xwindowdump"}, +"xxx": {"type":"document/unknown","icon":"unknown"}, +"xyz": {"type":"chemical/x-xyz"}, +"xz": {"type":"application/x-xz"}, +"yaml": {"type":"text/yaml"}, +"yang": {"type":"application/yang"}, +"yin": {"type":"application/yin+xml"}, +"yml": {"type":"text/yaml"}, +"z": {"type":"application/x-compress"}, +"z1": {"type":"application/x-zmachine"}, +"z2": {"type":"application/x-zmachine"}, +"z3": {"type":"application/x-zmachine"}, +"z4": {"type":"application/x-zmachine"}, +"z5": {"type":"application/x-zmachine"}, +"z6": {"type":"application/x-zmachine"}, +"z7": {"type":"application/x-zmachine"}, +"z8": {"type":"application/x-zmachine"}, +"zaz": {"type":"application/vnd.zzazz.deck+xml"}, +"zip": {"type":"application/zip","icon":"archive","string":"archive","groups":["archive"]}, +"zir": {"type":"application/vnd.zul"}, +"zirz": {"type":"application/vnd.zul"}, +"zmm": {"type":"application/vnd.handheld-entertainment+xml"}, +"zoo": {"type":"application/octet-stream"}, +"zsh": {"type":"text/x-script.zsh"} +} \ No newline at end of file diff --git a/src/assets/mimetoext.json b/src/assets/mimetoext.json new file mode 100644 index 000000000..438731f8b --- /dev/null +++ b/src/assets/mimetoext.json @@ -0,0 +1,1095 @@ +{ +"application/acad": ["dwg"], +"application/andrew-inset": ["ez"], +"application/applixware": ["aw"], +"application/arj": ["arj"], +"application/atom+xml": ["atom"], +"application/atomcat+xml": ["atomcat"], +"application/atomsvc+xml": ["atomsvc"], +"application/base64": ["mm","mme"], +"application/binhex": ["hqx"], +"application/binhex4": ["hqx"], +"application/book": ["boo","book"], +"application/ccxml+xml": ["ccxml"], +"application/cdf": ["cdf"], +"application/cdmi-capability": ["cdmia"], +"application/cdmi-container": ["cdmic"], +"application/cdmi-domain": ["cdmid"], +"application/cdmi-object": ["cdmio"], +"application/cdmi-queue": ["cdmiq"], +"application/clariscad": ["ccad"], +"application/commonground": ["dp"], +"application/cu-seeme": ["cu"], +"application/dash+xml": ["mpd"], +"application/davmount+xml": ["davmount"], +"application/docbook+xml": ["dbk"], +"application/drafting": ["drw"], +"application/dsptype": ["tsp"], +"application/dssc+der": ["dssc"], +"application/dssc+xml": ["xdssc"], +"application/dxf": ["dxf"], +"application/ecmascript": ["ecma","js"], +"application/emma+xml": ["emma"], +"application/envoy": ["evy"], +"application/epub+zip": ["epub"], +"application/excel": ["xl","xlw","xlb","xlc","xld","xlk","xla","xlm","xls","xlt","xlv","xll"], +"application/exi": ["exi"], +"application/font-tdpfr": ["pfr"], +"application/font-woff": ["woff"], +"application/fractals": ["fif"], +"application/freeloader": ["frl"], +"application/futuresplash": ["spl"], +"application/g-zip": ["tgz","gz","gzip"], +"application/gml+xml": ["gml"], +"application/gnutar": ["tgz"], +"application/gpx+xml": ["gpx"], +"application/groupwise": ["vew"], +"application/gxf": ["gxf"], +"application/hlp": ["hlp"], +"application/hta": ["hta"], +"application/hyperstudio": ["stk"], +"application/i-deas": ["unv"], +"application/iges": ["iges","igs"], +"application/inf": ["inf"], +"application/inkml+xml": ["ink","inkml"], +"application/inspiration": ["isf"], +"application/inspiration.template": ["ist"], +"application/ipfix": ["ipfix"], +"application/java": ["class"], +"application/java-archive": ["jar"], +"application/java-byte-code": ["class"], +"application/java-serialized-object": ["ser"], +"application/java-vm": ["class"], +"application/javascript": ["js"], +"application/json": ["json"], +"application/jsonml+json": ["jsonml"], +"application/lha": ["lha"], +"application/lost+xml": ["lostxml"], +"application/lzx": ["lzx"], +"application/mac-binary": ["bin"], +"application/mac-binhex": ["hqx"], +"application/mac-binhex40": ["hqx"], +"application/mac-compactpro": ["cpt"], +"application/macbinary": ["bin"], +"application/mads+xml": ["mads"], +"application/maple": ["mw","mws"], +"application/marc": ["mrc"], +"application/marcxml+xml": ["mrcx"], +"application/mathematica": ["ma","mb","nb"], +"application/mathml+xml": ["mathml"], +"application/mbedlet": ["mbd"], +"application/mbox": ["mbox"], +"application/mcad": ["mcd"], +"application/mediaservercontrol+xml": ["mscml"], +"application/metalink+xml": ["metalink"], +"application/metalink4+xml": ["meta4"], +"application/mets+xml": ["mets"], +"application/mime": ["aps"], +"application/mods+xml": ["mods"], +"application/mp21": ["mp21","m21"], +"application/mp4": ["mp4s"], +"application/msaccess": ["accdb"], +"application/mspowerpoint": ["pot","pps","ppt","ppz"], +"application/msword": ["doc","dot","w6w","wiz","word"], +"application/mswrite": ["wri"], +"application/mxf": ["mxf"], +"application/netmc": ["mcp"], +"application/octet-stream": ["bin","a","arj","asax","zoo","bpk","com","crx","deploy","dist","distz","dmg","dms","dump","elc","exe","fdk","arc","ipa","lha","lhx","lrf","lzh","lzx","mar","o","phar","pkg","psd","safariextz","saveme","so","uu","hta"], +"application/oda": ["oda"], +"application/oebps-package+xml": ["opf"], +"application/ogg": ["ogx"], +"application/omdoc+xml": ["omdoc"], +"application/onenote": ["onepkg","onetmp","onetoc","onetoc2"], +"application/oxps": ["oxps"], +"application/patch-ops-error+xml": ["xer"], +"application/pdf": ["pdf","fdf","xdp","xfd","xfdf"], +"application/pgp-encrypted": ["pgp"], +"application/pgp-signature": ["asc","sig"], +"application/pics-rules": ["prf"], +"application/pkcs-12": ["p12"], +"application/pkcs-crl": ["crl"], +"application/pkcs10": ["p10","csr"], +"application/pkcs7-mime": ["p7c","p7m"], +"application/pkcs7-signature": ["p7s"], +"application/pkcs8": ["p8","key"], +"application/pkix-attr-cert": ["ac"], +"application/pkix-cert": ["cer","crt"], +"application/pkix-crl": ["crl"], +"application/pkix-pkipath": ["pkipath"], +"application/pkixcmp": ["pki"], +"application/plain": ["text"], +"application/pls+xml": ["pls"], +"application/postscript": ["ps","ai","eps"], +"application/powerpoint": ["ppt"], +"application/pro_eng": ["part","prt"], +"application/prs.cww": ["cww"], +"application/pskc+xml": ["pskcxml"], +"application/rdf+xml": ["rdf"], +"application/reginfo+xml": ["rif"], +"application/relax-ng-compact-syntax": ["rnc"], +"application/resource-lists+xml": ["rl"], +"application/resource-lists-diff+xml": ["rld"], +"application/ringing-tones": ["rng"], +"application/rls-services+xml": ["rs"], +"application/rpki-ghostbusters": ["gbr"], +"application/rpki-manifest": ["mft"], +"application/rpki-roa": ["roa"], +"application/rsd+xml": ["rsd"], +"application/rss+xml": ["rss"], +"application/rtf": ["rtf","rtx"], +"application/sbml+xml": ["sbml"], +"application/scvp-cv-request": ["scq"], +"application/scvp-cv-response": ["scs"], +"application/scvp-vp-request": ["spq"], +"application/scvp-vp-response": ["spp"], +"application/sdp": ["sdp"], +"application/sea": ["sea"], +"application/set": ["set"], +"application/set-payment-initiation": ["setpay"], +"application/set-registration-initiation": ["setreg"], +"application/shf+xml": ["shf"], +"application/sla": ["stl"], +"application/smil": ["smil","smi"], +"application/smil+xml": ["smi","smil"], +"application/solids": ["sol"], +"application/sounder": ["sdr"], +"application/sparql-query": ["rq"], +"application/sparql-results+xml": ["srx"], +"application/srgs": ["gram"], +"application/srgs+xml": ["grxml"], +"application/sru+xml": ["sru"], +"application/ssdl+xml": ["ssdl"], +"application/ssml+xml": ["ssml"], +"application/step": ["step","stp"], +"application/streamingmedia": ["ssm"], +"application/tei+xml": ["tei","teicorpus"], +"application/thraud+xml": ["tfi"], +"application/timestamped-data": ["tsd"], +"application/toolbook": ["tbk"], +"application/vda": ["vda"], +"application/vnd.3gpp.pic-bw-large": ["plb"], +"application/vnd.3gpp.pic-bw-small": ["psb"], +"application/vnd.3gpp.pic-bw-var": ["pvb"], +"application/vnd.3gpp2.tcap": ["tcap"], +"application/vnd.3m.post-it-notes": ["pwn"], +"application/vnd.accpac.simply.aso": ["aso"], +"application/vnd.accpac.simply.imp": ["imp"], +"application/vnd.acucobol": ["acu"], +"application/vnd.acucorp": ["atc","acutc"], +"application/vnd.adobe.air-application-installer-package+zip": ["air"], +"application/vnd.adobe.formscentral.fcdt": ["fcdt"], +"application/vnd.adobe.fxp": ["fxp","fxpl"], +"application/vnd.adobe.xdp+xml": ["xdp"], +"application/vnd.adobe.xfdf": ["xfdf"], +"application/vnd.ahead.space": ["ahead"], +"application/vnd.airzip.filesecure.azf": ["azf"], +"application/vnd.airzip.filesecure.azs": ["azs"], +"application/vnd.amazon.ebook": ["azw"], +"application/vnd.americandynamics.acc": ["acc"], +"application/vnd.amiga.ami": ["ami"], +"application/vnd.android.package-archive": ["apk"], +"application/vnd.anser-web-certificate-issue-initiation": ["cii"], +"application/vnd.anser-web-funds-transfer-initiation": ["fti"], +"application/vnd.antix.game-component": ["atx"], +"application/vnd.apple.installer+xml": ["mpkg"], +"application/vnd.apple.mpegurl": ["m3u8"], +"application/vnd.aristanetworks.swi": ["swi"], +"application/vnd.astraea-software.iota": ["iota"], +"application/vnd.audiograph": ["aep"], +"application/vnd.blueice.multipass": ["mpm"], +"application/vnd.bmi": ["bmi"], +"application/vnd.businessobjects": ["rep"], +"application/vnd.chemdraw+xml": ["cdxml"], +"application/vnd.chipnuts.karaoke-mmd": ["mmd"], +"application/vnd.cinderella": ["cdy"], +"application/vnd.claymore": ["cla"], +"application/vnd.cloanto.rp9": ["rp9"], +"application/vnd.clonk.c4group": ["c4d","c4f","c4g","c4p","c4u"], +"application/vnd.cluetrust.cartomobile-config": ["c11amc"], +"application/vnd.cluetrust.cartomobile-config-pkg": ["c11amz"], +"application/vnd.commonspace": ["csp"], +"application/vnd.contact.cmsg": ["cdbcmsg"], +"application/vnd.cosmocaller": ["cmc"], +"application/vnd.crick.clicker": ["clkx"], +"application/vnd.crick.clicker.keyboard": ["clkk"], +"application/vnd.crick.clicker.palette": ["clkp"], +"application/vnd.crick.clicker.template": ["clkt"], +"application/vnd.crick.clicker.wordbank": ["clkw"], +"application/vnd.criticaltools.wbs+xml": ["wbs"], +"application/vnd.ctc-posml": ["pml"], +"application/vnd.cups-ppd": ["ppd"], +"application/vnd.curl.car": ["car"], +"application/vnd.curl.pcurl": ["pcurl"], +"application/vnd.dart": ["dart"], +"application/vnd.data-vision.rdz": ["rdz"], +"application/vnd.dece.data": ["uvd","uvf","uvvd","uvvf"], +"application/vnd.dece.ttml+xml": ["uvt","uvvt"], +"application/vnd.dece.unspecified": ["uvvx","uvx"], +"application/vnd.dece.zip": ["uvvz","uvz"], +"application/vnd.denovo.fcselayout-link": ["fe_launch"], +"application/vnd.dna": ["dna"], +"application/vnd.dolby.mlp": ["mlp"], +"application/vnd.dpgraph": ["dpg"], +"application/vnd.dreamfactory": ["dfac"], +"application/vnd.ds-keypoint": ["kpxx"], +"application/vnd.dvb.ait": ["ait"], +"application/vnd.dvb.service": ["svc"], +"application/vnd.dynageo": ["geo"], +"application/vnd.ecowin.chart": ["mag"], +"application/vnd.enliven": ["nml"], +"application/vnd.epson.esf": ["esf"], +"application/vnd.epson.msf": ["msf"], +"application/vnd.epson.quickanime": ["qam"], +"application/vnd.epson.salt": ["slt"], +"application/vnd.epson.ssf": ["ssf"], +"application/vnd.eszigno3+xml": ["es3","et3"], +"application/vnd.ezpix-album": ["ez2"], +"application/vnd.ezpix-package": ["ez3"], +"application/vnd.fdf": ["fdf"], +"application/vnd.fdsn.mseed": ["mseed"], +"application/vnd.fdsn.seed": ["dataless","seed"], +"application/vnd.flographit": ["gph"], +"application/vnd.fluxtime.clip": ["ftc"], +"application/vnd.framemaker": ["book","fm","frame","maker"], +"application/vnd.frogans.fnc": ["fnc"], +"application/vnd.frogans.ltf": ["ltf"], +"application/vnd.fsc.weblaunch": ["fsc"], +"application/vnd.fujitsu.oasys": ["oas"], +"application/vnd.fujitsu.oasys2": ["oa2"], +"application/vnd.fujitsu.oasys3": ["oa3"], +"application/vnd.fujitsu.oasysgp": ["fg5"], +"application/vnd.fujitsu.oasysprs": ["bh2"], +"application/vnd.fujixerox.ddd": ["ddd"], +"application/vnd.fujixerox.docuworks": ["xdw"], +"application/vnd.fujixerox.docuworks.binder": ["xbd"], +"application/vnd.fuzzysheet": ["fzs"], +"application/vnd.genomatix.tuxedo": ["txd"], +"application/vnd.geogebra.file": ["ggb"], +"application/vnd.geogebra.tool": ["ggt"], +"application/vnd.geometry-explorer": ["gex","gre"], +"application/vnd.geonext": ["gxt"], +"application/vnd.geoplan": ["g2w"], +"application/vnd.geospace": ["g3w"], +"application/vnd.gmx": ["gmx"], +"application/vnd.google-apps.document": ["gdoc"], +"application/vnd.google-apps.presentation": ["gslides"], +"application/vnd.google-apps.spreadsheet": ["gsheet"], +"application/vnd.google-earth.kml+xml": ["kml"], +"application/vnd.google-earth.kmz": ["kmz"], +"application/vnd.grafeq": ["gqf","gqs"], +"application/vnd.groove-account": ["gac"], +"application/vnd.groove-help": ["ghf"], +"application/vnd.groove-identity-message": ["gim"], +"application/vnd.groove-injector": ["grv"], +"application/vnd.groove-tool-message": ["gtm"], +"application/vnd.groove-tool-template": ["tpl"], +"application/vnd.groove-vcard": ["vcg"], +"application/vnd.hal+xml": ["hal"], +"application/vnd.handheld-entertainment+xml": ["zmm"], +"application/vnd.hbci": ["hbci"], +"application/vnd.hhe.lesson-player": ["les"], +"application/vnd.hp-hpgl": ["hpgl","hgl","hpg"], +"application/vnd.hp-hpid": ["hpid"], +"application/vnd.hp-hps": ["hps"], +"application/vnd.hp-jlyt": ["jlt"], +"application/vnd.hp-pcl": ["pcl"], +"application/vnd.hp-pclxl": ["pclxl"], +"application/vnd.hydrostatix.sof-data": ["sfd-hdstx"], +"application/vnd.ibm.minipay": ["mpy"], +"application/vnd.ibm.modcap": ["afp","list3820","listafp"], +"application/vnd.ibm.rights-management": ["irm"], +"application/vnd.ibm.secure-container": ["sc"], +"application/vnd.iccprofile": ["icc","icm"], +"application/vnd.igloader": ["igl"], +"application/vnd.immervision-ivp": ["ivp"], +"application/vnd.immervision-ivu": ["ivu"], +"application/vnd.insors.igm": ["igm"], +"application/vnd.intercon.formnet": ["xpw","xpx"], +"application/vnd.intergeo": ["i2g"], +"application/vnd.intu.qbo": ["qbo"], +"application/vnd.intu.qfx": ["qfx"], +"application/vnd.ipunplugged.rcprofile": ["rcprofile"], +"application/vnd.irepository.package+xml": ["irp"], +"application/vnd.is-xpr": ["xpr"], +"application/vnd.isac.fcs": ["fcs"], +"application/vnd.jam": ["jam"], +"application/vnd.jcp.javame.midlet-rms": ["rms"], +"application/vnd.jisp": ["jisp"], +"application/vnd.joost.joda-archive": ["joda"], +"application/vnd.kahootz": ["ktr","ktz"], +"application/vnd.kde.karbon": ["karbon"], +"application/vnd.kde.kchart": ["chrt"], +"application/vnd.kde.kformula": ["kfo"], +"application/vnd.kde.kivio": ["flw"], +"application/vnd.kde.kontour": ["kon"], +"application/vnd.kde.kpresenter": ["kpr","kpt"], +"application/vnd.kde.kspread": ["ksp"], +"application/vnd.kde.kword": ["kwd","kwt"], +"application/vnd.kenameaapp": ["htke"], +"application/vnd.kidspiration": ["kia"], +"application/vnd.kinar": ["kne","knp"], +"application/vnd.koan": ["skd","skm","skp","skt"], +"application/vnd.kodak-descriptor": ["sse"], +"application/vnd.las.las+xml": ["lasxml"], +"application/vnd.llamagraphics.life-balance.desktop": ["lbd"], +"application/vnd.llamagraphics.life-balance.exchange+xml": ["lbe"], +"application/vnd.lotus-1-2-3": ["123"], +"application/vnd.lotus-approach": ["apr"], +"application/vnd.lotus-freelance": ["pre"], +"application/vnd.lotus-notes": ["nsf"], +"application/vnd.lotus-organizer": ["org"], +"application/vnd.lotus-screencam": ["scm"], +"application/vnd.lotus-wordpro": ["lwp"], +"application/vnd.macports.portpkg": ["portpkg"], +"application/vnd.mcd": ["mcd"], +"application/vnd.medcalcdata": ["mc1"], +"application/vnd.mediastation.cdkey": ["cdkey"], +"application/vnd.mfer": ["mwf"], +"application/vnd.mfmp": ["mfm"], +"application/vnd.micrografx.flo": ["flo"], +"application/vnd.micrografx.igx": ["igx"], +"application/vnd.mif": ["mif"], +"application/vnd.mobius.daf": ["daf"], +"application/vnd.mobius.dis": ["dis"], +"application/vnd.mobius.mbk": ["mbk"], +"application/vnd.mobius.mqy": ["mqy"], +"application/vnd.mobius.msl": ["msl"], +"application/vnd.mobius.plc": ["plc"], +"application/vnd.mobius.txf": ["txf"], +"application/vnd.moodle.backup": ["mbz"], +"application/vnd.moodle.profiling": ["mpr"], +"application/vnd.mophun.application": ["mpn"], +"application/vnd.mophun.certificate": ["mpc"], +"application/vnd.mozilla.xul+xml": ["xul"], +"application/vnd.ms-artgalry": ["cil"], +"application/vnd.ms-cab-compressed": ["cab"], +"application/vnd.ms-excel": ["xls","xla","xlb","xlc","xll","xlm","xlt","xlw"], +"application/vnd.ms-excel.addin.macroenabled.12": ["xlam"], +"application/vnd.ms-excel.sheet.binary.macroenabled.12": ["xlsb"], +"application/vnd.ms-excel.sheet.macroenabled.12": ["xlsm"], +"application/vnd.ms-excel.template.macroenabled.12": ["xltm"], +"application/vnd.ms-fontobject": ["eot"], +"application/vnd.ms-htmlhelp": ["chm"], +"application/vnd.ms-ims": ["ims"], +"application/vnd.ms-lrm": ["lrm"], +"application/vnd.ms-officetheme": ["thmx"], +"application/vnd.ms-pki.certstore": ["sst"], +"application/vnd.ms-pki.pko": ["pko"], +"application/vnd.ms-pki.seccat": ["cat"], +"application/vnd.ms-pki.stl": ["stl"], +"application/vnd.ms-powerpoint": ["ppt","pot","ppa","pps","pwz"], +"application/vnd.ms-powerpoint.addin.macroenabled.12": ["ppam"], +"application/vnd.ms-powerpoint.presentation.macroenabled.12": ["pptm"], +"application/vnd.ms-powerpoint.slide.macroenabled.12": ["sldm"], +"application/vnd.ms-powerpoint.slideshow.macroenabled.12": ["ppsm"], +"application/vnd.ms-powerpoint.template.macroenabled.12": ["potm"], +"application/vnd.ms-project": ["mpp","mpt"], +"application/vnd.ms-word.document.macroenabled.12": ["docm"], +"application/vnd.ms-word.template.macroenabled.12": ["dotm"], +"application/vnd.ms-works": ["wcm","wdb","wks","wps"], +"application/vnd.ms-wpl": ["wpl"], +"application/vnd.ms-xpsdocument": ["xps"], +"application/vnd.mseq": ["mseq"], +"application/vnd.musician": ["mus"], +"application/vnd.muvee.style": ["msty"], +"application/vnd.mynfc": ["taglet"], +"application/vnd.neurolanguage.nlu": ["nlu"], +"application/vnd.nitf": ["nitf","ntf"], +"application/vnd.noblenet-directory": ["nnd"], +"application/vnd.noblenet-sealer": ["nns"], +"application/vnd.noblenet-web": ["nnw"], +"application/vnd.nokia.configuration-message": ["ncm"], +"application/vnd.nokia.n-gage.data": ["ngdat"], +"application/vnd.nokia.n-gage.symbian.install": ["n-gage"], +"application/vnd.nokia.radio-preset": ["rpst"], +"application/vnd.nokia.radio-presets": ["rpss"], +"application/vnd.nokia.ringing-tone": ["rng"], +"application/vnd.novadigm.edm": ["edm"], +"application/vnd.novadigm.edx": ["edx"], +"application/vnd.novadigm.ext": ["ext"], +"application/vnd.oasis.opendocument.chart": ["odc"], +"application/vnd.oasis.opendocument.chart-template": ["otc"], +"application/vnd.oasis.opendocument.database": ["odb"], +"application/vnd.oasis.opendocument.formula": ["odf"], +"application/vnd.oasis.opendocument.formula-template": ["odft"], +"application/vnd.oasis.opendocument.graphics": ["odg"], +"application/vnd.oasis.opendocument.graphics-template": ["otg"], +"application/vnd.oasis.opendocument.image": ["odi"], +"application/vnd.oasis.opendocument.image-template": ["oti"], +"application/vnd.oasis.opendocument.presentation": ["odp"], +"application/vnd.oasis.opendocument.presentation-template": ["otp"], +"application/vnd.oasis.opendocument.spreadsheet": ["ods"], +"application/vnd.oasis.opendocument.spreadsheet-template": ["ots"], +"application/vnd.oasis.opendocument.text": ["odt"], +"application/vnd.oasis.opendocument.text-master": ["odm"], +"application/vnd.oasis.opendocument.text-template": ["ott"], +"application/vnd.oasis.opendocument.text-web": ["oth"], +"application/vnd.olpc-sugar": ["xo"], +"application/vnd.oma.dd2+xml": ["dd2"], +"application/vnd.openofficeorg.extension": ["oxt"], +"application/vnd.openxmlformats-officedocument.presentationml.presentation": ["pptx"], +"application/vnd.openxmlformats-officedocument.presentationml.slide": ["sldx"], +"application/vnd.openxmlformats-officedocument.presentationml.slideshow": ["ppsx"], +"application/vnd.openxmlformats-officedocument.presentationml.template": ["potx"], +"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ["xlsx"], +"application/vnd.openxmlformats-officedocument.spreadsheetml.template": ["xltx"], +"application/vnd.openxmlformats-officedocument.wordprocessingml.document": ["docx"], +"application/vnd.openxmlformats-officedocument.wordprocessingml.template": ["dotx"], +"application/vnd.osgeo.mapguide.package": ["mgp"], +"application/vnd.osgi.dp": ["dp"], +"application/vnd.osgi.subsystem": ["esa"], +"application/vnd.palm": ["oprc","pdb","pqa"], +"application/vnd.pawaafile": ["paw"], +"application/vnd.pg.format": ["str"], +"application/vnd.pg.osasli": ["ei6"], +"application/vnd.picsel": ["efif"], +"application/vnd.pmi.widget": ["wg"], +"application/vnd.pocketlearn": ["plf"], +"application/vnd.powerbuilder6": ["pbd"], +"application/vnd.previewsystems.box": ["box"], +"application/vnd.proteus.magazine": ["mgz"], +"application/vnd.publishare-delta-tree": ["qps"], +"application/vnd.pvi.ptid1": ["ptid"], +"application/vnd.quark.quarkxpress": ["qwd","qwt","qxb","qxd","qxl","qxt"], +"application/vnd.realvnc.bed": ["bed"], +"application/vnd.recordare.musicxml": ["mxl"], +"application/vnd.recordare.musicxml+xml": ["musicxml"], +"application/vnd.rig.cryptonote": ["cryptonote"], +"application/vnd.rim.cod": ["cod"], +"application/vnd.rn-realmedia": ["rm"], +"application/vnd.rn-realmedia-vbr": ["rmvb"], +"application/vnd.rn-realplayer": ["rnx"], +"application/vnd.route66.link66+xml": ["link66"], +"application/vnd.sailingtracker.track": ["st"], +"application/vnd.seemail": ["see"], +"application/vnd.sema": ["sema"], +"application/vnd.semd": ["semd"], +"application/vnd.semf": ["semf"], +"application/vnd.shana.informed.formdata": ["ifm"], +"application/vnd.shana.informed.formtemplate": ["itp"], +"application/vnd.shana.informed.interchange": ["iif"], +"application/vnd.shana.informed.package": ["ipk"], +"application/vnd.simtech-mindmapper": ["twd","twds"], +"application/vnd.smaf": ["mmf"], +"application/vnd.smart.teacher": ["teacher"], +"application/vnd.solent.sdkm+xml": ["sdkd","sdkm"], +"application/vnd.spotfire.dxp": ["dxp"], +"application/vnd.spotfire.sfs": ["sfs"], +"application/vnd.stardivision.calc": ["sdc"], +"application/vnd.stardivision.draw": ["sda"], +"application/vnd.stardivision.impress": ["sdd"], +"application/vnd.stardivision.math": ["smf"], +"application/vnd.stardivision.writer": ["sdw","vor"], +"application/vnd.stardivision.writer-global": ["sgl"], +"application/vnd.stepmania.package": ["smzip"], +"application/vnd.stepmania.stepchart": ["sm"], +"application/vnd.sun.xml.calc": ["sxc"], +"application/vnd.sun.xml.calc.template": ["stc"], +"application/vnd.sun.xml.draw": ["sxd"], +"application/vnd.sun.xml.draw.template": ["std"], +"application/vnd.sun.xml.impress": ["sxi"], +"application/vnd.sun.xml.impress.template": ["sti"], +"application/vnd.sun.xml.math": ["sxm"], +"application/vnd.sun.xml.writer": ["sxw"], +"application/vnd.sun.xml.writer.global": ["sxg"], +"application/vnd.sun.xml.writer.template": ["stw"], +"application/vnd.sus-calendar": ["sus","susp"], +"application/vnd.svd": ["svd"], +"application/vnd.symbian.install": ["sis","sisx"], +"application/vnd.syncml+xml": ["xsm"], +"application/vnd.syncml.dm+wbxml": ["bdm"], +"application/vnd.syncml.dm+xml": ["xdm"], +"application/vnd.tao.intent-module-archive": ["tao"], +"application/vnd.tcpdump.pcap": ["cap","dmp","pcap"], +"application/vnd.tmobile-livetv": ["tmo"], +"application/vnd.trid.tpt": ["tpt"], +"application/vnd.triscape.mxs": ["mxs"], +"application/vnd.trueapp": ["tra"], +"application/vnd.ufdl": ["ufdl","ufd"], +"application/vnd.uiq.theme": ["utz"], +"application/vnd.umajin": ["umj"], +"application/vnd.unity": ["unityweb"], +"application/vnd.uoml+xml": ["uoml"], +"application/vnd.vcx": ["vcx"], +"application/vnd.visio": ["vsd","vss","vst","vsw"], +"application/vnd.visionary": ["vis"], +"application/vnd.vsf": ["vsf"], +"application/vnd.wap.wbxml": ["wbxml"], +"application/vnd.wap.wmlc": ["wmlc"], +"application/vnd.wap.wmlscriptc": ["wmlsc"], +"application/vnd.webturbo": ["wtb"], +"application/vnd.wolfram.player": ["nbp"], +"application/vnd.wordperfect": ["wpd"], +"application/vnd.wqd": ["wqd"], +"application/vnd.wt.stf": ["stf"], +"application/vnd.xara": ["xar","web"], +"application/vnd.xfdl": ["xfdl","xfd"], +"application/vnd.yamaha.hv-dic": ["hvd"], +"application/vnd.yamaha.hv-script": ["hvs"], +"application/vnd.yamaha.hv-voice": ["hvp"], +"application/vnd.yamaha.openscoreformat": ["osf"], +"application/vnd.yamaha.openscoreformat.osfpvg+xml": ["osfpvg"], +"application/vnd.yamaha.smaf-audio": ["saf"], +"application/vnd.yamaha.smaf-phrase": ["spf"], +"application/vnd.yellowriver-custom-menu": ["cmp"], +"application/vnd.zul": ["zir","zirz"], +"application/vnd.zzazz.deck+xml": ["zaz"], +"application/vocaltec-media-desc": ["vmd"], +"application/vocaltec-media-file": ["vmf"], +"application/voicexml+xml": ["vxml"], +"application/widget": ["wgt"], +"application/winhlp": ["hlp"], +"application/wordperfect": ["wp","wp5","wp6","wpd"], +"application/wordperfect6.0": ["w60","wp5"], +"application/wordperfect6.1": ["w61"], +"application/wsdl+xml": ["wsdl"], +"application/wspolicy+xml": ["wspolicy"], +"application/x-123": ["wk1"], +"application/x-7z-compressed": ["7z"], +"application/x-abiword": ["abw"], +"application/x-ace-compressed": ["ace"], +"application/x-aim": ["aim"], +"application/x-apple-diskimage": ["dmg"], +"application/x-authorware-bin": ["aab"], +"application/x-authorware-map": ["aam"], +"application/x-authorware-seg": ["aas"], +"application/x-bcpio": ["bcpio"], +"application/x-binary": ["bin"], +"application/x-binhex40": ["hqx"], +"application/x-bittorrent": ["torrent"], +"application/x-blorb": ["blorb","blb"], +"application/x-bsh": ["bsh","sh","shar"], +"application/x-bytecode.elisp (compiled elisp)": ["elc"], +"application/x-bytecode.python": ["pyc"], +"application/x-bzip": ["bz"], +"application/x-bzip2": ["bz2","boz"], +"application/x-cbr": ["cbr","cb7","cba","cbt","cbz"], +"application/x-cdf": ["cdf"], +"application/x-cdlink": ["vcd"], +"application/x-cfs-compressed": ["cfs"], +"application/x-chat": ["chat","cha"], +"application/x-chess-pgn": ["pgn"], +"application/x-cmu-raster": ["ras"], +"application/x-cocoa": ["cco"], +"application/x-coldfusion": ["cfc","cfm"], +"application/x-compactpro": ["cpt"], +"application/x-compress": ["z"], +"application/x-compressed": ["gz","tgz","z","zip"], +"application/x-conference": ["nsc"], +"application/x-cpio": ["cpio"], +"application/x-cpt": ["cpt"], +"application/x-csh": ["csh","cs"], +"application/x-debian-package": ["deb","udeb"], +"application/x-deepv": ["deepv"], +"application/x-dgc-compressed": ["dgc"], +"application/x-digidoc": ["bdoc","cdoc","ddoc"], +"application/x-director": ["cct","cst","cxt","dcr","dir","dxr","fgd","swa","w3d"], +"application/x-doom": ["wad"], +"application/x-dtbncx+xml": ["ncx"], +"application/x-dtbook+xml": ["dtb"], +"application/x-dtbresource+xml": ["res"], +"application/x-dvi": ["dvi"], +"application/x-elc": ["elc"], +"application/x-envoy": ["evy","env"], +"application/x-esrehber": ["es"], +"application/x-eva": ["eva"], +"application/x-excel": ["xla","xlw","xlc","xld","xlk","xlb","xlm","xls","xlt","xlv","xll"], +"application/x-font-bdf": ["bdf"], +"application/x-font-ghostscript": ["gsf"], +"application/x-font-linux-psf": ["psf"], +"application/x-font-otf": ["otf"], +"application/x-font-pcf": ["pcf"], +"application/x-font-snf": ["snf"], +"application/x-font-ttf": ["ttf","ttc"], +"application/x-font-type1": ["afm","pfa","pfb","pfm"], +"application/x-font-woff": ["woff"], +"application/x-frame": ["mif"], +"application/x-freearc": ["arc"], +"application/x-freelance": ["pre"], +"application/x-futuresplash": ["spl"], +"application/x-gca-compressed": ["gca"], +"application/x-glulx": ["ulx"], +"application/x-gnumeric": ["gnumeric"], +"application/x-gramps-xml": ["gramps"], +"application/x-gsp": ["gsp"], +"application/x-gss": ["gss"], +"application/x-gtar": ["gtar"], +"application/x-gzip": ["gz","gzip","tgz"], +"application/x-hdf": ["hdf"], +"application/x-helpfile": ["help","hlp"], +"application/x-httpd-imap": ["imap"], +"application/x-httpd-phps": ["phps"], +"application/x-ibooks+zip": ["ibooks"], +"application/x-ima": ["ima"], +"application/x-install-instructions": ["install"], +"application/x-internett-signup": ["ins"], +"application/x-inventor": ["iv"], +"application/x-ip2": ["ip"], +"application/x-iso9660-image": ["iso"], +"application/x-java-class": ["class"], +"application/x-java-commerce": ["jcm"], +"application/x-java-jnlp-file": ["jnlp"], +"application/x-javascript": ["js"], +"application/x-koan": ["skd","skm","skp","skt"], +"application/x-ksh": ["ksh"], +"application/x-latex": ["latex","ltx"], +"application/x-lha": ["lha"], +"application/x-lisp": ["lsp"], +"application/x-livescreen": ["ivy"], +"application/x-lotus": ["wq1"], +"application/x-lotusscreencam": ["scm"], +"application/x-lzh": ["lzh"], +"application/x-lzh-compressed": ["lha","lzh"], +"application/x-lzip": ["lz"], +"application/x-lzma": ["lzma"], +"application/x-lzop": ["lzo"], +"application/x-lzx": ["lzx"], +"application/x-mac-binhex40": ["hqx"], +"application/x-macbinary": ["bin"], +"application/x-magic-cap-package-1.0": ["mc$"], +"application/x-mathcad": ["mcd"], +"application/x-meme": ["mm"], +"application/x-midi": ["mid","midi"], +"application/x-mie": ["mie"], +"application/x-mif": ["mif"], +"application/x-mix-transfer": ["nix"], +"application/x-mobipocket-ebook": ["mobi","prc"], +"application/x-mplayer2": ["asx"], +"application/x-ms-application": ["application"], +"application/x-ms-shortcut": ["lnk"], +"application/x-ms-wmd": ["wmd"], +"application/x-ms-wmz": ["wmz"], +"application/x-ms-xbap": ["xbap"], +"application/x-msaccess": ["mdb"], +"application/x-msbinder": ["obd"], +"application/x-mscardfile": ["crd"], +"application/x-msclip": ["clp"], +"application/x-msdownload": ["dll","bat","com","exe","msi"], +"application/x-msexcel": ["xla","xls","xlw"], +"application/x-msmediaview": ["mvb","m13","m14"], +"application/x-msmetafile": ["emf","emz","wmf"], +"application/x-msmoney": ["mny"], +"application/x-mspowerpoint": ["ppt"], +"application/x-mspublisher": ["pub"], +"application/x-msschedule": ["scd"], +"application/x-msterminal": ["trm"], +"application/x-mswrite": ["wri"], +"application/x-navi-animation": ["ani"], +"application/x-navidoc": ["nvd"], +"application/x-navimap": ["map"], +"application/x-navistyle": ["stl"], +"application/x-netcdf": ["cdf","nc"], +"application/x-newton-compatible-pkg": ["pkg"], +"application/x-nokia-9000-communicator-add-on-software": ["aos"], +"application/x-nzb": ["nzb"], +"application/x-omc": ["omc"], +"application/x-omcdatamaker": ["omcd"], +"application/x-omcregerator": ["omcr"], +"application/x-pagemaker": ["pm4","pm5"], +"application/x-pcl": ["pcl"], +"application/x-pem-file": ["pem"], +"application/x-pixclscript": ["plx"], +"application/x-pkcs10": ["p10"], +"application/x-pkcs12": ["p12","pfx"], +"application/x-pkcs7-certificates": ["p7b","spc"], +"application/x-pkcs7-certreqresp": ["p7r"], +"application/x-pkcs7-crl": ["crl"], +"application/x-pkcs7-mime": ["p7c","p7m"], +"application/x-pkcs7-signature": ["p7a"], +"application/x-plist": ["plist"], +"application/x-pointplus": ["css"], +"application/x-portable-anymap": ["pnm"], +"application/x-project": ["mpc","mpt","mpv","mpx"], +"application/x-qpro": ["wb1"], +"application/x-rar-compressed": ["rar"], +"application/x-research-info-systems": ["ris"], +"application/x-rpm": ["rpm"], +"application/x-rtf": ["rtf"], +"application/x-sdp": ["sdp"], +"application/x-sea": ["sea"], +"application/x-seelogo": ["sl"], +"application/x-sh": ["sh"], +"application/x-shar": ["shar","sh"], +"application/x-shockwave-flash": ["swf","swfl"], +"application/x-silverlight-app": ["xap"], +"application/x-sit": ["sit"], +"application/x-smarttech-notebook": ["gallery","gallerycollection","galleryitem","nbk","notebook","xbk"], +"application/x-sprite": ["spr","sprite"], +"application/x-sql": ["sql"], +"application/x-stuffit": ["sit"], +"application/x-stuffitx": ["sitx"], +"application/x-subrip": ["srt"], +"application/x-sv4cpio": ["sv4cpio"], +"application/x-sv4crc": ["sv4crc"], +"application/x-t3vm-image": ["t3"], +"application/x-tads": ["gam"], +"application/x-tar": ["tar"], +"application/x-tbook": ["sbk","tbk"], +"application/x-tcl": ["tcl"], +"application/x-tex": ["tex"], +"application/x-tex-tfm": ["tfm"], +"application/x-texinfo": ["texi","texinfo"], +"application/x-tgif": ["obj"], +"application/x-troff": ["roff","t","tr"], +"application/x-troff-man": ["man"], +"application/x-troff-me": ["me"], +"application/x-troff-ms": ["ms"], +"application/x-troff-msvideo": ["avi"], +"application/x-ustar": ["ustar"], +"application/x-visio": ["vsd","vst","vsw"], +"application/x-vnd.audioexplosion.mzz": ["mzz"], +"application/x-vnd.ls-xpix": ["xpix"], +"application/x-vrml": ["vrml"], +"application/x-wais-source": ["src","wsrc"], +"application/x-winhelp": ["hlp"], +"application/x-wintalk": ["wtk"], +"application/x-world": ["svr","wrl"], +"application/x-wpwin": ["wpd"], +"application/x-wri": ["wri"], +"application/x-x509-ca-cert": ["crt","cer","der"], +"application/x-x509-user-cert": ["crt"], +"application/x-xfig": ["fig"], +"application/x-xliff+xml": ["xlf"], +"application/x-xpinstall": ["xpi"], +"application/x-xz": ["xz"], +"application/x-zip-compressed": ["zip"], +"application/x-zmachine": ["z1","z2","z3","z4","z5","z6","z7","z8"], +"application/xaml+xml": ["xaml"], +"application/xcap-diff+xml": ["xdf"], +"application/xenc+xml": ["xenc"], +"application/xhtml+xml": ["xhtml","xht"], +"application/xml": ["xml","xsl"], +"application/xml-dtd": ["dtd"], +"application/xop+xml": ["xop"], +"application/xproc+xml": ["xpl"], +"application/xslt+xml": ["xslt"], +"application/xspf+xml": ["xspf"], +"application/xv+xml": ["mxml","xhvml","xvm","xvml"], +"application/yang": ["yang"], +"application/yin+xml": ["yin"], +"application/zip": ["zip","h5p"], +"audio/aac": ["aac"], +"audio/adpcm": ["adp"], +"audio/aiff": ["aif","aifc","aiff"], +"audio/amr": ["amr"], +"audio/au": ["au"], +"audio/basic": ["au","snd"], +"audio/flac": ["flac"], +"audio/it": ["it"], +"audio/make": ["funk","my","pfunk"], +"audio/make.my.funk": ["pfunk"], +"audio/mid": ["rmi"], +"audio/midi": ["midi","kar","mid","rmi"], +"audio/mod": ["mod"], +"audio/mp3": ["mp3"], +"audio/mp4": ["mp4a","m4a"], +"audio/mpeg": ["m2a","m3a","mp2","mp2a","mp3","mpa","mpg","mpga"], +"audio/mpeg3": ["mp3"], +"audio/nspaudio": ["la","lma"], +"audio/ogg": ["ogg","oga","spx"], +"audio/s3m": ["s3m"], +"audio/silk": ["sil"], +"audio/tsp-audio": ["tsi"], +"audio/tsplayer": ["tsp"], +"audio/vnd.dece.audio": ["uva","uvva"], +"audio/vnd.digital-winds": ["eol"], +"audio/vnd.dra": ["dra"], +"audio/vnd.dts": ["dts"], +"audio/vnd.dts.hd": ["dtshd"], +"audio/vnd.lucent.voice": ["lvp"], +"audio/vnd.ms-playready.media.pya": ["pya"], +"audio/vnd.nuera.ecelp4800": ["ecelp4800"], +"audio/vnd.nuera.ecelp7470": ["ecelp7470"], +"audio/vnd.nuera.ecelp9600": ["ecelp9600"], +"audio/vnd.qcelp": ["qcp"], +"audio/vnd.rip": ["rip"], +"audio/voc": ["voc"], +"audio/voxware": ["vox"], +"audio/wav": ["wav"], +"audio/webm": ["weba"], +"audio/x-aac": ["aac"], +"audio/x-adpcm": ["snd"], +"audio/x-aiff": ["aiff","aif","aifc"], +"audio/x-au": ["au"], +"audio/x-caf": ["caf"], +"audio/x-flac": ["flac"], +"audio/x-gsm": ["gsd","gsm"], +"audio/x-jam": ["jam"], +"audio/x-liveaudio": ["lam"], +"audio/x-matroska": ["mka"], +"audio/x-mid": ["mid","midi"], +"audio/x-midi": ["mid","midi"], +"audio/x-mod": ["mod"], +"audio/x-mpeg": ["mp2"], +"audio/x-mpeg-3": ["mp3"], +"audio/x-mpegurl": ["m3u","m3u8"], +"audio/x-mpequrl": ["m3u"], +"audio/x-ms-wax": ["wax"], +"audio/x-ms-wma": ["wma"], +"audio/x-nspaudio": ["la","lma"], +"audio/x-pn-realaudio": ["ra","ram","rm","rmm","rmp"], +"audio/x-pn-realaudio-plugin": ["rmp","ra","ram","rm","rpm","rv"], +"audio/x-psid": ["sid"], +"audio/x-realaudio": ["ra"], +"audio/x-realaudio-plugin": ["ra"], +"audio/x-twinvq": ["vqf"], +"audio/x-twinvq-plugin": ["vqe","vql"], +"audio/x-vnd.audioexplosion.mjuicemediafile": ["mjf"], +"audio/x-voc": ["voc"], +"audio/x-wav": ["wav"], +"audio/xm": ["xm"], +"chemical/x-cdx": ["cdx"], +"chemical/x-cif": ["cif"], +"chemical/x-cmdf": ["cmdf"], +"chemical/x-cml": ["cml"], +"chemical/x-csml": ["csml"], +"chemical/x-pdb": ["pdb","xyz"], +"chemical/x-xyz": ["xyz"], +"document/unknown": ["xxx"], +"drawing/x-dwf (old)": ["dwf"], +"i-world/i-vrml": ["ivr"], +"image/bmp": ["bmp","bm"], +"image/cgm": ["cgm"], +"image/cmu-raster": ["ras","rast"], +"image/fif": ["fif"], +"image/florian": ["flo","turbot"], +"image/g3fax": ["g3"], +"image/gif": ["gif"], +"image/ief": ["ief","iefs"], +"image/jpeg": ["jpeg","jfif","jfif-tbnl","jpe","jpg"], +"image/jutvision": ["jut"], +"image/ktx": ["ktx"], +"image/naplps": ["nap","naplps"], +"image/pict": ["pct","pic","pict"], +"image/pjpeg": ["jfif","jpe","jpeg","jpg"], +"image/png": ["png","x-png"], +"image/prs.btif": ["btif"], +"image/sgi": ["sgi"], +"image/svg+xml": ["svg","svgz"], +"image/tiff": ["tiff","tif"], +"image/vasa": ["mcf"], +"image/vnd.adobe.photoshop": ["psd"], +"image/vnd.dece.graphic": ["uvg","uvi","uvvg","uvvi"], +"image/vnd.djvu": ["djvu","djv"], +"image/vnd.dvb.subtitle": ["sub"], +"image/vnd.dwg": ["dwg","dxf","svf"], +"image/vnd.dxf": ["dxf"], +"image/vnd.fastbidsheet": ["fbs"], +"image/vnd.fpx": ["fpx"], +"image/vnd.fst": ["fst"], +"image/vnd.fujixerox.edmics-mmr": ["mmr"], +"image/vnd.fujixerox.edmics-rlc": ["rlc"], +"image/vnd.microsoft.icon": ["ico"], +"image/vnd.ms-modi": ["mdi"], +"image/vnd.ms-photo": ["wdp"], +"image/vnd.net-fpx": ["npx","fpx"], +"image/vnd.rn-realflash": ["rf"], +"image/vnd.rn-realpix": ["rp"], +"image/vnd.wap.wbmp": ["wbmp"], +"image/vnd.xiff": ["xif"], +"image/webp": ["webp"], +"image/x-3ds": ["3ds"], +"image/x-cmu-raster": ["ras"], +"image/x-cmx": ["cmx"], +"image/x-dwg": ["dwg","dxf","svf"], +"image/x-freehand": ["fh","fh4","fh5","fh7","fhc"], +"image/x-icon": ["ico"], +"image/x-jg": ["art"], +"image/x-jps": ["jps"], +"image/x-mrsid-image": ["sid"], +"image/x-niff": ["nif","niff"], +"image/x-pcx": ["pcx"], +"image/x-pict": ["pct","pic","pict"], +"image/x-portable-anymap": ["pnm"], +"image/x-portable-bitmap": ["pbm"], +"image/x-portable-graymap": ["pgm"], +"image/x-portable-greymap": ["pgm"], +"image/x-portable-pixmap": ["ppm"], +"image/x-quicktime": ["qif","qti","qtif"], +"image/x-rgb": ["rgb"], +"image/x-tga": ["tga"], +"image/x-tiff": ["tif","tiff"], +"image/x-windows-bmp": ["bmp"], +"image/x-xbitmap": ["xbm"], +"image/x-xbm": ["xbm"], +"image/x-xpixmap": ["xpm","pm"], +"image/x-xwd": ["xwd"], +"image/x-xwindowdump": ["xwd"], +"image/xbm": ["xbm"], +"image/xpm": ["xpm"], +"message/rfc822": ["eml","mht","mhtml","mime"], +"model/iges": ["iges","igs"], +"model/mesh": ["mesh","msh","silo"], +"model/vnd.collada+xml": ["dae"], +"model/vnd.dwf": ["dwf"], +"model/vnd.gdl": ["gdl"], +"model/vnd.gtw": ["gtw"], +"model/vnd.mts": ["mts"], +"model/vnd.vtu": ["vtu"], +"model/vrml": ["vrml","wrl","wrz"], +"model/x-pov": ["pov"], +"model/x3d+binary": ["x3db","x3dbz"], +"model/x3d+vrml": ["x3dv","x3dvz"], +"model/x3d+xml": ["x3d","x3dz"], +"multipart/x-gzip": ["gzip"], +"multipart/x-ustar": ["ustar"], +"multipart/x-zip": ["zip"], +"music/crescendo": ["mid","midi"], +"music/x-karaoke": ["kar"], +"paleovu/x-pv": ["pvu"], +"shockwave/director": ["cct"], +"text/asp": ["asp"], +"text/cache-manifest": ["appcache"], +"text/calendar": ["ics","ifb"], +"text/css": ["css"], +"text/csv": ["csv"], +"text/ecmascript": ["js"], +"text/html": ["html","acgi","htc","htm","htmls","htx","shtml"], +"text/javascript": ["js"], +"text/mcf": ["mcf"], +"text/n3": ["n3"], +"text/pascal": ["pas"], +"text/plain": ["txt","applescript","asc","ascx","ashx","asm","asmx","asp","aspx","axd","c","c++","cc","com","conf","cpp","cs","cxx","def","f","f90","asa","g","h","hh","hpp","idc","in","ini","jav","java","list","log","lst","m","mar","php","pl","rb","sdml","text","for"], +"text/prs.lines.tag": ["dsc"], +"text/richtext": ["rtx","rt","rtf"], +"text/rtf": ["rtf"], +"text/scriplet": ["wsc"], +"text/sgml": ["sgml","sgm"], +"text/tab-separated-values": ["tsv"], +"text/troff": ["man","me","ms","roff","t","tr"], +"text/turtle": ["ttl"], +"text/uri-list": ["uri","uni","unis","uris","urls"], +"text/vcard": ["vcard"], +"text/vnd.abc": ["abc"], +"text/vnd.curl": ["curl"], +"text/vnd.curl.dcurl": ["dcurl"], +"text/vnd.curl.mcurl": ["mcurl"], +"text/vnd.curl.scurl": ["scurl"], +"text/vnd.dvb.subtitle": ["sub"], +"text/vnd.fly": ["fly"], +"text/vnd.fmi.flexstor": ["flx"], +"text/vnd.graphviz": ["gv"], +"text/vnd.in3d.3dml": ["3dml"], +"text/vnd.in3d.spot": ["spot"], +"text/vnd.rn-realtext": ["rt"], +"text/vnd.sun.j2me.app-descriptor": ["jad"], +"text/vnd.wap.wml": ["wml"], +"text/vnd.wap.wmlscript": ["wmls"], +"text/vtt": ["vtt"], +"text/webviewhtml": ["htt"], +"text/x-asm": ["asm","s"], +"text/x-audiosoft-intra": ["aip"], +"text/x-c": ["c","cc","cpp","cxx","dic","h","hh"], +"text/x-component": ["htc"], +"text/x-fortran": ["f","f77","f90","for"], +"text/x-h": ["h","hh"], +"text/x-java-source": ["jav","java"], +"text/x-la-asf": ["lsx"], +"text/x-m": ["m"], +"text/x-nfo": ["nfo"], +"text/x-opml": ["opml"], +"text/x-pascal": ["p","pas"], +"text/x-sass": ["sass"], +"text/x-script": ["hlb"], +"text/x-script.csh": ["csh"], +"text/x-script.elisp": ["el"], +"text/x-script.guile": ["scm"], +"text/x-script.ksh": ["ksh"], +"text/x-script.lisp": ["lsp"], +"text/x-script.perl": ["pl"], +"text/x-script.perl-module": ["pm"], +"text/x-script.phyton": ["py"], +"text/x-script.rexx": ["rexx"], +"text/x-script.scheme": ["scm"], +"text/x-script.sh": ["sh"], +"text/x-script.tcl": ["tcl"], +"text/x-script.tcsh": ["tcsh"], +"text/x-script.zsh": ["zsh"], +"text/x-scss": ["scss"], +"text/x-server-parsed-html": ["shtml","ssi"], +"text/x-setext": ["etx"], +"text/x-sfv": ["sfv"], +"text/x-sgml": ["sgm","sgml"], +"text/x-speech": ["spc","talk"], +"text/x-styl": ["styl"], +"text/x-uil": ["uil"], +"text/x-uuencode": ["uu","uue"], +"text/x-vcalendar": ["vcs"], +"text/x-vcard": ["vcf"], +"text/xml": ["resx","jcb","jcw","jmt","jmx","jcl","xsl","rhb","sqt","xml","jqz"], +"text/yaml": ["yaml","yml"], +"video/3gpp": ["3gp"], +"video/3gpp2": ["3g2"], +"video/animaflex": ["afl"], +"video/avi": ["avi"], +"video/avs-video": ["avs"], +"video/dl": ["dl"], +"video/fli": ["fli"], +"video/gl": ["gl"], +"video/h261": ["h261"], +"video/h263": ["h263"], +"video/h264": ["h264"], +"video/jpeg": ["jpgv"], +"video/jpm": ["jpgm","jpm"], +"video/mj2": ["mj2","mjp2"], +"video/mp4": ["mp4","f4v","m4v","mp4v","mpg4","fmp4"], +"video/mpeg": ["mpeg","m1v","m2v","mp2","mp3","mpa","mpe","mpg"], +"video/MP2T": ["ts"], +"video/msvideo": ["avi"], +"video/ogg": ["ogv"], +"video/quicktime": ["mov","3gp","moov","qt"], +"video/vdo": ["vdo"], +"video/vivo": ["viv","vivo"], +"video/vnd.dece.hd": ["uvh","uvvh"], +"video/vnd.dece.mobile": ["uvm","uvvm"], +"video/vnd.dece.pd": ["uvp","uvvp"], +"video/vnd.dece.sd": ["uvs","uvvs"], +"video/vnd.dece.video": ["uvv","uvvv"], +"video/vnd.dvb.file": ["dvb"], +"video/vnd.fvt": ["fvt"], +"video/vnd.mpegurl": ["m4u","mxu"], +"video/vnd.ms-playready.media.pyv": ["pyv"], +"video/vnd.rn-realvideo": ["rv"], +"video/vnd.uvvu.mp4": ["uvu","uvvu"], +"video/vnd.vivo": ["viv","vivo"], +"video/vosaic": ["vos"], +"video/webm": ["webm"], +"video/x-amt-demorun": ["xdr"], +"video/x-amt-showrun": ["xsr"], +"video/x-atomic3d-feature": ["fmf"], +"video/x-dl": ["dl"], +"video/x-dv": ["dv","dif"], +"video/x-f4v": ["f4v"], +"video/x-fli": ["fli"], +"video/x-flv": ["flv"], +"video/x-gl": ["gl"], +"video/x-isvideo": ["isu"], +"video/x-m4v": ["m4v"], +"video/x-matroska": ["mkv","mk3d","mks"], +"video/x-mng": ["mng"], +"video/x-motion-jpeg": ["mjpg"], +"video/x-mpeg": ["mp2","mp3"], +"video/x-mpeq2a": ["mp2"], +"video/x-ms-asf": ["asf","asx"], +"video/x-ms-asf-plugin": ["asx"], +"video/x-ms-vob": ["vob"], +"video/x-ms-wm": ["wm","avi"], +"video/x-ms-wmv": ["wmv"], +"video/x-ms-wmx": ["wmx"], +"video/x-ms-wvx": ["wvx"], +"video/x-msvideo": ["avi"], +"video/x-qtc": ["qtc"], +"video/x-scm": ["scm"], +"video/x-sgi-movie": ["movie","mv"], +"video/x-smv": ["smv"], +"windows/metafile": ["wmf"], +"www/mime": ["mime"], +"x-conference/x-cooltalk": ["ice"], +"x-music/x-midi": ["mid","midi"], +"x-world/x-3dmf": ["3dm","3dmf","qd3","qd3d"], +"x-world/x-svr": ["svr"], +"x-world/x-vrml": ["vrml","wrl","wrz"], +"x-world/x-vrt": ["vrt"], +"xgl/drawing": ["xgz"], +"xgl/movie": ["xmz"] +} \ No newline at end of file diff --git a/tsconfig.app.json b/tsconfig.app.json index f1fa53ec4..a323c7afd 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -3,8 +3,9 @@ "compilerOptions": { "outDir": "./out-tsc/app", "types": [ - "cordova", "cordova-plugin-file-transfer", + "cordova-plugin-inappbrowser", + "cordova", "node" ], "paths": { diff --git a/tsconfig.json b/tsconfig.json index 5e452a9cf..e1026f019 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,9 @@ "dom" ], "types": [ + "cordova-plugin-file-transfer", + "cordova-plugin-inappbrowser", + "cordova", "jest", "node" ], diff --git a/tsconfig.test.json b/tsconfig.test.json index 2d14a2529..810c0668d 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -6,6 +6,9 @@ "emitDecoratorMetadata": true, "outDir": "./out-tsc/tests", "types": [ + "cordova-plugin-file-transfer", + "cordova-plugin-inappbrowser", + "cordova", "jest", "node" ], diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 8f802020a..000000000 --- a/tslint.json +++ /dev/null @@ -1,144 +0,0 @@ -{ - "extends": "tslint:recommended", - "rules": { - "array-type": false, - "arrow-return-shorthand": true, - "curly": true, - "deprecation": { - "severity": "warning" - }, - "component-class-suffix": [true, "Page", "Component"], - "contextual-lifecycle": true, - "directive-class-suffix": true, - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "eofline": true, - "import-blacklist": [ - true, - "rxjs/Rx" - ], - "import-spacing": true, - "indent": { - "options": [ - "spaces" - ] - }, - "max-classes-per-file": false, - "max-line-length": [ - true, - 140 - ], - "member-ordering": [ - true, - { - "order": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } - ], - "no-angle-bracket-type-assertion": false, - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-empty": false, - "no-inferrable-types": [ - true, - "ignore-params" - ], - "no-non-null-assertion": true, - "no-redundant-jsdoc": true, - "no-shadowed-variable": false, - "no-switch-case-fall-through": true, - "no-unused-expression": false, - "no-var-requires": false, - "object-literal-key-quotes": [ - true, - "as-needed" - ], - "prefer-for-of": false, - "quotemark": [ - true, - "single" - ], - "semicolon": { - "options": [ - "always" - ] - }, - "space-before-function-paren": { - "options": { - "anonymous": "never", - "asyncArrow": "always", - "constructor": "never", - "method": "never", - "named": "never" - } - }, - "typedef-whitespace": { - "options": [ - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - }, - { - "call-signature": "onespace", - "index-signature": "onespace", - "parameter": "onespace", - "property-declaration": "onespace", - "variable-declaration": "onespace" - } - ] - }, - "variable-name": { - "options": [ - "ban-keywords", - "check-format", - "allow-pascal-case", - "allow-leading-underscore" - ] - }, - "whitespace": { - "options": [ - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type", - "check-typecast" - ] - }, - "no-conflicting-lifecycle": true, - "no-host-metadata-property": true, - "no-input-rename": true, - "no-inputs-metadata-property": true, - "no-output-native": true, - "no-output-on-prefix": true, - "no-output-rename": true, - "no-outputs-metadata-property": true, - "template-banana-in-box": true, - "template-no-negated-async": true, - "use-lifecycle-interface": true, - "use-pipe-transform-interface": true, - "object-literal-sort-keys": false, - "forin": false, - "triple-equals": false - }, - "rulesDirectory": [ - "codelyzer" - ] -} \ No newline at end of file