filestack-js
Version:
Official JavaScript library for Filestack
766 lines (765 loc) • 101 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.S3Uploader = void 0;
var tslib_1 = require("tslib");
/*
* Copyright (c) 2019 by Filestack.
* Some rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var debug_1 = tslib_1.__importDefault(require("debug"));
var p_queue_1 = tslib_1.__importDefault(require("p-queue"));
var filestack_error_1 = require("./../../../../filestack_error");
var request_1 = require("./../../../request");
var helpers_1 = require("./../../../request/helpers");
var utils_1 = require("./../../../utils");
var abstract_1 = require("./abstract");
var debug = (0, debug_1.default)('fs:upload:s3');
var COMPLETE_TIMEOUT = 1000 * 1;
var S3Uploader = /** @class */ (function (_super) {
tslib_1.__extends(S3Uploader, _super);
function S3Uploader(storeOptions, concurrency) {
var _this = _super.call(this, storeOptions, concurrency) || this;
_this.payloads = {};
_this.partsQueue = new p_queue_1.default({
autoStart: false,
concurrency: _this.concurrency,
});
_this.cancelToken = new request_1.FsCancelToken();
return _this;
}
/**
* Pause upload queue
*
* @memberof S3Uploader
*/
S3Uploader.prototype.pause = function () {
this.partsQueue.pause();
};
/**
* resume upload queue if its paused
*
* @memberof S3Uploader
*/
S3Uploader.prototype.resume = function () {
/* istanbul ignore next */
if (this.partsQueue.isPaused) {
this.partsQueue.start();
}
};
/**
* Aborts queue (all pending requests with will be aborted)
*
* @memberof S3Uploader
*/
S3Uploader.prototype.abort = function (msg) {
this.partsQueue.pause();
this.partsQueue.clear();
this.cancelToken.cancel(msg || 'Aborted by user');
};
/**
* Execute all queued files
*
* @returns {Promise<any>}
* @memberof S3Uploader
*/
S3Uploader.prototype.execute = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var tasks;
var _this = this;
return tslib_1.__generator(this, function (_a) {
tasks = Object.keys(this.payloads).map(function (id) {
return new Promise(function (resolve) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var e_1, file;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 5, , 6]);
return [4 /*yield*/, this.startRequest(id)];
case 1:
_a.sent();
return [4 /*yield*/, this.prepareParts(id)];
case 2:
_a.sent();
return [4 /*yield*/, this.startPartsQueue(id)];
case 3:
_a.sent();
return [4 /*yield*/, this.completeRequest(id)];
case 4:
_a.sent();
return [3 /*break*/, 6];
case 5:
e_1 = _a.sent();
/* istanbul ignore next */
this.emit('error', e_1);
debug("[".concat(id, "] File upload failed. %O, \nDetails: %O "), e_1.message, e_1.details);
return [3 /*break*/, 6];
case 6:
file = this.getPayloadById(id).file;
// release file buffer
file.release();
// cleanup payloads
delete this.payloads[id];
resolve(file);
return [2 /*return*/];
}
});
}); });
});
return [2 /*return*/, Promise.all(tasks)];
});
});
};
/**
* Add file to upload queue
*
* @param {File} file
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.addFile = function (file) {
debug('Add file to queue: \n %o', file);
var id = "".concat((0, utils_1.uniqueId)(15), "_").concat((0, utils_1.uniqueTime)());
file.status = "Initialized" /* FileState.INIT */;
// split file into parts and set it as waiting
this.payloads[id] = {
file: file,
parts: [],
};
return id;
};
/**
* Returns host for upload (region based)
*
* @private
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.getUploadUrl = function (id) {
var location_url = this.getDefaultFields(id, ['location_url']).location_url;
return location_url.indexOf('http') === 0 ? location_url : "https://".concat(location_url);
};
/**
* Returns formatted store options
*
* @private
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.getStoreOptions = function (id) {
var options = tslib_1.__assign({ location: abstract_1.DEFAULT_STORE_LOCATION }, this.storeOptions);
if (this.storeOptions.disableStorageKey) {
var payload = this.getPayloadById(id);
if (options.path && options.path.substr(-1) !== '/') {
options.path = "".concat(options.path, "/");
}
options.path = "".concat(options.path ? options.path : '/').concat(payload.file.name);
delete options.disableStorageKey;
}
return options;
};
/**
* Returns all default fields for filestack requests
*
* @private
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.getDefaultFields = function (id, requiredFields, fiiFallback) {
if (fiiFallback === void 0) { fiiFallback = false; }
var payload = this.getPayloadById(id);
var fields = tslib_1.__assign(tslib_1.__assign({}, this.security), { apikey: this.apikey, uri: payload.uri, location_url: payload.location_url, upload_id: payload.upload_id, region: payload.region, alt: payload.file.alt });
if (this.uploadMode === "intelligent" /* UploadMode.INTELLIGENT */ || (this.uploadMode === "fallback" /* UploadMode.FALLBACK */ && fiiFallback)) {
fields['fii'] = true;
}
return tslib_1.__assign(tslib_1.__assign({}, (0, utils_1.filterObject)(fields, requiredFields)), { store: this.getStoreOptions(id) });
};
/**
* Returns default headers needed for filestack request
*
* @private
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.getDefaultHeaders = function (id) {
var headers = {};
var file = this.getPayloadById(id);
if (file.location_region) {
headers['Filestack-Upload-Region'] = file.location_region;
}
return headers;
};
S3Uploader.prototype.getPayloadById = function (id) {
return this.payloads[id];
};
/**
* Split file onto parts for uploading with multipart mechanism and setup start
*
* @private
* @memberof S3Uploader
*/
S3Uploader.prototype.prepareParts = function (id) {
var file = this.getPayloadById(id).file;
var intelligentChunk = false;
// for intelligent or fallback mode we cant overwrite part size - requires 8MB
if (["intelligent" /* UploadMode.INTELLIGENT */, "fallback" /* UploadMode.FALLBACK */].indexOf(this.uploadMode) > -1) {
this.partSize = abstract_1.INTELLIGENT_CHUNK_SIZE;
intelligentChunk = true;
}
var _a = file.getPartsCount(this.partSize, intelligentChunk), partsCount = _a.partsCount, chunkSize = _a.chunkSize;
var parts = [];
for (var i = 0; i < partsCount; i++) {
parts[i] = tslib_1.__assign(tslib_1.__assign({}, file.getPartMetadata(i, chunkSize)), { offset: 0 });
}
// split file into parts and set it as waiting
this.payloads[id].parts = parts;
return Promise.resolve();
};
/**
* Make start request for getting needed upload fields
*
* @private
* @returns {Promise<any>}
* @memberof S3Uploader
*/
S3Uploader.prototype.startRequest = function (id) {
var _this = this;
var payload = this.getPayloadById(id);
if (payload.file.size === 0) {
this.setPayloadStatus(id, "Failed" /* FileState.FAILED */);
return Promise.reject(new filestack_error_1.FilestackError("Invalid file \"".concat(payload.file.name, "\" size - 0"), {}, filestack_error_1.FilestackErrorType.VALIDATION));
}
debug("[".concat(id, "] Make start request"));
return request_1.FsRequest.post("".concat(this.getUrl(), "/multipart/start"), tslib_1.__assign({ filename: payload.file.name, mimetype: payload.file.type, size: payload.file.size }, this.getDefaultFields(id, ['apikey', 'policy', 'signature', 'fii'], true)), {
timeout: this.timeout,
cancelToken: this.cancelToken,
headers: this.getDefaultHeaders(id),
retry: this.retryConfig,
})
.then(function (_a) {
var data = _a.data;
if (!data || !data.location_url || !data.region || !data.upload_id || !data.uri) {
debug("[".concat(id, "] Incorrect start response: \n%O\n"), data);
_this.setPayloadStatus(id, "Failed" /* FileState.FAILED */);
return Promise.reject(new filestack_error_1.FilestackError('Incorrect start response', data, filestack_error_1.FilestackErrorType.REQUEST));
}
debug("[".concat(id, "] Assign payload data: \n%O\n"), data);
_this.updatePayload(id, data);
// ii is not enabled in backend switch back to default upload mode
if (["intelligent" /* UploadMode.INTELLIGENT */, "fallback" /* UploadMode.FALLBACK */].indexOf(_this.uploadMode) > -1 && (!data.upload_type || data.upload_type !== 'intelligent_ingestion')) {
debug("[".concat(id, "] Intelligent Ingestion is not enabled on account, switch back to regular upload and lock mode change"));
_this.setUploadMode("default" /* UploadMode.DEFAULT */, true);
}
return data;
})
.catch(function (err) {
debug("[".concat(id, "] Start request error %O"), err);
_this.setPayloadStatus(id, "Failed" /* FileState.FAILED */);
return _this.rejectUpload('Cannot upload file. Start request failed', err);
});
};
/**
* Enqueue file parts to upload
*
* @private
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.startPartsQueue = function (id) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var payload, parts, waitingLength;
var _this = this;
return tslib_1.__generator(this, function (_a) {
payload = this.getPayloadById(id);
parts = payload.parts;
waitingLength = parts.length;
debug("[".concat(id, "] Create uploading queue from file. parts count - %d"), waitingLength);
return [2 /*return*/, new Promise(function (resolve, reject) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var _a;
var _this = this;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
parts.forEach(function (part) {
return _this.partsQueue
.add(function () { return _this.startPart(id, part.partNumber); })
.catch(function (e) {
_this.setPayloadStatus(id, "Failed" /* FileState.FAILED */);
debug("[".concat(id, "] Failed to upload part %s"), e.message);
_this.partsQueue.pause();
_this.partsQueue.clear();
return reject(e);
});
});
debug("[".concat(id, "] All tasks for %s enqueued. Start processing main upload queue"), id);
this.emit('start');
this.partsQueue.start();
_a = resolve;
return [4 /*yield*/, this.partsQueue.onIdle()];
case 1:
_a.apply(void 0, [_b.sent()]);
return [2 /*return*/];
}
});
}); })];
});
});
};
/**
* Decide if upload should be made using ii or regular upload
* It allows change upload mode during upload queue
*
* @private
* @param {number} partNumber
* @returns {Promise<any>}
* @memberof S3Uploader
*/
S3Uploader.prototype.startPart = function (id, partNumber) {
debug("[".concat(id, "] Start processing part ").concat(partNumber, " with mode ").concat(this.uploadMode));
var payload = this.getPayloadById(id);
payload.file.status = "Progress" /* FileState.PROGRESS */;
return (this.uploadMode !== "intelligent" /* UploadMode.INTELLIGENT */ ? this.uploadRegular : this.uploadIntelligent).apply(this, [id, partNumber]);
};
/**
* Returns part data needed for upload
*
* @private
* @param {string} id - id of a currently uploading file
* @param {FilePart} part
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.getS3PartMetadata = function (id, part, offset) {
var _this = this;
var url = this.getUploadUrl(id);
debug("[".concat(id, "] Get data for part ").concat(part.partNumber, ", url ").concat(url, ", Md5: ").concat(part.md5, ", Size: ").concat(part.size));
var data = tslib_1.__assign(tslib_1.__assign({}, this.getDefaultFields(id, ['apikey', 'uri', 'region', 'signature', 'policy', 'upload_id', 'fii'])), {
// method specific keys
part: part.partNumber + 1, size: part.size, offset: offset });
if (this.integrityCheck && part.md5) {
data.md5 = part.md5;
}
return request_1.FsRequest.post("".concat(url, "/multipart/upload"), data, {
headers: this.getDefaultHeaders(id),
cancelToken: this.cancelToken,
timeout: this.timeout,
retry: this.retryConfig,
}).catch(function (err) {
_this.setPayloadStatus(id, "Failed" /* FileState.FAILED */);
return _this.rejectUpload('Cannot get part metadata', err);
});
};
/**
* Regular multipart request to amazon
*
* @private
* @param {number} partNumber
* @returns {Promise<any>}
* @memberof S3Uploader
*/
S3Uploader.prototype.uploadRegular = function (id, partNumber) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var payload, partMetadata, part, _a, data, headers;
var _this = this;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
payload = this.getPayloadById(id);
partMetadata = payload.parts[partNumber];
return [4 /*yield*/, payload.file.getPartByMetadata(partMetadata, this.integrityCheck)];
case 1:
part = _b.sent();
return [4 /*yield*/, this.getS3PartMetadata(id, part)];
case 2:
_a = _b.sent(), data = _a.data, headers = _a.headers;
debug("[".concat(id, "] Received part ").concat(partNumber, " info body: \n%O\n headers: \n%O\n"), data, headers);
return [2 /*return*/, request_1.FsRequest.put(data.url, part.buffer, {
cancelToken: this.cancelToken,
timeout: this.timeout,
headers: data.headers,
filestackHeaders: false,
// for now we cant test progress callback from upload
/* istanbul ignore next */
onProgress: function (pr) { return _this.onProgressUpdate(id, partNumber, pr.loaded); },
retry: this.retryConfig && this.uploadMode !== "fallback" /* UploadMode.FALLBACK */ ? this.retryConfig : undefined,
})
.then(function (res) {
if (res.headers.etag) {
_this.setPartETag(id, partNumber, res.headers.etag);
}
else {
// release memory
part = null;
throw new filestack_error_1.FilestackError('Cannot upload file, check S3 bucket settings', 'Etag header is not exposed in CORS settings', filestack_error_1.FilestackErrorType.REQUEST);
}
debug("[".concat(id, "] S3 Upload response headers for ").concat(partNumber, ": \n%O\n"), res.headers);
_this.onProgressUpdate(id, partNumber, part.size);
// release memory
part = null;
return res;
})
.catch(function (err) {
var resp = err && err.response ? err.response : null;
/* istanbul ignore next */
if (resp && resp.status === 403) {
if (resp.data && resp.data.Error && resp.data.Error.code) {
var code = resp.data.Error.code;
if (Array.isArray(code)) {
code = code.pop();
}
switch (code) {
case 'RequestTimeTooSkewed':
return _this.startPart(id, partNumber);
default:
return Promise.reject(new filestack_error_1.FilestackError('Cannot upload file', resp.data.Error, filestack_error_1.FilestackErrorType.REQUEST));
}
}
}
// release memory
part = null;
if (err instanceof filestack_error_1.FilestackError) {
return Promise.reject(err);
}
// reset upload progress on failed part
_this.onProgressUpdate(id, partNumber, 0);
// if fallback, set upload mode to intelligent and restart current part
if ((_this.uploadMode === "fallback" /* UploadMode.FALLBACK */ && !_this.isModeLocked) || _this.uploadMode === "intelligent" /* UploadMode.INTELLIGENT */) {
debug("[".concat(id, "] Regular upload failed. Switching to intelligent ingestion mode"));
_this.setUploadMode("intelligent" /* UploadMode.INTELLIGENT */);
// restart part
return _this.startPart(id, partNumber);
}
return _this.rejectUpload('Cannot upload file part', err);
})];
}
});
});
};
/**
* Upload file using intelligent mechanism
*
* @private
* @param {string} id
* @param {number} partNumber
* @returns {Promise<any>}
* @memberof S3Uploader
*/
S3Uploader.prototype.uploadIntelligent = function (id, partNumber) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, this.uploadNextChunk(id, partNumber).then(function () { return _this.commitPart(id, partNumber); })];
});
});
};
/**
* Recursively upload file in chunk mode (intelligent ingession)
*
* @private
* @param {string} id
* @param {number} partNumber
* @param {number} chunkSize
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.uploadNextChunk = function (id, partNumber, chunkSize) {
if (chunkSize === void 0) { chunkSize = this.intelligentChunkSize; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var payload, part, chunk, data;
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
payload = this.getPayloadById(id);
part = payload.parts[partNumber];
chunkSize = part.size - part.offset;
return [4 /*yield*/, payload.file.getChunkByMetadata(part, part.offset, chunkSize, this.integrityCheck)];
case 1:
chunk = _a.sent();
debug("[".concat(id, "] PartNum: ").concat(partNumber, ", PartSize: ").concat(part.size, ", StartByte: ").concat(part.startByte, ", Offset: ").concat(part.offset, ", ChunkSize: ").concat(chunk.size, ",\n Left: ").concat(part.size - part.offset - chunk.size));
return [4 /*yield*/, this.getS3PartMetadata(id, chunk, part.offset).catch(function (err) {
debug("[".concat(id, "] Getting chunk data for ii failed %O, Chunk size: ").concat(chunkSize, ", offset ").concat(part.offset, ", part ").concat(partNumber), err);
return Promise.reject(err);
})];
case 2:
data = (_a.sent()).data;
return [2 /*return*/, request_1.FsRequest.put(data.url, chunk.buffer, {
cancelToken: this.cancelToken,
timeout: this.timeout,
headers: data.headers,
filestackHeaders: false,
// for now we cant test progress callback from upload
/* istanbul ignore next */
onProgress: function (pr) { return part ? _this.onProgressUpdate(id, partNumber, part.offset + pr.loaded) : null; },
})
.then(function (res) {
_this.onProgressUpdate(id, partNumber, part.offset + chunk.size);
var newOffset = Math.min(part.offset + chunkSize, part.size);
debug("[".concat(id, "] S3 Chunk uploaded! offset: ").concat(part.offset, ", part ").concat(partNumber, "! response headers for ").concat(partNumber, ": \n%O\n"), res.headers);
_this.setPartData(id, partNumber, 'offset', newOffset);
// if all chunks was uploaded then return resolve
if (newOffset === part.size) {
return Promise.resolve(res);
}
// release memory
part = null;
chunk = null;
return _this.uploadNextChunk(id, partNumber, chunkSize);
})
.catch(function (err) {
var resp = err && err.response ? err.response : null;
/* istanbul ignore next */
if (resp && resp.status === 403) {
if (resp.data && resp.data.Error && resp.data.Error.code) {
var code = resp.data.Error.code;
if (Array.isArray(code)) {
code = code.pop();
}
switch (code) {
case 'RequestTimeTooSkewed':
return _this.startPart(id, partNumber);
default:
return Promise.reject(new filestack_error_1.FilestackError('Cannot upload file', resp.data.Error, filestack_error_1.FilestackErrorType.REQUEST));
}
}
}
// reset progress on failed upload
_this.onProgressUpdate(id, partNumber, part.offset);
var nextChunkSize = Math.ceil(chunkSize / 2);
if (nextChunkSize < abstract_1.MIN_CHUNK_SIZE) {
debug("[".concat(id, "] Minimal chunk size limit. Upload file failed!"));
return Promise.reject(new filestack_error_1.FilestackError('Min chunk size reached', err.data, filestack_error_1.FilestackErrorType.REQUEST));
}
if ((0, helpers_1.shouldRetry)(err)) {
debug("[".concat(id, "] Request network error. Retry with new chunk size: ").concat(nextChunkSize));
return _this.uploadNextChunk(id, partNumber, nextChunkSize);
}
// release memory
part = null;
chunk = null;
return _this.rejectUpload('Cannot upload file part (FII)', err);
})];
}
});
});
};
/**
* Commit after upload all chunks of the part in ii mode
*
* @private
* @param {string} id
* @param {FilePart} part
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.commitPart = function (id, partNumber) {
var _this = this;
var payload = this.getPayloadById(id);
var part = payload.parts[partNumber];
return request_1.FsRequest.post("".concat(this.getUploadUrl(id), "/multipart/commit"), tslib_1.__assign(tslib_1.__assign({}, this.getDefaultFields(id, ['apikey', 'region', 'upload_id', 'policy', 'signature', 'uri'])), { size: payload.file.size, part: part.partNumber + 1 }), {
cancelToken: this.cancelToken,
timeout: this.timeout,
headers: this.getDefaultHeaders(id),
retry: this.retryConfig,
})
.then(function (res) {
debug("[".concat(id, "] Commit Part number ").concat(part.partNumber, ". Response: %O"), res.data);
return res;
})
.catch(function (err) {
return _this.rejectUpload('Cannot commit file part metadata', err);
});
};
/**
* Complete request to merge all parts and get file handle etc
*
* @private
* @returns
* @memberof S3Uploader
*/
S3Uploader.prototype.completeRequest = function (id) {
var _this = this;
var payload = this.getPayloadById(id);
var parts = [];
debug("[".concat(id, "] Run complete request"));
var partsHandle = payload.parts;
var partLen = partsHandle.length;
for (var i = 0; i < partLen; i++) {
if (partsHandle[i].etag) {
parts.push({ part_number: i + 1, etag: partsHandle[i].etag });
}
}
debug("[".concat(id, "] Etags %O"), parts);
return request_1.FsRequest.post("".concat(this.getUploadUrl(id), "/multipart/complete"), tslib_1.__assign(tslib_1.__assign({}, this.getDefaultFields(id, ['apikey', 'policy', 'signature', 'uri', 'region', 'upload_id', 'fii', 'alt'], true)), {
// method specific keys
filename: payload.file.name, mimetype: payload.file.type, size: payload.file.size, upload_tags: this.uploadTags && Object.keys(this.uploadTags).length ? this.uploadTags : undefined, parts: parts.length ? parts : undefined }), {
timeout: this.timeout,
cancelToken: this.cancelToken,
headers: this.getDefaultHeaders(id),
retry: this.retryConfig,
})
.then(function (res) {
// if parts hasnt been merged, retry complete request again
if (res.status === 202) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
return _this.completeRequest(id)
.then(resolve)
.catch(reject);
}, COMPLETE_TIMEOUT);
});
}
// update file object
var file = _this.getPayloadById(id).file;
file.handle = res.data.handle;
file.url = res.data.url;
file.container = res.data.container;
file.key = res.data.key;
file.uploadTags = res.data.upload_tags;
file.workflows = res.data.workflows;
file.status = res.data.status;
return file;
})
.catch(function (err) {
_this.setPayloadStatus(id, "Failed" /* FileState.FAILED */);
return _this.rejectUpload('Cannot complete file', err);
});
};
/**
* UUpgrade upload progress and run progress event
*
* @private
* @param {string} id
* @param {number} partNumber
* @param {number} loaded
* @memberof S3Uploader
*/
S3Uploader.prototype.onProgressUpdate = function (id, partNumber, loaded) {
this.setPartData(id, partNumber, 'progress', loaded);
this.emitProgress();
};
/**
* Emits normalized progress event
*
* @private
* @memberof S3Uploader
*/
S3Uploader.prototype.emitProgress = function () {
var totalSize = 0;
var totalBytes = 0;
var filesProgress = {};
for (var i in this.payloads) {
var payload = this.payloads[i];
// omit all failed files in progress event
// this shouldn't happend because of promises rejection in execute. Left to be sure
/* istanbul ignore next */
if (payload.file.status === "Failed" /* FileState.FAILED */) {
continue;
}
var totalParts = payload.parts.map(function (p) { return p.progress || 0; }).reduce(function (a, b) { return a + b; }, 0);
totalBytes = totalBytes + totalParts;
filesProgress[i] = {
totalBytes: totalParts,
totalPercent: Math.round((totalParts * 100) / payload.file.size) || 0,
};
totalSize = totalSize + payload.file.size;
}
var res = {
totalBytes: totalBytes || 0,
totalPercent: Math.round((totalBytes * 100) / totalSize) || 0,
files: filesProgress,
};
debug("Upload progress %O", res);
this.emit('progress', res);
};
/**
* Apply provided data to given payload
*
* @private
* @param {string} id
* @param {*} data
* @memberof S3Uploader
*/
S3Uploader.prototype.updatePayload = function (id, data) {
this.payloads[id] = tslib_1.__assign(tslib_1.__assign({}, this.payloads[id]), data);
};
/**
* Sets etag for part
*
* @private
* @param {number} partNumber
* @param {string} etag
* @memberof S3Uploader
*/
S3Uploader.prototype.setPartETag = function (id, partNumber, etag) {
debug("[".concat(id, "] Set ").concat(etag, " etag for part ").concat(partNumber));
this.getPayloadById(id).parts[partNumber].etag = etag;
};
/**
* Sets part value for a key
*
* @private
* @param {number} partNumber
* @param {string} etag
* @memberof S3Uploader
*/
S3Uploader.prototype.setPartData = function (id, partNumber, key, value) {
debug("[".concat(id, "] Set ").concat(key, " = ").concat(value, " for part ").concat(partNumber));
var payload = this.getPayloadById(id);
/* istanbul ignore next */
if (!payload) {
debug("[".concat(id, "] Cannot set ").concat(key, " = ").concat(value, " for part ").concat(partNumber));
return;
}
payload.parts[partNumber][key] = value;
};
/**
* Set payload file state
*
* @param id
* @param status
*/
S3Uploader.prototype.setPayloadStatus = function (id, status) {
debug("[".concat(id, "] Set payload status to ").concat(status));
/* istanbul ignore next: additional check in case if file will be deleted before setting status */
if (!this.payloads[id]) {
return;
}
this.payloads[id].file.status = status;
};
/**
* Returns error details if response exists
*
* @param err
*/
S3Uploader.prototype.parseError = function (err) {
if (!err.response) {
return {};
}
return {
code: err.response.status,
data: err.response.data,
headers: err.response.headers,
};
};
S3Uploader.prototype.rejectUpload = function (message, err) {
if (err instanceof request_1.FsRequestError && err.code === request_1.FsRequestErrorCode.ABORTED) {
return Promise.reject(new filestack_error_1.FilestackError(message, { reason: err.message }, filestack_error_1.FilestackErrorType.ABORTED));
}
return Promise.reject(new filestack_error_1.FilestackError(message, this.parseError(err), filestack_error_1.FilestackErrorType.REQUEST));
};
return S3Uploader;
}(abstract_1.UploaderAbstract));
exports.S3Uploader = S3Uploader;
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvYXBpL3VwbG9hZC91cGxvYWRlcnMvczMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILHdEQUEwQjtBQUMxQiw0REFBNkI7QUFFN0IsaUVBQW1GO0FBQ25GLDhDQUE4RztBQUM5RyxzREFBeUQ7QUFDekQsMENBQXNFO0FBR3RFLHVDQUEwSDtBQUUxSCxJQUFNLEtBQUssR0FBRyxJQUFBLGVBQUssRUFBQyxjQUFjLENBQUMsQ0FBQztBQUVwQyxJQUFNLGdCQUFnQixHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7QUFtQmxDO0lBQWdDLHNDQUFnQjtJQU05QyxvQkFBWSxZQUFnQyxFQUFFLFdBQVk7UUFBMUQsWUFDRSxrQkFBTSxZQUFZLEVBQUUsV0FBVyxDQUFDLFNBUWpDO1FBWE8sY0FBUSxHQUFxQyxFQUFFLENBQUM7UUFLdEQsS0FBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLGlCQUFNLENBQUM7WUFDM0IsU0FBUyxFQUFFLEtBQUs7WUFDaEIsV0FBVyxFQUFFLEtBQUksQ0FBQyxXQUFXO1NBQzlCLENBQUMsQ0FBQztRQUVILEtBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSx1QkFBYSxFQUFFLENBQUM7O0lBQ3pDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksMEJBQUssR0FBWjtRQUNFLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSwyQkFBTSxHQUFiO1FBQ0UsMEJBQTBCO1FBQzFCLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUU7WUFDNUIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztTQUN6QjtJQUNILENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksMEJBQUssR0FBWixVQUFhLEdBQVk7UUFDdkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRXhCLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxpQkFBaUIsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRDs7Ozs7T0FLRztJQUNVLDRCQUFPLEdBQXBCOzs7OztnQkFDUSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsR0FBRyxDQUMxQyxVQUFBLEVBQUU7b0JBQ0EsT0FBQSxJQUFJLE9BQU8sQ0FBQyxVQUFNLE9BQU87Ozs7OztvQ0FFckIscUJBQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsRUFBQTs7b0NBQTNCLFNBQTJCLENBQUM7b0NBQzVCLHFCQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLEVBQUE7O29DQUEzQixTQUEyQixDQUFDO29DQUM1QixxQkFBTSxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxFQUFBOztvQ0FBOUIsU0FBOEIsQ0FBQztvQ0FDL0IscUJBQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsRUFBQTs7b0NBQTlCLFNBQThCLENBQUM7Ozs7b0NBRS9CLDBCQUEwQjtvQ0FDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBQyxDQUFDLENBQUM7b0NBQ3RCLEtBQUssQ0FBQyxXQUFJLEVBQUUsNkNBQTBDLEVBQUUsR0FBQyxDQUFDLE9BQU8sRUFBRSxHQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7OztvQ0FHMUUsSUFBSSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDO29DQUUxQyxzQkFBc0I7b0NBQ3RCLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQ0FFZixtQkFBbUI7b0NBQ25CLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQztvQ0FFekIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDOzs7O3lCQUNmLENBQUM7Z0JBckJGLENBcUJFLENBQ0wsQ0FBQztnQkFFRixzQkFBTyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFDOzs7S0FDM0I7SUFFRDs7Ozs7O09BTUc7SUFDSSw0QkFBTyxHQUFkLFVBQWUsSUFBVTtRQUN2QixLQUFLLENBQUMsMEJBQTBCLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFeEMsSUFBTSxFQUFFLEdBQUcsVUFBRyxJQUFBLGdCQUFRLEVBQUMsRUFBRSxDQUFDLGNBQUksSUFBQSxrQkFBVSxHQUFFLENBQUUsQ0FBQztRQUU3QyxJQUFJLENBQUMsTUFBTSxxQ0FBaUIsQ0FBQztRQUU3Qiw4Q0FBOEM7UUFDOUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsR0FBRztZQUNsQixJQUFJLE1BQUE7WUFDSixLQUFLLEVBQUUsRUFBRTtTQUNWLENBQUM7UUFFRixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSyxpQ0FBWSxHQUFwQixVQUFxQixFQUFVO1FBQ3JCLElBQUEsWUFBWSxHQUFLLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLENBQUMsQ0FBQyxhQUFoRCxDQUFpRDtRQUNyRSxPQUFPLFlBQVksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLGtCQUFXLFlBQVksQ0FBRSxDQUFDO0lBQ3ZGLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSyxvQ0FBZSxHQUF2QixVQUF3QixFQUFVO1FBQ2hDLElBQUksT0FBTyxzQkFDVCxRQUFRLEVBQUUsaUNBQXNCLElBQzdCLElBQUksQ0FBQyxZQUFZLENBQ3JCLENBQUM7UUFFRixJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsaUJBQWlCLEVBQUU7WUFDdkMsSUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUV4QyxJQUFJLE9BQU8sQ0FBQyxJQUFJLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLEVBQUU7Z0JBQ25ELE9BQU8sQ0FBQyxJQUFJLEdBQUcsVUFBRyxPQUFPLENBQUMsSUFBSSxNQUFHLENBQUM7YUFDbkM7WUFFRCxPQUFPLENBQUMsSUFBSSxHQUFHLFVBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxTQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFFLENBQUM7WUFFMUUsT0FBTyxPQUFPLENBQUMsaUJBQWlCLENBQUM7U0FDbEM7UUFFRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0sscUNBQWdCLEdBQXhCLFVBQXlCLEVBQVUsRUFBRSxjQUF3QixFQUFFLFdBQTRCO1FBQTVCLDRCQUFBLEVBQUEsbUJBQTRCO1FBQ3pGLElBQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFeEMsSUFBSSxNQUFNLHlDQUNMLElBQUksQ0FBQyxRQUFRLEtBQ2hCLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxFQUNuQixHQUFHLEVBQUUsT0FBTyxDQUFDLEdBQUcsRUFDaEIsWUFBWSxFQUFFLE9BQU8sQ0FBQyxZQUFZLEVBQ2xDLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUyxFQUM1QixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sRUFDdEIsR0FBRyxFQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUN0QixDQUFDO1FBRUYsSUFBSSxJQUFJLENBQUMsVUFBVSwrQ0FBMkIsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLHlDQUF3QixJQUFJLFdBQVcsQ0FBQyxFQUFFO1lBQzFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUM7U0FDdEI7UUFFRCw2Q0FDSyxJQUFBLG9CQUFZLEVBQUMsTUFBTSxFQUFFLGNBQWMsQ0FBQyxLQUN2QyxLQUFLLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsSUFDL0I7SUFDSixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssc0NBQWlCLEdBQXpCLFVBQTBCLEVBQVU7UUFDbEMsSUFBSSxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2pCLElBQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFckMsSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQ3hCLE9BQU8sQ0FBQyx5QkFBeUIsQ0FBQyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUM7U0FDM0Q7UUFFRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRU8sbUNBQWMsR0FBdEIsVUFBdUIsRUFBVTtRQUMvQixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssaUNBQVksR0FBcEIsVUFBcUIsRUFBVTtRQUM3QixJQUFNLElBQUksR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUMxQyxJQUFJLGdCQUFnQixHQUFHLEtBQUssQ0FBQztRQUU3Qiw4RUFBOEU7UUFDOUUsSUFBSSxrRkFBNkMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFO1lBQy9FLElBQUksQ0FBQyxRQUFRLEdBQUcsaUNBQXNCLENBQUM7WUFDdkMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDO1NBQ3pCO1FBRUssSUFBQSxLQUE0QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsZ0JBQWdCLENBQUMsRUFBN0UsVUFBVSxnQkFBQSxFQUFFLFNBQVMsZUFBd0QsQ0FBQztRQUV0RixJQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7UUFFakIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFVBQVUsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUNuQyxLQUFLLENBQUMsQ0FBQyxDQUFDLHlDQUNILElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxLQUNyQyxNQUFNLEVBQUUsQ0FBQyxHQUNWLENBQUM7U0FDSDtRQUVELDhDQUE4QztRQUM5QyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFFaEMsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLGlDQUFZLEdBQXBCLFVBQXFCLEVBQVU7UUFBL0IsaUJBaURDO1FBaERDLElBQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFeEMsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxDQUFDLEVBQUU7WUFDM0IsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsa0NBQW1CLENBQUM7WUFDNUMsT0FBTyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksZ0NBQWMsQ0FBQyx5QkFBaUIsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLGdCQUFZLEVBQUUsRUFBRSxFQUFFLG9DQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7U0FDOUg7UUFFRCxLQUFLLENBQUMsV0FBSSxFQUFFLHlCQUFzQixDQUFDLENBQUM7UUFDcEMsT0FBTyxtQkFBUyxDQUFDLElBQUksQ0FDbkIsVUFBRyxJQUFJLENBQUMsTUFBTSxFQUFFLHFCQUFrQixxQkFFaEMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUMzQixRQUFRLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQzNCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksSUFDcEIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLEtBQUssQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUU5RTtZQUNFLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDN0IsT0FBTyxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLENBQUM7WUFDbkMsS0FBSyxFQUFFLElBQUksQ0FBQyxXQUFXO1NBQ3hCLENBQ0Y7YUFDRSxJQUFJLENBQUMsVUFBQyxFQUFRO2dCQUFOLElBQUksVUFBQTtZQUNYLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO2dCQUMvRSxLQUFLLENBQUMsV0FBSSxFQUFFLHVDQUFvQyxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUN4RCxLQUFJLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxrQ0FBbUIsQ0FBQztnQkFDNUMsT0FBTyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksZ0NBQWMsQ0FBQywwQkFBMEIsRUFBRSxJQUFJLEVBQUUsb0NBQWtCLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQzthQUN6RztZQUVELEtBQUssQ0FBQyxXQUFJLEVBQUUsa0NBQStCLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFFbkQsS0FBSSxDQUFDLGFBQWEsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFFN0Isa0VBQWtFO1lBQ2xFLElBQUksa0ZBQTZDLENBQUMsT0FBTyxDQUFDLEtBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLHVCQUF1QixDQUFDLEVBQUU7Z0JBQ3RKLEtBQUssQ0FBQyxXQUFJLEVBQUUsMEdBQXVHLENBQUMsQ0FBQztnQkFDckgsS0FBSSxDQUFDLGFBQWEscUNBQXFCLElBQUksQ0FBQyxDQUFDO2FBQzlDO1lBRUQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDLENBQUM7YUFDRCxLQUFLLENBQUMsVUFBQSxHQUFHO1lBQ1IsS0FBSyxDQUFDLFdBQUksRUFBRSw2QkFBMEIsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUM3QyxLQUFJLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxrQ0FBbUIsQ0FBQztZQUU1QyxPQUFPLEtBQUksQ0FBQyxZQUFZLENBQUMsMENBQTBDLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDNUUsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ1csb0NBQWUsR0FBN0IsVUFBOEIsRUFBVTs7Ozs7Z0JBQ2hDLE9BQU8sR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNsQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztnQkFDdEIsYUFBYSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUM7Z0JBRW5DLEtBQUssQ0FBQyxXQUFJLEVBQUUseURBQXNELEVBQUUsYUFBYSxDQUFDLENBQUM7Z0JBRW5GLHNCQUFPLElBQUksT0FBTyxDQUFDLFVBQU8sT0FBTyxFQUFFLE1BQU07Ozs7OztvQ0FDdkMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxVQUFBLElBQUk7d0NBQ2hCLE9BQUEsS0FBSSxDQUFDLFVBQVU7NkNBQ1osR0FBRyxDQUFDLGNBQU0sT0FBQSxLQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQW5DLENBQW1DLENBQUM7NkNBQzlDLEtBQUssQ0FBQyxVQUFBLENBQUM7NENBQ04sS0FBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsa0NBQW1CLENBQUM7NENBQzVDLEtBQUssQ0FBQyxXQUFJLEVBQUUsK0JBQTRCLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDOzRDQUVyRCxLQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDOzRDQUN4QixLQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDOzRDQUN4QixPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQzt3Q0FDbkIsQ0FBQyxDQUFDO29DQVRKLENBU0ksQ0FDTCxDQUFDO29DQUVGLEtBQUssQ0FBQyxXQUFJLEVBQUUsb0VBQWlFLEVBQUUsRUFBRSxDQUFDLENBQUM7b0NBQ25GLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7b0NBQ25CLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7b0NBRXhCLEtBQUEsT0FBTyxDQUFBO29DQUFDLHFCQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLEVBQUE7O29DQUF0QyxrQkFBUSxTQUE4QixFQUFDLENBQUM7Ozs7eUJBQ3pDLENBQUMsRUFBQzs7O0tBQ0o7SUFFRDs7Ozs7Ozs7T0FRRztJQUNLLDhCQUFTLEdBQWpCLFVBQWtCLEVBQVUsRUFBRSxVQUFrQjtRQUM5QyxLQUFLLENBQUMsV0FBSSxFQUFFLHFDQUEyQixVQUFVLHdCQUFjLElBQUksQ0FBQyxVQUFVLENBQUUsQ0FBQyxDQUFDO1FBRWxGLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFdEMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLHNDQUFxQixDQUFDO1FBQ3pDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSwrQ0FBMkIsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ2xJLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNLLHNDQUFpQixHQUF6QixVQUEwQixFQUFVLEVBQUUsSUFBYyxFQUFFLE1BQWU7UUFBckUsaUJBMkJDO1FBMUJDLElBQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFbEMsS0FBSyxDQUFDLFdBQUksRUFBRSxpQ0FBdUIsSUFBSSxDQUFDLFVBQVUsbUJBQVMsR0FBRyxvQkFBVSxJQUFJLENBQUMsR0FBRyxxQkFBVyxJQUFJLENBQUMsSUFBSSxDQUFFLENBQUMsQ0FBQztRQUV4RyxJQUFNLElBQUkseUNBQ0wsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxDQUFDLFFBQVEsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3BHLHVCQUF1QjtZQUN2QixJQUFJLEVBQUUsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLEVBQ3pCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUNmLE1BQU0sUUFBQSxHQUNQLENBQUM7UUFFRixJQUFJLElBQUksQ0FBQyxjQUFjLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRTtZQUNuQyxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUM7U0FDckI7UUFFRCxPQUFPLG1CQUFTLENBQUMsSUFBSSxDQUFDLFVBQUcsR0FBRyxzQkFBbUIsRUFBRSxJQUFJLEVBQUU7WUFDckQsT0FBTyxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLENBQUM7WUFDbkMsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQzdCLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixLQUFLLEVBQUUsSUFBSSxDQUFDLFdBQVc7U0FDeEIsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFBLEdBQUc7WUFDVixLQUFJLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxrQ0FBbUIsQ0FBQztZQUU1QyxPQUFPLEtBQUksQ0FBQyxZQUFZLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDNUQsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNXLGtDQUFhLEdBQTNCLFVBQTRCLEVBQVUsRUFBRSxVQUFrQjs7Ozs7Ozt3QkFDcEQsT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7d0JBQ2hDLFlBQVksR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO3dCQUNwQyxxQkFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUE7O3dCQUE5RSxJQUFJLEdBQUcsU0FBdUU7d0JBRXhELHFCQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUE7O3dCQUExRCxLQUFvQixTQUFzQyxFQUF4RCxJQUFJLFVBQUEsRUFBRSxPQUFPLGFBQUE7d0JBQ3JCLEtBQUssQ0FBQyxXQUFJLEVBQUUsNkJBQW1CLFVBQVUsdUNBQW9DLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO3dCQUM5RixzQkFBTyxtQkFBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUU7Z0NBQzFDLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVztnQ0FDN0IsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO2dDQUNyQixPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87Z0NBQ3JCLGdCQUFnQixFQUFFLEtBQUs7Z0NBQ3ZCLHFEQUFxRDtnQ0FDckQsMEJBQTBCO2dDQUMxQixVQUFVLEVBQUUsVUFBQyxFQUFpQixJQUFLLE9BQUEsS0FBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxVQUFVLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFoRCxDQUFnRDtnQ0FDbkYsS0FBSyxFQUFFLElBQUksQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLFVBQVUseUNBQXdCLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLFNBQVM7NkJBQ2xHLENBQUM7aUNBQ0QsSUFBSSxDQUFDLFVBQUEsR0FBRztnQ0FDUCxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFO29DQUNwQixLQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxVQUFVLEVBQUUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztpQ0FDcEQ7cUNBQU07b0NBQ0wsaUJBQWlCO29DQUNqQixJQUFJLEdBQUcsSUFBSSxDQUFDO29DQUNaLE1BQU0sSUFBSSxnQ0FBYyxDQUFDLDhDQUE4QyxFQUFFLDZDQUE2QyxFQUFFLG9DQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO2lDQUNySjtnQ0FFRCxLQUFLLENBQUMsV0FBSSxFQUFFLDhDQUFvQyxVQUFVL