UNPKG

ngx-image-upload

Version:
672 lines (659 loc) 84.1 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/common/http'), require('@angular/core'), require('@angular/common')) : typeof define === 'function' && define.amd ? define('ngx-image-upload', ['exports', '@angular/common/http', '@angular/core', '@angular/common'], factory) : (factory((global['ngx-image-upload'] = {}),global.ng.common.http,global.ng.core,global.ng.common)); }(this, (function (exports,i1,i0,common) { 'use strict'; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var NgxImageUploadService = (function () { function NgxImageUploadService(http) { this.http = http; } /** * @param {?} url * @param {?} image * @param {?=} headers * @param {?=} partName * @param {?=} customFormData * @param {?=} withCredentials * @return {?} */ NgxImageUploadService.prototype.postImage = /** * @param {?} url * @param {?} image * @param {?=} headers * @param {?=} partName * @param {?=} customFormData * @param {?=} withCredentials * @return {?} */ function (url, image, headers, partName, customFormData, withCredentials) { if (partName === void 0) { partName = 'image'; } if (!url || url === '') { throw new Error('请设置url参数'); } // add custom form data var /** @type {?} */ formData = new FormData(); for (var /** @type {?} */ key in customFormData) { formData.append(key, customFormData[key]); } formData.append(partName, image); return this.http.post(url, formData, { headers: headers, withCredentials: withCredentials }); }; NgxImageUploadService.decorators = [ { type: i0.Injectable, args: [{ providedIn: 'root' },] }, ]; /** @nocollapse */ NgxImageUploadService.ctorParameters = function () { return [ { type: i1.HttpClient } ]; }; /** @nocollapse */ NgxImageUploadService.ngInjectableDef = i0.defineInjectable({ factory: function NgxImageUploadService_Factory() { return new NgxImageUploadService(i0.inject(i1.HttpClient)); }, token: NgxImageUploadService, providedIn: "root" }); return NgxImageUploadService; }()); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All 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 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ function __awaiter(thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function () { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var FileHolder = (function () { function FileHolder(src, file) { this.src = src; this.file = file; this.pending = false; } return FileHolder; }()); var NgxImageUploadComponent = (function () { function NgxImageUploadComponent(imageService) { var _this = this; this.imageService = imageService; this.files = []; this.fileCounter = 0; this.fileOver = false; this.showFileTooLargeMessage = false; this.beforeUpload = function (data) { return data; }; this.buttonCaption = '添加图片'; this.disabled = false; this.cssClass = 'img-ul'; this.clearButtonCaption = '清除'; this.dropBoxMessage = '拖拽图片到此处'; this.max = 100; this.preview = true; this.withCredentials = false; this.uploadedFiles = []; this.removed = new i0.EventEmitter(); this.uploadStateChanged = new i0.EventEmitter(); this.uploadFinished = new i0.EventEmitter(); this.previewClicked = new i0.EventEmitter(); this.pendingFilesCounter = 0; this.onFileOver = function (isOver) { return _this.fileOver = isOver; }; this.countRemainingSlots = function () { return _this.max - _this.fileCounter; }; } /** * @return {?} */ NgxImageUploadComponent.prototype.ngOnInit = /** * @return {?} */ function () { if (!this.fileTooLargeMessage) { this.fileTooLargeMessage = '图片太大无法上传.' + (this.maxFileSize ? (' 最大允许 ' + this.maxFileSize / 1024) + 'KiB.' : ''); } this.supportedExtensions = this.supportedExtensions ? this.supportedExtensions.map(function (ext) { return 'image/' + ext; }) : ['image/*']; }; /** * @return {?} */ NgxImageUploadComponent.prototype.deleteAll = /** * @return {?} */ function () { var _this = this; this.files.forEach(function (f) { return _this.removed.emit(f); }); this.files = []; this.fileCounter = 0; if (this.inputElement) { this.inputElement.nativeElement.value = ''; } }; /** * @param {?} file * @return {?} */ NgxImageUploadComponent.prototype.deleteFile = /** * @param {?} file * @return {?} */ function (file) { var /** @type {?} */ index = this.files.indexOf(file); this.files.splice(index, 1); this.fileCounter--; if (this.inputElement) { this.inputElement.nativeElement.value = ''; } this.removed.emit(file); }; /** * @param {?} file * @return {?} */ NgxImageUploadComponent.prototype.previewFileClicked = /** * @param {?} file * @return {?} */ function (file) { this.previewClicked.emit(file); }; /** * @param {?} changes * @return {?} */ NgxImageUploadComponent.prototype.ngOnChanges = /** * @param {?} changes * @return {?} */ function (changes) { if (changes.uploadedFiles && changes.uploadedFiles.currentValue && changes.uploadedFiles.currentValue.length > 0) { this.processUploadedFiles(); } }; /** * @param {?} files * @return {?} */ NgxImageUploadComponent.prototype.onFileChange = /** * @param {?} files * @return {?} */ function (files) { if (this.disabled) return; // let remainingSlots = 0; var /** @type {?} */ remainingSlots = this.countRemainingSlots(); var /** @type {?} */ filesToUploadNum = files.length > remainingSlots ? remainingSlots : files.length; if (this.url && filesToUploadNum != 0) { this.uploadStateChanged.emit(true); } this.fileCounter += filesToUploadNum; this.showFileTooLargeMessage = false; this.uploadFiles(files, filesToUploadNum); }; /** * @param {?} response * @param {?} fileHolder * @return {?} */ NgxImageUploadComponent.prototype.onResponse = /** * @param {?} response * @param {?} fileHolder * @return {?} */ function (response, fileHolder) { fileHolder.serverResponse = { status: response.status, response: response }; fileHolder.pending = false; this.uploadFinished.emit(fileHolder); if (--this.pendingFilesCounter == 0) { this.uploadStateChanged.emit(false); } }; /** * @return {?} */ NgxImageUploadComponent.prototype.processUploadedFiles = /** * @return {?} */ function () { if (typeof this.uploadedFiles === 'string') { var /** @type {?} */ data = this.uploadedFiles; this.fileCounter = 1; this.max = 1; var /** @type {?} */ fileBlob = void 0, /** @type {?} */ file = void 0, /** @type {?} */ fileUrl = void 0; if (data instanceof Object) { fileUrl = data.url; fileBlob = (data.blob) ? data.blob : new Blob([data]); file = new File([fileBlob], data.fileName); } else { fileUrl = data; fileBlob = new Blob([fileUrl]); file = new File([fileBlob], fileUrl); } this.files = []; this.files.push(new FileHolder(fileUrl, file)); } else { this.max = this.max - Object.keys(this.uploadedFiles).length; for (var /** @type {?} */ i in this.uploadedFiles) { var /** @type {?} */ data = this.uploadedFiles[i]; var /** @type {?} */ fileBlob = void 0, /** @type {?} */ file = void 0, /** @type {?} */ fileUrl = void 0; if (data instanceof Object) { fileUrl = data.url; fileBlob = (data.blob) ? data.blob : new Blob([data]); file = new File([fileBlob], data.fileName); } else { fileUrl = data; fileBlob = new Blob([fileUrl]); file = new File([fileBlob], fileUrl); } this.files.push(new FileHolder(fileUrl, file)); } } }; /** * @param {?} files * @param {?} filesToUploadNum * @return {?} */ NgxImageUploadComponent.prototype.uploadFiles = /** * @param {?} files * @param {?} filesToUploadNum * @return {?} */ function (files, filesToUploadNum) { return __awaiter(this, void 0, void 0, function () { var _this = this; var _loop_1, this_1, i; return __generator(this, function (_a) { switch (_a.label) { case 0: _loop_1 = function (i) { var file, beforeUploadResult, img, reader; return __generator(this, function (_a) { switch (_a.label) { case 0: file = files[i]; if (this_1.maxFileSize && file.size > this_1.maxFileSize) { this_1.fileCounter--; this_1.inputElement.nativeElement.value = ''; this_1.showFileTooLargeMessage = true; return [2 /*return*/, "continue"]; } return [4 /*yield*/, this_1.beforeUpload({ file: file, url: this_1.url, abort: false })]; case 1: beforeUploadResult = _a.sent(); if (beforeUploadResult.abort) { this_1.fileCounter--; this_1.inputElement.nativeElement.value = ''; return [2 /*return*/, "continue"]; } img = document.createElement('img'); img.src = window.URL.createObjectURL(beforeUploadResult.file); reader = new FileReader(); reader.addEventListener('load', function (event) { var /** @type {?} */ fileHolder = new FileHolder(event.target.result, beforeUploadResult.file); _this.uploadSingleFile(fileHolder, beforeUploadResult.url, beforeUploadResult.formData); _this.files.push(fileHolder); }, false); reader.readAsDataURL(beforeUploadResult.file); return [2 /*return*/]; } }); }; this_1 = this; i = 0; _a.label = 1; case 1: if (!(i < filesToUploadNum)) return [3 /*break*/, 4]; return [5 /*yield**/, _loop_1(i)]; case 2: _a.sent(); _a.label = 3; case 3: i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/]; } }); }); }; /** * @param {?} fileHolder * @param {?=} url * @param {?=} customForm * @return {?} */ NgxImageUploadComponent.prototype.uploadSingleFile = /** * @param {?} fileHolder * @param {?=} url * @param {?=} customForm * @return {?} */ function (fileHolder, url, customForm) { var _this = this; if (url === void 0) { url = this.url; } if (url) { this.pendingFilesCounter++; fileHolder.pending = true; this.imageService .postImage(url, fileHolder.file, this.headers, this.partName, customForm, this.withCredentials) .subscribe(function (response) { return _this.onResponse(response, fileHolder); }, function (error) { _this.onResponse(error, fileHolder); _this.deleteFile(fileHolder); }); } else { this.uploadFinished.emit(fileHolder); } }; NgxImageUploadComponent.decorators = [ { type: i0.Component, args: [{ selector: 'ds-ngx-image-upload', template: "<div\n fileDrop\n [accept]=\"supportedExtensions\"\n (fileOver)=\"onFileOver($event)\"\n (fileDrop)=\"onFileChange($event)\"\n [ngClass]=\"cssClass\"\n [ngClass]=\"{'img-ul-file-is-over': fileOver}\" \n [ngStyle]=\"style?.layout\"\n>\n <p class=\"img-ul-file-too-large\" *ngIf=\"showFileTooLargeMessage\" [innerText]=\"fileTooLargeMessage\"></p>\n\n <div *ngIf=\"preview\" class=\"img-ul-container img-ul-hr-inline-group\" [ngStyle]=\"style?.previewPanel\">\n <!-- img -->\n <div\n class=\"img-ul-image\"\n *ngFor=\"let file of files\"\n (click)=\"previewFileClicked(file)\"\n >\n <!-- [ngStyle]=\"{'background-image': 'url('+ file.src +')'}\" -->\n <div class=\"img_div\"><img src={{file.src}} class=\"imgs\"></div>\n <div *ngIf=\"file.pending\" class=\"img-ul-loading-overlay\">\n <div class=\"img-ul-spinning-circle\"></div>\n </div>\n <div *ngIf=\"!file.pending\" \n [ngClass]=\"{'img-ul-disabled': disabled}\" \n class=\"img-ul-x-mark\" \n (click)=\"deleteFile(file)\">\n <span class=\"img-ul-close\"></span>\n </div>\n </div>\n </div>\n \n <div class=\"img-ul-file-upload img-ul-hr-inline-group\"> \n <label *ngIf=\"fileCounter != max\"\n class=\"img-ul-upload img-ul-button\" \n [ngStyle]=\"style?.selectButton\"\n [ngClass]=\"{'img-ul-disabled': disabled}\">\n <span [innerText]=\"buttonCaption\"></span>\n <input\n type=\"file\"\n [disabled]=\"disabled\"\n [accept]=\"supportedExtensions\"\n multiple (change)=\"onFileChange(input.files)\"\n #input>\n </label>\n </div>\n</div>", styles: [".img-ul{--common-radius:3px;border-radius:var(--common-radius);position:relative;color:#9b9b9b;font-weight:400}.img-ul-x-mark{background-color:#000;border-radius:10px;color:#fff;cursor:pointer;height:20px;opacity:.7;text-align:center;width:20px;position:absolute;top:-8px;right:-10px}.img_div{position:relative;width:120px;height:120px;overflow:hidden}.imgs{max-width:200%;height:auto;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);background:#000}.img-ul-file-is-over{border:var(--active-color) solid}.img-ul-hr-inline-group:after{clear:both;content:\"\";display:table}.img-ul-file-upload{display:inline-block;width:120px;height:120px;margin:10px;color:#000;text-align:center;line-height:120px}.img-ul-drag-box-msg{display:inline-block;font-weight:600;margin-left:12px}label.img-ul-button{border:1px dashed #d0d0d0;font-size:1em!important}label.img-ul-button input[type=file]{display:none;position:fixed;top:-99999px}.img-ul-clear{background-color:red;font-size:1em!important}.img-ul-clear:disabled{background-color:#ff6464;cursor:default}.img-ul-upload{background-color:var(--active-color);width:120px;height:120px}.img-ul-button{border:none;cursor:pointer;display:inline-block;float:left;font-size:1.25em;font-weight:500;text-transform:uppercase}.img-ul-button:active span{display:block;position:relative;top:1px}.img-ul-container{position:relative;display:inline-block}.img-ul-image{box-shadow:0 0 10px 2px #d0d0d0;background:center center/contain no-repeat;display:inline-block;float:left;height:120px;margin:6px;position:relative;width:120px}.img-ul-close{height:20px;opacity:.7;position:relative;width:20px}.img-ul-x-mark:hover .img-ul-close{opacity:1}.img-ul-close:after,.img-ul-close:before{background-color:#fff;border-radius:2px;content:'';height:10px;position:absolute;top:5px;width:2px}.img-ul-close:before{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.img-ul-close:after{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.img-ul-x-mark.img-ul-disabled{display:none}.img-ul-loading-overlay{background-color:#000;bottom:0;left:0;opacity:.7;position:absolute;right:0;top:0}.img-ul-spinning-circle{height:30px;width:30px;margin:auto;position:absolute;top:0;left:0;bottom:0;right:0;border-radius:50%;border:3px solid rgba(255,255,255,0);border-top:3px solid #fff;border-right:3px solid #fff;-webkit-animation:2s cubic-bezier(.085,.625,.855,.36) infinite spinner;animation:2s cubic-bezier(.085,.625,.855,.36) infinite spinner}.img-ul-file-too-large{color:red}.img-ul-upload.img-ul-disabled{background-color:#86e9c9;cursor:default}.img-ul-upload.img-ul-disabled:active span{top:0}@-webkit-keyframes spinner{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}"] },] }, ]; /** @nocollapse */ NgxImageUploadComponent.ctorParameters = function () { return [ { type: NgxImageUploadService } ]; }; NgxImageUploadComponent.propDecorators = { beforeUpload: [{ type: i0.Input }], buttonCaption: [{ type: i0.Input }], disabled: [{ type: i0.Input }], cssClass: [{ type: i0.Input, args: ['class',] }], clearButtonCaption: [{ type: i0.Input }], dropBoxMessage: [{ type: i0.Input }], fileTooLargeMessage: [{ type: i0.Input }], headers: [{ type: i0.Input }], max: [{ type: i0.Input }], maxFileSize: [{ type: i0.Input }], preview: [{ type: i0.Input }], partName: [{ type: i0.Input }], style: [{ type: i0.Input }], supportedExtensions: [{ type: i0.Input, args: ['extensions',] }], url: [{ type: i0.Input }], withCredentials: [{ type: i0.Input }], uploadedFiles: [{ type: i0.Input }], removed: [{ type: i0.Output }], uploadStateChanged: [{ type: i0.Output }], uploadFinished: [{ type: i0.Output }], previewClicked: [{ type: i0.Output }], inputElement: [{ type: i0.ViewChild, args: ['input',] }] }; return NgxImageUploadComponent; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var FileDropDirective = (function () { function FileDropDirective() { this.fileOver = new i0.EventEmitter(); this.fileDrop = new i0.EventEmitter(); } /** * @param {?} event * @return {?} */ FileDropDirective.prototype.onDrop = /** * @param {?} event * @return {?} */ function (event) { var /** @type {?} */ dataTransfer = FileDropDirective.getDataTransfer(event); if (!FileDropDirective.hasFiles(dataTransfer.types)) { return; } event.preventDefault(); var /** @type {?} */ files = this.filterFiles(dataTransfer.files); event.preventDefault(); this.fileOver.emit(false); this.fileDrop.emit(files); }; /** * @param {?} event * @return {?} */ FileDropDirective.prototype.onDragLeave = /** * @param {?} event * @return {?} */ function (event) { this.fileOver.emit(false); }; /** * @param {?} event * @return {?} */ FileDropDirective.prototype.onDragOver = /** * @param {?} event * @return {?} */ function (event) { var /** @type {?} */ dataTransfer = FileDropDirective.getDataTransfer(event); if (!FileDropDirective.hasFiles(dataTransfer.types)) { return; } dataTransfer.dropEffect = 'copy'; event.preventDefault(); this.fileOver.emit(true); }; /** * @param {?} files * @return {?} */ FileDropDirective.prototype.filterFiles = /** * @param {?} files * @return {?} */ function (files) { if (!this.accept || this.accept.length === 0) { return files; } var /** @type {?} */ acceptedFiles = []; for (var /** @type {?} */ i = 0; i < files.length; i++) { for (var /** @type {?} */ j = 0; j < this.accept.length; j++) { if (FileDropDirective.matchRule(this.accept[j], files[i].type)) { acceptedFiles.push(files[i]); break; } } } return acceptedFiles; }; /** * @param {?} event * @return {?} */ FileDropDirective.getDataTransfer = /** * @param {?} event * @return {?} */ function (event) { return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; }; /** * @param {?} types * @return {?} */ FileDropDirective.hasFiles = /** * @param {?} types * @return {?} */ function (types) { if (!types) { return false; } if (types.indexOf) { return types.indexOf('Files') !== -1; } if (types.contains) { return types.contains('Files'); } return false; }; /** * @param {?} rule * @param {?} candidate * @return {?} */ FileDropDirective.matchRule = /** * @param {?} rule * @param {?} candidate * @return {?} */ function (rule, candidate) { return new RegExp("^" + rule.split("*").join(".*") + "$").test(candidate); }; FileDropDirective.decorators = [ { type: i0.Directive, args: [{ selector: '[fileDrop]' },] }, ]; FileDropDirective.propDecorators = { accept: [{ type: i0.Input }], fileOver: [{ type: i0.Output }], fileDrop: [{ type: i0.Output }], onDrop: [{ type: i0.HostListener, args: ['drop', ['$event'],] }], onDragLeave: [{ type: i0.HostListener, args: ['dragleave', ['$event'],] }], onDragOver: [{ type: i0.HostListener, args: ['dragover', ['$event'],] }] }; return FileDropDirective; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var NgxImageUploadModule = (function () { function NgxImageUploadModule() { } NgxImageUploadModule.decorators = [ { type: i0.NgModule, args: [{ imports: [ common.CommonModule, i1.HttpClientModule ], declarations: [NgxImageUploadComponent, FileDropDirective], exports: [NgxImageUploadComponent] },] }, ]; return NgxImageUploadModule; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ exports.NgxImageUploadService = NgxImageUploadService; exports.FileHolder = FileHolder; exports.NgxImageUploadComponent = NgxImageUploadComponent; exports.NgxImageUploadModule = NgxImageUploadModule; exports.ɵa = FileDropDirective; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWltYWdlLXVwbG9hZC51bWQuanMubWFwIiwic291cmNlcyI6WyJuZzovL25neC1pbWFnZS11cGxvYWQvbGliL25neC1pbWFnZS11cGxvYWQuc2VydmljZS50cyIsbnVsbCwibmc6Ly9uZ3gtaW1hZ2UtdXBsb2FkL2xpYi9uZ3gtaW1hZ2UtdXBsb2FkLmNvbXBvbmVudC50cyIsIm5nOi8vbmd4LWltYWdlLXVwbG9hZC9maWxlLWRyb3AuZGlyZWN0aXZlLnRzIiwibmc6Ly9uZ3gtaW1hZ2UtdXBsb2FkL2xpYi9uZ3gtaW1hZ2UtdXBsb2FkLm1vZHVsZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBIdHRwQ2xpZW50LCBIdHRwSGVhZGVycyB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCdcbn0pXG5leHBvcnQgY2xhc3MgTmd4SW1hZ2VVcGxvYWRTZXJ2aWNlIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50KSB7XG4gIH1cblxuICBwdWJsaWMgcG9zdEltYWdlKHVybDogc3RyaW5nLCBpbWFnZTogRmlsZSwgaGVhZGVycz86IEh0dHBIZWFkZXJzIHwgeyBbbmFtZTogc3RyaW5nXTogYW55IH0sIHBhcnROYW1lOiBzdHJpbmcgPSAnaW1hZ2UnLCBjdXN0b21Gb3JtRGF0YT86IHsgW25hbWU6IHN0cmluZ106IGFueSB9LCB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuKTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICBpZiAoIXVybCB8fCB1cmwgPT09ICcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ8Oowq/Ct8Oowq7CvsOnwr3CrnVybMOlwo/CgsOmwpXCsCcpO1xuICAgIH1cblxuICAgIC8vIGFkZCBjdXN0b20gZm9ybSBkYXRhXG4gICAgbGV0IGZvcm1EYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgZm9yIChsZXQga2V5IGluIGN1c3RvbUZvcm1EYXRhKSB7XG4gICAgICBmb3JtRGF0YS5hcHBlbmQoa2V5LCBjdXN0b21Gb3JtRGF0YVtrZXldKTtcbiAgICB9XG4gICAgZm9ybURhdGEuYXBwZW5kKHBhcnROYW1lLCBpbWFnZSk7XG4gICAgcmV0dXJuIHRoaXMuaHR0cC5wb3N0KHVybCwgZm9ybURhdGEsIHsgaGVhZGVyczogaGVhZGVycywgd2l0aENyZWRlbnRpYWxzOiB3aXRoQ3JlZGVudGlhbHMgfSk7XG4gIH1cbn1cbiIsIi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3QgdXNlXHJcbnRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlXHJcbkxpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXHJcblxyXG5USElTIENPREUgSVMgUFJPVklERUQgT04gQU4gKkFTIElTKiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZXHJcbktJTkQsIEVJVEhFUiBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04gQU5ZIElNUExJRURcclxuV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIFRJVExFLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSxcclxuTUVSQ0hBTlRBQkxJVFkgT1IgTk9OLUlORlJJTkdFTUVOVC5cclxuXHJcblNlZSB0aGUgQXBhY2hlIFZlcnNpb24gMi4wIExpY2Vuc2UgZm9yIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xyXG5hbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoYi5oYXNPd25Qcm9wZXJ0eShwKSkgZFtwXSA9IGJbcF07IH07XHJcbiAgICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2V4dGVuZHMoZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxuICAgIGZ1bmN0aW9uIF9fKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gZDsgfVxyXG4gICAgZC5wcm90b3R5cGUgPSBiID09PSBudWxsID8gT2JqZWN0LmNyZWF0ZShiKSA6IChfXy5wcm90b3R5cGUgPSBiLnByb3RvdHlwZSwgbmV3IF9fKCkpO1xyXG59XHJcblxyXG5leHBvcnQgdmFyIF9fYXNzaWduID0gZnVuY3Rpb24oKSB7XHJcbiAgICBfX2Fzc2lnbiA9IE9iamVjdC5hc3NpZ24gfHwgZnVuY3Rpb24gX19hc3NpZ24odCkge1xyXG4gICAgICAgIGZvciAodmFyIHMsIGkgPSAxLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSA8IG47IGkrKykge1xyXG4gICAgICAgICAgICBzID0gYXJndW1lbnRzW2ldO1xyXG4gICAgICAgICAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkpIHRbcF0gPSBzW3BdO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdDtcclxuICAgIH1cclxuICAgIHJldHVybiBfX2Fzc2lnbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19yZXN0KHMsIGUpIHtcclxuICAgIHZhciB0ID0ge307XHJcbiAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkgJiYgZS5pbmRleE9mKHApIDwgMClcclxuICAgICAgICB0W3BdID0gc1twXTtcclxuICAgIGlmIChzICE9IG51bGwgJiYgdHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMgPT09IFwiZnVuY3Rpb25cIilcclxuICAgICAgICBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMClcclxuICAgICAgICAgICAgdFtwW2ldXSA9IHNbcFtpXV07XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUgPT09IFwiZnVuY3Rpb25cIikgciA9IFJlZmxlY3QuZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpO1xyXG4gICAgZWxzZSBmb3IgKHZhciBpID0gZGVjb3JhdG9ycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkgaWYgKGQgPSBkZWNvcmF0b3JzW2ldKSByID0gKGMgPCAzID8gZChyKSA6IGMgPiAzID8gZCh0YXJnZXQsIGtleSwgcikgOiBkKHRhcmdldCwga2V5KSkgfHwgcjtcclxuICAgIHJldHVybiBjID4gMyAmJiByICYmIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGtleSwgciksIHI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3BhcmFtKHBhcmFtSW5kZXgsIGRlY29yYXRvcikge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uICh0YXJnZXQsIGtleSkgeyBkZWNvcmF0b3IodGFyZ2V0LCBrZXksIHBhcmFtSW5kZXgpOyB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX21ldGFkYXRhKG1ldGFkYXRhS2V5LCBtZXRhZGF0YVZhbHVlKSB7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QubWV0YWRhdGEgPT09IFwiZnVuY3Rpb25cIikgcmV0dXJuIFJlZmxlY3QubWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hd2FpdGVyKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XHJcbiAgICAgICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZShyZXN1bHQudmFsdWUpOyB9KS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9XHJcbiAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xyXG4gICAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2dlbmVyYXRvcih0aGlzQXJnLCBib2R5KSB7XHJcbiAgICB2YXIgXyA9IHsgbGFiZWw6IDAsIHNlbnQ6IGZ1bmN0aW9uKCkgeyBpZiAodFswXSAmIDEpIHRocm93IHRbMV07IHJldHVybiB0WzFdOyB9LCB0cnlzOiBbXSwgb3BzOiBbXSB9LCBmLCB5LCB0LCBnO1xyXG4gICAgcmV0dXJuIGcgPSB7IG5leHQ6IHZlcmIoMCksIFwidGhyb3dcIjogdmVyYigxKSwgXCJyZXR1cm5cIjogdmVyYigyKSB9LCB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgKGdbU3ltYm9sLml0ZXJhdG9yXSA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpczsgfSksIGc7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4pIHsgcmV0dXJuIGZ1bmN0aW9uICh2KSB7IHJldHVybiBzdGVwKFtuLCB2XSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHN0ZXAob3ApIHtcclxuICAgICAgICBpZiAoZikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy5cIik7XHJcbiAgICAgICAgd2hpbGUgKF8pIHRyeSB7XHJcbiAgICAgICAgICAgIGlmIChmID0gMSwgeSAmJiAodCA9IG9wWzBdICYgMiA/IHlbXCJyZXR1cm5cIl0gOiBvcFswXSA/IHlbXCJ0aHJvd1wiXSB8fCAoKHQgPSB5W1wicmV0dXJuXCJdKSAmJiB0LmNhbGwoeSksIDApIDogeS5uZXh0KSAmJiAhKHQgPSB0LmNhbGwoeSwgb3BbMV0pKS5kb25lKSByZXR1cm4gdDtcclxuICAgICAgICAgICAgaWYgKHkgPSAwLCB0KSBvcCA9IFtvcFswXSAmIDIsIHQudmFsdWVdO1xyXG4gICAgICAgICAgICBzd2l0Y2ggKG9wWzBdKSB7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDA6IGNhc2UgMTogdCA9IG9wOyBicmVhaztcclxuICAgICAgICAgICAgICAgIGNhc2UgNDogXy5sYWJlbCsrOyByZXR1cm4geyB2YWx1ZTogb3BbMV0sIGRvbmU6IGZhbHNlIH07XHJcbiAgICAgICAgICAgICAgICBjYXNlIDU6IF8ubGFiZWwrKzsgeSA9IG9wWzFdOyBvcCA9IFswXTsgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDc6IG9wID0gXy5vcHMucG9wKCk7IF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgICAgIGlmICghKHQgPSBfLnRyeXMsIHQgPSB0Lmxlbmd0aCA+IDAgJiYgdFt0Lmxlbmd0aCAtIDFdKSAmJiAob3BbMF0gPT09IDYgfHwgb3BbMF0gPT09IDIpKSB7IF8gPSAwOyBjb250aW51ZTsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChvcFswXSA9PT0gMyAmJiAoIXQgfHwgKG9wWzFdID4gdFswXSAmJiBvcFsxXSA8IHRbM10pKSkgeyBfLmxhYmVsID0gb3BbMV07IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSA2ICYmIF8ubGFiZWwgPCB0WzFdKSB7IF8ubGFiZWwgPSB0WzFdOyB0ID0gb3A7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHQgJiYgXy5sYWJlbCA8IHRbMl0pIHsgXy5sYWJlbCA9IHRbMl07IF8ub3BzLnB1c2gob3ApOyBicmVhazsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0WzJdKSBfLm9wcy5wb3AoKTtcclxuICAgICAgICAgICAgICAgICAgICBfLnRyeXMucG9wKCk7IGNvbnRpbnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIG9wID0gYm9keS5jYWxsKHRoaXNBcmcsIF8pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHsgb3AgPSBbNiwgZV07IHkgPSAwOyB9IGZpbmFsbHkgeyBmID0gdCA9IDA7IH1cclxuICAgICAgICBpZiAob3BbMF0gJiA1KSB0aHJvdyBvcFsxXTsgcmV0dXJuIHsgdmFsdWU6IG9wWzBdID8gb3BbMV0gOiB2b2lkIDAsIGRvbmU6IHRydWUgfTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXhwb3J0U3RhcihtLCBleHBvcnRzKSB7XHJcbiAgICBmb3IgKHZhciBwIGluIG0pIGlmICghZXhwb3J0cy5oYXNPd25Qcm9wZXJ0eShwKSkgZXhwb3J0c1twXSA9IG1bcF07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3ZhbHVlcyhvKSB7XHJcbiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl0sIGkgPSAwO1xyXG4gICAgaWYgKG0pIHJldHVybiBtLmNhbGwobyk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAgIG5leHQ6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKG8gJiYgaSA+PSBvLmxlbmd0aCkgbyA9IHZvaWQgMDtcclxuICAgICAgICAgICAgcmV0dXJuIHsgdmFsdWU6IG8gJiYgb1tpKytdLCBkb25lOiAhbyB9O1xyXG4gICAgICAgIH1cclxuICAgIH07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3JlYWQobywgbikge1xyXG4gICAgdmFyIG0gPSB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgb1tTeW1ib2wuaXRlcmF0b3JdO1xyXG4gICAgaWYgKCFtKSByZXR1cm4gbztcclxuICAgIHZhciBpID0gbS5jYWxsKG8pLCByLCBhciA9IFtdLCBlO1xyXG4gICAgdHJ5IHtcclxuICAgICAgICB3aGlsZSAoKG4gPT09IHZvaWQgMCB8fCBuLS0gPiAwKSAmJiAhKHIgPSBpLm5leHQoKSkuZG9uZSkgYXIucHVzaChyLnZhbHVlKTtcclxuICAgIH1cclxuICAgIGNhdGNoIChlcnJvcikgeyBlID0geyBlcnJvcjogZXJyb3IgfTsgfVxyXG4gICAgZmluYWxseSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKHIgJiYgIXIuZG9uZSAmJiAobSA9IGlbXCJyZXR1cm5cIl0pKSBtLmNhbGwoaSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZpbmFsbHkgeyBpZiAoZSkgdGhyb3cgZS5lcnJvcjsgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGFyO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19zcHJlYWQoKSB7XHJcbiAgICBmb3IgKHZhciBhciA9IFtdLCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKylcclxuICAgICAgICBhciA9IGFyLmNvbmNhdChfX3JlYWQoYXJndW1lbnRzW2ldKSk7XHJcbiAgICByZXR1cm4gYXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0KHYpIHtcclxuICAgIHJldHVybiB0aGlzIGluc3RhbmNlb2YgX19hd2FpdCA/ICh0aGlzLnYgPSB2LCB0aGlzKSA6IG5ldyBfX2F3YWl0KHYpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY0dlbmVyYXRvcih0aGlzQXJnLCBfYXJndW1lbnRzLCBnZW5lcmF0b3IpIHtcclxuICAgIGlmICghU3ltYm9sLmFzeW5jSXRlcmF0b3IpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC5cIik7XHJcbiAgICB2YXIgZyA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSwgaSwgcSA9IFtdO1xyXG4gICAgcmV0dXJuIGkgPSB7fSwgdmVyYihcIm5leHRcIiksIHZlcmIoXCJ0aHJvd1wiKSwgdmVyYihcInJldHVyblwiKSwgaVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuKSB7IGlmIChnW25dKSBpW25dID0gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChhLCBiKSB7IHEucHVzaChbbiwgdiwgYSwgYl0pID4gMSB8fCByZXN1bWUobiwgdik7IH0pOyB9OyB9XHJcbiAgICBmdW5jdGlvbiByZXN1bWUobiwgdikgeyB0cnkgeyBzdGVwKGdbbl0odikpOyB9IGNhdGNoIChlKSB7IHNldHRsZShxWzBdWzNdLCBlKTsgfSB9XHJcbiAgICBmdW5jdGlvbiBzdGVwKHIpIHsgci52YWx1ZSBpbnN0YW5jZW9mIF9fYXdhaXQgPyBQcm9taXNlLnJlc29sdmUoci52YWx1ZS52KS50aGVuKGZ1bGZpbGwsIHJlamVjdCkgOiBzZXR0bGUocVswXVsyXSwgcik7IH1cclxuICAgIGZ1bmN0aW9uIGZ1bGZpbGwodmFsdWUpIHsgcmVzdW1lKFwibmV4dFwiLCB2YWx1ZSk7IH1cclxuICAgIGZ1bmN0aW9uIHJlamVjdCh2YWx1ZSkgeyByZXN1bWUoXCJ0aHJvd1wiLCB2YWx1ZSk7IH1cclxuICAgIGZ1bmN0aW9uIHNldHRsZShmLCB2KSB7IGlmIChmKHYpLCBxLnNoaWZ0KCksIHEubGVuZ3RoKSByZXN1bWUocVswXVswXSwgcVswXVsxXSk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fYXN5bmNEZWxlZ2F0b3Iobykge1xyXG4gICAgdmFyIGksIHA7XHJcbiAgICByZXR1cm4gaSA9IHt9LCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIsIGZ1bmN0aW9uIChlKSB7IHRocm93IGU7IH0pLCB2ZXJiKFwicmV0dXJuXCIpLCBpW1N5bWJvbC5pdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuLCBmKSB7IGlbbl0gPSBvW25dID8gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIChwID0gIXApID8geyB2YWx1ZTogX19hd2FpdChvW25dKHYpKSwgZG9uZTogbiA9PT0gXCJyZXR1cm5cIiB9IDogZiA/IGYodikgOiB2OyB9IDogZjsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY1ZhbHVlcyhvKSB7XHJcbiAgICBpZiAoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuXCIpO1xyXG4gICAgdmFyIG0gPSBvW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSwgaTtcclxuICAgIHJldHVybiBtID8gbS5jYWxsKG8pIDogKG8gPSB0eXBlb2YgX192YWx1ZXMgPT09IFwiZnVuY3Rpb25cIiA/IF9fdmFsdWVzKG8pIDogb1tTeW1ib2wuaXRlcmF0b3JdKCksIGkgPSB7fSwgdmVyYihcIm5leHRcIiksIHZlcmIoXCJ0aHJvd1wiKSwgdmVyYihcInJldHVyblwiKSwgaVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpKTtcclxuICAgIGZ1bmN0aW9uIHZlcmIobikgeyBpW25dID0gb1tuXSAmJiBmdW5jdGlvbiAodikgeyByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkgeyB2ID0gb1tuXSh2KSwgc2V0dGxlKHJlc29sdmUsIHJlamVjdCwgdi5kb25lLCB2LnZhbHVlKTsgfSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHNldHRsZShyZXNvbHZlLCByZWplY3QsIGQsIHYpIHsgUHJvbWlzZS5yZXNvbHZlKHYpLnRoZW4oZnVuY3Rpb24odikgeyByZXNvbHZlKHsgdmFsdWU6IHYsIGRvbmU6IGQgfSk7IH0sIHJlamVjdCk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fbWFrZVRlbXBsYXRlT2JqZWN0KGNvb2tlZCwgcmF3KSB7XHJcbiAgICBpZiAoT2JqZWN0LmRlZmluZVByb3BlcnR5KSB7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjb29rZWQsIFwicmF3XCIsIHsgdmFsdWU6IHJhdyB9KTsgfSBlbHNlIHsgY29va2VkLnJhdyA9IHJhdzsgfVxyXG4gICAgcmV0dXJuIGNvb2tlZDtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2ltcG9ydFN0YXIobW9kKSB7XHJcbiAgICBpZiAobW9kICYmIG1vZC5fX2VzTW9kdWxlKSByZXR1cm4gbW9kO1xyXG4gICAgdmFyIHJlc3VsdCA9IHt9O1xyXG4gICAgaWYgKG1vZCAhPSBudWxsKSBmb3IgKHZhciBrIGluIG1vZCkgaWYgKE9iamVjdC5oYXNPd25Qcm9wZXJ0eS5jYWxsKG1vZCwgaykpIHJlc3VsdFtrXSA9IG1vZFtrXTtcclxuICAgIHJlc3VsdC5kZWZhdWx0ID0gbW9kO1xyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9faW1wb3J0RGVmYXVsdChtb2QpIHtcclxuICAgIHJldHVybiAobW9kICYmIG1vZC5fX2VzTW9kdWxlKSA/IG1vZCA6IHsgZGVmYXVsdDogbW9kIH07XHJcbn1cclxuIiwiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIE9uQ2hhbmdlcywgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBFbGVtZW50UmVmLCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgVXBsb2FkTWV0YWRhdGEgfSBmcm9tICcuL2JlZm9yZS11cGxvYWQuaW50ZXJmYWNlJztcbmltcG9ydCB7IE5neEltYWdlVXBsb2FkU2VydmljZSB9IGZyb20gJy4vbmd4LWltYWdlLXVwbG9hZC5zZXJ2aWNlJztcbmltcG9ydCB7IFN0eWxlIH0gZnJvbSAnLi9zdHlsZSc7XG5cbmV4cG9ydCBjbGFzcyBGaWxlSG9sZGVyIHtcbiAgcHVibGljIHBlbmRpbmc6IGJvb2xlYW4gPSBmYWxzZTtcbiAgcHVibGljIHNlcnZlclJlc3BvbnNlOiB7IHN0YXR1czogbnVtYmVyLCByZXNwb25zZTogYW55IH07XG5cbiAgY29uc3RydWN0b3IocHVibGljIHNyYzogc3RyaW5nLCBwdWJsaWMgZmlsZTogRmlsZSkge1xuICB9XG59XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2RzLW5neC1pbWFnZS11cGxvYWQnLFxuICB0ZW1wbGF0ZTogYDxkaXZcbiAgICAgZmlsZURyb3BcbiAgICAgW2FjY2VwdF09XCJzdXBwb3J0ZWRFeHRlbnNpb25zXCJcbiAgICAgKGZpbGVPdmVyKT1cIm9uRmlsZU92ZXIoJGV2ZW50KVwiXG4gICAgIChmaWxlRHJvcCk9XCJvbkZpbGVDaGFuZ2UoJGV2ZW50KVwiXG4gICAgIFtuZ0NsYXNzXT1cImNzc0NsYXNzXCJcbiAgICAgW25nQ2xhc3NdPVwieydpbWctdWwtZmlsZS1pcy1vdmVyJzogZmlsZU92ZXJ9XCIgICAgIFxuICAgICBbbmdTdHlsZV09XCJzdHlsZT8ubGF5b3V0XCJcbj5cbiAgPHAgY2xhc3M9XCJpbWctdWwtZmlsZS10b28tbGFyZ2VcIiAqbmdJZj1cInNob3dGaWxlVG9vTGFyZ2VNZXNzYWdlXCIgW2lubmVyVGV4dF09XCJmaWxlVG9vTGFyZ2VNZXNzYWdlXCI+PC9wPlxuXG4gIDxkaXYgKm5nSWY9XCJwcmV2aWV3XCIgY2xhc3M9XCJpbWctdWwtY29udGFpbmVyIGltZy11bC1oci1pbmxpbmUtZ3JvdXBcIiBbbmdTdHlsZV09XCJzdHlsZT8ucHJldmlld1BhbmVsXCI+XG4gICAgPCEtLSBpbWcgLS0+XG4gICAgPGRpdlxuICAgICAgY2xhc3M9XCJpbWctdWwtaW1hZ2VcIlxuICAgICAgKm5nRm9yPVwibGV0IGZpbGUgb2YgZmlsZXNcIlxuICAgICAgKGNsaWNrKT1cInByZXZpZXdGaWxlQ2xpY2tlZChmaWxlKVwiXG4gICAgPlxuICAgICAgPCEtLSBbbmdTdHlsZV09XCJ7J2JhY2tncm91bmQtaW1hZ2UnOiAndXJsKCcrIGZpbGUuc3JjICsnKSd9XCIgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwiaW1nX2RpdlwiPjxpbWcgc3JjPXt7ZmlsZS5zcmN9fSBjbGFzcz1cImltZ3NcIj48L2Rpdj5cbiAgICAgIDxkaXYgKm5nSWY9XCJmaWxlLnBlbmRpbmdcIiBjbGFzcz1cImltZy11bC1sb2FkaW5nLW92ZXJsYXlcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImltZy11bC1zcGlubmluZy1jaXJjbGVcIj48L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiAqbmdJZj1cIiFmaWxlLnBlbmRpbmdcIiBcbiAgICAgICAgW25nQ2xhc3NdPVwieydpbWctdWwtZGlzYWJsZWQnOiBkaXNhYmxlZH1cIiBcbiAgICAgICAgY2xhc3M9XCJpbWctdWwteC1tYXJrXCIgXG4gICAgICAgIChjbGljayk9XCJkZWxldGVGaWxlKGZpbGUpXCI+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwiaW1nLXVsLWNsb3NlXCI+PC9zcGFuPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuICBcbiAgPGRpdiBjbGFzcz1cImltZy11bC1maWxlLXVwbG9hZCBpbWctdWwtaHItaW5saW5lLWdyb3VwXCI+ICAgIFxuICAgIDxsYWJlbCAqbmdJZj1cImZpbGVDb3VudGVyICE9IG1heFwiXG4gICAgICBjbGFzcz1cImltZy11bC11cGxvYWQgaW1nLXVsLWJ1dHRvblwiIFxuICAgICAgW25nU3R5bGVdPVwic3R5bGU/LnNlbGVjdEJ1dHRvblwiXG4gICAgICBbbmdDbGFzc109XCJ7J2ltZy11bC1kaXNhYmxlZCc6IGRpc2FibGVkfVwiPlxuICAgICAgPHNwYW4gW2lubmVyVGV4dF09XCJidXR0b25DYXB0aW9uXCI+PC9zcGFuPlxuICAgICAgPGlucHV0XG4gICAgICAgIHR5cGU9XCJmaWxlXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcbiAgICAgICAgW2FjY2VwdF09XCJzdXBwb3J0ZWRFeHRlbnNpb25zXCJcbiAgICAgICAgbXVsdGlwbGUgKGNoYW5nZSk9XCJvbkZpbGVDaGFuZ2UoaW5wdXQuZmlsZXMpXCJcbiAgICAgICAgI2lucHV0PlxuICAgIDwvbGFiZWw+XG4gIDwvZGl2PlxuPC9kaXY+YCxcbiAgc3R5bGVzOiBbYC5pbWctdWx7LS1jb21tb24tcmFkaXVzOjNweDtib3JkZXItcmFkaXVzOnZhcigtLWNvbW1vbi1yYWRpdXMpO3Bvc2l0aW9uOnJlbGF0aXZlO2NvbG9yOiM5YjliOWI7Zm9udC13ZWlnaHQ6NDAwfS5pbWctdWwteC1tYXJre2JhY2tncm91bmQtY29sb3I6IzAwMDtib3JkZXItcmFkaXVzOjEwcHg7Y29sb3I6I2ZmZjtjdXJzb3I6cG9pbnRlcjtoZWlnaHQ6MjBweDtvcGFjaXR5Oi43O3RleHQtYWxpZ246Y2VudGVyO3dpZHRoOjIwcHg7cG9zaXRpb246YWJzb2x1dGU7dG9wOi04cHg7cmlnaHQ6LTEwcHh9LmltZ19kaXZ7cG9zaXRpb246cmVsYXRpdmU7d2lkdGg6MTIwcHg7aGVpZ2h0OjEyMHB4O292ZXJmbG93OmhpZGRlbn0uaW1nc3ttYXgtd2lkdGg6MjAwJTtoZWlnaHQ6YXV0bztwb3NpdGlvbjphYnNvbHV0ZTt0b3A6NTAlO2xlZnQ6NTAlOy13ZWJraXQtdHJhbnNmb3JtOnRyYW5zbGF0ZSgtNTAlLC01MCUpO3RyYW5zZm9ybTp0cmFuc2xhdGUoLTUwJSwtNTA