UNPKG

@hpe/angular-toolkit

Version:

Hewlett-Packard Enterprise : Angular toolkit for rapid project development

965 lines (948 loc) 101 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@hpe/angular-toolkit/model'), require('@angular/common/http'), require('@angular/platform-browser'), require('rxjs'), require('rxjs/operators'), require('primeng/components/common/messageservice'), require('@angular/common'), require('primeng/api')) : typeof define === 'function' && define.amd ? define('@hpe/angular-toolkit/service', ['exports', '@angular/core', '@hpe/angular-toolkit/model', '@angular/common/http', '@angular/platform-browser', 'rxjs', 'rxjs/operators', 'primeng/components/common/messageservice', '@angular/common', 'primeng/api'], factory) : (factory((global.hpe = global.hpe || {}, global.hpe['angular-toolkit'] = global.hpe['angular-toolkit'] || {}, global.hpe['angular-toolkit'].service = {}),global.ng.core,global.hpe['angular-toolkit'].model,global.ng.common.http,global.ng.platformBrowser,global.rxjs,global.rxjs.operators,null,global.ng.common,null)); }(this, (function (exports,core,model,http,platformBrowser,rxjs,operators,messageservice,common,api) { 'use strict'; /*! ***************************************************************************** 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. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ //============================================================================= //=== //=== (C) Copyright 2018 Hewlett Packard Enterprise Development LP. //=== //=== Use of this source code is governed by an MIT-style license that can be //=== found in the LICENSE file //============================================================================= var AbstractSubscriber = (function () { //------------------------------------------------------------------------- //--- //--- Constructor //--- //------------------------------------------------------------------------- function AbstractSubscriber(eventBusService) { this.eventBusService = eventBusService; this.subscriptions = []; } /** * @return {?} */ AbstractSubscriber.prototype.ngOnDestroy = /** * @return {?} */ function () { this.subscriptions.forEach(function (s) { return s.unsubscribe(); }); }; //------------------------------------------------------------------------- //--- //--- API methods //--- //------------------------------------------------------------------------- /** * @param {?} eventCode * @param {?} handler * @return {?} */ AbstractSubscriber.prototype.subscribeToApp = /** * @param {?} eventCode * @param {?} handler * @return {?} */ function (eventCode, handler) { var /** @type {?} */ s = this.eventBusService.subscribeToApp(eventCode, handler); this.subscriptions.push(s); return s; }; //------------------------------------------------------------------------- /** * @param {?} event * @return {?} */ AbstractSubscriber.prototype.emitToApp = /** * @param {?} event * @return {?} */ function (event) { this.eventBusService.emitToApp(event); }; //------------------------------------------------------------------------- /** * @param {?} handler * @return {?} */ AbstractSubscriber.prototype.subscribeToError = /** * @param {?} handler * @return {?} */ function (handler) { var /** @type {?} */ s = this.eventBusService.subscribeToError(handler); this.subscriptions.push(s); return s; }; //------------------------------------------------------------------------- /** * @param {?} event * @return {?} */ AbstractSubscriber.prototype.emitToError = /** * @param {?} event * @return {?} */ function (event) { this.eventBusService.emitToError(event); }; return AbstractSubscriber; }()); //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var EventBusService = (function () { //------------------------------------------------------------------------- //--- //--- Constructor //--- //------------------------------------------------------------------------- function EventBusService() { this.eventEmitterMap = new Map(); this.errorEvents = new core.EventEmitter(); } /** * @param {?} eventCode * @param {?} handler * @return {?} */ EventBusService.prototype.subscribeToApp = /** * @param {?} eventCode * @param {?} handler * @return {?} */ function (eventCode, handler) { var /** @type {?} */ emitter = this.eventEmitterMap.get(eventCode); if (emitter == null) { emitter = new core.EventEmitter(); this.eventEmitterMap.set(eventCode, emitter); } return emitter.subscribe(handler, null, null); }; /** * @param {?} event * @return {?} */ EventBusService.prototype.emitToApp = /** * @param {?} event * @return {?} */ function (event) { var /** @type {?} */ emitter = this.eventEmitterMap.get(event.code); if (emitter != null) { console.log("Emitting event : " + JSON.stringify(event)); emitter.emit(event); } else { console.log("WARNING : Emitting an event without any handler : " + JSON.stringify(event)); } //--- Emitting to global handlers emitter = this.eventEmitterMap.get(model.AppEvent.ANY); if (emitter != null) { emitter.emit(event); } }; /** * @param {?} handler * @return {?} */ EventBusService.prototype.subscribeToError = /** * @param {?} handler * @return {?} */ function (handler) { return this.errorEvents.subscribe(handler, null, null); }; /** * @param {?} event * @return {?} */ EventBusService.prototype.emitToError = /** * @param {?} event * @return {?} */ function (event) { console.log("Emitting error event : " + JSON.stringify(event)); this.errorEvents.emit(event); }; EventBusService.decorators = [ { type: core.Injectable }, ]; /** @nocollapse */ EventBusService.ctorParameters = function () { return []; }; return EventBusService; }()); //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** @enum {number} */ var Status = { LOGIN: 0, LOADING: 1, READY: 2, }; Status[Status.LOGIN] = "LOGIN"; Status[Status.LOADING] = "LOADING"; Status[Status.READY] = "READY"; var ApplicationService = (function (_super) { __extends(ApplicationService, _super); //------------------------------------------------------------------------- //--- //--- Constructor //--- //------------------------------------------------------------------------- function ApplicationService(eventBusService) { var _this = _super.call(this, eventBusService) || this; _this.status = Status.LOGIN; _super.prototype.subscribeToApp.call(_this, model.AppEvent.LOGIN_SUCCESS, function (event) { return _this.onLoginSuccess(event); }); _super.prototype.subscribeToApp.call(_this, model.AppEvent.LOGIN_FAILED, function (event) { return _this.onLoginFailed(event); }); _super.prototype.subscribeToApp.call(_this, model.AppEvent.LOGOUT_SUCCESS, function (event) { return _this.onLogoutSuccess(event); }); _super.prototype.subscribeToApp.call(_this, model.AppEvent.LOGOUT_FAILED, function (event) { return _this.onLogoutFailed(event); }); _super.prototype.subscribeToApp.call(_this, model.AppEvent.INVALID_TOKEN, function (event) { return _this.onInvalidToken(event); }); _super.prototype.subscribeToApp.call(_this, model.AppEvent.APPLICATION_READY, function (event) { return _this.onApplicationReady(event); }); return _this; } /** * @return {?} */ ApplicationService.prototype.isStatusLogin = /** * @return {?} */ function () { return this.status == Status.LOGIN; }; /** * @return {?} */ ApplicationService.prototype.isStatusLoading = /** * @return {?} */ function () { return this.status == Status.LOADING; }; /** * @return {?} */ ApplicationService.prototype.isStatusReady = /** * @return {?} */ function () { return this.status == Status.READY; }; /** * @param {?} event * @return {?} */ ApplicationService.prototype.onLoginSuccess = /** * @param {?} event * @return {?} */ function (event) { this.status = Status.LOADING; }; /** * @param {?} event * @return {?} */ ApplicationService.prototype.onLoginFailed = /** * @param {?} event * @return {?} */ function (event) { this.status = Status.LOGIN; }; /** * @param {?} event * @return {?} */ ApplicationService.prototype.onLogoutSuccess = /** * @param {?} event * @return {?} */ function (event) { this.status = Status.LOGIN; }; /** * @param {?} event * @return {?} */ ApplicationService.prototype.onLogoutFailed = /** * @param {?} event * @return {?} */ function (event) { this.status = Status.LOGIN; }; /** * @param {?} event * @return {?} */ ApplicationService.prototype.onInvalidToken = /** * @param {?} event * @return {?} */ function (event) { this.status = Status.LOGIN; }; /** * @param {?} event * @return {?} */ ApplicationService.prototype.onApplicationReady = /** * @param {?} event * @return {?} */ function (event) { this.status = Status.READY; }; ApplicationService.decorators = [ { type: core.Injectable }, ]; /** @nocollapse */ ApplicationService.ctorParameters = function () { return [ { type: EventBusService, }, ]; }; return ApplicationService; }(AbstractSubscriber)); //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var HttpService = (function () { //------------------------------------------------------------------------- //--- //--- Constructor //--- //------------------------------------------------------------------------- function HttpService(httpClient, eventBusService, domSanitizer) { this.httpClient = httpClient; this.eventBusService = eventBusService; this.domSanitizer = domSanitizer; this.openRequests = 0; } Object.defineProperty(HttpService.prototype, "loading", { get: /** * @return {?} */ function () { return (this.openRequests > 0); }, enumerable: true, configurable: true }); /** * @param {?} url * @param {?=} options * @return {?} */ HttpService.prototype.getObject = /** * @param {?} url * @param {?=} options * @return {?} */ function (url, options) { var _this = this; this.showLoader(); //--- "Pragma": "no-cache" for IE 11 var /** @type {?} */ header = { "Pragma": "no-cache", "Cache-Control": "no-cache", "Expires": "0" }; return this.httpClient.get(url, { params: options, headers: header }).pipe(operators.catchError(function (error) { return _this.handleError(error); }), operators.finalize(function () { return _this.hideLoader(); })); }; /** * @param {?} url * @param {?=} options * @return {?} */ HttpService.prototype.getBlob = /** * @param {?} url * @param {?=} options * @return {?} */ function (url, options) { var _this = this; this.showLoader(); //--- Add timestamp to change static url to dynamic for IE 11 if (options != null) { options.ts = Date.now(); } return this.httpClient.get(url, { params: options, responseType: 'blob' }).pipe(operators.map(function (e) { return _this.getSanitizedUrl(URL.createObjectURL(e)); }), operators.catchError(function (error) { return _this.handleError(error); }), operators.finalize(function () { return _this.hideLoader(); })); }; /** * @param {?} url * @param {?} object * @param {?=} options * @return {?} */ HttpService.prototype.postObject = /** * @param {?} url * @param {?} object * @param {?=} options * @return {?} */ function (url, object, options) { var _this = this; this.showLoader(); return this.httpClient.post(url, object, options).pipe(operators.catchError(function (error) { return _this.handleError(error); }), operators.finalize(function () { return _this.hideLoader(); })); }; /** * @param {?} url * @return {?} */ HttpService.prototype.getSanitizedUrl = /** * @param {?} url * @return {?} */ function (url) { return this.domSanitizer.bypassSecurityTrustResourceUrl(url); }; /** * @param {?} response * @return {?} */ HttpService.prototype.handleError = /** * @param {?} response * @return {?} */ function (response) { console.log("Got the following HTTP error : " + JSON.stringify(response)); var /** @type {?} */ error; if (response.status == 422) { //--- Unprocessable entity error = response.error; } else { error = { code: response.status.toString(), error: response.error.toString() }; } this.eventBusService.emitToError(error); return rxjs.throwError(error); }; /** * @return {?} */ HttpService.prototype.showLoader = /** * @return {?} */ function () { if (++this.openRequests == 1) { this.eventBusService.emitToApp(new model.AppEvent(model.AppEvent.SUBMIT_START)); } }; /** * @return {?} */ HttpService.prototype.hideLoader = /** * @return {?} */ function () { if (--this.openRequests == 0) { this.eventBusService.emitToApp(new model.AppEvent(model.AppEvent.SUBMIT_END)); } }; HttpService.decorators = [ { type: core.Injectable }, ]; /** @nocollapse */ HttpService.ctorParameters = function () { return [ { type: http.HttpClient, }, { type: EventBusService, }, { type: platformBrowser.DomSanitizer, }, ]; }; return HttpService; }()); //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var LabelService = (function () { //------------------------------------------------------------------------- //--- //--- Constructor //--- //------------------------------------------------------------------------- function LabelService(httpService) { var _this = this; this.httpService = httpService; this.languages = ["en", "it"]; this.labelSet = new Map(); this.language = "en"; //--- Load language files this.languages.forEach(function (language) { _this.initLanguage(language); }); } /** * @param {?} language * @return {?} */ LabelService.prototype.setLanguage = /** * @param {?} language * @return {?} */ function (language) { this.language = language; }; /** * @param {?} entity * @param {?} code * @return {?} */ LabelService.prototype.getLabel = /** * @param {?} entity * @param {?} code * @return {?} */ function (entity, code) { if (code == null) { return null; } var /** @type {?} */ entitySet = this.getMapping(entity); if (entitySet == null) { return "?" + entity + "?"; } var /** @type {?} */ label = entitySet[code]; if (label == null) { return entity + ".?" + code + "?"; } return label; }; /** * @param {?} entity * @return {?} */ LabelService.prototype.getMapping = /** * @param {?} entity * @return {?} */ function (entity) { var /** @type {?} */ labels = this.labelSet.get(this.language); if (labels != null) { return labels.get(entity); } //--- Probably, we are still loading data return null; }; /** * @param {?} language * @return {?} */ LabelService.prototype.initLanguage = /** * @param {?} language * @return {?} */ function (language) { this.loadLanguageFile(language, LabelService.TOOLKIT_FILE); this.loadLanguageFile(language, LabelService.APPLICATION_FILE); }; /** * @param {?} language * @param {?} name * @return {?} */ LabelService.prototype.loadLanguageFile = /** * @param {?} language * @param {?} name * @return {?} */ function (language, name) { var _this = this; var /** @type {?} */ file = name + "-" + language + ".json"; this.httpService.getObject("asset/lang/" + file) .subscribe(function (result) { return _this.processFile(language, file, result); }, function (error) { return console.log("Cannot load labels file : " + file); }); }; /** * @param {?} language * @param {?} file * @param {?} data * @return {?} */ LabelService.prototype.processFile = /** * @param {?} language * @param {?} file * @param {?} data * @return {?} */ function (language, file, data) { console.log("Loaded labels file : " + file); var /** @type {?} */ labels = this.labelSet.get(language); if (labels == null) { labels = new Map(); this.labelSet.set(language, labels); } for (var /** @type {?} */ key in data) { labels.set(key, data[key]); } }; LabelService.TOOLKIT_FILE = "toolkit"; LabelService.APPLICATION_FILE = "application"; LabelService.decorators = [ { type: core.Injectable }, ]; /** @nocollapse */ LabelService.ctorParameters = function () { return [ { type: HttpService, }, ]; }; return LabelService; }()); //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var NotificationService = (function () { //------------------------------------------------------------------------- //--- //--- Constructor //--- //------------------------------------------------------------------------- function NotificationService(messageService) { this.messageService = messageService; } /** * @param {?} title * @param {?} message * @return {?} */ NotificationService.prototype.showSuccess = /** * @param {?} title * @param {?} message * @return {?} */ function (title, message) { this.show('success', title, message); }; /** * @param {?} title * @param {?} message * @return {?} */ NotificationService.prototype.showInfo = /** * @param {?} title * @param {?} message * @return {?} */ function (title, message) { this.show('info', title, message); }; /** * @param {?} title * @param {?} message * @return {?} */ NotificationService.prototype.showWarn = /** * @param {?} title * @param {?} message * @return {?} */ function (title, message) { this.show('warn', title, message); }; /** * @param {?} title * @param {?} message * @return {?} */ NotificationService.prototype.showError = /** * @param {?} title * @param {?} message * @return {?} */ function (title, message) { this.show('error', title, message); }; /** * @param {?} severity * @param {?} title * @param {?} message * @return {?} */ NotificationService.prototype.show = /** * @param {?} severity * @param {?} title * @param {?} message * @return {?} */ function (severity, title, message) { this.messageService.add({ severity: severity, summary: title, detail: message }); }; NotificationService.decorators = [ { type: core.Injectable }, ]; /** @nocollapse */ NotificationService.ctorParameters = function () { return [ { type: messageservice.MessageService, }, ]; }; return NotificationService; }()); //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var SessionService = (function (_super) { __extends(SessionService, _super); //------------------------------------------------------------------------- //--- //--- Constructor //--- //------------------------------------------------------------------------- function SessionService(eventBusService, httpService) { var _this = _super.call(this, eventBusService) || this; _this.httpService = httpService; _this.clearSession(); _super.prototype.subscribeToApp.call(_this, model.AppEvent.INVALID_TOKEN, function (event) { return _this.onInvalidToken(event); }); return _this; } /** * @param {?} cred * @return {?} */ SessionService.prototype.login = /** * @param {?} cred * @return {?} */ function (cred) { var _this = this; console.log("SessionService.login : Logging in user='" + cred.username + "'"); //--- Loads user profile from server this.httpService.postObject("/api/session/login", cred) .subscribe(function (result) { return _this.loginSuccess(result); }, function (error) { return _this.loginError(error); }); }; /** * @return {?} */ SessionService.prototype.logout = /** * @return {?} */ function () { var _this = this; console.log("SessionService.logout : Logging out user='" + (this.user || "???") + "'"); this.httpService.postObject("/api/session/logout", { token: this.token }) .subscribe(function (result) { return _this.logoutSuccess(); }, function (error) { return _this.logoutError(error); }); }; /** * @return {?} */ SessionService.prototype.clearSession = /** * @return {?} */ function () { console.log("SessionService.clearSession: Resetting session..."); this.session = null; this.token = null; this.user = null; this.profile = null; this.permissions = new Map(); }; Object.defineProperty(SessionService.prototype, "homePage", { get: /** * @return {?} */ function () { return (this.profile) ? this.profile.homePage : null; }, enumerable: true, configurable: true }); /** * @param {?} name * @return {?} */ SessionService.prototype.hasPermission = /** * @param {?} name * @return {?} */ function (name) { return (this.permissions.get(name)); }; /** * @param {?} session * @return {?} */ SessionService.prototype.loginSuccess = /** * @param {?} session * @return {?} */ function (session) { this.session = session; this.token = session.token; this.user = session.user; this.profile = session.profile; this.permissions = this.setupPermissionMap(this.profile.permissions); _super.prototype.emitToApp.call(this, new model.AppEvent(model.AppEvent.LOGIN_SUCCESS, session)); console.log("Login successful for user=" + this.user.username); }; /** * @param {?} response * @return {?} */ SessionService.prototype.loginError = /** * @param {?} response * @return {?} */ function (response) { _super.prototype.emitToApp.call(this, new model.AppEvent(model.AppEvent.LOGIN_FAILED, response)); }; /** * @return {?} */ SessionService.prototype.logoutSuccess = /** * @return {?} */ function () { var /** @type {?} */ username = this.user.username; this.clearSession(); _super.prototype.emitToApp.call(this, new model.AppEvent(model.AppEvent.LOGOUT_SUCCESS, username)); console.log("Logout successful for user=" + username); }; /** * @param {?} response * @return {?} */ SessionService.prototype.logoutError = /** * @param {?} response * @return {?} */ function (response) { this.clearSession(); _super.prototype.emitToApp.call(this, new model.AppEvent(model.AppEvent.LOGOUT_FAILED)); }; /** * @param {?} permissions * @return {?} */ SessionService.prototype.setupPermissionMap = /** * @param {?} permissions * @return {?} */ function (permissions) { var /** @type {?} */ map = new Map(); permissions.forEach(function (p) { return map.set(p, true); }); return map; }; /** * @param {?} event * @return {?} */ SessionService.prototype.onInvalidToken = /** * @param {?} event * @return {?} */ function (event) { this.clearSession(); }; SessionService.decorators = [ { type: core.Injectable }, ]; /** @nocollapse */ SessionService.ctorParameters = function () { return [ { type: EventBusService, }, { type: HttpService, }, ]; }; return SessionService; }(AbstractSubscriber)); //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ var HpeServiceModule = (function () { function HpeServiceModule() { } HpeServiceModule.decorators = [ { type: core.NgModule, args: [{ imports: [ common.CommonModule ], declarations: [], exports: [], providers: [ ApplicationService, EventBusService, HttpService, LabelService, NotificationService, SessionService, api.MessageService ], },] }, ]; return HpeServiceModule; }()); //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ //============================================================================= /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ exports.HpeServiceModule = HpeServiceModule; exports.AbstractSubscriber = AbstractSubscriber; exports.ApplicationService = ApplicationService; exports.EventBusService = EventBusService; exports.HttpService = HttpService; exports.LabelService = LabelService; exports.NotificationService = NotificationService; exports.SessionService = SessionService; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHBlLWFuZ3VsYXItdG9vbGtpdC1zZXJ2aWNlLnVtZC5qcy5tYXAiLCJzb3VyY2VzIjpbbnVsbCwibmc6Ly9AaHBlL2FuZ3VsYXItdG9vbGtpdC9zZXJ2aWNlL2Fic3RyYWN0LXN1YnNjcmliZXIudHMiLCJuZzovL0BocGUvYW5ndWxhci10b29sa2l0L3NlcnZpY2UvZXZlbnRidXMtc2VydmljZS50cyIsIm5nOi8vQGhwZS9hbmd1bGFyLXRvb2xraXQvc2VydmljZS9hcHBsaWNhdGlvbi1zZXJ2aWNlLnRzIiwibmc6Ly9AaHBlL2FuZ3VsYXItdG9vbGtpdC9zZXJ2aWNlL2h0dHAtc2VydmljZS50cyIsIm5nOi8vQGhwZS9hbmd1bGFyLXRvb2xraXQvc2VydmljZS9sYWJlbC1zZXJ2aWNlLnRzIiwibmc6Ly9AaHBlL2FuZ3VsYXItdG9vbGtpdC9zZXJ2aWNlL25vdGlmaWNhdGlvbi1zZXJ2aWNlLnRzIiwibmc6Ly9AaHBlL2FuZ3VsYXItdG9vbGtpdC9zZXJ2aWNlL3Nlc3Npb24tc2VydmljZS50cyIsIm5nOi8vQGhwZS9hbmd1bGFyLXRvb2xraXQvc2VydmljZS9tb2R1bGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyohICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbkNvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxyXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpOyB5b3UgbWF5IG5vdCB1c2VcclxudGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGVcclxuTGljZW5zZSBhdCBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcclxuXHJcblRISVMgQ09ERSBJUyBQUk9WSURFRCBPTiBBTiAqQVMgSVMqIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTllcclxuS0lORCwgRUlUSEVSIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIFdJVEhPVVQgTElNSVRBVElPTiBBTlkgSU1QTElFRFxyXG5XQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgVElUTEUsIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLFxyXG5NRVJDSEFOVEFCTElUWSBPUiBOT04tSU5GUklOR0VNRU5ULlxyXG5cclxuU2VlIHRoZSBBcGFjaGUgVmVyc2lvbiAyLjAgTGljZW5zZSBmb3Igc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zXHJcbmFuZCBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogKi9cclxuLyogZ2xvYmFsIFJlZmxlY3QsIFByb21pc2UgKi9cclxuXHJcbnZhciBleHRlbmRTdGF0aWNzID0gZnVuY3Rpb24oZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyA9IE9iamVjdC5zZXRQcm90b3R5cGVPZiB8fFxyXG4gICAgICAgICh7IF9fcHJvdG9fXzogW10gfSBpbnN0YW5jZW9mIEFycmF5ICYmIGZ1bmN0aW9uIChkLCBiKSB7IGQuX19wcm90b19fID0gYjsgfSkgfHxcclxuICAgICAgICBmdW5jdGlvbiAoZCwgYikgeyBmb3IgKHZhciBwIGluIGIpIGlmIChiLmhhc093blByb3BlcnR5KHApKSBkW3BdID0gYltwXTsgfTtcclxuICAgIHJldHVybiBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG4gICAgZnVuY3Rpb24gX18oKSB7IHRoaXMuY29uc3RydWN0b3IgPSBkOyB9XHJcbiAgICBkLnByb3RvdHlwZSA9IGIgPT09IG51bGwgPyBPYmplY3QuY3JlYXRlKGIpIDogKF9fLnByb3RvdHlwZSA9IGIucHJvdG90eXBlLCBuZXcgX18oKSk7XHJcbn1cclxuXHJcbmV4cG9ydCB2YXIgX19hc3NpZ24gPSBmdW5jdGlvbigpIHtcclxuICAgIF9fYXNzaWduID0gT2JqZWN0LmFzc2lnbiB8fCBmdW5jdGlvbiBfX2Fzc2lnbih0KSB7XHJcbiAgICAgICAgZm9yICh2YXIgcywgaSA9IDEsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XHJcbiAgICAgICAgICAgIHMgPSBhcmd1bWVudHNbaV07XHJcbiAgICAgICAgICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSkgdFtwXSA9IHNbcF07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0O1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3Jlc3QocywgZSkge1xyXG4gICAgdmFyIHQgPSB7fTtcclxuICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKVxyXG4gICAgICAgIHRbcF0gPSBzW3BdO1xyXG4gICAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKVxyXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBwID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhzKTsgaSA8IHAubGVuZ3RoOyBpKyspIGlmIChlLmluZGV4T2YocFtpXSkgPCAwKVxyXG4gICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgIHJldHVybiB0O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYykge1xyXG4gICAgdmFyIGMgPSBhcmd1bWVudHMubGVuZ3RoLCByID0gYyA8IDMgPyB0YXJnZXQgOiBkZXNjID09PSBudWxsID8gZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBrZXkpIDogZGVzYywgZDtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSA9PT0gXCJmdW5jdGlvblwiKSByID0gUmVmbGVjdC5kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYyk7XHJcbiAgICBlbHNlIGZvciAodmFyIGkgPSBkZWNvcmF0b3JzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSBpZiAoZCA9IGRlY29yYXRvcnNbaV0pIHIgPSAoYyA8IDMgPyBkKHIpIDogYyA+IDMgPyBkKHRhcmdldCwga2V5LCByKSA6IGQodGFyZ2V0LCBrZXkpKSB8fCByO1xyXG4gICAgcmV0dXJuIGMgPiAzICYmIHIgJiYgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwga2V5LCByKSwgcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcGFyYW0ocGFyYW1JbmRleCwgZGVjb3JhdG9yKSB7XHJcbiAgICByZXR1cm4gZnVuY3Rpb24gKHRhcmdldCwga2V5KSB7IGRlY29yYXRvcih0YXJnZXQsIGtleSwgcGFyYW1JbmRleCk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fbWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpIHtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5tZXRhZGF0YSA9PT0gXCJmdW5jdGlvblwiKSByZXR1cm4gUmVmbGVjdC5tZXRhZGF0YShtZXRhZGF0YUtleSwgbWV0YWRhdGFWYWx1ZSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0ZXIodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHJlc3VsdC52YWx1ZSk7IH0pLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZ2VuZXJhdG9yKHRoaXNBcmcsIGJvZHkpIHtcclxuICAgIHZhciBfID0geyBsYWJlbDogMCwgc2VudDogZnVuY3Rpb24oKSB7IGlmICh0WzBdICYgMSkgdGhyb3cgdFsxXTsgcmV0dXJuIHRbMV07IH0sIHRyeXM6IFtdLCBvcHM6IFtdIH0sIGYsIHksIHQsIGc7XHJcbiAgICByZXR1cm4gZyA9IHsgbmV4dDogdmVyYigwKSwgXCJ0aHJvd1wiOiB2ZXJiKDEpLCBcInJldHVyblwiOiB2ZXJiKDIpIH0sIHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiAoZ1tTeW1ib2wuaXRlcmF0b3JdID0gZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzOyB9KSwgZztcclxuICAgIGZ1bmN0aW9uIHZlcmIobikgeyByZXR1cm4gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIHN0ZXAoW24sIHZdKTsgfTsgfVxyXG4gICAgZnVuY3Rpb24gc3RlcChvcCkge1xyXG4gICAgICAgIGlmIChmKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLlwiKTtcclxuICAgICAgICB3aGlsZSAoXykgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKGYgPSAxLCB5ICYmICh0ID0gb3BbMF0gJiAyID8geVtcInJldHVyblwiXSA6IG9wWzBdID8geVtcInRocm93XCJdIHx8ICgodCA9IHlbXCJyZXR1cm5cIl0pICYmIHQuY2FsbCh5KSwgMCkgOiB5Lm5leHQpICYmICEodCA9IHQuY2FsbCh5LCBvcFsxXSkpLmRvbmUpIHJldHVybiB0O1xyXG4gICAgICAgICAgICBpZiAoeSA9IDAsIHQpIG9wID0gW29wWzBdICYgMiwgdC52YWx1ZV07XHJcbiAgICAgICAgICAgIHN3aXRjaCAob3BbMF0pIHtcclxuICAgICAgICAgICAgICAgIGNhc2UgMDogY2FzZSAxOiB0ID0gb3A7IGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSA0OiBfLmxhYmVsKys7IHJldHVybiB7IHZhbHVlOiBvcFsxXSwgZG9uZTogZmFsc2UgfTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNTogXy5sYWJlbCsrOyB5ID0gb3BbMV07IG9wID0gWzBdOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNzogb3AgPSBfLm9wcy5wb3AoKTsgXy50cnlzLnBvcCgpOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEodCA9IF8udHJ5cywgdCA9IHQubGVuZ3RoID4gMCAmJiB0W3QubGVuZ3RoIC0gMV0pICYmIChvcFswXSA9PT0gNiB8fCBvcFswXSA9PT0gMikpIHsgXyA9IDA7IGNvbnRpbnVlOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSAzICYmICghdCB8fCAob3BbMV0gPiB0WzBdICYmIG9wWzFdIDwgdFszXSkpKSB7IF8ubGFiZWwgPSBvcFsxXTsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAob3BbMF0gPT09IDYgJiYgXy5sYWJlbCA8IHRbMV0pIHsgXy5sYWJlbCA9IHRbMV07IHQgPSBvcDsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAodCAmJiBfLmxhYmVsIDwgdFsyXSkgeyBfLmxhYmVsID0gdFsyXTsgXy5vcHMucHVzaChvcCk7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRbMl0pIF8ub3BzLnBvcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgb3AgPSBib2R5LmNhbGwodGhpc0FyZywgXyk7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkgeyBvcCA9IFs2LCBlXTsgeSA9IDA7IH0gZmluYWxseSB7IGYgPSB0ID0gMDsgfVxyXG4gICAgICAgIGlmIChvcFswXSAmIDUpIHRocm93IG9wWzFdOyByZXR1cm4geyB2YWx1ZTogb3BbMF0gPyBvcFsxXSA6IHZvaWQgMCwgZG9uZTogdHJ1ZSB9O1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19leHBvcnRTdGFyKG0sIGV4cG9ydHMpIHtcclxuICAgIGZvciAodmFyIHAgaW4gbSkgaWYgKCFleHBvcnRzLmhhc093blByb3BlcnR5KHApKSBleHBvcnRzW3BdID0gbVtwXTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fdmFsdWVzKG8pIHtcclxuICAgIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9bU3ltYm9sLml0ZXJhdG9yXSwgaSA9IDA7XHJcbiAgICBpZiAobSkgcmV0dXJuIG0uY2FsbChvKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgICAgbmV4dDogZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAobyAmJiBpID49IG8ubGVuZ3RoKSBvID0gdm9pZCAwO1xyXG4gICAgICAgICAgICByZXR1cm4geyB2YWx1ZTogbyAmJiBvW2krK10sIGRvbmU6ICFvIH07XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVhZChvLCBuKSB7XHJcbiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl07XHJcbiAgICBpZiAoIW0pIHJldHVybiBvO1xyXG4gICAgdmFyIGkgPSBtLmNhbGwobyksIHIsIGFyID0gW10sIGU7XHJcbiAgICB0cnkge1xyXG4gICAgICAgIHdoaWxlICgobiA9PT0gdm9pZCAwIHx8IG4tLSA+IDApICYmICEociA9IGkubmV4dCgpKS5kb25lKSBhci5wdXNoKHIudmFsdWUpO1xyXG4gICAgfVxyXG4gICAgY2F0Y2ggKGVycm9yKSB7IGUgPSB7IGVycm9yOiBlcnJvciB9OyB9XHJcbiAgICBmaW5hbGx5IHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBpZiAociAmJiAhci5kb25lICYmIChtID0gaVtcInJldHVyblwiXSkpIG0uY2FsbChpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZmluYWxseSB7IGlmIChlKSB0aHJvdyBlLmVycm9yOyB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gYXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3NwcmVhZCgpIHtcclxuICAgIGZvciAodmFyIGFyID0gW10sIGkgPSAwOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIGFyID0gYXIuY29uY2F0KF9fcmVhZChhcmd1bWVudHNbaV0pKTtcclxuICAgIHJldHVybiBhcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fYXdhaXQodikge1xyXG4gICAgcmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBfX2F3YWl0ID8gKHRoaXMudiA9IHYsIHRoaXMpIDogbmV3IF9fYXdhaXQodik7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2FzeW5jR2VuZXJhdG9yKHRoaXNBcmcsIF9hcmd1bWVudHMsIGdlbmVyYXRvcikge1xyXG4gICAgaWYgKCFTeW1ib2wuYXN5bmNJdGVyYXRvcikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLlwiKTtcclxuICAgIHZhciBnID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pLCBpLCBxID0gW107XHJcbiAgICByZXR1cm4gaSA9IHt9LCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIpLCB2ZXJiKFwicmV0dXJuXCIpLCBpW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXM7IH0sIGk7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4pIHsgaWYgKGdbbl0pIGlbbl0gPSBmdW5jdGlvbiAodikgeyByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKGEsIGIpIHsgcS5wdXNoKFtuLCB2LCBhLCBiXSkgPiAxIHx8IHJlc3VtZShuLCB2KTsgfSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHJlc3VtZShuLCB2KSB7IHRyeSB7IHN0ZXAoZ1tuXSh2KSk7IH0gY2F0Y2ggKGUpIHsgc2V0dGxlKHFbMF1bM10sIGUpOyB9IH1cclxuICAgIGZ1bmN0aW9uIHN0ZXAocikgeyByLnZhbHVlIGluc3RhbmNlb2YgX19hd2FpdCA/IFByb21pc2UucmVzb2x2ZShyLnZhbHVlLnYpLnRoZW4oZnVsZmlsbCwgcmVqZWN0KSA6IHNldHRsZShxWzBdWzJdLCByKTsgfVxyXG4gICAgZnVuY3Rpb24gZnVsZmlsbCh2YWx1ZSkgeyByZXN1bWUoXCJuZXh0XCIsIHZhbHVlKTsgfVxyXG4gICAgZnVuY3Rpb24gcmVqZWN0KHZhbHVlKSB7IHJlc3VtZShcInRocm93XCIsIHZhbHVlKTsgfVxyXG4gICAgZnVuY3Rpb24gc2V0dGxlKGYsIHYpIHsgaWYgKGYodiksIHEuc2hpZnQoKSwgcS5sZW5ndGgpIHJlc3VtZShxWzBdWzBdLCBxWzBdWzFdKTsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY0RlbGVnYXRvcihvKSB7XHJcbiAgICB2YXIgaSwgcDtcclxuICAgIHJldHVybiBpID0ge30sIHZlcmIoXCJuZXh0XCIpLCB2ZXJiKFwidGhyb3dcIiwgZnVuY3Rpb24gKGUpIHsgdGhyb3cgZTsgfSksIHZlcmIoXCJyZXR1cm5cIiksIGlbU3ltYm9sLml0ZXJhdG9yXSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXM7IH0sIGk7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4sIGYpIHsgaVtuXSA9IG9bbl0gPyBmdW5jdGlvbiAodikgeyByZXR1cm4gKHAgPSAhcCkgPyB7IHZhbHVlOiBfX2F3YWl0KG9bbl0odikpLCBkb25lOiBuID09PSBcInJldHVyblwiIH0gOiBmID8gZih2KSA6IHY7IH0gOiBmOyB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2FzeW5jVmFsdWVzKG8pIHtcclxuICAgIGlmICghU3ltYm9sLmFzeW5jSXRlcmF0b3IpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC5cIik7XHJcbiAgICB2YXIgbSA9IG9bU3ltYm9sLmFzeW5jSXRlcmF0b3JdLCBpO1xyXG4gICAgcmV0dXJuIG0gPyBtLmNhbGwobykgOiAobyA9IHR5cGVvZiBfX3ZhbHVlcyA9PT0gXCJmdW5jdGlvblwiID8gX192YWx1ZXMobykgOiBvW1N5bWJvbC5pdGVyYXRvcl0oKSwgaSA9IHt9LCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIpLCB2ZXJiKFwicmV0dXJuXCIpLCBpW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXM7IH0sIGkpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuKSB7IGlbbl0gPSBvW25dICYmIGZ1bmN0aW9uICh2KSB7IHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7IHYgPSBvW25dKHYpLCBzZXR0bGUocmVzb2x2ZSwgcmVqZWN0LCB2LmRvbmUsIHYudmFsdWUpOyB9KTsgfTsgfVxyXG4gICAgZnVuY3Rpb24gc2V0dGxlKHJlc29sdmUsIHJlamVjdCwgZCwgdikgeyBQcm9taXNlLnJlc29sdmUodikudGhlbihmdW5jdGlvbih2KSB7IHJlc29sdmUoeyB2YWx1ZTogdiwgZG9uZTogZCB9KTsgfSwgcmVqZWN0KTsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19tYWtlVGVtcGxhdGVPYmplY3QoY29va2VkLCByYXcpIHtcclxuICAgIGlmIChPYmplY3QuZGVmaW5lUHJvcGVydHkpIHsgT2JqZWN0LmRlZmluZVByb3BlcnR5KGNvb2tlZCwgXCJyYXdcIiwgeyB2YWx1ZTogcmF3IH0pOyB9IGVsc2UgeyBjb29rZWQucmF3ID0gcmF3OyB9XHJcbiAgICByZXR1cm4gY29va2VkO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9faW1wb3J0U3Rhcihtb2QpIHtcclxuICAgIGlmIChtb2QgJiYgbW9kLl9fZXNNb2R1bGUpIHJldHVybiBtb2Q7XHJcbiAgICB2YXIgcmVzdWx0ID0ge307XHJcbiAgICBpZiAobW9kICE9IG51bGwpIGZvciAodmFyIGsgaW4gbW9kKSBpZiAoT2JqZWN0Lmhhc093blByb3BlcnR5LmNhbGwobW9kLCBrKSkgcmVzdWx0W2tdID0gbW9kW2tdO1xyXG4gICAgcmVzdWx0LmRlZmF1bHQgPSBtb2Q7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19pbXBvcnREZWZhdWx0KG1vZCkge1xyXG4gICAgcmV0dXJuIChtb2QgJiYgbW9kLl9fZXNNb2R1bGUpID8gbW9kIDogeyBkZWZhdWx0OiBtb2QgfTtcclxufVxyXG4iLCIvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLz09PVxuLy89PT0gKEMpIENvcHlyaWdodCAyMDE4IEhld2xldHQgUGFja2FyZCBFbnRlcnByaXNlIERldmVsb3BtZW50IExQLlxuLy89PT1cbi8vPT09IFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4vLz09PSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlXG4vLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmltcG9ydCB7T25EZXN0cm95fSAgICBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHtTdWJzY3JpcHRpb259IGZyb20gXCJyeGpzXCI7XG5cbmltcG9ydCB7RXZlbnRIYW5kbGVyLCBFcnJvckhhbmRsZXIsIEFwcEV2ZW50LCBFcnJvckV2ZW50fSBmcm9tIFwiQGhwZS9hbmd1bGFyLXRvb2xraXQvbW9kZWxcIjtcblxuaW1wb3J0IHtFdmVudEJ1c1NlcnZpY2V9IGZyb20gXCIuL2V2ZW50YnVzLXNlcnZpY2VcIjtcblxuLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgY2xhc3MgQWJzdHJhY3RTdWJzY3JpYmVyIGltcGxlbWVudHMgT25EZXN0cm95IHtcblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8tLS1cblx0Ly8tLS0gVmFyaWFibGVzXG5cdC8vLS0tXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHByaXZhdGUgc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW10gPSBbXTtcblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8tLS1cblx0Ly8tLS0gQ29uc3RydWN0b3Jcblx0Ly8tLS1cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0Y29uc3RydWN0b3IocHJpdmF0ZSBldmVudEJ1c1NlcnZpY2UgOiBFdmVudEJ1c1NlcnZpY2UpIHt9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIExpZmVjeWNsZSBtZXRob2RzXG5cdC8vLS0tXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHB1YmxpYyBuZ09uRGVzdHJveSgpIHtcblx0XHR0aGlzLnN1YnNjcmlwdGlvbnMuZm9yRWFjaCggKHMgOiBTdWJzY3JpcHRpb24pID0+IHMudW5zdWJzY3JpYmUoKSk7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8tLS1cblx0Ly8tLS0gQVBJIG1ldGhvZHNcblx0Ly8tLS