karma-coverage
Advanced tools
Comparing version
@@ -1,19 +0,19 @@ | ||
var coverageMap = {}; | ||
var coverageMap = {} | ||
function addCoverage(coverageObj){ | ||
coverageMap[coverageObj.path] = coverageObj; | ||
function addCoverage (coverageObj) { | ||
coverageMap[coverageObj.path] = coverageObj | ||
} | ||
function getCoverageMap(){ | ||
return coverageMap; | ||
function getCoverageMap () { | ||
return coverageMap | ||
} | ||
function resetCoverage(){ | ||
coverageMap = {}; | ||
function resetCoverage () { | ||
coverageMap = {} | ||
} | ||
module.exports = { | ||
add: addCoverage, | ||
get: getCoverageMap, | ||
reset: resetCoverage | ||
}; | ||
add: addCoverage, | ||
get: getCoverageMap, | ||
reset: resetCoverage | ||
} |
module.exports = { | ||
'preprocessor:coverage': ['factory', require('./preprocessor')], | ||
'reporter:coverage': ['type', require('./reporter')] | ||
}; | ||
} |
@@ -1,88 +0,89 @@ | ||
var istanbul = require('istanbul'), | ||
minimatch = require('minimatch'), | ||
globalSourceCache = require('./sourceCache'), | ||
extend = require('util')._extend, | ||
coverageMap = require('./coverageMap'); | ||
var istanbul = require('istanbul'), | ||
minimatch = require('minimatch'), | ||
globalSourceCache = require('./sourceCache'), | ||
extend = require('util')._extend, | ||
coverageMap = require('./coverageMap') | ||
var createCoveragePreprocessor = function(logger, basePath, reporters, coverageReporter) { | ||
var log = logger.create('preprocessor.coverage'); | ||
var instrumenterOverrides = (coverageReporter && coverageReporter.instrumenter) || {}; | ||
var instrumenters = extend({istanbul: istanbul}, (coverageReporter && coverageReporter.instrumenters)); | ||
var sourceCache = globalSourceCache.getByBasePath(basePath); | ||
var includeAllSources = coverageReporter && coverageReporter.includeAllSources === true; | ||
var instrumentersOptions = Object.keys(instrumenters).reduce(function getInstumenterOptions(memo, instrumenterName){ | ||
memo[instrumenterName] = (coverageReporter && coverageReporter.instrumenterOptions && coverageReporter.instrumenterOptions[instrumenterName]) || {}; | ||
return memo; | ||
}, {}); | ||
var createCoveragePreprocessor = function (logger, basePath, reporters, coverageReporter) { | ||
var log = logger.create('preprocessor.coverage') | ||
var instrumenterOverrides = (coverageReporter && coverageReporter.instrumenter) || {} | ||
var instrumenters = extend({istanbul: istanbul}, (coverageReporter && coverageReporter.instrumenters)) | ||
var sourceCache = globalSourceCache.getByBasePath(basePath) | ||
var includeAllSources = coverageReporter && coverageReporter.includeAllSources === true | ||
var instrumentersOptions = Object.keys(instrumenters).reduce(function getInstumenterOptions (memo, instrumenterName) { | ||
memo[instrumenterName] = (coverageReporter && coverageReporter.instrumenterOptions && coverageReporter.instrumenterOptions[instrumenterName]) || {} | ||
return memo | ||
}, {}) | ||
// if coverage reporter is not used, do not preprocess the files | ||
if (reporters.indexOf('coverage') === -1) { | ||
return function(content, _, done) { | ||
done(content); | ||
}; | ||
return function (content, _, done) { | ||
done(content) | ||
} | ||
} | ||
// check instrumenter override requests | ||
function checkInstrumenters() { | ||
var literal; | ||
function checkInstrumenters () { | ||
var literal | ||
for (var pattern in instrumenterOverrides) { | ||
literal = String(instrumenterOverrides[pattern]); | ||
literal = String(instrumenterOverrides[pattern]) | ||
if (Object.keys(instrumenters).indexOf(literal) < 0) { | ||
log.error('Unknown instrumenter: %s', literal); | ||
return false; | ||
log.error('Unknown instrumenter: %s', literal) | ||
return false | ||
} | ||
} | ||
return true; | ||
return true | ||
} | ||
if (!checkInstrumenters()) { | ||
return function(content, _, done) { | ||
return done(1); | ||
}; | ||
return function (content, _, done) { | ||
return done(1) | ||
} | ||
} | ||
return function(content, file, done) { | ||
log.debug('Processing "%s".', file.originalPath); | ||
return function (content, file, done) { | ||
log.debug('Processing "%s".', file.originalPath) | ||
var jsPath = file.originalPath.replace(basePath + '/', './'); | ||
var jsPath = file.originalPath.replace(basePath + '/', './') | ||
// default instrumenters | ||
var instrumenterLiteral = 'istanbul'; | ||
var instrumenterLiteral = 'istanbul' | ||
for (var pattern in instrumenterOverrides) { | ||
if (minimatch(file.originalPath, pattern, {dot: true})) { | ||
instrumenterLiteral = String(instrumenterOverrides[pattern]); | ||
instrumenterLiteral = String(instrumenterOverrides[pattern]) | ||
} | ||
} | ||
var instrumenter = new instrumenters[instrumenterLiteral].Instrumenter(instrumentersOptions[instrumenterLiteral] || {}); | ||
var instrumenter = new instrumenters[instrumenterLiteral].Instrumenter(instrumentersOptions[instrumenterLiteral] || {}) | ||
instrumenter.instrument(content, jsPath, function(err, instrumentedCode) { | ||
instrumenter.instrument(content, jsPath, function (err, instrumentedCode) { | ||
if (err) { | ||
log.error('%s\n at %s', err.message, file.originalPath); | ||
log.error('%s\n at %s', err.message, file.originalPath) | ||
} | ||
// remember the actual immediate instrumented JS for given original path | ||
sourceCache[jsPath] = content; | ||
sourceCache[jsPath] = content | ||
if (includeAllSources) { | ||
var coverageObjRegex = /\{.*"path".*"fnMap".*"statementMap".*"branchMap".*\}/g; | ||
var coverageObjMatch = coverageObjRegex.exec(instrumentedCode); | ||
var coverageObjRegex = /\{.*"path".*"fnMap".*"statementMap".*"branchMap".*\}/g | ||
var coverageObjMatch = coverageObjRegex.exec(instrumentedCode) | ||
if (coverageObjMatch !== null) { | ||
var coverageObj = JSON.parse(coverageObjMatch[0]); | ||
coverageMap.add(coverageObj); | ||
var coverageObj = JSON.parse(coverageObjMatch[0]) | ||
coverageMap.add(coverageObj) | ||
} | ||
} | ||
done(instrumentedCode); | ||
}); | ||
}; | ||
}; | ||
done(instrumentedCode) | ||
}) | ||
} | ||
} | ||
createCoveragePreprocessor.$inject = ['logger', | ||
'config.basePath', | ||
'config.reporters', | ||
'config.coverageReporter']; | ||
createCoveragePreprocessor.$inject = [ | ||
'logger', | ||
'config.basePath', | ||
'config.reporters', | ||
'config.coverageReporter' | ||
] | ||
module.exports = createCoveragePreprocessor; | ||
module.exports = createCoveragePreprocessor |
@@ -1,67 +0,71 @@ | ||
var path = require('path'); | ||
var fs = require('fs'); | ||
var util = require('util'); | ||
var istanbul = require('istanbul'); | ||
var dateformat = require('dateformat'); | ||
var globalSourceCache = require('./sourceCache'); | ||
var coverageMap = require('./coverageMap'); | ||
var path = require('path') | ||
var util = require('util') | ||
var istanbul = require('istanbul') | ||
var globalSourceCache = require('./sourceCache') | ||
var coverageMap = require('./coverageMap') | ||
var Store = istanbul.Store | ||
var Store = istanbul.Store; | ||
var SourceCacheStore = function (opts) { | ||
Store.call(this, opts) | ||
opts = opts || {} | ||
this.sourceCache = opts.sourceCache | ||
} | ||
SourceCacheStore.TYPE = 'sourceCacheLookup' | ||
util.inherits(SourceCacheStore, Store) | ||
var SourceCacheStore = function(opts) { | ||
Store.call(this, opts); | ||
opts = opts || {}; | ||
this.sourceCache = opts.sourceCache; | ||
}; | ||
SourceCacheStore.TYPE = 'sourceCacheLookup'; | ||
util.inherits(SourceCacheStore, Store); | ||
Store.mix(SourceCacheStore, { | ||
keys : function() { | ||
throw 'not implemented'; | ||
keys: function () { | ||
throw new Error('Not implemented') | ||
}, | ||
get : function(key) { | ||
return this.sourceCache[key]; | ||
get: function (key) { | ||
return this.sourceCache[key] | ||
}, | ||
hasKey : function(key) { | ||
return this.sourceCache.hasOwnProperty(key); | ||
hasKey: function (key) { | ||
return this.sourceCache.hasOwnProperty(key) | ||
}, | ||
set : function(key, contents) { | ||
throw 'not applicable'; | ||
set: function (key, contents) { | ||
throw new Error('Not applicable') | ||
} | ||
}); | ||
}) | ||
// TODO(vojta): inject only what required (config.basePath, config.coverageReporter) | ||
var CoverageReporter = function(rootConfig, helper, logger) { | ||
var log = logger.create('coverage'); | ||
var config = rootConfig.coverageReporter || {}; | ||
var basePath = rootConfig.basePath; | ||
var reporters = config.reporters; | ||
var sourceCache = globalSourceCache.getByBasePath(basePath); | ||
var includeAllSources = config.includeAllSources === true; | ||
var CoverageReporter = function (rootConfig, helper, logger) { | ||
var _ = helper._ | ||
var log = logger.create('coverage') | ||
var config = rootConfig.coverageReporter || {} | ||
var basePath = rootConfig.basePath | ||
var reporters = config.reporters | ||
var sourceCache = globalSourceCache.getByBasePath(basePath) | ||
var includeAllSources = config.includeAllSources === true | ||
if (config.watermarks) { | ||
config.watermarks = helper.merge({}, istanbul.config.defaultConfig().reporting.watermarks, config.watermarks) | ||
} | ||
if (!helper.isDefined(reporters)) { | ||
reporters = [config]; | ||
reporters = [config] | ||
} | ||
this.adapters = []; | ||
var collectors; | ||
var pendingFileWritings = 0; | ||
var fileWritingFinished = function() {}; | ||
this.adapters = [] | ||
var collectors | ||
var pendingFileWritings = 0 | ||
var fileWritingFinished = function () {} | ||
function writeReport(reporter, collector) { | ||
function writeReport (reporter, collector) { | ||
try { | ||
reporter.writeReport(collector, true); | ||
reporter.writeReport(collector, true) | ||
} catch (e) { | ||
log.error(e); | ||
log.error(e) | ||
} | ||
if (!--pendingFileWritings) { | ||
// cleanup collectors | ||
Object.keys(collectors).forEach(function(key) { | ||
collectors[key].dispose(); | ||
}); | ||
fileWritingFinished(); | ||
--pendingFileWritings | ||
} | ||
function disposeCollectors () { | ||
if (pendingFileWritings <= 0) { | ||
Object.keys(collectors).forEach(function (key) { | ||
collectors[key].dispose() | ||
}) | ||
fileWritingFinished() | ||
} | ||
@@ -80,95 +84,100 @@ } | ||
*/ | ||
function generateOutputDir(browserName, dir, subdir) { | ||
dir = dir || 'coverage'; | ||
subdir = subdir || browserName; | ||
function generateOutputDir (browserName, dir, subdir) { | ||
dir = dir || 'coverage' | ||
subdir = subdir || browserName | ||
if (typeof subdir === 'function') { | ||
subdir = subdir(browserName); | ||
subdir = subdir(browserName) | ||
} | ||
return path.join(dir, subdir); | ||
return path.join(dir, subdir) | ||
} | ||
this.onRunStart = function(browsers) { | ||
collectors = Object.create(null); | ||
this.onRunStart = function (browsers) { | ||
collectors = Object.create(null) | ||
// TODO(vojta): remove once we don't care about Karma 0.10 | ||
if (browsers) { | ||
browsers.forEach(this.onBrowserStart.bind(this)); | ||
browsers.forEach(this.onBrowserStart.bind(this)) | ||
} | ||
}; | ||
} | ||
this.onBrowserStart = function(browser) { | ||
collectors[browser.id] = new istanbul.Collector(); | ||
if(includeAllSources){ | ||
collectors[browser.id].add(coverageMap.get()); | ||
this.onBrowserStart = function (browser) { | ||
collectors[browser.id] = new istanbul.Collector() | ||
if (includeAllSources) { | ||
collectors[browser.id].add(coverageMap.get()) | ||
} | ||
}; | ||
} | ||
this.onBrowserComplete = function(browser, result) { | ||
var collector = collectors[browser.id]; | ||
this.onBrowserComplete = function (browser, result) { | ||
var collector = collectors[browser.id] | ||
if (!collector) { | ||
return; | ||
return | ||
} | ||
if (result && result.coverage) { | ||
collector.add(result.coverage); | ||
collector.add(result.coverage) | ||
} | ||
}; | ||
} | ||
this.onSpecComplete = function(browser, result) { | ||
this.onSpecComplete = function (browser, result) { | ||
if (result.coverage) { | ||
collectors[browser.id].add(result.coverage); | ||
collectors[browser.id].add(result.coverage) | ||
} | ||
}; | ||
} | ||
this.onRunComplete = function(browsers) { | ||
reporters.forEach(function(reporterConfig) { | ||
browsers.forEach(function(browser) { | ||
var collector = collectors[browser.id]; | ||
this.onRunComplete = function (browsers) { | ||
reporters.forEach(function (reporterConfig) { | ||
browsers.forEach(function (browser) { | ||
var collector = collectors[browser.id] | ||
if (collector) { | ||
pendingFileWritings++; | ||
pendingFileWritings++ | ||
var outputDir = helper.normalizeWinPath(path.resolve(basePath, generateOutputDir(browser.name, | ||
reporterConfig.dir || config.dir, | ||
reporterConfig.subdir || config.subdir))); | ||
var mainDir = reporterConfig.dir || config.dir | ||
var subDir = reporterConfig.subdir || config.subdir | ||
var simpleOutputDir = generateOutputDir(browser.name, mainDir, subDir) | ||
var resolvedOutputDir = path.resolve(basePath, simpleOutputDir) | ||
var options = helper.merge({}, reporterConfig, { | ||
dir : outputDir, | ||
sourceStore : new SourceCacheStore({ | ||
var outputDir = helper.normalizeWinPath(resolvedOutputDir) | ||
var options = helper.merge({ | ||
sourceStore: _.isEmpty(sourceCache) ? null : new SourceCacheStore({ | ||
sourceCache: sourceCache | ||
}) | ||
}); | ||
var reporter = istanbul.Report.create(reporterConfig.type || 'html', options); | ||
}, config, reporterConfig, { | ||
dir: outputDir | ||
}) | ||
var reporter = istanbul.Report.create(reporterConfig.type || 'html', options) | ||
// If reporting to console, skip directory creation | ||
if (reporterConfig.type && reporterConfig.type.match(/^(text|text-summary)$/) && typeof reporterConfig.file === 'undefined') { | ||
writeReport(reporter, collector); | ||
return; | ||
writeReport(reporter, collector) | ||
return | ||
} | ||
helper.mkdirIfNotExists(outputDir, function() { | ||
log.debug('Writing coverage to %s', outputDir); | ||
writeReport(reporter, collector); | ||
}); | ||
helper.mkdirIfNotExists(outputDir, function () { | ||
log.debug('Writing coverage to %s', outputDir) | ||
writeReport(reporter, collector) | ||
disposeCollectors() | ||
}) | ||
} | ||
}); | ||
}); | ||
}; | ||
}) | ||
}) | ||
this.onExit = function(done) { | ||
disposeCollectors() | ||
} | ||
this.onExit = function (done) { | ||
if (pendingFileWritings) { | ||
fileWritingFinished = done; | ||
fileWritingFinished = done | ||
} else { | ||
done(); | ||
done() | ||
} | ||
}; | ||
}; | ||
} | ||
} | ||
CoverageReporter.$inject = ['config', 'helper', 'logger']; | ||
CoverageReporter.$inject = ['config', 'helper', 'logger'] | ||
// PUBLISH | ||
module.exports = CoverageReporter; | ||
module.exports = CoverageReporter |
@@ -0,6 +1,5 @@ | ||
var cacheByBasePath = {} | ||
var cacheByBasePath = {}; | ||
exports.getByBasePath = function (basePath) { | ||
return cacheByBasePath[basePath] ? cacheByBasePath[basePath] : (cacheByBasePath[basePath] = {}); | ||
}; | ||
return cacheByBasePath[basePath] ? cacheByBasePath[basePath] : (cacheByBasePath[basePath] = {}) | ||
} |
{ | ||
"name": "karma-coverage", | ||
"version": "0.3.1", | ||
"version": "0.4.0", | ||
"description": "A Karma plugin. Generate code coverage.", | ||
@@ -22,32 +22,59 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"istanbul": "~0.3.0", | ||
"dateformat": "~1.0.6", | ||
"minimatch": "~0.3.0" | ||
"istanbul": "^0.3.0", | ||
"dateformat": "^1.0.6", | ||
"minimatch": "^2.0.8" | ||
}, | ||
"peerDependencies": { | ||
"karma": ">=0.9" | ||
}, | ||
"license": "MIT", | ||
"devDependencies": { | ||
"chai": "~1.7.2", | ||
"grunt": "~0.4.1", | ||
"grunt-auto-release": "~0.0.1", | ||
"grunt-bump": "~0.0.7", | ||
"grunt-contrib-jshint": "~0.6.0", | ||
"grunt-npm": "~0.0.2", | ||
"grunt-simple-mocha": "~0.4.0", | ||
"karma": "~0.12.0", | ||
"lodash": "^2.4.1", | ||
"chai": "^2.3.0", | ||
"eslint": "^0.22.1", | ||
"eslint-config-standard": "^2.0.1", | ||
"eslint-plugin-react": "^2.5.0", | ||
"grunt": "^0.4.1", | ||
"grunt-bump": "^0.3.1", | ||
"grunt-conventional-changelog": "^1.2.2", | ||
"grunt-eslint": "^14.0.0", | ||
"grunt-npm": "^0.0.2", | ||
"grunt-simple-mocha": "^0.4.0", | ||
"karma": "^0.12.0", | ||
"load-grunt-tasks": "^3.2.0", | ||
"lodash": "^3.9.3", | ||
"mocks": "0.0.11", | ||
"sinon": "~1.7.3", | ||
"sinon-chai": "~2.4.0" | ||
"sinon": "^1.14.1", | ||
"sinon-chai": "^2.8.0" | ||
}, | ||
"contributors": [ | ||
"Friedel Ziegelmayer <friedel.ziegelmayer@gmail.com>", | ||
"Aymeric Beaumet <aymeric@beaumet.me>", | ||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", | ||
"Tim Kang <timkang@ucla.edu>", | ||
"Maksim Ryzhikov <rv.maksim@gmail.com>", | ||
"Allen Bierbaum <abierbaum@gmail.com>", | ||
"Matt Winchester <m_winche@yahoo.com>", | ||
"Douglas Duteil <douglasduteil@gmail.com>", | ||
"Wei Kin Huang <weikin.huang04@gmail.com>", | ||
"Michael Stramel <m.stramel89@gmail.com>", | ||
"Nick Malaguti <nmalaguti@palantir.com>", | ||
"Nick Matantsev <nick.matantsev@gmail.com>", | ||
"Petar Manev <petar.manev2010@gmail.com>", | ||
"Robin Böhm <robinboehm@googlemail.com>", | ||
"Ron Derksen <ron.derksen@informaat.nl>", | ||
"Sahat Yalkabov <sakhat@gmail.com>", | ||
"Tanjo, Hiroyuki <expheno@gmail.com>", | ||
"Taylor Hakes <taylor@taylorhakes.com>", | ||
"Timo Tijhof <krinklemail@gmail.com>", | ||
"Tom Kirkpatrick <tom@systemseed.com>", | ||
"Vincent Lemeunier <vincent.lemeunier+git@gmail.com>", | ||
"Yusuke Suzuki <utatane.tea@gmail.com>", | ||
"aprooks <alexander.prooks@gmail.com>", | ||
"piecyk <piecyk@gmail.com>", | ||
"Chris Gladd <chris.m.gladd@gmail.com>", | ||
"Dmitry Petrov <dpetroff@gmail.com>", | ||
"Greg Varsanyi <gvarsanyi@gmail.com>", | ||
"Joseph Connolly <joec@avinetworks.com>", | ||
"Joshua Appelman <jappelman@xebia.com>", | ||
"Julie <ju.ralph@gmail.com>", | ||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", | ||
"Petar Manev <petar.manev2010@gmail.com>" | ||
"Kyle Welsby <kyle@mekyle.com>", | ||
"Maciej Rzepiński <maciej.rzepinski@gmail.com>", | ||
"Mark Ethan Trostler <mark@zzo.com>" | ||
] | ||
} |
@@ -1,3 +0,8 @@ | ||
# karma-coverage [](https://travis-ci.org/karma-runner/karma-coverage) | ||
# karma-coverage | ||
[](https://github.com/karma-runner/karma-coverage) | ||
[](https://www.npmjs.com/package/karma-coverage) [](https://www.npmjs.com/package/karma-coverage) | ||
[](https://travis-ci.org/karma-runner/karma-coverage) [](https://david-dm.org/karma-runner/karma-coverage) [](https://david-dm.org/karma-runner/karma-coverage#info=devDependencies) | ||
> Generate code coverage using [Istanbul]. | ||
@@ -7,15 +12,7 @@ | ||
The easiest way is to keep `karma-coverage` as a devDependency in your `package.json`. | ||
```json | ||
{ | ||
"devDependencies": { | ||
"karma": "~0.10", | ||
"karma-coverage": "~0.1" | ||
} | ||
} | ||
``` | ||
The easiest way is to install `karma-coverage` as a `devDependency`, | ||
by running | ||
You can simple do it by: | ||
```bash | ||
npm install karma-coverage --save-dev | ||
npm install karma karma-coverage --save-dev | ||
``` | ||
@@ -227,2 +224,16 @@ | ||
#### sourceStore | ||
**Type:** istanbul.Store | ||
You can opt to specify a source store allowing for external coverage collectors access to the instrumented code. | ||
```javascript | ||
coverageReporter: { | ||
type : 'text', | ||
dir : 'coverage/', | ||
file : 'coverage.txt', | ||
sourceStore : require('istanbul').Store.create('fslookup') | ||
} | ||
``` | ||
#### multiple reporters | ||
@@ -289,2 +300,2 @@ You can use multiple reporters, by providing array of options. | ||
[homepage]: http://karma-runner.github.com | ||
[Istanbul]: https://github.com/yahoo/istanbul | ||
[Istanbul]: https://github.com/gotwarlost/istanbul |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
28370
55.97%3
-25%10
25%300
26.05%299
3.82%16
33.33%2
Infinity%- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated