From cb870572fa2b97954ea47e770006e06d9362daaa Mon Sep 17 00:00:00 2001 From: Gaurav Munjal Date: Mon, 15 Oct 2018 17:06:45 -0400 Subject: [PATCH] Get tests passing again --- .eslintrc.js | 2 + lib/displayutils.js | 50 +++++++++++++ lib/old-tap-reporter.js | 62 ++++++++++++++++ lib/strutils.js | 45 +++++++++++ .../blueprints/ember-cli-eslint-test.js | 6 +- node-tests/test.js | 43 +++++------ package.json | 2 +- testem.js | 7 +- tests/dummy/app/routes/thing.jsx | 4 +- yarn.lock | 74 +++++++++---------- 10 files changed, 227 insertions(+), 68 deletions(-) create mode 100644 lib/displayutils.js create mode 100644 lib/old-tap-reporter.js create mode 100644 lib/strutils.js diff --git a/.eslintrc.js b/.eslintrc.js index 4c662f0d..021e2020 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -26,6 +26,8 @@ module.exports = { 'testem.js', 'blueprints/*/index.js', 'config/**/*.js', + 'lib/**/*.js', + 'node_tests/**/*.js', 'tests/dummy/config/**/*.js' ], excludedFiles: [ diff --git a/lib/displayutils.js b/lib/displayutils.js new file mode 100644 index 00000000..995ac1dc --- /dev/null +++ b/lib/displayutils.js @@ -0,0 +1,50 @@ +'use strict'; + +var util = require('util'); + +// Method to format test results. +var strutils = require('./strutils'); + +function resultDisplay(id, prefix, result) { + + var parts = []; + if (prefix) { + parts.push(prefix); + } + if (result.name) { + parts.push(result.name.trim()); + } + + var line = parts.join(' - '); + return (result.skipped ? 'skip ' : (result.passed ? 'ok ' : 'not ok ')) + id + ' ' + line; +} + +function yamlDisplay(err, logs) { + var testLogs; + var failed = Object.keys(err || {}) + .filter(function(key) { + return key !== 'passed'; + }) + .map(function(key) { + return key + ': >\n' + strutils.indent(String(err[key])); + }); + if (logs) { + testLogs = ['Log: |'].concat(logs.map(function(log) {return strutils.indent(util.inspect(log));})); + } else { + testLogs = []; + } + return strutils.indent([ + '---', + strutils.indent(failed.concat(testLogs).join('\n')), + '...'].join('\n')); +} + +function resultString(id, prefix, result, quietLogs) { + var string = resultDisplay(id, prefix, result) + '\n'; + if (result.error || (!quietLogs && result.logs && result.logs.length)) { + string += yamlDisplay(result.error, result.logs) + '\n'; + } + return string; +} + +exports.resultString = resultString; diff --git a/lib/old-tap-reporter.js b/lib/old-tap-reporter.js new file mode 100644 index 00000000..73ddeb4e --- /dev/null +++ b/lib/old-tap-reporter.js @@ -0,0 +1,62 @@ +// Copied from https://github.com/testem/testem/blob/79e75d850942804e197d4bb676b9cbc5c4026b53/lib/reporters/tap_reporter.js +'use strict'; + +var displayutils = require('./displayutils'); + +function TapReporter(silent, out, config) { + this.out = out || process.stdout; + this.silent = silent; + this.quietLogs = !!config.get('tap_quiet_logs'); + this.stoppedOnError = null; + this.id = 1; + this.total = 0; + this.pass = 0; + this.skipped = 0; + this.results = []; + this.errors = []; + this.logs = []; +} +TapReporter.prototype = { + report: function(prefix, data) { + this.results.push({ + launcher: prefix, + result: data + }); + this.display(prefix, data); + this.total++; + if (data.skipped) { + this.skipped++; + } else if (data.passed) { + this.pass++; + } + }, + summaryDisplay: function() { + var lines = [ + '1..' + this.total, + '# tests ' + this.total, + '# pass ' + this.pass, + '# skip ' + this.skipped, + '# fail ' + (this.total - this.pass - this.skipped) + ]; + + if (this.pass + this.skipped === this.total) { + lines.push(''); + lines.push('# ok'); + } + return lines.join('\n'); + }, + display: function(prefix, result) { + if (this.silent) { + return; + } + this.out.write(displayutils.resultString(this.id++, prefix, result, this.quietLogs)); + }, + finish: function() { + if (this.silent) { + return; + } + this.out.write('\n' + this.summaryDisplay() + '\n'); + } +}; + +module.exports = TapReporter; diff --git a/lib/strutils.js b/lib/strutils.js new file mode 100644 index 00000000..85bb0233 --- /dev/null +++ b/lib/strutils.js @@ -0,0 +1,45 @@ +'use strict'; + +// String padding function adapted from +function pad(str, l, s, t) { + var ol = l; + return (s || (s = ' '), (l -= str.length) > 0 ? + (s = new Array(Math.ceil(l / s.length) + 1).join(s)) + .substr(0, t = !t ? l : t === 1 ? 0 : + Math.ceil(l / 2)) + str + s.substr(0, l - t) : str).substring(0, ol); +} + +function indent(text, width) { + return text.split('\n').map(function(line) { + return new Array((width || 4) + 1).join(' ') + line; + }).join('\n'); +} + +function splitLines(text, colLimit) { + if (!text) { + return []; + } + var firstSplit = text.split('\n'); + var secondSplit = []; + firstSplit.forEach(function(line) { + while (line.length > colLimit) { + var first = line.substring(0, colLimit); + secondSplit.push(first); + line = line.substring(colLimit); + } + secondSplit.push(line); + }); + return secondSplit; +} + +// Simple template function. Replaces occurences of "" with param[name] +function template(str, params) { + return !str.replace ? str : str.replace(/<(.+?)>/g, function(unchanged, name) { + return name in params ? params[name] : unchanged; + }); +} + +exports.pad = pad; +exports.indent = indent; +exports.splitLines = splitLines; +exports.template = template; diff --git a/node-tests/blueprints/ember-cli-eslint-test.js b/node-tests/blueprints/ember-cli-eslint-test.js index 81653f75..a9826ee2 100644 --- a/node-tests/blueprints/ember-cli-eslint-test.js +++ b/node-tests/blueprints/ember-cli-eslint-test.js @@ -48,7 +48,7 @@ describe('Acceptance: install ember-cli-eslint', function() { it('removes the JSHint addon', function() { var args = ['ember-cli-eslint', 'foo']; - td.when(prompt(td.matchers.anything())).thenResolve({ deleteFiles: 'all' }); + td.when(prompt(td.matchers.anything())).thenResolve({ answer: 'overwrite', deleteFiles: 'all' }); return emberNew() .then(function() { @@ -88,7 +88,7 @@ describe('Acceptance: install ember-cli-eslint', function() { path.join('.', 'tests', 'dummy', 'app', 'dist', '.jshintrc') ]; - td.when(prompt(td.matchers.anything())).thenResolve({ deleteFiles: 'all' }); + td.when(prompt(td.matchers.anything())).thenResolve({ answer: 'overwrite', deleteFiles: 'all' }); return emberNew() .then(function() { @@ -109,7 +109,7 @@ describe('Acceptance: install ember-cli-eslint', function() { it('does not remove any files if it shouldn\'t', function() { var args = ['ember-cli-eslint', 'foo']; - td.when(prompt(td.matchers.anything())).thenResolve({ deleteFiles: 'none' }); + td.when(prompt(td.matchers.anything())).thenResolve({ answer: 'overwrite', deleteFiles: 'none' }); return emberNew() .then(function() { diff --git a/node-tests/test.js b/node-tests/test.js index a7cd3334..f8fee958 100644 --- a/node-tests/test.js +++ b/node-tests/test.js @@ -1,3 +1,5 @@ +'use strict' + var fs = require('fs-extra'); var exec = require('child_process').exec; @@ -28,13 +30,12 @@ describe('ember-cli-eslint', function() { .to.contain(`ok 2 ${browser} - ESLint | controllers/thing.js: should pass ESLint`) .to.contain(`ok 3 ${browser} - ESLint | helpers/destroy-app.js: should pass ESLint`) .to.contain(`ok 4 ${browser} - ESLint | helpers/module-for-acceptance.js: should pass ESLint`) - .to.contain(`ok 5 ${browser} - ESLint | helpers/resolver.js: should pass ESLint`) - .to.contain(`ok 6 ${browser} - ESLint | helpers/start-app.js: should pass ESLint`) - .to.contain(`ok 7 ${browser} - ESLint | models/thing.js: should pass ESLint`) - .to.contain(`ok 8 ${browser} - ESLint | resolver.js: should pass ESLint`) - .to.contain(`ok 9 ${browser} - ESLint | router.js: should pass ESLint`) - .to.contain(`ok 10 ${browser} - ESLint | test-helper.js: should pass ESLint`) - .to.not.contain(`not ok 11 ${browser} - ESLint | unused.js: should pass ESLint`); + .to.contain(`ok 5 ${browser} - ESLint | helpers/start-app.js: should pass ESLint`) + .to.contain(`ok 6 ${browser} - ESLint | models/thing.js: should pass ESLint`) + .to.contain(`ok 7 ${browser} - ESLint | resolver.js: should pass ESLint`) + .to.contain(`ok 8 ${browser} - ESLint | router.js: should pass ESLint`) + .to.contain(`ok 9 ${browser} - ESLint | test-helper.js: should pass ESLint`) + .to.not.contain(`not ok 10 ${browser} - ESLint | unused.js: should pass ESLint`); }) }); @@ -50,13 +51,12 @@ describe('ember-cli-eslint', function() { .to.contain(`ok 2 ${browser} - ESLint | controllers/thing.js: should pass ESLint`) .to.contain(`ok 3 ${browser} - ESLint | helpers/destroy-app.js: should pass ESLint`) .to.contain(`ok 4 ${browser} - ESLint | helpers/module-for-acceptance.js: should pass ESLint`) - .to.contain(`ok 5 ${browser} - ESLint | helpers/resolver.js: should pass ESLint`) - .to.contain(`ok 6 ${browser} - ESLint | helpers/start-app.js: should pass ESLint`) - .to.contain(`ok 7 ${browser} - ESLint | models/thing.js: should pass ESLint`) - .to.contain(`ok 8 ${browser} - ESLint | resolver.js: should pass ESLint`) - .to.contain(`ok 9 ${browser} - ESLint | router.js: should pass ESLint`) - .to.contain(`ok 10 ${browser} - ESLint | test-helper.js: should pass ESLint`) - .to.contain(`not ok 11 ${browser} - ESLint | unused.js: should pass ESLint`); + .to.contain(`ok 5 ${browser} - ESLint | helpers/start-app.js: should pass ESLint`) + .to.contain(`ok 6 ${browser} - ESLint | models/thing.js: should pass ESLint`) + .to.contain(`ok 7 ${browser} - ESLint | resolver.js: should pass ESLint`) + .to.contain(`ok 8 ${browser} - ESLint | router.js: should pass ESLint`) + .to.contain(`ok 9 ${browser} - ESLint | test-helper.js: should pass ESLint`) + .to.contain(`not ok 10 ${browser} - ESLint | unused.js: should pass ESLint`); }) }); @@ -76,9 +76,8 @@ describe('ember-cli-eslint', function() { expect(result.stdout.match(/[^\r\n]+/g)) .to.contain(`ok 6 ${browser} - ESLint | tests: helpers/destroy-app.js`) .to.contain(`ok 7 ${browser} - ESLint | tests: helpers/module-for-acceptance.js`) - .to.contain(`ok 8 ${browser} - ESLint | tests: helpers/resolver.js`) - .to.contain(`ok 9 ${browser} - ESLint | tests: helpers/start-app.js`) - .to.contain(`ok 10 ${browser} - ESLint | tests: test-helper.js`); + .to.contain(`ok 8 ${browser} - ESLint | tests: helpers/start-app.js`) + .to.contain(`ok 9 ${browser} - ESLint | tests: test-helper.js`); }) }); @@ -100,9 +99,8 @@ describe('ember-cli-eslint', function() { expect(result.stdout.match(/[^\r\n]+/g)) .to.contain(`ok 7 ${browser} - ESLint | tests: helpers/destroy-app.js`) .to.contain(`ok 8 ${browser} - ESLint | tests: helpers/module-for-acceptance.js`) - .to.contain(`ok 9 ${browser} - ESLint | tests: helpers/resolver.js`) - .to.contain(`ok 10 ${browser} - ESLint | tests: helpers/start-app.js`) - .to.contain(`ok 11 ${browser} - ESLint | tests: test-helper.js`); + .to.contain(`ok 9 ${browser} - ESLint | tests: helpers/start-app.js`) + .to.contain(`ok 10 ${browser} - ESLint | tests: test-helper.js`); }) }); @@ -123,9 +121,8 @@ describe('ember-cli-eslint', function() { expect(result.stdout.match(/[^\r\n]+/g)) .to.contain(`ok 7 ${browser} - ESLint | tests: helpers/destroy-app.js`) .to.contain(`ok 8 ${browser} - ESLint | tests: helpers/module-for-acceptance.js`) - .to.contain(`ok 9 ${browser} - ESLint | tests: helpers/resolver.js`) - .to.contain(`ok 10 ${browser} - ESLint | tests: helpers/start-app.js`) - .to.contain(`ok 11 ${browser} - ESLint | tests: test-helper.js`); + .to.contain(`ok 9 ${browser} - ESLint | tests: helpers/start-app.js`) + .to.contain(`ok 10 ${browser} - ESLint | tests: test-helper.js`); }) }); }); diff --git a/package.json b/package.json index b2d80b67..027373da 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "chai": "^4.0.2", "ember-cli": "~3.4.3", "ember-cli-babel": "^6.16.0", - "ember-cli-blueprint-test-helpers": "^0.18.0", + "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", "ember-cli-htmlbars": "^3.0.1", "ember-cli-htmlbars-inline-precompile": "^1.0.3", diff --git a/testem.js b/testem.js index 7460dc66..2ac9a229 100644 --- a/testem.js +++ b/testem.js @@ -1,11 +1,14 @@ +var CustomReporter = require('./lib/old-tap-reporter'); + module.exports = { "test_page": "tests/index.html?hidepassed", "disable_watching": true, + "reporter": CustomReporter, "launch_in_ci": [ "Chrome" ], - launch_in_dev: [ - 'Chrome' + "launch_in_dev": [ + "Chrome" ], browser_args: { Chrome: { diff --git a/tests/dummy/app/routes/thing.jsx b/tests/dummy/app/routes/thing.jsx index 26d9f312..6c74252a 100644 --- a/tests/dummy/app/routes/thing.jsx +++ b/tests/dummy/app/routes/thing.jsx @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import Route from '@ember/routing/route'; -export default Ember.Route.extend({ +export default Route.extend({ }); diff --git a/yarn.lock b/yarn.lock index 878e6199..7f856b87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2179,11 +2179,6 @@ colors@^1.1.2: resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= -colors@~0.6.0-1: - version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" - integrity sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w= - commander@2.12.2: version "2.12.2" resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" @@ -2208,11 +2203,6 @@ commander@^2.6.0: dependencies: graceful-readlink ">= 1.0.0" -commander@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" - integrity sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E= - commander@~2.17.1: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" @@ -2696,20 +2686,18 @@ ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2: clone "^2.0.0" ember-cli-version-checker "^2.0.0" -ember-cli-blueprint-test-helpers@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.0.tgz#bc101b3e1df9b9b5db6ff626d71521e4926599d1" - integrity sha1-vBAbPh35ubXbb/Ym1xUh5JJlmdE= +ember-cli-blueprint-test-helpers@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" + integrity sha512-lyfCvR5gxbNn5mJKfVAUj3Q5K1VyJo3miAaQ9zk2dL7ijs281C3j73WYyCK7tWBoBJ04jOzkb+YXV6jFwVpvsA== dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" chai-files "^1.0.0" debug "^3.0.0" ember-cli-internal-test-helpers "^0.9.1" - exists-sync "0.0.3" - findup "^0.1.5" - fs-extra "^4.0.0" - lodash.merge "^4.4.0" + fs-extra "^5.0.0" + testdouble "^3.2.6" tmp-sync "^1.0.0" ember-cli-broccoli-sane-watcher@^2.1.1: @@ -3803,14 +3791,6 @@ findup-sync@2.0.0: micromatch "^3.0.4" resolve-dir "^1.0.1" -findup@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" - integrity sha1-itkpozk7rGJ5V6fl3kYjsGsOLOs= - dependencies: - colors "~0.6.0-1" - commander "~2.1.0" - fireworm@^0.7.0: version "0.7.1" resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" @@ -3933,15 +3913,6 @@ fs-extra@^2.0.0: graceful-fs "^4.1.2" jsonfile "^2.1.0" -fs-extra@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" - integrity sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" @@ -5450,7 +5421,7 @@ lodash.keys@~2.3.0: lodash._shimkeys "~2.3.0" lodash.isobject "~2.3.0" -lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.6.0: +lodash.merge@^4.3.0, lodash.merge@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" integrity sha1-aYhLoUSsM/5plzemCG3v+t0PicU= @@ -5540,6 +5511,11 @@ lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.17.2, l resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= +lodash@^4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -6546,6 +6522,14 @@ quibble@^0.5.1: dependencies: lodash "^4.17.2" +quibble@^0.5.5: + version "0.5.5" + resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" + integrity sha512-cIePu3BtGlaTW1bjFgBcLT6QMxD8PtnZDCmPJUzO+RepIz8GuXsmZIEPGFjlPxzG9zfIj4nNLPxBDlUbvr9ESg== + dependencies: + lodash "^4.17.2" + resolve "^1.7.1" + quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" @@ -6852,7 +6836,7 @@ resolve@^1.3.3: dependencies: path-parse "^1.0.5" -resolve@^1.5.0, resolve@^1.6.0, resolve@^1.8.1: +resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== @@ -7681,6 +7665,17 @@ testdouble@^3.1.0: resolve "^1.3.3" stringify-object-es5 "^2.5.0" +testdouble@^3.2.6: + version "3.8.2" + resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.8.2.tgz#f9e8499c2bae2dc1ad1b438a23c74e2808afa058" + integrity sha512-K1R8h5QGbYYZYHRMXnSkgKD8fVNYtj36Km1wZ5+GNcMmESjy2KwIpRhBdJiYVDaByLUKJ0EoLI0uWC6tku3yiw== + dependencies: + es6-map "^0.1.5" + lodash "^4.17.11" + quibble "^0.5.5" + stringify-object-es5 "^2.5.0" + theredoc "^1.0.0" + testem@^2.9.2: version "2.13.0" resolved "https://registry.yarnpkg.com/testem/-/testem-2.13.0.tgz#587f3460a923779949804efac0fcc2015835dd63" @@ -7725,6 +7720,11 @@ text-table@~0.2.0: resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" integrity sha1-vozyLWU3nBUTGfiPAzWtj2Z6vco= +theredoc@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" + integrity sha512-KU3SA3TjRRM932jpNfD3u4Ec3bSvedyo5ITPI7zgWYnKep7BwQQaxlhI9qbO+lKJoRnoAbEVfMcAHRuKVYikDA== + through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"