UNPKG

cnpmcore

Version:
268 lines 24.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); 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 __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SavePackageVersionController = void 0; const lodash_1 = require("lodash"); const egg_errors_1 = require("egg-errors"); const tegg_1 = require("@eggjs/tegg"); const ssri = __importStar(require("ssri")); const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name")); const typebox_1 = require("@sinclair/typebox"); const AbstractController_1 = require("../AbstractController"); const PackageUtil_1 = require("../../../common/PackageUtil"); const PackageManagerService_1 = require("../../../core/service/PackageManagerService"); const typebox_2 = require("../../typebox"); const RegistryManagerService_1 = require("../../../core/service/RegistryManagerService"); const CacheAdapter_1 = require("../../../common/adapter/CacheAdapter"); const STRICT_CHECK_TARBALL_FIELDS = ['name', 'version', 'scripts', 'dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies', 'license', 'licenses', 'bin']; const FullPackageRule = typebox_1.Type.Object({ name: typebox_2.Name, // Since we don't validate versions & _attachments previous, here we use Type.Any() just for object validate versions: typebox_1.Type.Optional(typebox_1.Type.Any()), _attachments: typebox_1.Type.Optional(typebox_1.Type.Any()), description: typebox_1.Type.Optional(typebox_2.Description), 'dist-tags': typebox_1.Type.Optional(typebox_1.Type.Record(typebox_1.Type.String(), typebox_1.Type.String())), readme: typebox_1.Type.Optional(typebox_1.Type.String({ transform: ['trim'] })), }); // base64 regex https://stackoverflow.com/questions/475074/regex-to-parse-or-validate-base64-data/475217#475217 const PACKAGE_ATTACH_DATA_RE = /^[A-Za-z0-9+/]{4}/; let SavePackageVersionController = class SavePackageVersionController extends AbstractController_1.AbstractController { // https://github.com/cnpm/cnpmjs.org/blob/master/docs/registry-api.md#publish-a-new-package // https://github.com/npm/libnpmpublish/blob/main/publish.js#L43 async save(ctx, fullname, pkg) { this.validateNpmCommand(ctx); ctx.tValidate(FullPackageRule, pkg); const { user } = await this.ensurePublishAccess(ctx, fullname, false); fullname = fullname.trim(); if (fullname !== pkg.name) { throw new egg_errors_1.UnprocessableEntityError(`fullname(${fullname}) not match package.name(${pkg.name})`); } // Using https://github.com/npm/validate-npm-package-name to validate package name const validateResult = (0, validate_npm_package_name_1.default)(pkg.name); if (!validateResult.validForNewPackages) { // if pkg already exists, still allow to publish const [scope, name] = (0, PackageUtil_1.getScopeAndName)(fullname); const pkg = await this.packageRepository.findPackage(scope, name); if (!pkg) { const errors = (validateResult.errors || validateResult.warnings || []).join(', '); throw new egg_errors_1.UnprocessableEntityError(`package.name invalid, errors: ${errors}`); } } const versions = Object.values(pkg.versions); if (versions.length === 0) { throw new egg_errors_1.UnprocessableEntityError('versions is empty'); } // auth maintainter const attachments = pkg._attachments ?? {}; const attachmentFilename = Object.keys(attachments)[0]; if (!attachmentFilename) { // `deprecated: ''` meaning remove deprecated message const isDeprecatedRequest = versions.some(version => 'deprecated' in version); // handle deprecated request // PUT /:fullname?write=true // https://github.com/npm/cli/blob/latest/lib/commands/deprecate.js#L48 if (isDeprecatedRequest) { return await this.saveDeprecatedVersions(pkg.name, versions); } // invalid attachments throw new egg_errors_1.UnprocessableEntityError('_attachments is empty'); } // handle add new version const packageVersion = versions[0]; // check version format ctx.tValidate(typebox_2.VersionRule, packageVersion); const attachment = attachments[attachmentFilename]; const distTags = pkg['dist-tags'] ?? {}; let tagNames = Object.keys(distTags); if (tagNames.length === 0) { throw new egg_errors_1.UnprocessableEntityError('dist-tags is empty'); } const [scope, name] = (0, PackageUtil_1.getScopeAndName)(fullname); // see @https://github.com/cnpm/cnpmcore/issues/574 // add default latest tag if (!pkg['dist-tags'].latest) { const existsPkg = await this.packageRepository.findPackage(scope, name); const existsLatestTag = existsPkg && await this.packageRepository.findPackageTag(existsPkg?.packageId, 'latest'); if (!existsPkg || !existsLatestTag) { this.logger.warn('[package:version:add] add default latest tag'); pkg['dist-tags'].latest = pkg['dist-tags'][tagNames[0]]; tagNames = [...tagNames, 'latest']; } } const tagWithVersion = { tag: tagNames[0], version: distTags[tagNames[0]] }; ctx.tValidate(typebox_2.TagWithVersionRule, tagWithVersion); if (tagWithVersion.version !== packageVersion.version) { throw new egg_errors_1.UnprocessableEntityError(`dist-tags version "${tagWithVersion.version}" not match package version "${packageVersion.version}"`); } // check attachment data format and size if (!attachment.data || typeof attachment.data !== 'string') { throw new egg_errors_1.UnprocessableEntityError('attachment.data format invalid'); } if (!PACKAGE_ATTACH_DATA_RE.test(attachment.data)) { throw new egg_errors_1.UnprocessableEntityError('attachment.data string format invalid'); } const tarballBytes = Buffer.from(attachment.data, 'base64'); if (tarballBytes.length !== attachment.length) { throw new egg_errors_1.UnprocessableEntityError(`attachment size ${attachment.length} not match download size ${tarballBytes.length}`); } // check integrity or shasum const integrity = packageVersion.dist?.integrity; // for content security reason // check integrity if (integrity) { const algorithm = ssri.checkData(tarballBytes, integrity); if (!algorithm) { throw new egg_errors_1.UnprocessableEntityError('dist.integrity invalid'); } } else { const integrityObj = ssri.fromData(tarballBytes, { algorithms: ['sha1'], }); const shasum = integrityObj.sha1[0].hexDigest(); if (packageVersion.dist?.shasum && packageVersion.dist.shasum !== shasum) { // if integrity not exists, check shasum throw new egg_errors_1.UnprocessableEntityError('dist.shasum invalid'); } } // https://github.com/cnpm/cnpmcore/issues/542 // check tgz & manifests if (this.config.cnpmcore.strictValidateTarballPkg) { const tarballPkg = await (0, PackageUtil_1.extractPackageJSON)(tarballBytes); const versionManifest = pkg.versions[tarballPkg.version]; const diffKeys = STRICT_CHECK_TARBALL_FIELDS.filter(key => { const targetKey = key; return !(0, lodash_1.isEqual)(tarballPkg[key], versionManifest[targetKey]); }); if (diffKeys.length > 0) { throw new egg_errors_1.UnprocessableEntityError(`${diffKeys} mismatch between tarball and manifest`); } } // make sure readme is string const readme = typeof packageVersion.readme === 'string' ? packageVersion.readme : ''; // remove readme packageVersion.readme = undefined; // make sure description is string if (typeof packageVersion.description !== 'string') { packageVersion.description = ''; } const registry = await this.registryManagerService.ensureSelfRegistry(); let packageVersionEntity; const lockName = `${pkg.name}:publish`; const lockRes = await this.cacheAdapter.usingLock(`${pkg.name}:publish`, 60, async () => { packageVersionEntity = await this.packageManagerService.publish({ scope, name, version: packageVersion.version, description: packageVersion.description, packageJson: packageVersion, readme, dist: { content: tarballBytes, }, tags: tagNames, registryId: registry.registryId, isPrivate: true, }, user); }); // lock fail if (!lockRes) { this.logger.warn('[package:version:add] check lock:%s fail', lockName); throw new egg_errors_1.ConflictError('Unable to create the publication lock, please try again later.'); } this.logger.info('[package:version:add] %s@%s, packageVersionId: %s, tag: %s, userId: %s', packageVersion.name, packageVersion.version, packageVersionEntity?.packageVersionId, tagWithVersion.tag, user?.userId); ctx.status = 201; return { ok: true, rev: `${packageVersionEntity?.id}-${packageVersionEntity?.packageVersionId}`, }; } // https://github.com/cnpm/cnpmjs.org/issues/415 async saveDeprecatedVersions(fullname, versions) { const pkg = await this.getPackageEntityByFullname(fullname); await this.packageManagerService.saveDeprecatedVersions(pkg, versions.map(v => { return { version: v.version, deprecated: v.deprecated }; })); return { ok: true }; } validateNpmCommand(ctx) { // forbidden star/unstar request // npm@6: referer: 'star [REDACTED]' // npm@>=7: 'npm-command': 'star' let command = ctx.get('npm-command'); if (!command) { command = ctx.get('referer').split(' ', 1)[0]; } if (command === 'star' || command === 'unstar') { throw new egg_errors_1.ForbiddenError(`npm ${command} is not allowed`); } } }; exports.SavePackageVersionController = SavePackageVersionController; __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageManagerService_1.PackageManagerService) ], SavePackageVersionController.prototype, "packageManagerService", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", RegistryManagerService_1.RegistryManagerService) ], SavePackageVersionController.prototype, "registryManagerService", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", CacheAdapter_1.CacheAdapter) ], SavePackageVersionController.prototype, "cacheAdapter", void 0); __decorate([ (0, tegg_1.HTTPMethod)({ // PUT /:fullname // https://www.npmjs.com/package/path-to-regexp#custom-matching-parameters path: `/:fullname(${PackageUtil_1.FULLNAME_REG_STRING})`, method: tegg_1.HTTPMethodEnum.PUT, }), __param(0, (0, tegg_1.Context)()), __param(1, (0, tegg_1.HTTPParam)()), __param(2, (0, tegg_1.HTTPBody)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, String, Object]), __metadata("design:returntype", Promise) ], SavePackageVersionController.prototype, "save", null); exports.SavePackageVersionController = SavePackageVersionController = __decorate([ (0, tegg_1.HTTPController)() ], SavePackageVersionController); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2F2ZVBhY2thZ2VWZXJzaW9uQ29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2FwcC9wb3J0L2NvbnRyb2xsZXIvcGFja2FnZS9TYXZlUGFja2FnZVZlcnNpb25Db250cm9sbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQ0EsbUNBQWlDO0FBQ2pDLDJDQUlvQjtBQUNwQixzQ0FTcUI7QUFDckIsMkNBQTZCO0FBQzdCLDBGQUErRDtBQUMvRCwrQ0FBaUQ7QUFDakQsOERBQTJEO0FBQzNELDZEQUF1RztBQUN2Ryx1RkFBb0Y7QUFFcEYsMkNBS3VCO0FBQ3ZCLHlGQUFzRjtBQUV0Rix1RUFBb0U7QUFFcEUsTUFBTSwyQkFBMkIsR0FBMEIsQ0FBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxjQUFjLEVBQUUsaUJBQWlCLEVBQUUsa0JBQWtCLEVBQUUsc0JBQXNCLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxLQUFLLENBQUUsQ0FBQztBQWN6TSxNQUFNLGVBQWUsR0FBRyxjQUFJLENBQUMsTUFBTSxDQUFDO0lBQ2xDLElBQUksRUFBRSxjQUFRO0lBQ2QsNEdBQTRHO0lBQzVHLFFBQVEsRUFBRSxjQUFJLENBQUMsUUFBUSxDQUFDLGNBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUNuQyxZQUFZLEVBQUUsY0FBSSxDQUFDLFFBQVEsQ0FBQyxjQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDdkMsV0FBVyxFQUFFLGNBQUksQ0FBQyxRQUFRLENBQUMscUJBQWUsQ0FBQztJQUMzQyxXQUFXLEVBQUUsY0FBSSxDQUFDLFFBQVEsQ0FBQyxjQUFJLENBQUMsTUFBTSxDQUFDLGNBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxjQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUNyRSxNQUFNLEVBQUUsY0FBSSxDQUFDLFFBQVEsQ0FBQyxjQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsU0FBUyxFQUFFLENBQUUsTUFBTSxDQUFFLEVBQUUsQ0FBQyxDQUFDO0NBQzlELENBQUMsQ0FBQztBQVlILCtHQUErRztBQUMvRyxNQUFNLHNCQUFzQixHQUFHLG1CQUFtQixDQUFDO0FBRzVDLElBQU0sNEJBQTRCLEdBQWxDLE1BQU0sNEJBQTZCLFNBQVEsdUNBQWtCO0lBVWxFLDRGQUE0RjtJQUM1RixnRUFBZ0U7SUFPMUQsQUFBTixLQUFLLENBQUMsSUFBSSxDQUFZLEdBQWUsRUFBZSxRQUFnQixFQUFjLEdBQWdCO1FBQ2hHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM3QixHQUFHLENBQUMsU0FBUyxDQUFDLGVBQWUsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNwQyxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsbUJBQW1CLENBQUMsR0FBRyxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN0RSxRQUFRLEdBQUcsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzNCLElBQUksUUFBUSxLQUFLLEdBQUcsQ0FBQyxJQUFJLEVBQUU7WUFDekIsTUFBTSxJQUFJLHFDQUF3QixDQUFDLFlBQVksUUFBUSw0QkFBNEIsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7U0FDakc7UUFFRCxrRkFBa0Y7UUFDbEYsTUFBTSxjQUFjLEdBQUcsSUFBQSxtQ0FBc0IsRUFBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDeEQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxtQkFBbUIsRUFBRTtZQUN2QyxnREFBZ0Q7WUFDaEQsTUFBTSxDQUFFLEtBQUssRUFBRSxJQUFJLENBQUUsR0FBRyxJQUFBLDZCQUFlLEVBQUMsUUFBUSxDQUFDLENBQUM7WUFDbEQsTUFBTSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNsRSxJQUFJLENBQUMsR0FBRyxFQUFFO2dCQUNSLE1BQU0sTUFBTSxHQUFHLENBQUMsY0FBYyxDQUFDLE1BQU0sSUFBSSxjQUFjLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDbkYsTUFBTSxJQUFJLHFDQUF3QixDQUFDLGlDQUFpQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO2FBQy9FO1NBQ0Y7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM3QyxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQ3pCLE1BQU0sSUFBSSxxQ0FBd0IsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1NBQ3pEO1FBRUQsbUJBQW1CO1FBQ25CLE1BQU0sV0FBVyxHQUFHLEdBQUcsQ0FBQyxZQUFZLElBQUksRUFBRSxDQUFDO1FBQzNDLE1BQU0sa0JBQWtCLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUV2RCxJQUFJLENBQUMsa0JBQWtCLEVBQUU7WUFDdkIscURBQXFEO1lBQ3JELE1BQU0sbUJBQW1CLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLFlBQVksSUFBSSxPQUFPLENBQUMsQ0FBQztZQUM5RSw0QkFBNEI7WUFDNUIsNEJBQTRCO1lBQzVCLHVFQUF1RTtZQUN2RSxJQUFJLG1CQUFtQixFQUFFO2dCQUN2QixPQUFPLE1BQU0sSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7YUFDOUQ7WUFFRCxzQkFBc0I7WUFDdEIsTUFBTSxJQUFJLHFDQUF3QixDQUFDLHVCQUF1QixDQUFDLENBQUM7U0FDN0Q7UUFFRCx5QkFBeUI7UUFDekIsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25DLHVCQUF1QjtRQUN2QixHQUFHLENBQUMsU0FBUyxDQUFDLHFCQUFXLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFFM0MsTUFBTSxVQUFVLEdBQUcsV0FBVyxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDbkQsTUFBTSxRQUFRLEdBQUcsR0FBRyxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN4QyxJQUFJLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3JDLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7WUFDekIsTUFBTSxJQUFJLHFDQUF3QixDQUFDLG9CQUFvQixDQUFDLENBQUM7U0FDMUQ7UUFFRCxNQUFNLENBQUUsS0FBSyxFQUFFLElBQUksQ0FBRSxHQUFHLElBQUEsNkJBQWUsRUFBQyxRQUFRLENBQUMsQ0FBQztRQUNsRCxtREFBbUQ7UUFDbkQseUJBQXlCO1FBQ3pCLElBQUksQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFFLENBQUMsTUFBTSxFQUFFO1lBQzdCLE1BQU0sU0FBUyxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDeEUsTUFBTSxlQUFlLEdBQUcsU0FBUyxJQUFJLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLGNBQWMsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ2pILElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxlQUFlLEVBQUU7Z0JBQ2xDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLDhDQUE4QyxDQUFDLENBQUM7Z0JBQ2pFLEdBQUcsQ0FBQyxXQUFXLENBQUUsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDLFdBQVcsQ0FBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUMxRCxRQUFRLEdBQUcsQ0FBRSxHQUFHLFFBQVEsRUFBRSxRQUFRLENBQUUsQ0FBQzthQUN0QztTQUNGO1FBRUQsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM1RSxHQUFHLENBQUMsU0FBUyxDQUFDLDRCQUFrQixFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ2xELElBQUksY0FBYyxDQUFDLE9BQU8sS0FBSyxjQUFjLENBQUMsT0FBTyxFQUFFO1lBQ3JELE1BQU0sSUFBSSxxQ0FBd0IsQ0FBQyxzQkFBc0IsY0FBYyxDQUFDLE9BQU8sZ0NBQWdDLGNBQWMsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO1NBQzNJO1FBRUQsd0NBQXdDO1FBQ3hDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxJQUFJLE9BQU8sVUFBVSxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUU7WUFDM0QsTUFBTSxJQUFJLHFDQUF3QixDQUFDLGdDQUFnQyxDQUFDLENBQUM7U0FDdEU7UUFDRCxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUNqRCxNQUFNLElBQUkscUNBQXdCLENBQUMsdUNBQXVDLENBQUMsQ0FBQztTQUM3RTtRQUNELE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQztRQUM1RCxJQUFJLFlBQVksQ0FBQyxNQUFNLEtBQUssVUFBVSxDQUFDLE1BQU0sRUFBRTtZQUM3QyxNQUFNLElBQUkscUNBQXdCLENBQUMsbUJBQW1CLFVBQVUsQ0FBQyxNQUFNLDRCQUE0QixZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztTQUMzSDtRQUVELDRCQUE0QjtRQUM1QixNQUFNLFNBQVMsR0FBRyxjQUFjLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQztRQUNqRCw4QkFBOEI7UUFDOUIsa0JBQWtCO1FBQ2xCLElBQUksU0FBUyxFQUFFO1lBQ2IsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDMUQsSUFBSSxDQUFDLFNBQVMsRUFBRTtnQkFDZCxNQUFNLElBQUkscUNBQXdCLENBQUMsd0JBQXdCLENBQUMsQ0FBQzthQUM5RDtTQUNGO2FBQU07WUFDTCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksRUFBRTtnQkFDL0MsVUFBVSxFQUFFLENBQUUsTUFBTSxDQUFFO2FBQ3ZCLENBQUMsQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDaEQsSUFBSSxjQUFjLENBQUMsSUFBSSxFQUFFLE1BQU0sSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLE1BQU0sS0FBSyxNQUFNLEVBQUU7Z0JBQ3hFLHdDQUF3QztnQkFDeEMsTUFBTSxJQUFJLHFDQUF3QixDQUFDLHFCQUFxQixDQUFDLENBQUM7YUFDM0Q7U0FDRjtRQUVELDhDQUE4QztRQUM5Qyx3QkFBd0I7UUFDeEIsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyx3QkFBd0IsRUFBRTtZQUNqRCxNQUFNLFVBQVUsR0FBRyxNQUFNLElBQUEsZ0NBQWtCLEVBQUMsWUFBWSxDQUFDLENBQUM7WUFDMUQsTUFBTSxlQUFlLEdBQUcsR0FBRyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDekQsTUFBTSxRQUFRLEdBQUcsMkJBQTJCLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUN4RCxNQUFNLFNBQVMsR0FBRyxHQUE4QyxDQUFDO2dCQUNqRSxPQUFPLENBQUMsSUFBQSxnQkFBTyxFQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxlQUFlLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztZQUMvRCxDQUFDLENBQUMsQ0FBQztZQUNILElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7Z0JBQ3ZCLE1BQU0sSUFBSSxxQ0FBd0IsQ0FBQyxHQUFHLFFBQVEsd0NBQXdDLENBQUMsQ0FBQzthQUN6RjtTQUNGO1FBR0QsNkJBQTZCO1FBQzdCLE1BQU0sTUFBTSxHQUFHLE9BQU8sY0FBYyxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN0RixnQkFBZ0I7UUFDaEIsY0FBYyxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUM7UUFDbEMsa0NBQWtDO1FBQ2xDLElBQUksT0FBTyxjQUFjLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtZQUNsRCxjQUFjLENBQUMsV0FBVyxHQUFHLEVBQUUsQ0FBQztTQUNqQztRQUVELE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLHNCQUFzQixDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFFeEUsSUFBSSxvQkFBc0QsQ0FBQztRQUMzRCxNQUFNLFFBQVEsR0FBRyxHQUFHLEdBQUcsQ0FBQyxJQUFJLFVBQVUsQ0FBQztRQUN2QyxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLEdBQUcsR0FBRyxDQUFDLElBQUksVUFBVSxFQUFFLEVBQUUsRUFBRSxLQUFLLElBQUksRUFBRTtZQUN0RixvQkFBb0IsR0FBRyxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLENBQUM7Z0JBQzlELEtBQUs7Z0JBQ0wsSUFBSTtnQkFDSixPQUFPLEVBQUUsY0FBYyxDQUFDLE9BQU87Z0JBQy9CLFdBQVcsRUFBRSxjQUFjLENBQUMsV0FBcUI7Z0JBQ2pELFdBQVcsRUFBRSxjQUFpQztnQkFDOUMsTUFBTTtnQkFDTixJQUFJLEVBQUU7b0JBQ0osT0FBTyxFQUFFLFlBQVk7aUJBQ3RCO2dCQUNELElBQUksRUFBRSxRQUFRO2dCQUNkLFVBQVUsRUFBRSxRQUFRLENBQUMsVUFBVTtnQkFDL0IsU0FBUyxFQUFFLElBQUk7YUFDaEIsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNYLENBQUMsQ0FBQyxDQUFDO1FBRUgsWUFBWTtRQUNaLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDWixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQywwQ0FBMEMsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUN2RSxNQUFNLElBQUksMEJBQWEsQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1NBQzNGO1FBRUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0VBQXdFLEVBQ3ZGLGNBQWMsQ0FBQyxJQUFJLEVBQUUsY0FBYyxDQUFDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxnQkFBZ0IsRUFDbkYsY0FBYyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDcEMsR0FBRyxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUM7UUFDakIsT0FBTztZQUNMLEVBQUUsRUFBRSxJQUFJO1lBQ1IsR0FBRyxFQUFFLEdBQUcsb0JBQW9CLEVBQUUsRUFBRSxJQUFJLG9CQUFvQixFQUFFLGdCQUFnQixFQUFFO1NBQzdFLENBQUM7SUFDSixDQUFDO0lBRUQsZ0RBQWdEO0lBQ3hDLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxRQUFnQixFQUFFLFFBQTBCO1FBQy9FLE1BQU0sR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLDBCQUEwQixDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzVELE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLHNCQUFzQixDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFO1lBQzVFLE9BQU8sRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLFVBQVcsRUFBRSxDQUFDO1FBQzNELENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDSixPQUFPLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFTyxrQkFBa0IsQ0FBQyxHQUFlO1FBQ3hDLGdDQUFnQztRQUNoQyxvQ0FBb0M7UUFDcEMsaUNBQWlDO1FBQ2pDLElBQUksT0FBTyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDckMsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNaLE9BQU8sR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDL0M7UUFDRCxJQUFJLE9BQU8sS0FBSyxNQUFNLElBQUksT0FBTyxLQUFLLFFBQVEsRUFBRTtZQUM5QyxNQUFNLElBQUksMkJBQWMsQ0FBQyxPQUFPLE9BQU8saUJBQWlCLENBQUMsQ0FBQztTQUMzRDtJQUNILENBQUM7Q0FDRixDQUFBO0FBOU1ZLG9FQUE0QjtBQUV0QjtJQURoQixJQUFBLGFBQU0sR0FBRTs4QkFDK0IsNkNBQXFCOzJFQUFDO0FBRzdDO0lBRGhCLElBQUEsYUFBTSxHQUFFOzhCQUNnQywrQ0FBc0I7NEVBQUM7QUFHL0M7SUFEaEIsSUFBQSxhQUFNLEdBQUU7OEJBQ3NCLDJCQUFZO2tFQUFDO0FBVXRDO0lBTkwsSUFBQSxpQkFBVSxFQUFDO1FBQ1YsaUJBQWlCO1FBQ2pCLDBFQUEwRTtRQUMxRSxJQUFJLEVBQUUsY0FBYyxpQ0FBbUIsR0FBRztRQUMxQyxNQUFNLEVBQUUscUJBQWMsQ0FBQyxHQUFHO0tBQzNCLENBQUM7SUFDVSxXQUFBLElBQUEsY0FBTyxHQUFFLENBQUE7SUFBbUIsV0FBQSxJQUFBLGdCQUFTLEdBQUUsQ0FBQTtJQUFvQixXQUFBLElBQUEsZUFBUSxHQUFFLENBQUE7Ozs7d0RBcUtoRjt1Q0F2TFUsNEJBQTRCO0lBRHhDLElBQUEscUJBQWMsR0FBRTtHQUNKLDRCQUE0QixDQThNeEMifQ==