UNPKG

oss-client

Version:

Aliyun OSS(Object Storage Service) Node.js Client

898 lines 67 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OSSObject = void 0; const node_fs_1 = require("node:fs"); const node_assert_1 = require("node:assert"); const node_querystring_1 = __importDefault(require("node:querystring")); const promises_1 = __importDefault(require("node:fs/promises")); const mime_1 = __importDefault(require("mime")); const is_type_of_1 = require("is-type-of"); const OSSBaseClient_js_1 = require("./OSSBaseClient.js"); const index_js_1 = require("./util/index.js"); class OSSObject extends OSSBaseClient_js_1.OSSBaseClient { #bucket; #bucketEndpoint; constructor(options) { if (!options.cname) { node_assert_1.strict.ok(options.bucket, 'bucket required'); } if (options.bucket) { (0, index_js_1.checkBucketName)(options.bucket); } super(options); if (options.cname) { // ignore bucket on cname set to true this.#bucket = ''; this.#bucketEndpoint = this.options.endpoint; } else { this.#bucket = options.bucket ?? ''; const urlObject = new URL(this.options.endpoint); urlObject.hostname = `${this.#bucket}.${urlObject.hostname}`; this.#bucketEndpoint = urlObject.toString(); } } /** public methods */ /** * AppendObject * @see https://help.aliyun.com/zh/oss/developer-reference/appendobject */ async append(name, file, options) { const position = options?.position ?? '0'; const result = await this.#sendPutRequest(name, { ...options, subResource: { append: '', position: `${position}`, }, }, file, 'POST'); return { ...result, nextAppendPosition: result.res.headers['x-oss-next-append-position'], }; } /** * put an object from String(file path)/Buffer/Readable * @param {String} name the object key * @param {Mixed} file String(file path)/Buffer/Readable * @param {Object} options options * {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64 * {String} options.callback.url the OSS sends a callback request to this URL * {String} options.callback.host The host header value for initiating callback requests * {String} options.callback.body The value of the request body when a callback is initiated * {String} options.callback.contentType The Content-Type of the callback requests initiated * {Object} options.callback.customValue Custom parameters are a map of key-values, e.g: * customValue = { * key1: 'value1', * key2: 'value2' * } * @returns {Object} result */ async put(name, file, options) { if (typeof file === 'string' || (0, is_type_of_1.isReadable)(file) || Buffer.isBuffer(file)) { return await this.#sendPutRequest(name, options ?? {}, file); } throw new TypeError('Must provide String/Buffer/ReadableStream for put.'); } /** * put an object from ReadableStream. */ async putStream(name, stream, options) { return await this.#sendPutRequest(name, options ?? {}, stream); } async putMeta(name, meta, options) { return await this.copy(name, name, { meta, ...options, }); } /** * GetBucket (ListObjects) * @see https://help.aliyun.com/zh/oss/developer-reference/listobjects */ async list(query, options) { // prefix, marker, max-keys, delimiter const params = this.#objectRequestParams('GET', '', options); if (query) { params.query = query; } params.xmlResponse = true; params.successStatuses = [200]; const { data, res } = await this.request(params); let contents = data.Contents; let objects = []; if (contents) { if (!Array.isArray(contents)) { contents = [contents]; } objects = contents.map(obj => ({ name: obj.Key, url: this.#objectUrl(obj.Key), lastModified: obj.LastModified, etag: obj.ETag, type: obj.Type, size: Number(obj.Size), storageClass: obj.StorageClass, owner: { id: obj.Owner.ID, displayName: obj.Owner.DisplayName, }, })); } let commonPrefixes = data.CommonPrefixes; let prefixes = []; if (commonPrefixes) { if (!Array.isArray(commonPrefixes)) { commonPrefixes = [commonPrefixes]; } prefixes = commonPrefixes.map(item => item.Prefix); } return { res, objects, prefixes: prefixes || [], nextMarker: data.NextMarker || null, isTruncated: data.IsTruncated === 'true', }; } /** * ListObjectsV2(GetBucketV2) * @see https://help.aliyun.com/zh/oss/developer-reference/listobjectsv2 */ async listV2(query, options) { const params = this.#objectRequestParams('GET', '', options); params.query = { 'list-type': '2', }; const continuationToken = query?.['continuation-token'] ?? query?.continuationToken; if (continuationToken) { // should set subResource to add sign string params.subResource = { 'continuation-token': continuationToken, }; } if (query?.prefix) { params.query.prefix = query.prefix; } if (query?.delimiter) { params.query.delimiter = query.delimiter; } if (query?.['max-keys']) { params.query['max-keys'] = `${query['max-keys']}`; } if (query?.['start-after']) { params.query['start-after'] = query['start-after']; } if (query?.['encoding-type']) { params.query['encoding-type'] = query['encoding-type']; } if (query?.['fetch-owner']) { params.query['fetch-owner'] = 'true'; } params.xmlResponse = true; params.successStatuses = [200]; const { data, res } = await this.request(params); let contents = data.Contents; let objects = []; if (contents) { if (!Array.isArray(contents)) { contents = [contents]; } objects = contents.map(obj => ({ name: obj.Key, url: this.#objectUrl(obj.Key), lastModified: obj.LastModified, etag: obj.ETag, type: obj.Type, size: Number(obj.Size), storageClass: obj.StorageClass, owner: obj.Owner ? { id: obj.Owner.ID, displayName: obj.Owner.DisplayName, } : undefined, })); } let commonPrefixes = data.CommonPrefixes; let prefixes = []; if (commonPrefixes) { if (!Array.isArray(commonPrefixes)) { commonPrefixes = [commonPrefixes]; } prefixes = commonPrefixes.map(item => item.Prefix); } return { res, objects, prefixes, isTruncated: data.IsTruncated === 'true', keyCount: Number.parseInt(data.KeyCount), continuationToken: data.ContinuationToken, nextContinuationToken: data.NextContinuationToken, }; } async get(name, file, options) { let writeStream; let needDestroy = false; if ((0, is_type_of_1.isWritable)(file)) { writeStream = file; } else if (typeof file === 'string') { writeStream = (0, node_fs_1.createWriteStream)(file); needDestroy = true; } else { // get(name, options) options = file; } options = this.#formatGetOptions(options); let result; try { const params = this.#objectRequestParams('GET', name, options); params.writeStream = writeStream; params.successStatuses = [200, 206, 304]; result = await this.request(params); if (needDestroy && writeStream) { writeStream.destroy(); } } catch (err) { if (needDestroy && writeStream) { writeStream.destroy(); // should delete the exists file before throw error await promises_1.default.rm(file, { force: true }); } throw err; } return { res: result.res, content: result.data, }; } async getStream(name, options) { options = this.#formatGetOptions(options); const params = this.#objectRequestParams('GET', name, options); params.streaming = true; params.successStatuses = [200, 206, 304]; const { res } = await this.request(params); return { stream: res, res, }; } /** * PutObjectACL * @see https://help.aliyun.com/zh/oss/developer-reference/putobjectacl */ async putACL(name, acl, options) { options = options ?? {}; if (options.subres && !options.subResource) { options.subResource = options.subres; } if (!options.subResource) { options.subResource = {}; } options.subResource.acl = ''; if (options.versionId) { options.subResource.versionId = options.versionId; } options.headers = options.headers ?? {}; options.headers['x-oss-object-acl'] = acl; name = this.#objectName(name); const params = this.#objectRequestParams('PUT', name, options); params.successStatuses = [200]; const { res } = await this.request(params); return { res, }; } /** * GetObjectACL * @see https://help.aliyun.com/zh/oss/developer-reference/getobjectacl */ async getACL(name, options) { options = options ?? {}; if (options.subres && !options.subResource) { options.subResource = options.subres; delete options.subres; } if (!options.subResource) { options.subResource = {}; } options.subResource.acl = ''; if (options.versionId) { options.subResource.versionId = options.versionId; } name = this.#objectName(name); const params = this.#objectRequestParams('GET', name, options); params.successStatuses = [200]; params.xmlResponse = true; const { data, res } = await this.request(params); return { acl: data.AccessControlList.Grant, owner: { id: data.Owner.ID, displayName: data.Owner.DisplayName, }, res, }; } // /** // * Restore Object // * @param {String} name the object key // * @param {Object} options {type : Archive or ColdArchive} // * @return {{res}} result // */ // proto.restore = async function restore(name, options = { type: 'Archive' }) { // options = options || {}; // options.subres = Object.assign({ restore: '' }, options.subres); // if (options.versionId) { // options.subres.versionId = options.versionId; // } // const params = this._objectRequestParams('POST', name, options); // if (options.type === 'ColdArchive') { // const paramsXMLObj = { // RestoreRequest: { // Days: options.Days ? options.Days : 2, // JobParameters: { // Tier: options.JobParameters ? options.JobParameters : 'Standard', // }, // }, // }; // params.content = obj2xml(paramsXMLObj, { // headers: true, // }); // params.mime = 'xml'; // } // params.successStatuses = [ 202 ]; // const result = await this.request(params); // return { // res: result.res, // }; // }; /** * DeleteObject * @see https://help.aliyun.com/zh/oss/developer-reference/deleteobject */ async delete(name, options) { const requestOptions = { timeout: options?.timeout, subResource: {}, }; if (options?.versionId) { requestOptions.subResource.versionId = options.versionId; } const params = this.#objectRequestParams('DELETE', name, requestOptions); params.successStatuses = [204]; const { res } = await this.request(params); return { res, status: res.status, headers: res.headers, size: res.size, rt: res.rt, }; } /** * DeleteMultipleObjects * @see https://help.aliyun.com/zh/oss/developer-reference/deletemultipleobjects */ async deleteMulti(namesOrObjects, options) { const objects = []; node_assert_1.strict.ok(namesOrObjects.length > 0, 'namesOrObjects is empty'); for (const nameOrObject of namesOrObjects) { if (typeof nameOrObject === 'string') { objects.push({ Key: this.#objectName(nameOrObject) }); } else { node_assert_1.strict.ok(nameOrObject.key, 'key is empty'); objects.push({ Key: this.#objectName(nameOrObject.key), VersionId: nameOrObject.versionId, }); } } const xml = (0, index_js_1.json2xml)({ Delete: { Quiet: !!options?.quiet, Object: objects, }, }, { headers: true }); const requestOptions = { timeout: options?.timeout, // ?delete subResource: { delete: '' }, }; if (options?.versionId) { requestOptions.subResource.versionId = options.versionId; } const params = this.#objectRequestParams('POST', '', requestOptions); params.mime = 'xml'; params.content = Buffer.from(xml, 'utf8'); params.xmlResponse = true; params.successStatuses = [200]; const { data, res } = await this.request(params); // quiet will return null let deleted = data?.Deleted || []; if (deleted && !Array.isArray(deleted)) { deleted = [deleted]; } return { res, deleted, }; } /** * HeadObject * @see https://help.aliyun.com/zh/oss/developer-reference/headobject */ async head(name, options) { options = options ?? {}; if (options.subres && !options.subResource) { options.subResource = options.subres; } if (options.versionId) { if (!options.subResource) { options.subResource = {}; } options.subResource.versionId = options.versionId; } const params = this.#objectRequestParams('HEAD', name, options); params.successStatuses = [200, 304]; const { res } = await this.request(params); const meta = {}; const result = { meta, res, status: res.status, }; for (const k in res.headers) { if (k.startsWith('x-oss-meta-')) { const key = k.slice(11); meta[key] = res.headers[k]; } } return result; } /** * GetObjectMeta * @see https://help.aliyun.com/zh/oss/developer-reference/getobjectmeta */ async getObjectMeta(name, options) { options = options ?? {}; name = this.#objectName(name); if (options.subres && !options.subResource) { options.subResource = options.subres; } if (!options.subResource) { options.subResource = {}; } if (options.versionId) { options.subResource.versionId = options.versionId; } options.subResource.objectMeta = ''; const params = this.#objectRequestParams('HEAD', name, options); params.successStatuses = [200]; const { res } = await this.request(params); return { status: res.status, res, }; } /** * PutSymlink * @see https://help.aliyun.com/zh/oss/developer-reference/putsymlink */ async putSymlink(name, targetName, options) { options = options ?? {}; if (!options.subResource) { options.subResource = {}; } options.subResource.symlink = ''; if (options.versionId) { options.subResource.versionId = options.versionId; } options.headers = options.headers ?? {}; this.#convertMetaToHeaders(options.meta, options.headers); targetName = this.escape(this.#objectName(targetName)); options.headers['x-oss-symlink-target'] = targetName; if (options.storageClass) { options.headers['x-oss-storage-class'] = options.storageClass; } name = this.#objectName(name); const params = this.#objectRequestParams('PUT', name, options); params.successStatuses = [200]; const { res } = await this.request(params); return { res, }; } /** * GetSymlink * @see https://help.aliyun.com/zh/oss/developer-reference/getsymlink */ async getSymlink(name, options) { options = options ?? {}; if (!options.subResource) { options.subResource = {}; } options.subResource.symlink = ''; if (options.versionId) { options.subResource.versionId = options.versionId; } name = this.#objectName(name); const params = this.#objectRequestParams('GET', name, options); params.successStatuses = [200]; const { res } = await this.request(params); const target = res.headers['x-oss-symlink-target']; const meta = {}; for (const k in res.headers) { if (k.startsWith('x-oss-meta-')) { const key = k.slice(11); meta[key] = res.headers[k]; } } return { targetName: decodeURIComponent(target), res, meta, }; } /** * PutObjectTagging * @see https://help.aliyun.com/zh/oss/developer-reference/putobjecttagging */ async putObjectTagging(name, tag, options) { (0, index_js_1.checkObjectTag)(tag); options = options ?? {}; if (!options.subResource) { options.subResource = {}; } options.subResource.tagging = ''; if (options.versionId) { options.subResource.versionId = options.versionId; } name = this.#objectName(name); const params = this.#objectRequestParams('PUT', name, options); params.successStatuses = [200]; const tags = []; for (const key in tag) { tags.push({ Key: key, Value: tag[key] }); } const paramXMLObj = { Tagging: { TagSet: { Tag: tags, }, }, }; params.mime = 'xml'; params.content = Buffer.from((0, index_js_1.json2xml)(paramXMLObj)); const { res } = await this.request(params); return { res, status: res.status, }; } /** * GetObjectTagging * @see https://help.aliyun.com/zh/oss/developer-reference/getobjecttagging */ async getObjectTagging(name, options) { options = options ?? {}; if (!options.subResource) { options.subResource = {}; } options.subResource.tagging = ''; if (options.versionId) { options.subResource.versionId = options.versionId; } name = this.#objectName(name); const params = this.#objectRequestParams('GET', name, options); params.successStatuses = [200]; params.xmlResponse = true; const { res, data } = await this.request(params); // console.log(data.toString()); let tags = data.TagSet?.Tag; if (tags && !Array.isArray(tags)) { tags = [tags]; } const tag = {}; if (tags) { for (const item of tags) { tag[item.Key] = item.Value; } } return { status: res.status, res, tag, }; } /** * DeleteObjectTagging * @see https://help.aliyun.com/zh/oss/developer-reference/deleteobjecttagging */ async deleteObjectTagging(name, options) { options = options ?? {}; if (!options.subResource) { options.subResource = {}; } options.subResource.tagging = ''; if (options.versionId) { options.subResource.versionId = options.versionId; } name = this.#objectName(name); const params = this.#objectRequestParams('DELETE', name, options); params.successStatuses = [204]; const { res } = await this.request(params); return { status: res.status, res, }; } /** * signatureUrl URL签名 * @see https://help.aliyun.com/zh/oss/developer-reference/signed-urls */ signatureUrl(name, options) { options = options ?? {}; name = this.#objectName(name); options.method = options.method ?? 'GET'; const expires = options.expires ?? 1800; const expiresTimestamp = (0, index_js_1.timestamp)() + expires; const params = { bucket: this.#bucket, object: name, }; const resource = this.getResource(params); const signRes = (0, index_js_1.signatureForURL)(this.options.accessKeySecret, options, resource, expiresTimestamp); const url = this.getRequestURL({ object: name, subResource: { OSSAccessKeyId: this.options.accessKeyId, Expires: expiresTimestamp, Signature: signRes.Signature, ...signRes.subResource, }, }); return url; } async asyncSignatureUrl(name, options) { return this.signatureUrl(name, options); } /** * Get Object url by name * @param {string} name - object name * @param {string} [baseUrl] - If provide `baseUrl`, will use `baseUrl` instead the default `endpoint and bucket`. * @returns {string} object url include bucket */ generateObjectUrl(name, baseUrl) { const urlObject = new URL(baseUrl ?? this.getRequestEndpoint()); urlObject.pathname = this.escape(this.#objectName(name)); return urlObject.toString(); } /** * @alias generateObjectUrl */ getObjectUrl(name, baseUrl) { return this.generateObjectUrl(name, baseUrl); } /** * @param {object | string} policy specifies the validity of the fields in the request. * @returns {object} params.OSSAccessKeyId * params.Signature * params.policy JSON text encoded with UTF-8 and Base64. */ calculatePostSignature(policy) { if (typeof policy !== 'object' && typeof policy !== 'string') { throw new TypeError('policy must be JSON string or Object'); } const policyString = Buffer.from((0, index_js_1.policyToJSONString)(policy), 'utf8').toString('base64'); const Signature = (0, index_js_1.computeSignature)(this.options.accessKeySecret, policyString); return { OSSAccessKeyId: this.options.accessKeyId, Signature, policy: policyString, }; } async copy(name, sourceName, sourceBucket, options) { if (typeof sourceBucket === 'object') { options = sourceBucket; // 兼容旧版本,旧版本第三个参数为options sourceBucket = undefined; } options = options ?? {}; options.headers = options.headers ?? {}; let hasMetadata = !!options.meta; const REPLACE_HEADERS = new Set([ 'content-type', 'content-encoding', 'content-language', 'content-disposition', 'cache-control', 'expires', ]); for (const key in options.headers) { const lowerCaseKey = key.toLowerCase(); options.headers[`x-oss-copy-source-${lowerCaseKey}`] = options.headers[key]; if (REPLACE_HEADERS.has(lowerCaseKey)) { hasMetadata = true; } } if (hasMetadata) { options.headers['x-oss-metadata-directive'] = 'REPLACE'; } this.#convertMetaToHeaders(options.meta, options.headers); sourceName = this.#getCopySourceName(sourceName, sourceBucket); if (options.versionId) { sourceName = `${sourceName}?versionId=${options.versionId}`; } options.headers['x-oss-copy-source'] = sourceName; const params = this.#objectRequestParams('PUT', name, options); params.xmlResponse = true; params.successStatuses = [200, 304]; const { data, res } = await this.request(params); return { data: data ? { etag: data.ETag ?? '', lastModified: data.LastModified ?? '', } : null, res, }; } /** * 另存为 * @see https://help.aliyun.com/zh/oss/user-guide/sys-or-saveas */ async processObjectSave(sourceObject, targetObject, process, targetBucket) { targetObject = this.#objectName(targetObject); const params = this.#objectRequestParams('POST', sourceObject, { subResource: { 'x-oss-process': '', }, }); const bucketParam = targetBucket ? `,b_${Buffer.from(targetBucket).toString('base64')}` : ''; targetObject = Buffer.from(targetObject).toString('base64'); const content = { 'x-oss-process': `${process}|sys/saveas,o_${targetObject}${bucketParam}`, }; params.content = Buffer.from(node_querystring_1.default.stringify(content)); params.successStatuses = [200]; const result = await this.request(params); return { res: result.res, status: result.res.status, }; } /** protected methods */ getRequestEndpoint() { return this.#bucketEndpoint; } /** private methods */ #getCopySourceName(sourceName, bucketName) { if (typeof bucketName === 'string') { sourceName = this.#objectName(sourceName); // eslint-disable-next-line no-negated-condition } else if (sourceName[0] !== '/') { bucketName = this.#bucket; } else { bucketName = sourceName.replace(/\/(.+?)(\/.*)/, '$1'); sourceName = sourceName.replace(/(\/.+?\/)(.*)/, '$2'); } sourceName = encodeURIComponent(sourceName); if (bucketName) { (0, index_js_1.checkBucketName)(bucketName); sourceName = `/${bucketName}/${sourceName}`; } return sourceName; } async #sendPutRequest(name, options, fileOrBufferOrStream, method = 'PUT') { options.headers = options.headers ?? {}; if (options.headers['Content-Type'] && !options.headers['content-type']) { options.headers['content-type'] = options.headers['Content-Type']; delete options.headers['Content-Type']; } name = this.#objectName(name); this.#convertMetaToHeaders(options.meta, options.headers); // don't override exists headers if (options.callback && !options.headers['x-oss-callback']) { const callbackOptions = (0, index_js_1.encodeCallback)(options.callback); options.headers['x-oss-callback'] = callbackOptions.callback; if (callbackOptions.callbackVar) { options.headers['x-oss-callback-var'] = callbackOptions.callbackVar; } } const params = this.#objectRequestParams(method, name, options); if (typeof fileOrBufferOrStream === 'string') { const stats = await promises_1.default.stat(fileOrBufferOrStream); if (!stats.isFile()) { throw new TypeError(`${fileOrBufferOrStream} is not file`); } if (!options.mime) { const mimeFromFile = mime_1.default.getType(fileOrBufferOrStream); if (mimeFromFile) { options.mime = mimeFromFile; } } params.stream = (0, node_fs_1.createReadStream)(fileOrBufferOrStream); } else if (Buffer.isBuffer(fileOrBufferOrStream)) { params.content = fileOrBufferOrStream; } else { params.stream = fileOrBufferOrStream; } params.mime = options.mime; params.successStatuses = [200]; const { res, data } = await this.request(params); const putResult = { name, url: this.#objectUrl(name), res, data: {}, }; if (params.headers?.['x-oss-callback']) { putResult.data = JSON.parse(data.toString()); } return putResult; } #objectUrl(name) { return this.getRequestURL({ object: name }); } #formatGetOptions(options) { options = options ?? {}; // 兼容老的 subres 参数 if (options.subres && !options.subResource) { options.subResource = options.subres; } if (!options.subResource) { options.subResource = {}; } if (options.versionId) { options.subResource.versionId = options.versionId; } if (options.process) { options.subResource['x-oss-process'] = options.process; } return options; } /** * generator request params */ #objectRequestParams(method, name, options) { name = this.#objectName(name); const params = { object: name, bucket: this.#bucket, method, headers: options?.headers, subResource: options?.subResource, timeout: options?.timeout, }; return params; } #objectName(name) { return name.replace(/^\/+/, ''); } #convertMetaToHeaders(meta, headers) { if (!meta) { return; } for (const key in meta) { headers[`x-oss-meta-${key}`] = `${meta[key]}`; } } } exports.OSSObject = OSSObject; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT1NTT2JqZWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL09TU09iamVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSxxQ0FBOEQ7QUFDOUQsNkNBQStDO0FBQy9DLHdFQUEyQztBQUMzQyxnRUFBa0M7QUFFbEMsZ0RBQXdCO0FBQ3hCLDJDQUFvRDtBQXlCcEQseURBRzRCO0FBNkI1Qiw4Q0FTeUI7QUF5QnpCLE1BQWEsU0FBVSxTQUFRLGdDQUFhO0lBQzFDLE9BQU8sQ0FBUztJQUNoQixlQUFlLENBQVM7SUFFeEIsWUFBWSxPQUFtQztRQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ25CLG9CQUFNLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztRQUMvQyxDQUFDO1FBQ0QsSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbkIsSUFBQSwwQkFBZSxFQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNsQyxDQUFDO1FBQ0QsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbEIscUNBQXFDO1lBQ3JDLElBQUksQ0FBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2xCLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7UUFDL0MsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO1lBQ3BDLE1BQU0sU0FBUyxHQUFHLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDakQsU0FBUyxDQUFDLFFBQVEsR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLElBQUksU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFD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