cnpmcore
Version:
Private NPM Registry for Enterprise
389 lines • 40.9 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _PackageVersionFileService_instances, _PackageVersionFileService_unpkgWhiteListCheckTime, _PackageVersionFileService_unpkgWhiteListCurrentVersion, _PackageVersionFileService_unpkgWhiteListAllowPackages, _PackageVersionFileService_unpkgWhiteListAllowScopes, _PackageVersionFileService_unpkgWhiteListAllowLargePackages, _PackageVersionFileService_unpkgWhiteListAllowLargeScopes, _PackageVersionFileService_unpkgWhiteListBlockSyncScopes, _PackageVersionFileService_unpkgWhiteListBlockSyncPackages, _PackageVersionFileService_ensurePackageVersionFilesSync, _PackageVersionFileService_updateUnpkgWhiteList, _PackageVersionFileService_savePackageVersionFile, _PackageVersionFileService_getDirectoryAndName, _PackageVersionFileService_formatTarEntryFilename, _PackageVersionFileService_matchReadmeFilename, _PackageVersionFileService_preferMarkdownReadme;
import { randomUUID } from 'node:crypto';
import fs from 'node:fs/promises';
import { basename, dirname, join } from 'node:path';
import { AccessLevel, Inject, SingletonProto } from 'egg';
import { ConflictError, ForbiddenError } from 'egg/errors';
import semver from 'semver';
import * as tar from 'tar';
import { AbstractService } from "../../common/AbstractService.js";
import { createTempDir, mimeLookup } from "../../common/FileUtil.js";
import { calculateIntegrity, getFullname } from "../../common/PackageUtil.js";
import { isDuplicateKeyError } from "../../repository/util/ErrorUtil.js";
import { PackageVersionFile } from "../entity/PackageVersionFile.js";
export const UNPKG_WHITE_LIST_URL = 'https://github.com/cnpm/unpkg-white-list';
const CHECK_TIMEOUT = process.env.NODE_ENV === 'test' ? 1 : 60_000;
let PackageVersionFileService = class PackageVersionFileService extends AbstractService {
constructor() {
super(...arguments);
_PackageVersionFileService_instances.add(this);
_PackageVersionFileService_unpkgWhiteListCheckTime.set(this, 0);
_PackageVersionFileService_unpkgWhiteListCurrentVersion.set(this, '');
_PackageVersionFileService_unpkgWhiteListAllowPackages.set(this, {});
_PackageVersionFileService_unpkgWhiteListAllowScopes.set(this, []);
// allow large packages, e.g. 100MB
// e.g.: { '@foo/bar': { version: '*' } }
_PackageVersionFileService_unpkgWhiteListAllowLargePackages.set(this, {});
// allow large package scopes, e.g. ['@foo', '@bar']
_PackageVersionFileService_unpkgWhiteListAllowLargeScopes.set(this, []);
// block sync scopes, e.g. ['@foo', '@bar']
_PackageVersionFileService_unpkgWhiteListBlockSyncScopes.set(this, []);
// block sync packages, e.g. ['@foo/foo', '@foo/bar']
_PackageVersionFileService_unpkgWhiteListBlockSyncPackages.set(this, []);
}
get unpkgWhiteListVersion() {
return __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListCurrentVersion, "f");
}
async listPackageVersionFiles(pkgVersion, directory) {
await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_ensurePackageVersionFilesSync).call(this, pkgVersion);
return await this.packageVersionFileRepository.listPackageVersionFiles(pkgVersion.packageVersionId, directory);
}
async showPackageVersionFile(pkgVersion, path) {
await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_ensurePackageVersionFilesSync).call(this, pkgVersion);
const { directory, name } = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_getDirectoryAndName).call(this, path);
return await this.packageVersionFileRepository.findPackageVersionFile(pkgVersion.packageVersionId, directory, name);
}
async isLargePackageVersionAllowed(pkgScope, pkgName, pkgVersion) {
if (!this.config.cnpmcore.enableSyncUnpkgFilesWhiteList)
return false;
await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_updateUnpkgWhiteList).call(this);
// check allow large scopes
if (__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowLargeScopes, "f").includes(pkgScope))
return true;
const fullname = getFullname(pkgScope, pkgName);
const pkgConfig = __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowLargePackages, "f")[fullname];
if (!pkgConfig?.version)
return false;
return semver.satisfies(pkgVersion, pkgConfig.version, {
includePrerelease: true,
});
}
/**
* Check if the package is blocked to sync
* @param pkgScope - The scope of the package
* @param pkgName - The name of the package
* @returns True if the package is blocked to sync, false otherwise
*/
async isPackageBlockedToSync(pkgScope, pkgName) {
if (!this.config.cnpmcore.enableSyncUnpkgFilesWhiteList)
return false;
await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_updateUnpkgWhiteList).call(this);
// check block scopes
if (__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListBlockSyncScopes, "f").includes(pkgScope))
return true;
// check block packages
const fullname = getFullname(pkgScope, pkgName);
return __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListBlockSyncPackages, "f").includes(fullname);
}
async checkPackageVersionInUnpkgWhiteList(pkgScope, pkgName, pkgVersion) {
if (!this.config.cnpmcore.enableSyncUnpkgFilesWhiteList)
return;
await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_updateUnpkgWhiteList).call(this);
// check allow scopes
if (__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowScopes, "f").includes(pkgScope))
return;
// check allow packages
const fullname = getFullname(pkgScope, pkgName);
const pkgConfig = __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowPackages, "f")[fullname];
if (!pkgConfig?.version) {
throw new ForbiddenError(`"${fullname}" is not allow to unpkg files, see ${UNPKG_WHITE_LIST_URL}, white list version: ${__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListCurrentVersion, "f")}`);
}
// satisfies not include prerelease version by default
// https://docs.npmjs.com/about-semantic-versioning#using-semantic-versioning-to-specify-update-types-your-package-can-accept
// [x, *] means any version, here use `semver` to check
if (!semver.satisfies(pkgVersion, pkgConfig.version, {
includePrerelease: true,
})) {
throw new ForbiddenError(`"${fullname}@${pkgVersion}" not satisfies "${pkgConfig.version}" to unpkg files, see ${UNPKG_WHITE_LIST_URL}, white list version: ${__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListCurrentVersion, "f")}`);
}
}
// sync package readme based on latest version
async syncPackageReadme(pkg, latestPkgVersion) {
const dirname = `unpkg_${pkg.fullname.replace('/', '_')}@${latestPkgVersion.version}_latest_readme_${randomUUID()}`;
const tmpdir = await createTempDir(this.config.dataDir, dirname);
const tarFile = `${tmpdir}.tgz`;
const readmeFilenames = [];
try {
this.logger.info('[PackageVersionFileService.syncPackageReadme:download-start] dist:%s(path:%s, size:%s) => tarFile:%s', latestPkgVersion.tarDist.distId, latestPkgVersion.tarDist.path, latestPkgVersion.tarDist.size, tarFile);
await this.distRepository.downloadDistToFile(latestPkgVersion.tarDist, tarFile);
this.logger.info('[PackageVersionFileService.syncPackageReadme:extract-start] tmpdir:%s', tmpdir);
await tar.extract({
file: tarFile,
cwd: tmpdir,
strip: 1,
onentry: (entry) => {
const filename = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_formatTarEntryFilename).call(this, entry);
if (!filename)
return;
if (__classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_matchReadmeFilename).call(this, filename)) {
readmeFilenames.push(filename);
}
},
});
if (readmeFilenames.length > 0) {
const readmeFilename = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_preferMarkdownReadme).call(this, readmeFilenames);
const readmeFile = join(tmpdir, readmeFilename);
await this.packageManagerService.savePackageReadme(pkg, readmeFile);
}
}
catch (err) {
this.logger.warn('[PackageVersionFileService.syncPackageReadme:error] packageVersionId: %s, readmeFilenames: %j, tmpdir: %s, error: %s', latestPkgVersion.packageVersionId, readmeFilenames, tmpdir, err);
// ignore TAR_BAD_ARCHIVE error
if (err.code === 'TAR_BAD_ARCHIVE')
return;
throw err;
}
finally {
try {
await fs.rm(tarFile, { force: true });
await fs.rm(tmpdir, { recursive: true, force: true });
}
catch (err) {
this.logger.warn('[PackageVersionFileService.syncPackageReadme:warn] remove tmpdir: %s, error: %s', tmpdir, err);
}
}
}
async syncPackageVersionFiles(pkgVersion) {
const files = [];
// must set enableUnpkg and enableSyncUnpkgFiles = true both
if (!this.config.cnpmcore.enableUnpkg)
return files;
if (!this.config.cnpmcore.enableSyncUnpkgFiles)
return files;
const pkg = await this.packageRepository.findPackageByPackageId(pkgVersion.packageId);
if (!pkg)
return files;
// check unpkg white list
await this.checkPackageVersionInUnpkgWhiteList(pkg.scope, pkg.name, pkgVersion.version);
const dirname = `unpkg_${pkg.fullname.replace('/', '_')}@${pkgVersion.version}_${randomUUID()}`;
const tmpdir = await createTempDir(this.config.dataDir, dirname);
const tarFile = `${tmpdir}.tgz`;
const paths = [];
const readmeFilenames = [];
try {
this.logger.info('[PackageVersionFileService.syncPackageVersionFiles:download-start] dist:%s(path:%s, size:%s) => tarFile:%s', pkgVersion.tarDist.distId, pkgVersion.tarDist.path, pkgVersion.tarDist.size, tarFile);
await this.distRepository.downloadDistToFile(pkgVersion.tarDist, tarFile);
this.logger.info('[PackageVersionFileService.syncPackageVersionFiles:extract-start] tmpdir:%s', tmpdir);
await tar.extract({
file: tarFile,
cwd: tmpdir,
strip: 1,
onentry: (entry) => {
const filename = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_formatTarEntryFilename).call(this, entry);
if (!filename)
return;
paths.push(`/${filename}`);
if (__classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_matchReadmeFilename).call(this, filename)) {
readmeFilenames.push(filename);
}
},
});
for (const path of paths) {
const localFile = join(tmpdir, path);
const file = await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_savePackageVersionFile).call(this, pkg, pkgVersion, path, localFile);
files.push(file);
}
this.logger.info('[PackageVersionFileService.syncPackageVersionFiles:success] packageVersionId: %s, %d paths, %d files, tmpdir: %s', pkgVersion.packageVersionId, paths.length, files.length, tmpdir);
if (readmeFilenames.length > 0) {
const readmeFilename = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_preferMarkdownReadme).call(this, readmeFilenames);
const readmeFile = join(tmpdir, readmeFilename);
await this.packageManagerService.savePackageVersionReadme(pkgVersion, readmeFile);
}
return files;
}
catch (err) {
this.logger.warn('[PackageVersionFileService.syncPackageVersionFiles:error] packageVersionId: %s, %d paths, tmpdir: %s, error: %s', pkgVersion.packageVersionId, paths.length, tmpdir, err);
// ignore TAR_BAD_ARCHIVE error
if (err.code === 'TAR_BAD_ARCHIVE')
return files;
throw err;
}
finally {
try {
await fs.rm(tarFile, { force: true });
await fs.rm(tmpdir, { recursive: true, force: true });
}
catch (err) {
this.logger.warn('[PackageVersionFileService.syncPackageVersionFiles:warn] remove tmpdir: %s, error: %s', tmpdir, err);
}
}
}
};
_PackageVersionFileService_unpkgWhiteListCheckTime = new WeakMap();
_PackageVersionFileService_unpkgWhiteListCurrentVersion = new WeakMap();
_PackageVersionFileService_unpkgWhiteListAllowPackages = new WeakMap();
_PackageVersionFileService_unpkgWhiteListAllowScopes = new WeakMap();
_PackageVersionFileService_unpkgWhiteListAllowLargePackages = new WeakMap();
_PackageVersionFileService_unpkgWhiteListAllowLargeScopes = new WeakMap();
_PackageVersionFileService_unpkgWhiteListBlockSyncScopes = new WeakMap();
_PackageVersionFileService_unpkgWhiteListBlockSyncPackages = new WeakMap();
_PackageVersionFileService_instances = new WeakSet();
_PackageVersionFileService_ensurePackageVersionFilesSync = async function _PackageVersionFileService_ensurePackageVersionFilesSync(pkgVersion) {
const hasFiles = await this.packageVersionFileRepository.hasPackageVersionFiles(pkgVersion.packageVersionId);
if (!hasFiles) {
const lockName = `${pkgVersion.packageVersionId}:syncFiles`;
const lockRes = await this.cacheAdapter.usingLock(lockName, 60, async () => {
await this.syncPackageVersionFiles(pkgVersion);
});
// lock fail
if (!lockRes) {
this.logger.warn('[package:version:syncPackageVersionFiles] check lock:%s fail', lockName);
throw new ConflictError('Package version file sync is currently in progress. Please try again later.');
}
}
};
_PackageVersionFileService_updateUnpkgWhiteList = async function _PackageVersionFileService_updateUnpkgWhiteList() {
if (!this.config.cnpmcore.enableSyncUnpkgFilesWhiteList)
return;
if (Date.now() - __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListCheckTime, "f") <= CHECK_TIMEOUT) {
// check update every 60s
return;
}
__classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListCheckTime, Date.now(), "f");
const whiteListScope = '';
const whiteListPackageName = 'unpkg-white-list';
const whiteListPackageVersion = await this.packageVersionRepository.findVersionByTag(whiteListScope, whiteListPackageName, 'latest');
if (!whiteListPackageVersion)
return;
// same version, skip update for performance
if (__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListCurrentVersion, "f") === whiteListPackageVersion)
return;
// update the new version white list
const { manifest } = await this.packageManagerService.showPackageVersionManifest(whiteListScope, whiteListPackageName, whiteListPackageVersion, false, true);
if (!manifest)
return;
__classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListCurrentVersion, manifest.version, "f");
__classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListAllowPackages, manifest.allowPackages ?? {}, "f");
__classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListAllowScopes, manifest.allowScopes ?? [], "f");
__classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListAllowLargePackages, manifest.allowLargePackages ?? {}, "f");
__classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListAllowLargeScopes, manifest.allowLargeScopes ?? [], "f");
__classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListBlockSyncScopes, manifest.blockSyncScopes ?? [], "f");
__classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListBlockSyncPackages, manifest.blockSyncPackages ?? [], "f");
this.logger.info('[PackageVersionFileService.updateUnpkgWhiteList] version:%s, total %s packages, %s scopes, %s large packages, %s block sync scopes, %s block sync packages', whiteListPackageVersion, Object.keys(__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowPackages, "f")).length, __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowScopes, "f").length, Object.keys(__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowLargePackages, "f")).length, __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListBlockSyncScopes, "f").length, __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListBlockSyncPackages, "f").length);
};
_PackageVersionFileService_savePackageVersionFile = async function _PackageVersionFileService_savePackageVersionFile(pkg, pkgVersion, path, localFile) {
const { directory, name } = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_getDirectoryAndName).call(this, path);
let file = await this.packageVersionFileRepository.findPackageVersionFile(pkgVersion.packageVersionId, directory, name);
if (file)
return file;
const stat = await fs.stat(localFile);
const distIntegrity = await calculateIntegrity(localFile);
// make sure dist.path store to ascii, e.g. '/resource/ToOneFromχ.js' => '/resource/ToOneFrom%CF%87.js'
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
const distPath = encodeURI(path);
const dist = pkg.createPackageVersionFile(distPath, pkgVersion.version, {
size: stat.size,
shasum: distIntegrity.shasum,
integrity: distIntegrity.integrity,
});
await this.distRepository.saveDist(dist, localFile);
file = PackageVersionFile.create({
packageVersionId: pkgVersion.packageVersionId,
directory,
name,
dist,
contentType: mimeLookup(path),
mtime: pkgVersion.publishTime,
});
try {
await this.packageVersionFileRepository.createPackageVersionFile(file);
this.logger.info('[PackageVersionFileService.#savePackageVersionFile:success] fileId: %s, size: %s, path: %s', file.packageVersionFileId, dist.size, file.path);
}
catch (err) {
// ignore Duplicate entry
if (isDuplicateKeyError(err)) {
return file;
}
throw err;
}
return file;
};
_PackageVersionFileService_getDirectoryAndName = function _PackageVersionFileService_getDirectoryAndName(path) {
return {
directory: dirname(path),
name: basename(path),
};
};
_PackageVersionFileService_formatTarEntryFilename = function _PackageVersionFileService_formatTarEntryFilename(entry) {
if (entry.type !== 'File')
return;
// ignore hidden dir
if (entry.path.includes('/./'))
return;
// https://github.com/cnpm/cnpmcore/issues/452#issuecomment-1570077310
// strip first dir, e.g.: 'package/', 'lodash-es/'
const filename = entry.path.split('/').slice(1).join('/');
return filename;
};
_PackageVersionFileService_matchReadmeFilename = function _PackageVersionFileService_matchReadmeFilename(filename) {
// support README,README.*
// https://github.com/npm/read-package-json/blob/main/lib/read-json.js#L280
return /^README(\.\w{1,20}|$)/i.test(filename);
};
_PackageVersionFileService_preferMarkdownReadme = function _PackageVersionFileService_preferMarkdownReadme(files) {
let fallback = 0;
const markdownRE = /\.m?a?r?k?d?o?w?n?$/i;
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (markdownRE.test(file)) {
return file;
}
else if (file.toLowerCase() === 'README') {
fallback = i;
}
}
// prefer README.md, followed by README; otherwise, return
// the first filename (which could be README)
return files[fallback];
};
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageVersionFileService.prototype, "packageVersionRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageVersionFileService.prototype, "packageRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageVersionFileService.prototype, "packageVersionFileRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageVersionFileService.prototype, "distRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageVersionFileService.prototype, "packageManagerService", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageVersionFileService.prototype, "cacheAdapter", void 0);
PackageVersionFileService = __decorate([
SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
], PackageVersionFileService);
export { PackageVersionFileService };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFja2FnZVZlcnNpb25GaWxlU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2FwcC9jb3JlL3NlcnZpY2UvUGFja2FnZVZlcnNpb25GaWxlU2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xDLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVwRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxjQUFjLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFDMUQsT0FBTyxFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDM0QsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQzVCLE9BQU8sS0FBSyxHQUFHLE1BQU0sS0FBSyxDQUFDO0FBRTNCLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVsRSxPQUFPLEVBQUUsYUFBYSxFQUFFLFVBQVUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxXQUFXLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUs5RSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUd6RSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUdyRSxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRywwQ0FBMEMsQ0FBQztBQUMvRSxNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0FBSzVELElBQU0seUJBQXlC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