UNPKG

ngx-paypal-with-intent

Version:

Paypal integration for Angular 6, 7 and beyond

408 lines 44.4 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ import { ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild, } from '@angular/core'; import { interval, Subject } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; import { PayPalFunding } from '../models/paypal-funding'; import { PayPalIntegrationType } from '../models/paypal-integration'; import { PayPalConfig } from '../models/paypal-models'; export class NgxPaypalComponent { constructor() { /** * Indicates if global configuration (provided via 'forRoot') is used */ this.useGlobalConfig = false; /** * Used for indicating delayed rendered if container is not yet ready in DOM */ this.registerPayPalScriptWhenContainerIsReady = false; /** * Polling interval if paypal script is pending */ this.defaultPollInterval = 50; /** * Polling will stop after polling reaches this number */ this.maximumPollWaitTime = 5000; /** * Name of the global variable where paypal is stored */ this.paypalWindowName = 'paypal'; /** * Name of the global variable indicating that script was initiated (added to page) */ this.paypalWindowScriptInitiated = 'ngx-paypal-script-initiated'; /** * PayPal integration script url */ this.paypalScriptUrl = 'https://www.paypalobjects.com/api/checkout.js'; this.payPalButtonContainerIdPrefix = 'ngx-paypal-button-container-'; this.ngUnsubscribe = new Subject(); } /** * @param {?} content * @return {?} */ set payPalButtonContainerElem(content) { if (content) { this._payPalButtonContainerElem = content; } } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { // init when config once its available if (this.config) { this.initPayPal(); } } /** * @return {?} */ ngAfterViewInit() { // register script if element is ready in dom if (this.registerPayPalScriptWhenContainerIsReady && this._payPalButtonContainerElem) { this.setupScript(); this.registerPayPalScriptWhenContainerIsReady = false; } } /** * @return {?} */ ngOnDestroy() { this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); } /** * @return {?} */ initPayPal() { // set unique paypal container button id this.payPalButtonContainerId = `${this.payPalButtonContainerIdPrefix}${this.getPseudoUniqueNumber()}`; // check if paypal was already register and if so, don't add it to page again if (!window[this.paypalWindowName]) { // check if script is pending if (window[this.paypalWindowScriptInitiated] === true) { this.pollUntilScriptAvailable(); } else { // register script and set global flag window[this.paypalWindowScriptInitiated] = true; this.addPayPalScriptToPage(); } } else { // just register payment this.handleScriptRegistering(); } } /** * @return {?} */ getPseudoUniqueNumber() { return new Date().valueOf(); } /** * Used when there are multiple paypal components on the same page beacuse only 1 of them * may register paypal script. The other has to be polling until paypal is available or component destroyed * @return {?} */ pollUntilScriptAvailable() { /** @type {?} */ const obs = interval(this.defaultPollInterval) .pipe(takeUntil(this.ngUnsubscribe), map((x) => { if (x >= this.maximumPollWaitTime) { console.warn(`PayPal script was not loaded after '${this.maximumPollWaitTime}' maximum polling time.`); obs.unsubscribe(); return; } // check if paypal script exists if (window[this.paypalWindowName]) { // register script this.handleScriptRegistering(); // stop execution obs.unsubscribe(); } })) .subscribe(); } /** * @return {?} */ addPayPalScriptToPage() { /** @type {?} */ const script = document.createElement('script'); script.innerHTML = ''; script.src = this.paypalScriptUrl; script.onload = () => this.handleScriptRegistering(); script.async = true; script.defer = true; this.paypalScriptElem.nativeElement.appendChild(script); } /** * @return {?} */ handleScriptRegistering() { // check if container with requested id exists // this is here because dynamically switching between components would cause PayPal to // throw an error if the container already existed before if (this._payPalButtonContainerElem && this._payPalButtonContainerElem.nativeElement && this._payPalButtonContainerElem.nativeElement.id === this.payPalButtonContainerId) { // container is ready, setup script right away this.setupScript(); } else { // container is not ready, delay registering until it is this.registerPayPalScriptWhenContainerIsReady = true; } } /** * @return {?} */ setupScript() { // first clear container if (!this._payPalButtonContainerElem) { throw Error(`Cannot setup script because paypal button container with id '${this.payPalButtonContainerId}' is not yet ready`); } this._payPalButtonContainerElem.nativeElement.innerHTML = ''; if (!window[this.paypalWindowName]) { throw Error('PayPal script is not available'); } // render PayPal button as per their docs at // https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/add-paypal-button/ window[this.paypalWindowName].Button.render({ // set environment env: this.config.environment.toString(), // Show the buyer a 'Pay Now' button in the checkout flow commit: this.config.commit, // init client for client side integration client: this.getClient(), // set button config if available style: this.config.button, // set funding if available funding: this.getFunding(), // payment() is called when the button is clicked payment: (data, actions) => { if (this.config.integrationType === PayPalIntegrationType.ServerSideREST) { // client needs to create payment on server side if (!this.config.payment) { throw Error(`You need set up a create payment method and return PayPal's payment id when using server side integration`); } // Paypal expects promise with payment id (string) to be returned return this.config.payment().toPromise() .then(paymentId => { return paymentId; }); } if (this.config.integrationType === PayPalIntegrationType.ClientSideREST) { if (!this.config.transactions || !Array.isArray(this.config.transactions) || this.config.transactions.length <= 0) { throw Error(`You need to provide at least 1 transaction for client side integration`); } /** @type {?} */ const experienceConfig = this.config.experience; return actions.payment.create({ payment: { // Allow user to specifify intent, else use default 'sale'. intent: this.config.intent ? this.config.intent : 'sale', transactions: this.config.transactions }, experience: { input_fields: { no_shipping: (experienceConfig && experienceConfig.noShipping) ? 1 : 0 }, presentation: { brand_name: (experienceConfig && experienceConfig.brandName) ? experienceConfig.brandName : null, logo_image: (experienceConfig && experienceConfig.logoImage) ? experienceConfig.logoImage : null, locale_code: (experienceConfig && experienceConfig.localeCode) ? experienceConfig.localeCode : null } } }); } }, // onAuthorize() is called when the buyer approves the payment onAuthorize: (data, actions) => { if (this.config.integrationType === PayPalIntegrationType.ServerSideREST) { // client needs to server to execute the payment if (!this.config.onAuthorize) { throw Error(`You need set up an execute method when using server side integration`); } // Paypal expects promise return this.config.onAuthorize(data, actions).toPromise(); } if (this.config.integrationType === PayPalIntegrationType.ClientSideREST) { // Make a call to the REST api to execute the payment return actions.payment.execute().then(() => { if (!this.config.onPaymentComplete) { throw Error(`You should provide some callback when payment is finished when using client side integration`); } this.config.onPaymentComplete(data, actions); }); } }, onError: (err) => { if (this.config.onError) { this.config.onError(err); } }, onCancel: (data, actions) => { if (this.config.onCancel) { this.config.onCancel(data, actions); } }, onClick: () => { if (this.config.onClick) { this.config.onClick(); } }, validate: (actions) => { if (this.config.validate) { this.config.validate(actions); } } }, `#${this.payPalButtonContainerId}`); } /** * @return {?} */ getClient() { if (this.config.integrationType === PayPalIntegrationType.ClientSideREST) { if (!this.config.client) { throw Error(`You need to setup client information when using client side integration`); } return { production: this.config.client.production, sandbox: this.config.client.sandbox }; } return undefined; } /** * @return {?} */ getFunding() { // resolve funding to use paypal's properties if (!this.config.funding) { // no funding provided return undefined; } /** @type {?} */ const allowed = []; /** @type {?} */ const disallowed = []; if (this.config.funding.allowed) { this.config.funding.allowed.forEach(type => { allowed.push(this.mapFundingType(type)); }); } if (this.config.funding.disallowed) { this.config.funding.disallowed.forEach(type => { disallowed.push(this.mapFundingType(type)); }); } return { allowed: allowed, disallowed: disallowed }; } /** * @param {?} type * @return {?} */ mapFundingType(type) { if (type === PayPalFunding.Card) { return paypal.FUNDING.CARD; } if (type === PayPalFunding.Credit) { return paypal.FUNDING.CREDIT; } if (type === PayPalFunding.Elv) { return paypal.FUNDING.ELV; } throw Error(`Unsupported funding type '${type}'`); } } NgxPaypalComponent.decorators = [ { type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngx-paypal', template: ` <div #payPalScriptElem></div> <div #payPalButtonContainerElem [id]="payPalButtonContainerId"></div> ` }] } ]; /** @nocollapse */ NgxPaypalComponent.ctorParameters = () => []; NgxPaypalComponent.propDecorators = { config: [{ type: Input }], useGlobalConfig: [{ type: Input }], paypalScriptElem: [{ type: ViewChild, args: ['payPalScriptElem',] }], payPalButtonContainerElem: [{ type: ViewChild, args: ['payPalButtonContainerElem',] }] }; if (false) { /** * Configuration for paypal. * @type {?} */ NgxPaypalComponent.prototype.config; /** * Indicates if global configuration (provided via 'forRoot') is used * @type {?} */ NgxPaypalComponent.prototype.useGlobalConfig; /** * Container for paypal script * @type {?} */ NgxPaypalComponent.prototype.paypalScriptElem; /** * Used for indicating delayed rendered if container is not yet ready in DOM * @type {?} */ NgxPaypalComponent.prototype.registerPayPalScriptWhenContainerIsReady; /** * Holds current container element * @type {?} */ NgxPaypalComponent.prototype._payPalButtonContainerElem; /** * Polling interval if paypal script is pending * @type {?} */ NgxPaypalComponent.prototype.defaultPollInterval; /** * Polling will stop after polling reaches this number * @type {?} */ NgxPaypalComponent.prototype.maximumPollWaitTime; /** * Name of the global variable where paypal is stored * @type {?} */ NgxPaypalComponent.prototype.paypalWindowName; /** * Name of the global variable indicating that script was initiated (added to page) * @type {?} */ NgxPaypalComponent.prototype.paypalWindowScriptInitiated; /** * PayPal integration script url * @type {?} */ NgxPaypalComponent.prototype.paypalScriptUrl; /** * Id of the element where PayPal button will be rendered * @type {?} */ NgxPaypalComponent.prototype.payPalButtonContainerId; /** @type {?} */ NgxPaypalComponent.prototype.payPalButtonContainerIdPrefix; /** @type {?} */ NgxPaypalComponent.prototype.ngUnsubscribe; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF5cGFsLWNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25neC1wYXlwYWwtd2l0aC1pbnRlbnQvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50cy9wYXlwYWwtY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBRUgsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxVQUFVLEVBQ1YsS0FBSyxFQUlMLFNBQVMsR0FDWixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN6QyxPQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRWhELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNyRSxPQUFPLEVBQTZDLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBZWxHLE1BQU0sT0FBTyxrQkFBa0I7SUFrRTNCOzs7O1FBeERTLG9CQUFlLEdBQUcsS0FBSyxDQUFDOzs7O1FBVXpCLDZDQUF3QyxHQUFHLEtBQUssQ0FBQzs7OztRQWV4Qyx3QkFBbUIsR0FBRyxFQUFFLENBQUM7Ozs7UUFLekIsd0JBQW1CLEdBQUcsSUFBSSxDQUFDOzs7O1FBSzNCLHFCQUFnQixHQUFHLFFBQVEsQ0FBQzs7OztRQUs1QixnQ0FBMkIsR0FBRyw2QkFBNkIsQ0FBQzs7OztRQUs1RCxvQkFBZSxHQUFHLCtDQUErQyxDQUFDO1FBT2xFLGtDQUE2QixHQUFHLDhCQUE4QixDQUFDO1FBRS9ELGtCQUFhLEdBQWtCLElBQUksT0FBTyxFQUFRLENBQUM7SUFJcEUsQ0FBQzs7Ozs7SUExQ0QsSUFBNEMseUJBQXlCLENBQUMsT0FBbUI7UUFDckYsSUFBSSxPQUFPLEVBQUU7WUFDVCxJQUFJLENBQUMsMEJBQTBCLEdBQUcsT0FBTyxDQUFD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dGVjdGlvblN0cmF0ZWd5LFxuICAgIENvbXBvbmVudCxcbiAgICBFbGVtZW50UmVmLFxuICAgIElucHV0LFxuICAgIE9uQ2hhbmdlcyxcbiAgICBPbkRlc3Ryb3ksXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBWaWV3Q2hpbGQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaW50ZXJ2YWwsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBQYXlQYWxGdW5kaW5nIH0gZnJvbSAnLi4vbW9kZWxzL3BheXBhbC1mdW5kaW5nJztcbmltcG9ydCB7IFBheVBhbEludGVncmF0aW9uVHlwZSB9IGZyb20gJy4uL21vZGVscy9wYXlwYWwtaW50ZWdyYXRpb24nO1xuaW1wb3J0IHsgSVBheXBhbENsaWVudCwgSVBheVBhbFBheW1lbnRDb21wbGV0ZURhdGEsIFBheVBhbENvbmZpZyB9IGZyb20gJy4uL21vZGVscy9wYXlwYWwtbW9kZWxzJztcblxuLyoqXG4gKiBHbG9iYWwgdmFyaWFibGUgd2hlcmUgUGF5UGFsIGlzIGxvYWRlZCB0b1xuICovXG5kZWNsYXJlIHZhciBwYXlwYWw6IGFueTtcblxuQENvbXBvbmVudCh7XG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gICAgc2VsZWN0b3I6ICduZ3gtcGF5cGFsJyxcbiAgICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgI3BheVBhbFNjcmlwdEVsZW0+PC9kaXY+XG4gICAgPGRpdiAjcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbSBbaWRdPVwicGF5UGFsQnV0dG9uQ29udGFpbmVySWRcIj48L2Rpdj5cbiAgICBgXG59KVxuZXhwb3J0IGNsYXNzIE5neFBheXBhbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcblxuICAgIC8qKlxuICAgICAqIENvbmZpZ3VyYXRpb24gZm9yIHBheXBhbC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBjb25maWc6IFBheVBhbENvbmZpZztcblxuICAgIC8qKlxuICAgICAqIEluZGljYXRlcyBpZiBnbG9iYWwgY29uZmlndXJhdGlvbiAocHJvdmlkZWQgdmlhICdmb3JSb290JykgaXMgdXNlZFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHVzZUdsb2JhbENvbmZpZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogQ29udGFpbmVyIGZvciBwYXlwYWwgc2NyaXB0XG4gICAgICovXG4gICAgQFZpZXdDaGlsZCgncGF5UGFsU2NyaXB0RWxlbScpIHBheXBhbFNjcmlwdEVsZW06IEVsZW1lbnRSZWY7XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIGZvciBpbmRpY2F0aW5nIGRlbGF5ZWQgcmVuZGVyZWQgaWYgY29udGFpbmVyIGlzIG5vdCB5ZXQgcmVhZHkgaW4gRE9NXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWdpc3RlclBheVBhbFNjcmlwdFdoZW5Db250YWluZXJJc1JlYWR5ID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBIb2xkcyBjdXJyZW50IGNvbnRhaW5lciBlbGVtZW50XG4gICAgICovXG4gICAgcHJpdmF0ZSBfcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbT86IEVsZW1lbnRSZWY7XG4gICAgQFZpZXdDaGlsZCgncGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbScpIHNldCBwYXlQYWxCdXR0b25Db250YWluZXJFbGVtKGNvbnRlbnQ6IEVsZW1lbnRSZWYpIHtcbiAgICAgICAgaWYgKGNvbnRlbnQpIHtcbiAgICAgICAgICAgIHRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0gPSBjb250ZW50O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUG9sbGluZyBpbnRlcnZhbCBpZiBwYXlwYWwgc2NyaXB0IGlzIHBlbmRpbmdcbiAgICAgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IGRlZmF1bHRQb2xsSW50ZXJ2YWwgPSA1MDtcblxuICAgIC8qKlxuICAgICAqIFBvbGxpbmcgd2lsbCBzdG9wIGFmdGVyIHBvbGxpbmcgcmVhY2hlcyB0aGlzIG51bWJlclxuICAgICAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbWF4aW11bVBvbGxXYWl0VGltZSA9IDUwMDA7XG5cbiAgICAvKipcbiAgICAqIE5hbWUgb2YgdGhlIGdsb2JhbCB2YXJpYWJsZSB3aGVyZSBwYXlwYWwgaXMgc3RvcmVkXG4gICAgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IHBheXBhbFdpbmRvd05hbWUgPSAncGF5cGFsJztcblxuICAgIC8qKlxuICAgICAqIE5hbWUgb2YgdGhlIGdsb2JhbCB2YXJpYWJsZSBpbmRpY2F0aW5nIHRoYXQgc2NyaXB0IHdhcyBpbml0aWF0ZWQgKGFkZGVkIHRvIHBhZ2UpXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBwYXlwYWxXaW5kb3dTY3JpcHRJbml0aWF0ZWQgPSAnbmd4LXBheXBhbC1zY3JpcHQtaW5pdGlhdGVkJztcblxuICAgIC8qKlxuICAgICAqIFBheVBhbCBpbnRlZ3JhdGlvbiBzY3JpcHQgdXJsXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBwYXlwYWxTY3JpcHRVcmwgPSAnaHR0cHM6Ly93d3cucGF5cGFsb2JqZWN0cy5jb20vYXBpL2NoZWNrb3V0LmpzJztcblxuICAgIC8qKlxuICAgICAqIElkIG9mIHRoZSBlbGVtZW50IHdoZXJlIFBheVBhbCBidXR0b24gd2lsbCBiZSByZW5kZXJlZFxuICAgICAqL1xuICAgIHB1YmxpYyBwYXlQYWxCdXR0b25Db250YWluZXJJZD86IHN0cmluZztcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgcGF5UGFsQnV0dG9uQ29udGFpbmVySWRQcmVmaXggPSAnbmd4LXBheXBhbC1idXR0b24tY29udGFpbmVyLSc7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IG5nVW5zdWJzY3JpYmU6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgKSB7XG4gICAgfVxuXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgICAgICAvLyBpbml0IHdoZW4gY29uZmlnIG9uY2UgaXRzIGF2YWlsYWJsZVxuICAgICAgICBpZiAodGhpcy5jb25maWcpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdFBheVBhbCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICAvLyByZWdpc3RlciBzY3JpcHQgaWYgZWxlbWVudCBpcyByZWFkeSBpbiBkb21cbiAgICAgICAgaWYgKHRoaXMucmVnaXN0ZXJQYXlQYWxTY3JpcHRXaGVuQ29udGFpbmVySXNSZWFkeSAmJiB0aGlzLl9wYXlQYWxCdXR0b25Db250YWluZXJFbGVtKSB7XG4gICAgICAgICAgICB0aGlzLnNldHVwU2NyaXB0KCk7XG4gICAgICAgICAgICB0aGlzLnJlZ2lzdGVyUGF5UGFsU2NyaXB0V2hlbkNvbnRhaW5lcklzUmVhZHkgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLm5nVW5zdWJzY3JpYmUubmV4dCgpO1xuICAgICAgICB0aGlzLm5nVW5zdWJzY3JpYmUuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGluaXRQYXlQYWwoKTogdm9pZCB7XG4gICAgICAgIC8vIHNldCB1bmlxdWUgcGF5cGFsIGNvbnRhaW5lciBidXR0b24gaWRcbiAgICAgICAgdGhpcy5wYXlQYWxCdXR0b25Db250YWluZXJJZCA9IGAke3RoaXMucGF5UGFsQnV0dG9uQ29udGFpbmVySWRQcmVmaXh9JHt0aGlzLmdldFBzZXVkb1VuaXF1ZU51bWJlcigpfWA7XG4gICAgICAgIC8vIGNoZWNrIGlmIHBheXBhbCB3YXMgYWxyZWFkeSByZWdpc3RlciBhbmQgaWYgc28sIGRvbid0IGFkZCBpdCB0byBwYWdlIGFnYWluXG4gICAgICAgIGlmICghd2luZG93W3RoaXMucGF5cGFsV2luZG93TmFtZV0pIHtcbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIHNjcmlwdCBpcyBwZW5kaW5nXG4gICAgICAgICAgICBpZiAod2luZG93W3RoaXMucGF5cGFsV2luZG93U2NyaXB0SW5pdGlhdGVkXSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMucG9sbFVudGlsU2NyaXB0QXZhaWxhYmxlKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHJlZ2lzdGVyIHNjcmlwdCBhbmQgc2V0IGdsb2JhbCBmbGFnXG4gICAgICAgICAgICAgICAgd2luZG93W3RoaXMucGF5cGFsV2luZG93U2NyaXB0SW5pdGlhdGVkXSA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5hZGRQYXlQYWxTY3JpcHRUb1BhZ2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8ganVzdCByZWdpc3RlciBwYXltZW50XG4gICAgICAgICAgICB0aGlzLmhhbmRsZVNjcmlwdFJlZ2lzdGVyaW5nKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFBzZXVkb1VuaXF1ZU51bWJlcigpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gbmV3IERhdGUoKS52YWx1ZU9mKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXNlZCB3aGVuIHRoZXJlIGFyZSBtdWx0aXBsZSBwYXlwYWwgY29tcG9uZW50cyBvbiB0aGUgc2FtZSBwYWdlIGJlYWN1c2Ugb25seSAxIG9mIHRoZW1cbiAgICAgKiBtYXkgcmVnaXN0ZXIgcGF5cGFsIHNjcmlwdC4gVGhlIG90aGVyIGhhcyB0byBiZSBwb2xsaW5nIHVudGlsIHBheXBhbCBpcyBhdmFpbGFibGUgb3IgY29tcG9uZW50IGRlc3Ryb3llZFxuICAgICAqL1xuICAgIHByaXZhdGUgcG9sbFVudGlsU2NyaXB0QXZhaWxhYmxlKCk6IHZvaWQge1xuICAgICAgICBjb25zdCBvYnMgPSBpbnRlcnZhbCh0aGlzLmRlZmF1bHRQb2xsSW50ZXJ2YWwpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5uZ1Vuc3Vic2NyaWJlKSxcbiAgICAgICAgICAgICAgICBtYXAoKHgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHggPj0gdGhpcy5tYXhpbXVtUG9sbFdhaXRUaW1lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oYFBheVBhbCBzY3JpcHQgd2FzIG5vdCBsb2FkZWQgYWZ0ZXIgJyR7dGhpcy5tYXhpbXVtUG9sbFdhaXRUaW1lfScgbWF4aW11bSBwb2xsaW5nIHRpbWUuYCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBvYnMudW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIGNoZWNrIGlmIHBheXBhbCBzY3JpcHQgZXhpc3RzXG4gICAgICAgICAgICAgICAgICAgIGlmICh3aW5kb3dbdGhpcy5wYXlwYWxXaW5kb3dOYW1lXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVnaXN0ZXIgc2NyaXB0XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZVNjcmlwdFJlZ2lzdGVyaW5nKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0b3AgZXhlY3V0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICBvYnMudW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhZGRQYXlQYWxTY3JpcHRUb1BhZ2UoKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpO1xuICAgICAgICBzY3JpcHQuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIHNjcmlwdC5zcmMgPSB0aGlzLnBheXBhbFNjcmlwdFVybDtcbiAgICAgICAgc2NyaXB0Lm9ubG9hZCA9ICgpID0+IHRoaXMuaGFuZGxlU2NyaXB0UmVnaXN0ZXJpbmcoKTtcbiAgICAgICAgc2NyaXB0LmFzeW5jID0gdHJ1ZTtcbiAgICAgICAgc2NyaXB0LmRlZmVyID0gdHJ1ZTtcblxuICAgICAgICB0aGlzLnBheXBhbFNjcmlwdEVsZW0ubmF0aXZlRWxlbWVudC5hcHBlbmRDaGlsZChzY3JpcHQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaGFuZGxlU2NyaXB0UmVnaXN0ZXJpbmcoKTogdm9pZCB7XG4gICAgICAgIC8vIGNoZWNrIGlmIGNvbnRhaW5lciB3aXRoIHJlcXVlc3RlZCBpZCBleGlzdHNcbiAgICAgICAgLy8gdGhpcyBpcyBoZXJlIGJlY2F1c2UgZHluYW1pY2FsbHkgc3dpdGNoaW5nIGJldHdlZW4gY29tcG9uZW50cyB3b3VsZCBjYXVzZSBQYXlQYWwgdG9cbiAgICAgICAgLy8gdGhyb3cgYW4gZXJyb3IgaWYgdGhlIGNvbnRhaW5lciBhbHJlYWR5IGV4aXN0ZWQgYmVmb3JlXG4gICAgICAgIGlmICh0aGlzLl9wYXlQYWxCdXR0b25Db250YWluZXJFbGVtICYmIHRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0ubmF0aXZlRWxlbWVudCAmJlxuICAgICAgICAgICAgdGhpcy5fcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbS5uYXRpdmVFbGVtZW50LmlkID09PSB0aGlzLnBheVBhbEJ1dHRvbkNvbnRhaW5lcklkKSB7XG4gICAgICAgICAgICAvLyBjb250YWluZXIgaXMgcmVhZHksIHNldHVwIHNjcmlwdCByaWdodCBhd2F5XG4gICAgICAgICAgICB0aGlzLnNldHVwU2NyaXB0KCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBjb250YWluZXIgaXMgbm90IHJlYWR5LCBkZWxheSByZWdpc3RlcmluZyB1bnRpbCBpdCBpc1xuICAgICAgICAgICAgdGhpcy5yZWdpc3RlclBheVBhbFNjcmlwdFdoZW5Db250YWluZXJJc1JlYWR5ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgc2V0dXBTY3JpcHQoKTogdm9pZCB7XG4gICAgICAgIC8vIGZpcnN0IGNsZWFyIGNvbnRhaW5lclxuICAgICAgICBpZiAoIXRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0pIHtcbiAgICAgICAgICAgIHRocm93IEVycm9yKGBDYW5ub3Qgc2V0dXAgc2NyaXB0IGJlY2F1c2UgcGF5cGFsIGJ1dHRvbiBjb250YWluZXIgd2l0aCBpZCAnJHt0aGlzLnBheVBhbEJ1dHRvbkNvbnRhaW5lcklkfScgaXMgbm90IHlldCByZWFkeWApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbS5uYXRpdmVFbGVtZW50LmlubmVySFRNTCA9ICcnO1xuXG4gICAgICAgIGlmICghd2luZG93W3RoaXMucGF5cGFsV2luZG93TmFtZV0pIHtcbiAgICAgICAgICAgIHRocm93IEVycm9yKCdQYXlQYWwgc2NyaXB0IGlzIG5vdCBhdmFpbGFibGUnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHJlbmRlciBQYXlQYWwgYnV0dG9uIGFzIHBlciB0aGVpciBkb2NzIGF0XG4gICAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLnBheXBhbC5jb20vZG9jcy9pbnRlZ3JhdGlvbi9kaXJlY3QvZXhwcmVzcy1jaGVja291dC9pbnRlZ3JhdGlvbi1qc3Y0L2FkZC1wYXlwYWwtYnV0dG9uL1xuICAgICAgICB3aW5kb3dbdGhpcy5wYXlwYWxXaW5kb3dOYW1lXS5CdXR0b24ucmVuZGVyKHtcbiAgICAgICAgICAgIC8vIHNldCBlbnZpcm9ubWVudFxuICAgICAgICAgICAgZW52OiB0aGlzLmNvbmZpZy5lbnZpcm9ubWVudC50b1N0cmluZygpLFxuXG4gICAgICAgICAgICAvLyBTaG93IHRoZSBidXllciBhICdQYXkgTm93JyBidXR0b24gaW4gdGhlIGNoZWNrb3V0IGZsb3dcbiAgICAgICAgICAgIGNvbW1pdDogdGhpcy5jb25maWcuY29tbWl0LFxuXG4gICAgICAgICAgICAvLyBpbml0IGNsaWVudCBmb3IgY2xpZW50IHNpZGUgaW50ZWdyYXRpb25cbiAgICAgICAgICAgIGNsaWVudDogdGhpcy5nZXRDbGllbnQoKSxcblxuICAgICAgICAgICAgLy8gc2V0IGJ1dHRvbiBjb25maWcgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBzdHlsZTogdGhpcy5jb25maWcuYnV0dG9uLFxuXG4gICAgICAgICAgICAvLyBzZXQgZnVuZGluZyBpZiBhdmFpbGFibGVcbiAgICAgICAgICAgIGZ1bmRpbmc6IHRoaXMuZ2V0RnVuZGluZygpLFxuXG4gICAgICAgICAgICAvLyBwYXltZW50KCkgaXMgY2FsbGVkIHdoZW4gdGhlIGJ1dHRvbiBpcyBjbGlja2VkXG4gICAgICAgICAgICBwYXltZW50OiAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5pbnRlZ3JhdGlvblR5cGUgPT09IFBheVBhbEludGVncmF0aW9uVHlwZS5TZXJ2ZXJTaWRlUkVTVCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBjbGllbnQgbmVlZHMgdG8gY3JlYXRlIHBheW1lbnQgb24gc2VydmVyIHNpZGVcbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5wYXltZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihgWW91IG5lZWQgc2V0IHVwIGEgY3JlYXRlIHBheW1lbnQgbWV0aG9kIGFuZCByZXR1cm5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQYXlQYWwncyBwYXltZW50IGlkIHdoZW4gdXNpbmcgc2VydmVyIHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFBheXBhbCBleHBlY3RzIHByb21pc2Ugd2l0aCBwYXltZW50IGlkIChzdHJpbmcpIHRvIGJlIHJldHVybmVkXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbmZpZy5wYXltZW50KCkudG9Qcm9taXNlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKHBheW1lbnRJZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBheW1lbnRJZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5pbnRlZ3JhdGlvblR5cGUgPT09IFBheVBhbEludGVncmF0aW9uVHlwZS5DbGllbnRTaWRlUkVTVCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuY29uZmlnLnRyYW5zYWN0aW9ucyB8fCAhQXJyYXkuaXNBcnJheSh0aGlzLmNvbmZpZy50cmFuc2FjdGlvbnMpIHx8IHRoaXMuY29uZmlnLnRyYW5zYWN0aW9ucy5sZW5ndGggPD0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoYFlvdSBuZWVkIHRvIHByb3ZpZGUgYXQgbGVhc3QgMSB0cmFuc2FjdGlvbiBmb3IgY2xpZW50IHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4cGVyaWVuY2VDb25maWcgPSB0aGlzLmNvbmZpZy5leHBlcmllbmNlO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5wYXltZW50LmNyZWF0ZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXltZW50OiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWxsb3cgdXNlciB0byBzcGVjaWZpZnkgaW50ZW50LCBlbHNlIHVzZSBkZWZhdWx0ICdzYWxlJy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlbnQ6IHRoaXMuY29uZmlnLmludGVudCA/IHRoaXMuY29uZmlnLmludGVudCA6ICdzYWxlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2FjdGlvbnM6IHRoaXMuY29uZmlnLnRyYW5zYWN0aW9uc1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4cGVyaWVuY2U6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dF9maWVsZHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9fc2hpcHBpbmc6IChleHBlcmllbmNlQ29uZmlnICYmIGV4cGVyaWVuY2VDb25maWcubm9TaGlwcGluZykgPyAxIDogMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlc2VudGF0aW9uOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyYW5kX25hbWU6IChleHBlcmllbmNlQ29uZmlnICYmIGV4cGVyaWVuY2VDb25maWcuYnJhbmROYW1lKSA/IGV4cGVyaWVuY2VDb25maWcuYnJhbmROYW1lIDogbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nb19pbWFnZTogKGV4cGVyaWVuY2VDb25maWcgJiYgZXhwZXJpZW5jZUNvbmZpZy5sb2dvSW1hZ2UpID8gZXhwZXJpZW5jZUNvbmZpZy5sb2dvSW1hZ2UgOiBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhbGVfY29kZTogKGV4cGVyaWVuY2VDb25maWcgJiYgZXhwZXJpZW5jZUNvbmZpZy5sb2NhbGVDb2RlKSA/IGV4cGVyaWVuY2VDb25maWcubG9jYWxlQ29kZSA6IG51bGxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIC8vIG9uQXV0aG9yaXplKCkgaXMgY2FsbGVkIHdoZW4gdGhlIGJ1eWVyIGFwcHJvdmVzIHRoZSBwYXltZW50XG4gICAgICAgICAgICBvbkF1dGhvcml6ZTogKGRhdGE6IElQYXlQYWxQYXltZW50Q29tcGxldGVEYXRhLCBhY3Rpb25zOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jb25maWcuaW50ZWdyYXRpb25UeXBlID09PSBQYXlQYWxJbnRlZ3JhdGlvblR5cGUuU2VydmVyU2lkZVJFU1QpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gY2xpZW50IG5lZWRzIHRvIHNlcnZlciB0byBleGVjdXRlIHRoZSBwYXltZW50XG4gICAgICAgICAgICAgICAgICAgIGlmICghdGhpcy5jb25maWcub25BdXRob3JpemUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGBZb3UgbmVlZCBzZXQgdXAgYW4gZXhlY3V0ZSBtZXRob2Qgd2hlbiB1c2luZyBzZXJ2ZXIgc2lkZSBpbnRlZ3JhdGlvbmApO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUGF5cGFsIGV4cGVjdHMgcHJvbWlzZVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5jb25maWcub25BdXRob3JpemUoZGF0YSwgYWN0aW9ucykudG9Qcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLmludGVncmF0aW9uVHlwZSA9PT0gUGF5UGFsSW50ZWdyYXRpb25UeXBlLkNsaWVudFNpZGVSRVNUKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIE1ha2UgYSBjYWxsIHRvIHRoZSBSRVNUIGFwaSB0byBleGVjdXRlIHRoZSBwYXltZW50XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBhY3Rpb25zLnBheW1lbnQuZXhlY3V0ZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5vblBheW1lbnRDb21wbGV0ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGBZb3Ugc2hvdWxkIHByb3ZpZGUgc29tZSBjYWxsYmFjayB3aGVuIHBheW1lbnQgaXMgZmluaXNoZWQgd2hlbiB1c2luZyBjbGllbnQgc2lkZSBpbnRlZ3JhdGlvbmApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcub25QYXltZW50Q29tcGxldGUoZGF0YSwgYWN0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIG9uRXJyb3I6IChlcnIpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jb25maWcub25FcnJvcikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5vbkVycm9yKGVycik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgb25DYW5jZWw6IChkYXRhLCBhY3Rpb25zKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLm9uQ2FuY2VsKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLm9uQ2FuY2VsKGRhdGEsIGFjdGlvbnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkNsaWNrOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLm9uQ2xpY2spIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcub25DbGljaygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB2YWxpZGF0ZTogKGFjdGlvbnMpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jb25maWcudmFsaWRhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcudmFsaWRhdGUoYWN0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LCBgIyR7dGhpcy5wYXlQYWxCdXR0b25Db250YWluZXJJZH1gKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldENsaWVudCgpOiBJUGF5cGFsQ2xpZW50IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmludGVncmF0aW9uVHlwZSA9PT0gUGF5UGFsSW50ZWdyYXRpb25UeXBlLkNsaWVudFNpZGVSRVNUKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuY29uZmlnLmNsaWVudCkge1xuICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGBZb3UgbmVlZCB0byBzZXR1cCBjbGllbnQgaW5mb3JtYXRpb24gd2hlbiB1c2luZyBjbGllbnQgc2lkZSBpbnRlZ3JhdGlvbmApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHByb2R1Y3Rpb246IHRoaXMuY29uZmlnLmNsaWVudC5wcm9kdWN0aW9uLFxuICAgICAgICAgICAgICAgIHNhbmRib3g6IHRoaXMuY29uZmlnLmNsaWVudC5zYW5kYm94XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldEZ1bmRpbmcoKToge1xuICAgICAgICBhbGxvd2VkOiBhbnlbXSxcbiAgICAgICAgZGlzYWxsb3dlZDogYW55W11cbiAgICB9IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgLy8gcmVzb2x2ZSBmdW5kaW5nIHRvIHVzZSBwYXlwYWwncyBwcm9wZXJ0aWVzXG4gICAgICAgIGlmICghdGhpcy5jb25maWcuZnVuZGluZykge1xuICAgICAgICAgICAgLy8gbm8gZnVuZGluZyBwcm92aWRlZFxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGFsbG93ZWQ6IGFueVtdID0gW107XG4gICAgICAgIGNvbnN0IGRpc2FsbG93ZWQ6IGFueVtdID0gW107XG5cbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmZ1bmRpbmcuYWxsb3dlZCkge1xuICAgICAgICAgICAgdGhpcy5jb25maWcuZnVuZGluZy5hbGxvd2VkLmZvckVhY2godHlwZSA9PiB7XG4gICAgICAgICAgICAgICAgYWxsb3dlZC5wdXNoKHRoaXMubWFwRnVuZGluZ1R5cGUodHlwZSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5jb25maWcuZnVuZGluZy5kaXNhbGxvd2VkKSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5mdW5kaW5nLmRpc2FsbG93ZWQuZm9yRWFjaCh0eXBlID0+IHtcbiAgICAgICAgICAgICAgICBkaXNhbGxvd2VkLnB1c2godGhpcy5tYXBGdW5kaW5nVHlwZSh0eXBlKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBhbGxvd2VkOiBhbGxvd2VkLFxuICAgICAgICAgICAgZGlzYWxsb3dlZDogZGlzYWxsb3dlZFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgbWFwRnVuZGluZ1R5cGUodHlwZTogUGF5UGFsRnVuZGluZyk6IGFueSB7XG4gICAgICAgIGlmICh0eXBlID09PSBQYXlQYWxGdW5kaW5nLkNhcmQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXlwYWwuRlVORElORy5DQVJEO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlID09PSBQYXlQYWxGdW5kaW5nLkNyZWRpdCkge1xuICAgICAgICAgICAgcmV0dXJuIHBheXBhbC5GVU5ESU5HLkNSRURJVDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZSA9PT0gUGF5UGFsRnVuZGluZy5FbHYpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXlwYWwuRlVORElORy5FTFY7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgRXJyb3IoYFVuc3VwcG9ydGVkIGZ1bmRpbmcgdHlwZSAnJHt0eXBlfSdgKTtcbiAgICB9XG59XG5cbiJdfQ==