UNPKG

cnpmcore

Version:

Private NPM Registry for Enterprise

389 lines 40.9 kB
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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