2022-11-10 11:43:16 +01:00
|
|
|
'use strict';var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var _path = require('path');var _path2 = _interopRequireDefault(_path);
|
2020-08-26 01:57:08 +02:00
|
|
|
var _fs = require('fs');var _fs2 = _interopRequireDefault(_fs);
|
2022-11-10 11:43:16 +01:00
|
|
|
var _readPkgUp = require('eslint-module-utils/readPkgUp');var _readPkgUp2 = _interopRequireDefault(_readPkgUp);
|
2020-08-26 01:57:08 +02:00
|
|
|
var _minimatch = require('minimatch');var _minimatch2 = _interopRequireDefault(_minimatch);
|
|
|
|
var _resolve = require('eslint-module-utils/resolve');var _resolve2 = _interopRequireDefault(_resolve);
|
|
|
|
var _moduleVisitor = require('eslint-module-utils/moduleVisitor');var _moduleVisitor2 = _interopRequireDefault(_moduleVisitor);
|
|
|
|
var _importType = require('../core/importType');var _importType2 = _interopRequireDefault(_importType);
|
2022-11-10 11:43:16 +01:00
|
|
|
var _packagePath = require('../core/packagePath');
|
|
|
|
var _docsUrl = require('../docsUrl');var _docsUrl2 = _interopRequireDefault(_docsUrl);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { 'default': obj };}
|
2020-08-26 01:57:08 +02:00
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
var depFieldCache = new Map();
|
|
|
|
|
|
|
|
function hasKeys() {var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
2020-08-26 01:57:08 +02:00
|
|
|
return Object.keys(obj).length > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function arrayOrKeys(arrayOrObject) {
|
|
|
|
return Array.isArray(arrayOrObject) ? arrayOrObject : Object.keys(arrayOrObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
function extractDepFields(pkg) {
|
|
|
|
return {
|
|
|
|
dependencies: pkg.dependencies || {},
|
|
|
|
devDependencies: pkg.devDependencies || {},
|
|
|
|
optionalDependencies: pkg.optionalDependencies || {},
|
|
|
|
peerDependencies: pkg.peerDependencies || {},
|
|
|
|
// BundledDeps should be in the form of an array, but object notation is also supported by
|
|
|
|
// `npm`, so we convert it to an array if it is an object
|
|
|
|
bundledDependencies: arrayOrKeys(pkg.bundleDependencies || pkg.bundledDependencies || []) };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function getDependencies(context, packageDir) {
|
2022-11-10 11:43:16 +01:00
|
|
|
var paths = [];
|
2020-08-26 01:57:08 +02:00
|
|
|
try {
|
2022-11-10 11:43:16 +01:00
|
|
|
var packageContent = {
|
2020-08-26 01:57:08 +02:00
|
|
|
dependencies: {},
|
|
|
|
devDependencies: {},
|
|
|
|
optionalDependencies: {},
|
|
|
|
peerDependencies: {},
|
|
|
|
bundledDependencies: [] };
|
|
|
|
|
|
|
|
|
|
|
|
if (packageDir && packageDir.length > 0) {
|
|
|
|
if (!Array.isArray(packageDir)) {
|
2022-11-10 11:43:16 +01:00
|
|
|
paths = [_path2['default'].resolve(packageDir)];
|
2020-08-26 01:57:08 +02:00
|
|
|
} else {
|
2022-11-10 11:43:16 +01:00
|
|
|
paths = packageDir.map(function (dir) {return _path2['default'].resolve(dir);});
|
2020-08-26 01:57:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (paths.length > 0) {
|
|
|
|
// use rule config to find package.json
|
2022-11-10 11:43:16 +01:00
|
|
|
paths.forEach(function (dir) {
|
|
|
|
var packageJsonPath = _path2['default'].join(dir, 'package.json');
|
|
|
|
if (!depFieldCache.has(packageJsonPath)) {
|
|
|
|
var depFields = extractDepFields(
|
|
|
|
JSON.parse(_fs2['default'].readFileSync(packageJsonPath, 'utf8')));
|
|
|
|
|
|
|
|
depFieldCache.set(packageJsonPath, depFields);
|
|
|
|
}
|
|
|
|
var _packageContent = depFieldCache.get(packageJsonPath);
|
|
|
|
Object.keys(packageContent).forEach(function (depsKey) {return (
|
|
|
|
Object.assign(packageContent[depsKey], _packageContent[depsKey]));});
|
2020-08-26 01:57:08 +02:00
|
|
|
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// use closest package.json
|
|
|
|
Object.assign(
|
|
|
|
packageContent,
|
|
|
|
extractDepFields(
|
2022-11-10 11:43:16 +01:00
|
|
|
(0, _readPkgUp2['default'])({ cwd: context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename(), normalize: false }).pkg));
|
2020-08-26 01:57:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (![
|
|
|
|
packageContent.dependencies,
|
|
|
|
packageContent.devDependencies,
|
|
|
|
packageContent.optionalDependencies,
|
|
|
|
packageContent.peerDependencies,
|
|
|
|
packageContent.bundledDependencies].
|
|
|
|
some(hasKeys)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return packageContent;
|
|
|
|
} catch (e) {
|
|
|
|
if (paths.length > 0 && e.code === 'ENOENT') {
|
|
|
|
context.report({
|
|
|
|
message: 'The package.json file could not be found.',
|
|
|
|
loc: { line: 0, column: 0 } });
|
|
|
|
|
|
|
|
}
|
|
|
|
if (e.name === 'JSONError' || e instanceof SyntaxError) {
|
|
|
|
context.report({
|
|
|
|
message: 'The package.json file could not be parsed: ' + e.message,
|
|
|
|
loc: { line: 0, column: 0 } });
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function missingErrorMessage(packageName) {
|
2022-11-10 11:43:16 +01:00
|
|
|
return '\'' + String(packageName) + '\' should be listed in the project\'s dependencies. ' + ('Run \'npm i -S ' + String(
|
|
|
|
packageName) + '\' to add it');
|
2020-08-26 01:57:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function devDepErrorMessage(packageName) {
|
2022-11-10 11:43:16 +01:00
|
|
|
return '\'' + String(packageName) + '\' should be listed in the project\'s dependencies, not devDependencies.';
|
2020-08-26 01:57:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function optDepErrorMessage(packageName) {
|
2022-11-10 11:43:16 +01:00
|
|
|
return '\'' + String(packageName) + '\' should be listed in the project\'s dependencies, ' + 'not optionalDependencies.';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function getModuleOriginalName(name) {var _name$split =
|
|
|
|
name.split('/'),_name$split2 = _slicedToArray(_name$split, 2),first = _name$split2[0],second = _name$split2[1];
|
|
|
|
return first.startsWith('@') ? String(first) + '/' + String(second) : first;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getModuleRealName(resolved) {
|
|
|
|
return (0, _packagePath.getFilePackageName)(resolved);
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkDependencyDeclaration(deps, packageName, declarationStatus) {
|
|
|
|
var newDeclarationStatus = declarationStatus || {
|
|
|
|
isInDeps: false,
|
|
|
|
isInDevDeps: false,
|
|
|
|
isInOptDeps: false,
|
|
|
|
isInPeerDeps: false,
|
|
|
|
isInBundledDeps: false };
|
|
|
|
|
|
|
|
|
|
|
|
// in case of sub package.json inside a module
|
|
|
|
// check the dependencies on all hierarchy
|
|
|
|
var packageHierarchy = [];
|
|
|
|
var packageNameParts = packageName ? packageName.split('/') : [];
|
|
|
|
packageNameParts.forEach(function (namePart, index) {
|
|
|
|
if (!namePart.startsWith('@')) {
|
|
|
|
var ancestor = packageNameParts.slice(0, index + 1).join('/');
|
|
|
|
packageHierarchy.push(ancestor);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return packageHierarchy.reduce(function (result, ancestorName) {
|
|
|
|
return {
|
|
|
|
isInDeps: result.isInDeps || deps.dependencies[ancestorName] !== undefined,
|
|
|
|
isInDevDeps: result.isInDevDeps || deps.devDependencies[ancestorName] !== undefined,
|
|
|
|
isInOptDeps: result.isInOptDeps || deps.optionalDependencies[ancestorName] !== undefined,
|
|
|
|
isInPeerDeps: result.isInPeerDeps || deps.peerDependencies[ancestorName] !== undefined,
|
|
|
|
isInBundledDeps:
|
|
|
|
result.isInBundledDeps || deps.bundledDependencies.indexOf(ancestorName) !== -1 };
|
|
|
|
|
|
|
|
}, newDeclarationStatus);
|
2020-08-26 01:57:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function reportIfMissing(context, deps, depsOptions, node, name) {
|
|
|
|
// Do not report when importing types
|
2022-11-10 11:43:16 +01:00
|
|
|
if (
|
|
|
|
node.importKind === 'type' ||
|
|
|
|
node.importKind === 'typeof')
|
|
|
|
{
|
2020-08-26 01:57:08 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
if ((0, _importType2['default'])(name, context) !== 'external') {
|
2020-08-26 01:57:08 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
var resolved = (0, _resolve2['default'])(name, context);
|
2020-08-26 01:57:08 +02:00
|
|
|
if (!resolved) {return;}
|
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
var importPackageName = getModuleOriginalName(name);
|
|
|
|
var declarationStatus = checkDependencyDeclaration(deps, importPackageName);
|
|
|
|
|
|
|
|
if (
|
|
|
|
declarationStatus.isInDeps ||
|
|
|
|
depsOptions.allowDevDeps && declarationStatus.isInDevDeps ||
|
|
|
|
depsOptions.allowPeerDeps && declarationStatus.isInPeerDeps ||
|
|
|
|
depsOptions.allowOptDeps && declarationStatus.isInOptDeps ||
|
|
|
|
depsOptions.allowBundledDeps && declarationStatus.isInBundledDeps)
|
2020-08-26 01:57:08 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
// test the real name from the resolved package.json
|
|
|
|
// if not aliased imports (alias/react for example), importPackageName can be misinterpreted
|
|
|
|
var realPackageName = getModuleRealName(resolved);
|
|
|
|
if (realPackageName && realPackageName !== importPackageName) {
|
|
|
|
declarationStatus = checkDependencyDeclaration(deps, realPackageName, declarationStatus);
|
|
|
|
|
|
|
|
if (
|
|
|
|
declarationStatus.isInDeps ||
|
|
|
|
depsOptions.allowDevDeps && declarationStatus.isInDevDeps ||
|
|
|
|
depsOptions.allowPeerDeps && declarationStatus.isInPeerDeps ||
|
|
|
|
depsOptions.allowOptDeps && declarationStatus.isInOptDeps ||
|
|
|
|
depsOptions.allowBundledDeps && declarationStatus.isInBundledDeps)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (declarationStatus.isInDevDeps && !depsOptions.allowDevDeps) {
|
|
|
|
context.report(node, devDepErrorMessage(realPackageName || importPackageName));
|
2020-08-26 01:57:08 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
if (declarationStatus.isInOptDeps && !depsOptions.allowOptDeps) {
|
|
|
|
context.report(node, optDepErrorMessage(realPackageName || importPackageName));
|
2020-08-26 01:57:08 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
context.report(node, missingErrorMessage(realPackageName || importPackageName));
|
2020-08-26 01:57:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function testConfig(config, filename) {
|
|
|
|
// Simplest configuration first, either a boolean or nothing.
|
|
|
|
if (typeof config === 'boolean' || typeof config === 'undefined') {
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
// Array of globs.
|
2022-11-10 11:43:16 +01:00
|
|
|
return config.some(function (c) {return (
|
|
|
|
(0, _minimatch2['default'])(filename, c) ||
|
|
|
|
(0, _minimatch2['default'])(filename, _path2['default'].join(process.cwd(), c)));});
|
2020-08-26 01:57:08 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
meta: {
|
|
|
|
type: 'problem',
|
|
|
|
docs: {
|
2022-11-10 11:43:16 +01:00
|
|
|
url: (0, _docsUrl2['default'])('no-extraneous-dependencies') },
|
2020-08-26 01:57:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
schema: [
|
|
|
|
{
|
|
|
|
'type': 'object',
|
|
|
|
'properties': {
|
|
|
|
'devDependencies': { 'type': ['boolean', 'array'] },
|
|
|
|
'optionalDependencies': { 'type': ['boolean', 'array'] },
|
|
|
|
'peerDependencies': { 'type': ['boolean', 'array'] },
|
|
|
|
'bundledDependencies': { 'type': ['boolean', 'array'] },
|
|
|
|
'packageDir': { 'type': ['string', 'array'] } },
|
|
|
|
|
|
|
|
'additionalProperties': false }] },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
create: function () {function create(context) {
|
|
|
|
var options = context.options[0] || {};
|
|
|
|
var filename = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
|
|
|
|
var deps = getDependencies(context, options.packageDir) || extractDepFields({});
|
2020-08-26 01:57:08 +02:00
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
var depsOptions = {
|
|
|
|
allowDevDeps: testConfig(options.devDependencies, filename) !== false,
|
|
|
|
allowOptDeps: testConfig(options.optionalDependencies, filename) !== false,
|
|
|
|
allowPeerDeps: testConfig(options.peerDependencies, filename) !== false,
|
|
|
|
allowBundledDeps: testConfig(options.bundledDependencies, filename) !== false };
|
2020-08-26 01:57:08 +02:00
|
|
|
|
|
|
|
|
2022-11-10 11:43:16 +01:00
|
|
|
return (0, _moduleVisitor2['default'])(function (source, node) {
|
|
|
|
reportIfMissing(context, deps, depsOptions, node, source.value);
|
|
|
|
}, { commonjs: true });
|
|
|
|
}return create;}() };
|
|
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydWxlcy9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcy5qcyJdLCJuYW1lcyI6WyJkZXBGaWVsZENhY2hlIiwiTWFwIiwiaGFzS2V5cyIsIm9iaiIsIk9iamVjdCIsImtleXMiLCJsZW5ndGgiLCJhcnJheU9yS2V5cyIsImFycmF5T3JPYmplY3QiLCJBcnJheSIsImlzQXJyYXkiLCJleHRyYWN0RGVwRmllbGRzIiwicGtnIiwiZGVwZW5kZW5jaWVzIiwiZGV2RGVwZW5kZW5jaWVzIiwib3B0aW9uYWxEZXBlbmRlbmNpZXMiLCJwZWVyRGVwZW5kZW5jaWVzIiwiYnVuZGxlZERlcGVuZGVuY2llcyIsImJ1bmRsZURlcGVuZGVuY2llcyIsImdldERlcGVuZGVuY2llcyIsImNvbnRleHQiLCJwYWNrYWdlRGlyIiwicGF0aHMiLCJwYWNrYWdlQ29udGVudCIsInBhdGgiLCJyZXNvbHZlIiwibWFwIiwiZGlyIiwiZm9yRWFjaCIsInBhY2thZ2VKc29uUGF0aCIsImpvaW4iLCJoYXMiLCJkZXBGaWVsZHMiLCJKU09OIiwicGFyc2UiLCJmcyIsInJlYWRGaWxlU3luYyIsInNldCIsIl9wYWNrYWdlQ29udGVudCIsImdldCIsImFzc2lnbiIsImRlcHNLZXkiLCJjd2QiLCJnZXRQaHlzaWNhbEZpbGVuYW1lIiwiZ2V0RmlsZW5hbWUiLCJub3JtYWxpemUiLCJzb21lIiwiZSIsImNvZGUiLCJyZXBvcnQiLCJtZXNzYWdlIiwibG9jIiwibGluZSIsImNvbHVtbiIsIm5hbWUiLCJTeW50YXhFcnJvciIsIm1pc3NpbmdFcnJvck1lc3NhZ2UiLCJwYWNrYWdlTmFtZSIsImRldkRlcEVycm9yTWVzc2FnZSIsIm9wdERlcEVycm9yTWVzc2FnZSIsImdldE1vZHVsZU9yaWdpbmFsTmFtZSIsInNwbGl0IiwiZmlyc3QiLCJzZWNvbmQiLCJzdGFydHNXaXRoIiwiZ2V0TW9kdWxlUmVhbE5hbWUiLCJyZXNvbHZlZCIsImNoZWNrRGVwZW5kZW5jeURlY2xhcmF0aW9uIiwiZGVwcyIsImRlY2xhcmF0aW9uU3RhdHVzIiwibmV3RGVjbGFyYXRpb25TdGF0dXMiLCJpc0luRGVwcyIsImlzSW5EZXZEZXBzIiwiaXNJbk9wdERlcHMiLCJpc0luUGVlckRlcHMiLCJpc0luQnVuZGxlZERlcHMiLCJwYWNrYWdlSGllcmFyY2h5IiwicGFja2FnZU5hbWVQYXJ0cyIsIm5hbWVQYXJ0IiwiaW5kZXgiLCJhbmNlc3RvciIsInNsaWNlIiwicHVzaCIsInJlZHVjZSIsInJlc3VsdCIsImFuY2VzdG9yTmFtZSIsInVuZGVmaW5lZCIsImluZGV4T2YiLCJyZXBvcnRJZk1pc3NpbmciLCJkZXBzT3B0aW9ucyIsIm5vZGUiLCJpbXBvcnRLaW5kIiwiaW1wb3J0UGFja2FnZU5hbWUiLCJhbGxvd0RldkRlcHMiLCJhbGxvd1BlZXJEZXBzIiwiYWxsb3dPcHREZXBzIiwiYWxsb3dCdW5kbGVkRGVwcyIsInJlYWxQYWNrYWdlTmFtZSIsInRlc3RDb25maWciLCJjb25maWciLCJmaWxlbmFtZSIsImMiLCJwcm9jZXNzIiwibW9kdWxlIiwiZXhwb3J0cyIsIm1ldGEiLCJ0eXBlIiwiZG9jcyIsInVybCIsInNjaGVtYSIsImNyZWF0ZSIsIm9wdGlvbnMiLCJzb3VyY2UiLCJ2YWx1ZSIsImNvbW1vbmpzIl0sIm1hcHBpbmdzIjoicW9CQUFBLDRCO0FBQ0Esd0I7QUFDQSwwRDtBQUNBLHNDO0FBQ0Esc0Q7QUFDQSxrRTtBQUNBLGdEO0FBQ0E7QUFDQSxxQzs7QUFFQSxJQUFNQSxnQkFBZ0IsSUFBSUMsR0FBSixFQUF0Qjs7QUFFQSxTQUFTQyxPQUFULEdBQTJCLEtBQVZDLEdBQVUsdUVBQUosRUFBSTtBQUN6QixTQUFPQyxPQUFPQyxJQUFQLENBQVlGLEdBQVosRUFBaUJHLE1BQWpCLEdBQTBCLENBQWpDO0FBQ0Q7O0FBRUQsU0FBU0MsV0FBVCxDQUFxQkMsYUFBckIsRUFBb0M7QUFDbEMsU0FBT0MsTUFBTUMsT0FBTixDQUFjRixhQUFkLElBQStCQSxhQUEvQixHQUErQ0osT0FBT0MsSUFBUCxDQUFZRyxhQUFaLENBQXREO0FBQ0Q7O0FBRUQsU0FBU0csZ0JBQVQsQ0FBMEJDLEdBQTFCLEVBQStCO0FBQzdCLFNBQU87QUFDTEMsa0JBQWNELElBQUlDLFlBQUosSUFBb0IsRUFEN0I7QUFFTEMscUJBQWlCRixJQUFJRSxlQUFKLElBQXVCLEVBRm5DO0FBR0xDLDBCQUFzQkgsSUFBSUcsb0JBQUosSUFBNEIsRUFIN0M7QUFJTEMsc0JBQWtCSixJQUFJSSxnQkFBSixJQUF3QixFQUpyQztBQUtMO0FBQ0E7QUFDQUMseUJBQXFCVixZQUFZSyxJQUFJTSxrQkFBSixJQUEwQk4sSUFBSUssbUJBQTlCLElBQXFELEVBQWpFLENBUGhCLEVBQVA7O0FBU0Q7O0FBRUQsU0FBU0UsZUFBVCxDQUF5QkMsT0FBekIsRUFBa0NDLFVBQWxDLEVBQThDO0FBQzVDLE1BQUlDLFFBQVEsRUFBWjtBQUNBLE1BQUk7QUFDRixRQUFNQyxpQkFBaUI7QUFDckJWLG9CQUFjLEVBRE87QUFFckJDLHVCQUFpQixFQUZJO0FBR3JCQyw0QkFBc0IsRUFIRDtBQUlyQkMsd0JBQWtCLEVBSkc7QUFLckJDLDJCQUFxQixFQUxBLEVBQXZCOzs7QUFRQSxRQUFJSSxjQUFjQSxXQUFXZixNQUFYLEdBQW9CLENBQXRDLEVBQXlDO0FBQ3ZDLFVBQUksQ0FBQ0csTUFBTUMsT0FBTixDQUFjVyxVQUFkLENBQUwsRUFBZ0M7QUFDOUJDLGdCQUFRLENBQUNFLGtCQUFLQyxPQUFMLENBQWFKLFVBQWIsQ0FBRCxDQUFSO0FBQ0QsT0FGRCxNQUVPO0FBQ0xDLGdCQUFRRCxXQUFXSyxHQUFYLENBQWUsdUJBQU9GLGtCQUFLQyxPQUFMLENBQWFFLEdBQWIsQ0FBUCxFQUFmLENBQVI7QUFDRDtBQUNGOztBQUVELFFBQUlMLE1BQU1oQixNQUFOLEdBQWUsQ0FBbkIsRUFBc0I7QUFDcEI7QUFDQWdCLFlBQU1NLE9BQU4sQ0FBYyxlQUFPO0FBQ25CLFlBQU1DLGtCQUFrQkwsa0JBQUtNLElBQUwsQ0FBVUgsR0FBVixFQUFlLGNBQWYsQ0FBeEI7QUFDQSxZQUFJLENBQUMzQixjQUFjK0IsR0FBZCxDQUFrQkYsZUFBbEIsQ0FBTCxFQUF5QztBQUN2QyxjQUFNRyxZQUFZckI7QUFDaEJzQixlQUFLQyxLQUFMLENBQVdDLGdCQUFHQyxZQUFILENBQWdCUCxlQUFoQixFQUFpQyxNQUFqQyxDQUFYLENBRGdCLENBQWxCOztBQUdBN0Isd0JBQWNxQyxHQUFkLENBQWtCUixlQUFsQixFQUFtQ0csU0FBbkM7QUFDRDtBQUNELFlBQU1NLGtCQUFrQnRDLGNBQWN1QyxHQUFkLENBQWtCVixlQUFsQixDQUF4QjtBQUNBekIsZUFBT0MsSUFBUCxDQUFZa0IsY0FBWixFQUE0QkssT0FBNUIsQ0FBb0M7QUFDbEN4QixtQkFBT29DLE1BQVAsQ0FBY2pCLGVBQWV
|