UNPKG

ngx-paypal-with-intent

Version:

Paypal integration for Angular 6, 7 and beyond

506 lines 59 kB
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('rxjs'), require('rxjs/operators')) :
    typeof define === 'function' && define.amd ? define('ngx-paypal', ['exports', '@angular/core', 'rxjs', 'rxjs/operators'], factory) :
    (factory((global['ngx-paypal'] = {}),global.ng.core,global.rxjs,global.rxjs.operators));
}(this, (function (exports,core,rxjs,operators) { 'use strict';

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */
    /** @enum {number} */
    var PayPalFunding = {
        Card: 0,
        Credit: 1,
        Elv: 2,
    };
    PayPalFunding[PayPalFunding.Card] = 'Card';
    PayPalFunding[PayPalFunding.Credit] = 'Credit';
    PayPalFunding[PayPalFunding.Elv] = 'Elv';

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */
    /** @enum {number} */
    var PayPalIntegrationType = {
        ClientSideREST: 0,
        ServerSideREST: 1,
    };
    PayPalIntegrationType[PayPalIntegrationType.ClientSideREST] = 'ClientSideREST';
    PayPalIntegrationType[PayPalIntegrationType.ServerSideREST] = 'ServerSideREST';

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */
    var NgxPaypalComponent = /** @class */ (function () {
        function NgxPaypalComponent() {
            /**
             * 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 rxjs.Subject();
        }
        Object.defineProperty(NgxPaypalComponent.prototype, "payPalButtonContainerElem", {
            set: /**
             * @param {?} content
             * @return {?}
             */ function (content) {
                if (content) {
                    this._payPalButtonContainerElem = content;
                }
            },
            enumerable: true,
            configurable: true
        });
        /**
         * @param {?} changes
         * @return {?}
         */
        NgxPaypalComponent.prototype.ngOnChanges = /**
         * @param {?} changes
         * @return {?}
         */
            function (changes) {
                // init when config once its available
                if (this.config) {
                    this.initPayPal();
                }
            };
        /**
         * @return {?}
         */
        NgxPaypalComponent.prototype.ngAfterViewInit = /**
         * @return {?}
         */
            function () {
                // register script if element is ready in dom
                if (this.registerPayPalScriptWhenContainerIsReady && this._payPalButtonContainerElem) {
                    this.setupScript();
                    this.registerPayPalScriptWhenContainerIsReady = false;
                }
            };
        /**
         * @return {?}
         */
        NgxPaypalComponent.prototype.ngOnDestroy = /**
         * @return {?}
         */
            function () {
                this.ngUnsubscribe.next();
                this.ngUnsubscribe.complete();
            };
        /**
         * @return {?}
         */
        NgxPaypalComponent.prototype.initPayPal = /**
         * @return {?}
         */
            function () {
                // 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 {?}
         */
        NgxPaypalComponent.prototype.getPseudoUniqueNumber = /**
         * @return {?}
         */
            function () {
                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
         */
        /**
         * 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 {?}
         */
        NgxPaypalComponent.prototype.pollUntilScriptAvailable = /**
         * 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 {?}
         */
            function () {
                var _this = this;
                /** @type {?} */
                var obs = rxjs.interval(this.defaultPollInterval)
                    .pipe(operators.takeUntil(this.ngUnsubscribe), operators.map(function (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 {?}
         */
        NgxPaypalComponent.prototype.addPayPalScriptToPage = /**
         * @return {?}
         */
            function () {
                var _this = this;
                /** @type {?} */
                var script = document.createElement('script');
                script.innerHTML = '';
                script.src = this.paypalScriptUrl;
                script.onload = function () { return _this.handleScriptRegistering(); };
                script.async = true;
                script.defer = true;
                this.paypalScriptElem.nativeElement.appendChild(script);
            };
        /**
         * @return {?}
         */
        NgxPaypalComponent.prototype.handleScriptRegistering = /**
         * @return {?}
         */
            function () {
                // 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 {?}
         */
        NgxPaypalComponent.prototype.setupScript = /**
         * @return {?}
         */
            function () {
                var _this = this;
                // 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: function (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\n                            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(function (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 {?} */
                            var experienceConfig = _this.config.experience;
                            return actions.payment.create({
                                // Allow user to specifify intent, else use default 'sale'.
                                intent: _this.config.intent ? _this.config.intent : 'sale',
                                payment: {
                                    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: function (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(function () {
                                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: function (err) {
                        if (_this.config.onError) {
                            _this.config.onError(err);
                        }
                    },
                    onCancel: function (data, actions) {
                        if (_this.config.onCancel) {
                            _this.config.onCancel(data, actions);
                        }
                    },
                    onClick: function () {
                        if (_this.config.onClick) {
                            _this.config.onClick();
                        }
                    },
                    validate: function (actions) {
                        if (_this.config.validate) {
                            _this.config.validate(actions);
                        }
                    }
                }, "#" + this.payPalButtonContainerId);
            };
        /**
         * @return {?}
         */
        NgxPaypalComponent.prototype.getClient = /**
         * @return {?}
         */
            function () {
                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 {?}
         */
        NgxPaypalComponent.prototype.getFunding = /**
         * @return {?}
         */
            function () {
                var _this = this;
                // resolve funding to use paypal's properties
                if (!this.config.funding) {
                    // no funding provided
                    return undefined;
                }
                /** @type {?} */
                var allowed = [];
                /** @type {?} */
                var disallowed = [];
                if (this.config.funding.allowed) {
                    this.config.funding.allowed.forEach(function (type) {
                        allowed.push(_this.mapFundingType(type));
                    });
                }
                if (this.config.funding.disallowed) {
                    this.config.funding.disallowed.forEach(function (type) {
                        disallowed.push(_this.mapFundingType(type));
                    });
                }
                return {
                    allowed: allowed,
                    disallowed: disallowed
                };
            };
        /**
         * @param {?} type
         * @return {?}
         */
        NgxPaypalComponent.prototype.mapFundingType = /**
         * @param {?} type
         * @return {?}
         */
            function (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: core.Component, args: [{
                        changeDetection: core.ChangeDetectionStrategy.OnPush,
                        selector: 'ngx-paypal',
                        template: "\n    <div #payPalScriptElem></div>\n    <div #payPalButtonContainerElem [id]=\"payPalButtonContainerId\"></div>\n    "
                    }] }
        ];
        /** @nocollapse */
        NgxPaypalComponent.ctorParameters = function () { return []; };
        NgxPaypalComponent.propDecorators = {
            config: [{ type: core.Input }],
            useGlobalConfig: [{ type: core.Input }],
            paypalScriptElem: [{ type: core.ViewChild, args: ['payPalScriptElem',] }],
            payPalButtonContainerElem: [{ type: core.ViewChild, args: ['payPalButtonContainerElem',] }]
        };
        return NgxPaypalComponent;
    }());

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */
    var NgxPayPalModule = /** @class */ (function () {
        function NgxPayPalModule() {
        }
        NgxPayPalModule.decorators = [
            { type: core.NgModule, args: [{
                        imports: [],
                        declarations: [
                            NgxPaypalComponent,
                        ],
                        exports: [
                            NgxPaypalComponent,
                        ]
                    },] }
        ];
        return NgxPayPalModule;
    }());

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */
    /** @enum {string} */
    var PayPalEnvironment = {
        Sandbox: 'sandbox',
        Production: 'production',
    };

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */
    var PayPalConfig = /** @class */ (function () {
        function PayPalConfig(integrationType, environment, config) {
            this.integrationType = integrationType;
            this.environment = environment;
            /**
             * Show 'Pay Now' button config
             */
            this.commit = true;
            /**
             * Set the intent of the payment.
             */
            this.intent = 'sale';
            Object.assign(this, config);
        }
        return PayPalConfig;
    }());

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */

    /**
     * @fileoverview added by tsickle
     * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
     */

    exports.NgxPayPalModule = NgxPayPalModule;
    exports.PayPalEnvironment = PayPalEnvironment;
    exports.PayPalFunding = PayPalFunding;
    exports.PayPalIntegrationType = PayPalIntegrationType;
    exports.PayPalConfig = PayPalConfig;
    exports.NgxPaypalComponent = NgxPaypalComponent;
    exports.ɵa = NgxPaypalComponent;

    Object.defineProperty(exports, '__esModule', { value: true });

})));

//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXBheXBhbC51bWQuanMubWFwIiwic291cmNlcyI6WyJuZzovL25neC1wYXlwYWwvbGliL21vZGVscy9wYXlwYWwtZnVuZGluZy50cyIsIm5nOi8vbmd4LXBheXBhbC9saWIvbW9kZWxzL3BheXBhbC1pbnRlZ3JhdGlvbi50cyIsIm5nOi8vbmd4LXBheXBhbC9saWIvY29tcG9uZW50cy9wYXlwYWwtY29tcG9uZW50LnRzIiwibmc6Ly9uZ3gtcGF5cGFsL2xpYi9uZ3gtcGF5cGFsLm1vZHVsZS50cyIsIm5nOi8vbmd4LXBheXBhbC9saWIvbW9kZWxzL3BheXBhbC1lbnZpcm9ubWVudC50cyIsIm5nOi8vbmd4LXBheXBhbC9saWIvbW9kZWxzL3BheXBhbC1tb2RlbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGVudW0gUGF5UGFsRnVuZGluZyB7XG4gICAgQ2FyZCxcbiAgICBDcmVkaXQsXG4gICAgRWx2XG59XG4iLCJleHBvcnQgZW51bSBQYXlQYWxJbnRlZ3JhdGlvblR5cGUge1xuICAgIENsaWVudFNpZGVSRVNULFxuICAgIFNlcnZlclNpZGVSRVNULFxufVxuIiwiaW1wb3J0IHtcbiAgICBBZnRlclZpZXdJbml0LFxuICAgIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICAgIENvbXBvbmVudCxcbiAgICBFbGVtZW50UmVmLFxuICAgIElucHV0LFxuICAgIE9uQ2hhbmdlcyxcbiAgICBPbkRlc3Ryb3ksXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBWaWV3Q2hpbGQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaW50ZXJ2YWwsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBQYXlQYWxGdW5kaW5nIH0gZnJvbSAnLi4vbW9kZWxzL3BheXBhbC1mdW5kaW5nJztcbmltcG9ydCB7IFBheVBhbEludGVncmF0aW9uVHlwZSB9IGZyb20gJy4uL21vZGVscy9wYXlwYWwtaW50ZWdyYXRpb24nO1xuaW1wb3J0IHsgSVBheXBhbENsaWVudCwgSVBheVBhbFBheW1lbnRDb21wbGV0ZURhdGEsIFBheVBhbENvbmZpZyB9IGZyb20gJy4uL21vZGVscy9wYXlwYWwtbW9kZWxzJztcblxuLyoqXG4gKiBHbG9iYWwgdmFyaWFibGUgd2hlcmUgUGF5UGFsIGlzIGxvYWRlZCB0b1xuICovXG5kZWNsYXJlIHZhciBwYXlwYWw6IGFueTtcblxuQENvbXBvbmVudCh7XG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gICAgc2VsZWN0b3I6ICduZ3gtcGF5cGFsJyxcbiAgICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgI3BheVBhbFNjcmlwdEVsZW0+PC9kaXY+XG4gICAgPGRpdiAjcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbSBbaWRdPVwicGF5UGFsQnV0dG9uQ29udGFpbmVySWRcIj48L2Rpdj5cbiAgICBgXG59KVxuZXhwb3J0IGNsYXNzIE5neFBheXBhbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcblxuICAgIC8qKlxuICAgICAqIENvbmZpZ3VyYXRpb24gZm9yIHBheXBhbC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBjb25maWc6IFBheVBhbENvbmZpZztcblxuICAgIC8qKlxuICAgICAqIEluZGljYXRlcyBpZiBnbG9iYWwgY29uZmlndXJhdGlvbiAocHJvdmlkZWQgdmlhICdmb3JSb290JykgaXMgdXNlZFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHVzZUdsb2JhbENvbmZpZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogQ29udGFpbmVyIGZvciBwYXlwYWwgc2NyaXB0XG4gICAgICovXG4gICAgQFZpZXdDaGlsZCgncGF5UGFsU2NyaXB0RWxlbScpIHBheXBhbFNjcmlwdEVsZW06IEVsZW1lbnRSZWY7XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIGZvciBpbmRpY2F0aW5nIGRlbGF5ZWQgcmVuZGVyZWQgaWYgY29udGFpbmVyIGlzIG5vdCB5ZXQgcmVhZHkgaW4gRE9NXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWdpc3RlclBheVBhbFNjcmlwdFdoZW5Db250YWluZXJJc1JlYWR5ID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBIb2xkcyBjdXJyZW50IGNvbnRhaW5lciBlbGVtZW50XG4gICAgICovXG4gICAgcHJpdmF0ZSBfcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbT86IEVsZW1lbnRSZWY7XG4gICAgQFZpZXdDaGlsZCgncGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbScpIHNldCBwYXlQYWxCdXR0b25Db250YWluZXJFbGVtKGNvbnRlbnQ6IEVsZW1lbnRSZWYpIHtcbiAgICAgICAgaWYgKGNvbnRlbnQpIHtcbiAgICAgICAgICAgIHRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0gPSBjb250ZW50O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUG9sbGluZyBpbnRlcnZhbCBpZiBwYXlwYWwgc2NyaXB0IGlzIHBlbmRpbmdcbiAgICAgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IGRlZmF1bHRQb2xsSW50ZXJ2YWwgPSA1MDtcblxuICAgIC8qKlxuICAgICAqIFBvbGxpbmcgd2lsbCBzdG9wIGFmdGVyIHBvbGxpbmcgcmVhY2hlcyB0aGlzIG51bWJlclxuICAgICAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbWF4aW11bVBvbGxXYWl0VGltZSA9IDUwMDA7XG5cbiAgICAvKipcbiAgICAqIE5hbWUgb2YgdGhlIGdsb2JhbCB2YXJpYWJsZSB3aGVyZSBwYXlwYWwgaXMgc3RvcmVkXG4gICAgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IHBheXBhbFdpbmRvd05hbWUgPSAncGF5cGFsJztcblxuICAgIC8qKlxuICAgICAqIE5hbWUgb2YgdGhlIGdsb2JhbCB2YXJpYWJsZSBpbmRpY2F0aW5nIHRoYXQgc2NyaXB0IHdhcyBpbml0aWF0ZWQgKGFkZGVkIHRvIHBhZ2UpXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBwYXlwYWxXaW5kb3dTY3JpcHRJbml0aWF0ZWQgPSAnbmd4LXBheXBhbC1zY3JpcHQtaW5pdGlhdGVkJztcblxuICAgIC8qKlxuICAgICAqIFBheVBhbCBpbnRlZ3JhdGlvbiBzY3JpcHQgdXJsXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBwYXlwYWxTY3JpcHRVcmwgPSAnaHR0cHM6Ly93d3cucGF5cGFsb2JqZWN0cy5jb20vYXBpL2NoZWNrb3V0LmpzJztcblxuICAgIC8qKlxuICAgICAqIElkIG9mIHRoZSBlbGVtZW50IHdoZXJlIFBheVBhbCBidXR0b24gd2lsbCBiZSByZW5kZXJlZFxuICAgICAqL1xuICAgIHB1YmxpYyBwYXlQYWxCdXR0b25Db250YWluZXJJZD86IHN0cmluZztcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgcGF5UGFsQnV0dG9uQ29udGFpbmVySWRQcmVmaXggPSAnbmd4LXBheXBhbC1idXR0b24tY29udGFpbmVyLSc7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IG5nVW5zdWJzY3JpYmU6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgKSB7XG4gICAgfVxuXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgICAgICAvLyBpbml0IHdoZW4gY29uZmlnIG9uY2UgaXRzIGF2YWlsYWJsZVxuICAgICAgICBpZiAodGhpcy5jb25maWcpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdFBheVBhbCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICAvLyByZWdpc3RlciBzY3JpcHQgaWYgZWxlbWVudCBpcyByZWFkeSBpbiBkb21cbiAgICAgICAgaWYgKHRoaXMucmVnaXN0ZXJQYXlQYWxTY3JpcHRXaGVuQ29udGFpbmVySXNSZWFkeSAmJiB0aGlzLl9wYXlQYWxCdXR0b25Db250YWluZXJFbGVtKSB7XG4gICAgICAgICAgICB0aGlzLnNldHVwU2NyaXB0KCk7XG4gICAgICAgICAgICB0aGlzLnJlZ2lzdGVyUGF5UGFsU2NyaXB0V2hlbkNvbnRhaW5lcklzUmVhZHkgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLm5nVW5zdWJzY3JpYmUubmV4dCgpO1xuICAgICAgICB0aGlzLm5nVW5zdWJzY3JpYmUuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGluaXRQYXlQYWwoKTogdm9pZCB7XG4gICAgICAgIC8vIHNldCB1bmlxdWUgcGF5cGFsIGNvbnRhaW5lciBidXR0b24gaWRcbiAgICAgICAgdGhpcy5wYXlQYWxCdXR0b25Db250YWluZXJJZCA9IGAke3RoaXMucGF5UGFsQnV0dG9uQ29udGFpbmVySWRQcmVmaXh9JHt0aGlzLmdldFBzZXVkb1VuaXF1ZU51bWJlcigpfWA7XG4gICAgICAgIC8vIGNoZWNrIGlmIHBheXBhbCB3YXMgYWxyZWFkeSByZWdpc3RlciBhbmQgaWYgc28sIGRvbid0IGFkZCBpdCB0byBwYWdlIGFnYWluXG4gICAgICAgIGlmICghd2luZG93W3RoaXMucGF5cGFsV2luZG93TmFtZV0pIHtcbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIHNjcmlwdCBpcyBwZW5kaW5nXG4gICAgICAgICAgICBpZiAod2luZG93W3RoaXMucGF5cGFsV2luZG93U2NyaXB0SW5pdGlhdGVkXSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMucG9sbFVudGlsU2NyaXB0QXZhaWxhYmxlKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHJlZ2lzdGVyIHNjcmlwdCBhbmQgc2V0IGdsb2JhbCBmbGFnXG4gICAgICAgICAgICAgICAgd2luZG93W3RoaXMucGF5cGFsV2luZG93U2NyaXB0SW5pdGlhdGVkXSA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5hZGRQYXlQYWxTY3JpcHRUb1BhZ2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8ganVzdCByZWdpc3RlciBwYXltZW50XG4gICAgICAgICAgICB0aGlzLmhhbmRsZVNjcmlwdFJlZ2lzdGVyaW5nKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFBzZXVkb1VuaXF1ZU51bWJlcigpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gbmV3IERhdGUoKS52YWx1ZU9mKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXNlZCB3aGVuIHRoZXJlIGFyZSBtdWx0aXBsZSBwYXlwYWwgY29tcG9uZW50cyBvbiB0aGUgc2FtZSBwYWdlIGJlYWN1c2Ugb25seSAxIG9mIHRoZW1cbiAgICAgKiBtYXkgcmVnaXN0ZXIgcGF5cGFsIHNjcmlwdC4gVGhlIG90aGVyIGhhcyB0byBiZSBwb2xsaW5nIHVudGlsIHBheXBhbCBpcyBhdmFpbGFibGUgb3IgY29tcG9uZW50IGRlc3Ryb3llZFxuICAgICAqL1xuICAgIHByaXZhdGUgcG9sbFVudGlsU2NyaXB0QXZhaWxhYmxlKCk6IHZvaWQge1xuICAgICAgICBjb25zdCBvYnMgPSBpbnRlcnZhbCh0aGlzLmRlZmF1bHRQb2xsSW50ZXJ2YWwpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5uZ1Vuc3Vic2NyaWJlKSxcbiAgICAgICAgICAgICAgICBtYXAoKHgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHggPj0gdGhpcy5tYXhpbXVtUG9sbFdhaXRUaW1lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oYFBheVBhbCBzY3JpcHQgd2FzIG5vdCBsb2FkZWQgYWZ0ZXIgJyR7dGhpcy5tYXhpbXVtUG9sbFdhaXRUaW1lfScgbWF4aW11bSBwb2xsaW5nIHRpbWUuYCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBvYnMudW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIGNoZWNrIGlmIHBheXBhbCBzY3JpcHQgZXhpc3RzXG4gICAgICAgICAgICAgICAgICAgIGlmICh3aW5kb3dbdGhpcy5wYXlwYWxXaW5kb3dOYW1lXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVnaXN0ZXIgc2NyaXB0XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZVNjcmlwdFJlZ2lzdGVyaW5nKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0b3AgZXhlY3V0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICBvYnMudW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhZGRQYXlQYWxTY3JpcHRUb1BhZ2UoKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpO1xuICAgICAgICBzY3JpcHQuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIHNjcmlwdC5zcmMgPSB0aGlzLnBheXBhbFNjcmlwdFVybDtcbiAgICAgICAgc2NyaXB0Lm9ubG9hZCA9ICgpID0+IHRoaXMuaGFuZGxlU2NyaXB0UmVnaXN0ZXJpbmcoKTtcbiAgICAgICAgc2NyaXB0LmFzeW5jID0gdHJ1ZTtcbiAgICAgICAgc2NyaXB0LmRlZmVyID0gdHJ1ZTtcblxuICAgICAgICB0aGlzLnBheXBhbFNjcmlwdEVsZW0ubmF0aXZlRWxlbWVudC5hcHBlbmRDaGlsZChzY3JpcHQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaGFuZGxlU2NyaXB0UmVnaXN0ZXJpbmcoKTogdm9pZCB7XG4gICAgICAgIC8vIGNoZWNrIGlmIGNvbnRhaW5lciB3aXRoIHJlcXVlc3RlZCBpZCBleGlzdHNcbiAgICAgICAgLy8gdGhpcyBpcyBoZXJlIGJlY2F1c2UgZHluYW1pY2FsbHkgc3dpdGNoaW5nIGJldHdlZW4gY29tcG9uZW50cyB3b3VsZCBjYXVzZSBQYXlQYWwgdG9cbiAgICAgICAgLy8gdGhyb3cgYW4gZXJyb3IgaWYgdGhlIGNvbnRhaW5lciBhbHJlYWR5IGV4aXN0ZWQgYmVmb3JlXG4gICAgICAgIGlmICh0aGlzLl9wYXlQYWxCdXR0b25Db250YWluZXJFbGVtICYmIHRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0ubmF0aXZlRWxlbWVudCAmJlxuICAgICAgICAgICAgdGhpcy5fcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbS5uYXRpdmVFbGVtZW50LmlkID09PSB0aGlzLnBheVBhbEJ1dHRvbkNvbnRhaW5lcklkKSB7XG4gICAgICAgICAgICAvLyBjb250YWluZXIgaXMgcmVhZHksIHNldHVwIHNjcmlwdCByaWdodCBhd2F5XG4gICAgICAgICAgICB0aGlzLnNldHVwU2NyaXB0KCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBjb250YWluZXIgaXMgbm90IHJlYWR5LCBkZWxheSByZWdpc3RlcmluZyB1bnRpbCBpdCBpc1xuICAgICAgICAgICAgdGhpcy5yZWdpc3RlclBheVBhbFNjcmlwdFdoZW5Db250YWluZXJJc1JlYWR5ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgc2V0dXBTY3JpcHQoKTogdm9pZCB7XG4gICAgICAgIC8vIGZpcnN0IGNsZWFyIGNvbnRhaW5lclxuICAgICAgICBpZiAoIXRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0pIHtcbiAgICAgICAgICAgIHRocm93IEVycm9yKGBDYW5ub3Qgc2V0dXAgc2NyaXB0IGJlY2F1c2UgcGF5cGFsIGJ1dHRvbiBjb250YWluZXIgd2l0aCBpZCAnJHt0aGlzLnBheVBhbEJ1dHRvbkNvbnRhaW5lcklkfScgaXMgbm90IHlldCByZWFkeWApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbS5uYXRpdmVFbGVtZW50LmlubmVySFRNTCA9ICcnO1xuXG4gICAgICAgIGlmICghd2luZG93W3RoaXMucGF5cGFsV2luZG93TmFtZV0pIHtcbiAgICAgICAgICAgIHRocm93IEVycm9yKCdQYXlQYWwgc2NyaXB0IGlzIG5vdCBhdmFpbGFibGUnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHJlbmRlciBQYXlQYWwgYnV0dG9uIGFzIHBlciB0aGVpciBkb2NzIGF0XG4gICAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLnBheXBhbC5jb20vZG9jcy9pbnRlZ3JhdGlvbi9kaXJlY3QvZXhwcmVzcy1jaGVja291dC9pbnRlZ3JhdGlvbi1qc3Y0L2FkZC1wYXlwYWwtYnV0dG9uL1xuICAgICAgICB3aW5kb3dbdGhpcy5wYXlwYWxXaW5kb3dOYW1lXS5CdXR0b24ucmVuZGVyKHtcbiAgICAgICAgICAgIC8vIHNldCBlbnZpcm9ubWVudFxuICAgICAgICAgICAgZW52OiB0aGlzLmNvbmZpZy5lbnZpcm9ubWVudC50b1N0cmluZygpLFxuXG4gICAgICAgICAgICAvLyBTaG93IHRoZSBidXllciBhICdQYXkgTm93JyBidXR0b24gaW4gdGhlIGNoZWNrb3V0IGZsb3dcbiAgICAgICAgICAgIGNvbW1pdDogdGhpcy5jb25maWcuY29tbWl0LFxuXG4gICAgICAgICAgICAvLyBpbml0IGNsaWVudCBmb3IgY2xpZW50IHNpZGUgaW50ZWdyYXRpb25cbiAgICAgICAgICAgIGNsaWVudDogdGhpcy5nZXRDbGllbnQoKSxcblxuICAgICAgICAgICAgLy8gc2V0IGJ1dHRvbiBjb25maWcgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBzdHlsZTogdGhpcy5jb25maWcuYnV0dG9uLFxuXG4gICAgICAgICAgICAvLyBzZXQgZnVuZGluZyBpZiBhdmFpbGFibGVcbiAgICAgICAgICAgIGZ1bmRpbmc6IHRoaXMuZ2V0RnVuZGluZygpLFxuXG4gICAgICAgICAgICAvLyBwYXltZW50KCkgaXMgY2FsbGVkIHdoZW4gdGhlIGJ1dHRvbiBpcyBjbGlja2VkXG4gICAgICAgICAgICBwYXltZW50OiAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5pbnRlZ3JhdGlvblR5cGUgPT09IFBheVBhbEludGVncmF0aW9uVHlwZS5TZXJ2ZXJTaWRlUkVTVCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBjbGllbnQgbmVlZHMgdG8gY3JlYXRlIHBheW1lbnQgb24gc2VydmVyIHNpZGVcbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5wYXltZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihgWW91IG5lZWQgc2V0IHVwIGEgY3JlYXRlIHBheW1lbnQgbWV0aG9kIGFuZCByZXR1cm5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQYXlQYWwncyBwYXltZW50IGlkIHdoZW4gdXNpbmcgc2VydmVyIHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFBheXBhbCBleHBlY3RzIHByb21pc2Ugd2l0aCBwYXltZW50IGlkIChzdHJpbmcpIHRvIGJlIHJldHVybmVkXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbmZpZy5wYXltZW50KCkudG9Qcm9taXNlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKHBheW1lbnRJZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBheW1lbnRJZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5pbnRlZ3JhdGlvblR5cGUgPT09IFBheVBhbEludGVncmF0aW9uVHlwZS5DbGllbnRTaWRlUkVTVCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuY29uZmlnLnRyYW5zYWN0aW9ucyB8fCAhQXJyYXkuaXNBcnJheSh0aGlzLmNvbmZpZy50cmFuc2FjdGlvbnMpIHx8IHRoaXMuY29uZmlnLnRyYW5zYWN0aW9ucy5sZW5ndGggPD0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoYFlvdSBuZWVkIHRvIHByb3ZpZGUgYXQgbGVhc3QgMSB0cmFuc2FjdGlvbiBmb3IgY2xpZW50IHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4cGVyaWVuY2VDb25maWcgPSB0aGlzLmNvbmZpZy5leHBlcmllbmNlO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5wYXltZW50LmNyZWF0ZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBBbGxvdyB1c2VyIHRvIHNwZWNpZmlmeSBpbnRlbnQsIGVsc2UgdXNlIGRlZmF1bHQgJ3NhbGUnLlxuICAgICAgICAgICAgICAgICAgICAgICAgaW50ZW50OiB0aGlzLmNvbmZpZy5pbnRlbnQgPyB0aGlzLmNvbmZpZy5pbnRlbnQgOiAnc2FsZScsXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXltZW50OiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNhY3Rpb25zOiB0aGlzLmNvbmZpZy50cmFuc2FjdGlvbnNcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBleHBlcmllbmNlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXRfZmllbGRzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vX3NoaXBwaW5nOiAoZXhwZXJpZW5jZUNvbmZpZyAmJiBleHBlcmllbmNlQ29uZmlnLm5vU2hpcHBpbmcpID8gMSA6IDBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZXNlbnRhdGlvbjoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmFuZF9uYW1lOiAoZXhwZXJpZW5jZUNvbmZpZyAmJiBleHBlcmllbmNlQ29uZmlnLmJyYW5kTmFtZSkgPyBleHBlcmllbmNlQ29uZmlnLmJyYW5kTmFtZSA6IG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ29faW1hZ2U6IChleHBlcmllbmNlQ29uZmlnICYmIGV4cGVyaWVuY2VDb25maWcubG9nb0ltYWdlKSA/IGV4cGVyaWVuY2VDb25maWcubG9nb0ltYWdlIDogbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jYWxlX2NvZGU6IChleHBlcmllbmNlQ29uZmlnICYmIGV4cGVyaWVuY2VDb25maWcubG9jYWxlQ29kZSkgPyBleHBlcmllbmNlQ29uZmlnLmxvY2FsZUNvZGUgOiBudWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICAvLyBvbkF1dGhvcml6ZSgpIGlzIGNhbGxlZCB3aGVuIHRoZSBidXllciBhcHByb3ZlcyB0aGUgcGF5bWVudFxuICAgICAgICAgICAgb25BdXRob3JpemU6IChkYXRhOiBJUGF5UGFsUGF5bWVudENvbXBsZXRlRGF0YSwgYWN0aW9uczogYW55KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLmludGVncmF0aW9uVHlwZSA9PT0gUGF5UGFsSW50ZWdyYXRpb25UeXBlLlNlcnZlclNpZGVSRVNUKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGNsaWVudCBuZWVkcyB0byBzZXJ2ZXIgdG8gZXhlY3V0ZSB0aGUgcGF5bWVudFxuICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuY29uZmlnLm9uQXV0aG9yaXplKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihgWW91IG5lZWQgc2V0IHVwIGFuIGV4ZWN1dGUgbWV0aG9kIHdoZW4gdXNpbmcgc2VydmVyIHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFBheXBhbCBleHBlY3RzIHByb21pc2VcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlnLm9uQXV0aG9yaXplKGRhdGEsIGFjdGlvbnMpLnRvUHJvbWlzZSgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5pbnRlZ3JhdGlvblR5cGUgPT09IFBheVBhbEludGVncmF0aW9uVHlwZS5DbGllbnRTaWRlUkVTVCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBNYWtlIGEgY2FsbCB0byB0aGUgUkVTVCBhcGkgdG8gZXhlY3V0ZSB0aGUgcGF5bWVudFxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5wYXltZW50LmV4ZWN1dGUoKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghdGhpcy5jb25maWcub25QYXltZW50Q29tcGxldGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihgWW91IHNob3VsZCBwcm92aWRlIHNvbWUgY2FsbGJhY2sgd2hlbiBwYXltZW50IGlzIGZpbmlzaGVkIHdoZW4gdXNpbmcgY2xpZW50IHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLm9uUGF5bWVudENvbXBsZXRlKGRhdGEsIGFjdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBvbkVycm9yOiAoZXJyKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLm9uRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcub25FcnJvcihlcnIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIG9uQ2FuY2VsOiAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5vbkNhbmNlbCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5vbkNhbmNlbChkYXRhLCBhY3Rpb25zKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25DbGljazogKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5vbkNsaWNrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLm9uQ2xpY2soKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdmFsaWRhdGU6IChhY3Rpb25zKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLnZhbGlkYXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLnZhbGlkYXRlKGFjdGlvbnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSwgYCMke3RoaXMucGF5UGFsQnV0dG9uQ29udGFpbmVySWR9YCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRDbGllbnQoKTogSVBheXBhbENsaWVudCB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy5pbnRlZ3JhdGlvblR5cGUgPT09IFBheVBhbEludGVncmF0aW9uVHlwZS5DbGllbnRTaWRlUkVTVCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5jbGllbnQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihgWW91IG5lZWQgdG8gc2V0dXAgY2xpZW50IGluZm9ybWF0aW9uIHdoZW4gdXNpbmcgY2xpZW50IHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBwcm9kdWN0aW9uOiB0aGlzLmNvbmZpZy5jbGllbnQucHJvZHVjdGlvbixcbiAgICAgICAgICAgICAgICBzYW5kYm94OiB0aGlzLmNvbmZpZy5jbGllbnQuc2FuZGJveFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRGdW5kaW5nKCk6IHtcbiAgICAgICAgYWxsb3dlZDogYW55W10sXG4gICAgICAgIGRpc2FsbG93ZWQ6IGFueVtdXG4gICAgfSB8IHVuZGVmaW5lZCB7XG4gICAgICAgIC8vIHJlc29sdmUgZnVuZGluZyB0byB1c2UgcGF5cGFsJ3MgcHJvcGVydGllc1xuICAgICAgICBpZiAoIXRoaXMuY29uZmlnLmZ1bmRpbmcpIHtcbiAgICAgICAgICAgIC8vIG5vIGZ1bmRpbmcgcHJvdmlkZWRcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBhbGxvd2VkOiBhbnlbXSA9IFtdO1xuICAgICAgICBjb25zdCBkaXNhbGxvd2VkOiBhbnlbXSA9IFtdO1xuXG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy5mdW5kaW5nLmFsbG93ZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY29uZmlnLmZ1bmRpbmcuYWxsb3dlZC5mb3JFYWNoKHR5cGUgPT4ge1xuICAgICAgICAgICAgICAgIGFsbG93ZWQucHVzaCh0aGlzLm1hcEZ1bmRpbmdUeXBlKHR5cGUpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmZ1bmRpbmcuZGlzYWxsb3dlZCkge1xuICAgICAgICAgICAgdGhpcy5jb25maWcuZnVuZGluZy5kaXNhbGxvd2VkLmZvckVhY2godHlwZSA9PiB7XG4gICAgICAgICAgICAgICAgZGlzYWxsb3dlZC5wdXNoKHRoaXMubWFwRnVuZGluZ1R5cGUodHlwZSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYWxsb3dlZDogYWxsb3dlZCxcbiAgICAgICAgICAgIGRpc2FsbG93ZWQ6IGRpc2FsbG93ZWRcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG1hcEZ1bmRpbmdUeXBlKHR5cGU6IFBheVBhbEZ1bmRpbmcpOiBhbnkge1xuICAgICAgICBpZiAodHlwZSA9PT0gUGF5UGFsRnVuZGluZy5DYXJkKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF5cGFsLkZVTkRJTkcuQ0FSRDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZSA9PT0gUGF5UGFsRnVuZGluZy5DcmVkaXQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXlwYWwuRlVORElORy5DUkVESVQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGUgPT09IFBheVBhbEZ1bmRpbmcuRWx2KSB7XG4gICAgICAgICAgICByZXR1cm4gcGF5cGFsLkZVTkRJTkcuRUxWO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IEVycm9yKGBVbnN1cHBvcnRlZCBmdW5kaW5nIHR5cGUgJyR7dHlwZX0nYCk7XG4gICAgfVxufVxuXG4iLCJpbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBOZ3hQYXlwYWxDb21wb25lbnQgfSBmcm9tICcuL2NvbXBvbmVudHMvcGF5cGFsLWNvbXBvbmVudCc7XG5cbkBOZ01vZHVsZSh7XG4gIGltcG9ydHM6IFtcbiAgXSxcbiAgZGVjbGFyYXRpb25zOiBbXG4gICAgTmd4UGF5cGFsQ29tcG9uZW50LFxuICBdLFxuICBleHBvcnRzOiBbXG4gICAgTmd4UGF5cGFsQ29tcG9uZW50LFxuICBdXG59KVxuZXhwb3J0IGNsYXNzIE5neFBheVBhbE1vZHVsZSB7XG59XG5cblxuIiwiZXhwb3J0IGVudW0gUGF5UGFsRW52aXJvbm1lbnQge1xuICAgIFNhbmRib3ggPSAnc2FuZGJveCcsXG4gICAgUHJvZHVjdGlvbiA9ICdwcm9kdWN0aW9uJ1xufVxuIiwiaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBQYXlQYWxGdW5kaW5nIH0gZnJvbSAnLi9wYXlwYWwtZnVuZGluZyc7XG5pbXBvcnQgeyBQYXlQYWxFbnZpcm9ubWVudCB9IGZyb20gJy4vcGF5cGFsLWVudmlyb25tZW50JztcbmltcG9ydCB7IFBheVBhbEludGVncmF0aW9uVHlwZSB9IGZyb20gJy4vcGF5cGFsLWludGVncmF0aW9uJztcblxuZXhwb3J0IGNsYXNzIFBheVBhbENvbmZpZyB7XG5cbiAgICAvKipcbiAgICAgKiBTaG93ICdQYXkgTm93JyBidXR0b24gY29uZmlnXG4gICAgICovXG4gICAgcHVibGljIGNvbW1pdCA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIGludGVudCBvZiB0aGUgcGF5bWVudC5cbiAgICAgKi9cbiAgICBwdWJsaWMgaW50ZW50ID0gJ3NhbGUnO1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGVkIHRvIGNyZWF0ZSBuZXcgcGF5bWVudCBmb3Igc2VydmVyIHNpZGUgaW50ZWdyYXRpb25cbiAgICAgKi9cbiAgICBwdWJsaWMgcGF5bWVudD86ICgpID0+IE9ic2VydmFibGU8c3RyaW5nPjtcblxuICAgIC8qKlxuICAgICAqIENhbGxlZCB0byBleGVjdXRlIHBheW1lbnQgZm9yIHNlcnZlciBzaWRlIGludGVncmF0aW9uXG4gICAgICovXG4gICAgcHVibGljIG9uQXV0aG9yaXplPzogKGRhdGE6IElQYXlQYWxQYXltZW50Q29tcGxldGVEYXRhLCBhY3Rpb25zOiBhbnkpID0+IE9ic2VydmFibGU8dm9pZD47XG5cbiAgICAvKipcbiAgICAgKiBDbGllbnQgdG9rZW5zIGZvciBjbGllbnQgc2lkZSBpbnRlZ3JhdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBjbGllbnQ/OiBJUGF5cGFsQ2xpZW50O1xuXG4gICAgLyoqXG4gICAgICogQXJyYXkgb2YgdHJhbnNhY3Rpb24sIHJlcXVpcmVkIGZvciBjbGllbnQgc2lkZSBpbnRlZ3JhdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyB0cmFuc2FjdGlvbnM/OiBJUGF5UGFsVHJhbnNhY3Rpb25bXTtcblxuICAgIC8qKlxuICAgICAqIFBheW1lbnQgRXhwZXJpZW5jZSBjb25maWd1cmF0aW9uc1xuICAgICAqL1xuICAgIHB1YmxpYyBleHBlcmllbmNlPzogSVBheVBhbEV4cGVyaWVuY2U7XG5cbiAgICAvKipcbiAgICAgKiBDYWxsZWQgZm9yIGNsaWVudCBzaWRlIGludGVncmF0aW9uIHdoZW4gcGF5bWVudCBpcyBleGVjdXRlZFxuICAgICAqL1xuICAgIHB1YmxpYyBvblBheW1lbnRDb21wbGV0ZT86IChkYXRhOiBJUGF5UGFsUGF5bWVudENvbXBsZXRlRGF0YSwgYWN0aW9uczogYW55KSA9PiB2b2lkO1xuXG4gICAgLyoqXG4gICAgICogQnV0dG9uIGNvbmZpZ3VyYXRpb25cbiAgICAgKi9cbiAgICBwdWJsaWMgYnV0dG9uPzogSVBheVBhbEJ1dHRvblN0eWxlO1xuXG4gICAgLyoqXG4gICAgICogUGF5cGFsIGZ1bmRpbmcgY29uZmlndXJhdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBmdW5kaW5nPzogSVBheVBhbEZ1bmRpbmc7XG5cbiAgICAvKipcbiAgICAgKiBDYWxsZWQgd2hlbiBQYXlQYWwgZXhwZXJpZW5jZXMgYW4gZXJyb3JcbiAgICAgKi9cbiAgICBwdWJsaWMgb25FcnJvcj86IChlcnI6IGFueSkgPT4gdm9pZDtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgaGFuZGxlciB3aWxsIGJlIGNhbGxlZCBmb3IgZXZlcnkgY2xpY2sgb24gdGhlIFBheVBhbCBidXR0b25cbiAgICAgKi9cbiAgICBwdWJsaWMgb25DbGljaz86ICgpID0+IHZvaWQ7XG5cbiAgICAvKipcbiAgICAgKiBDYWxsZWQgd2hlbiB1c2VyIGNhbmNlbHMgcGF5bWVudFxuICAgICAqL1xuICAgIHB1YmxpYyBvbkNhbmNlbD86IChkYXRhOiBJUGF5UGFsQ2FuY2VsUGF5bWVudCwgYWN0aW9uczogYW55KSA9PiB2b2lkO1xuXG4gICAgLyoqXG4gICAgICogQ2FuIGJlIHVzZWQgdG8gdmFsaWRhdGlvbiBhcyBjYW4gYmUgc2VlbiBoZXJlOiBodHRwczovL2RldmVsb3Blci5wYXlwYWwuY29tL2RlbW8vY2hlY2tvdXQvIy9wYXR0ZXJuL3ZhbGlkYXRpb25cbiAgICAgKi9cbiAgICBwdWJsaWMgdmFsaWRhdGU/OiAoYWN0aW9uczogYW55KSA9PiB2b2lkO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUeXBlIG9mIHRoZSBpbnRlZ3JhdGlvblxuICAgICAgICAgKi9cbiAgICAgICAgcHVibGljIGludGVncmF0aW9uVHlwZTogUGF5UGFsSW50ZWdyYXRpb25UeXBlLFxuICAgICAgICAvKipcbiAgICAgICAgICogRW52aXJvbm1lbnRcbiAgICAgICAgICovXG4gICAgICAgIHB1YmxpYyBlbnZpcm9ubWVudDogUGF5UGFsRW52aXJvbm1lbnQsXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgICAgb25FcnJvcj86IChlcnI6IGFueSkgPT4gdm9pZCxcbiAgICAgICAgICAgIG9uQ2xpY2s/OiAoKSA9PiB2b2lkLFxuICAgICAgICAgICAgdmFsaWRhdGU/OiAoYWN0aW9uczogYW55KSA9PiB2b2lkO1xuICAgICAgICAgICAgb25DYW5jZWw/OiAoZGF0YTogSVBheVBhbENhbmNlbFBheW1lbnQsIGFjdGlvbnM6IGFueSkgPT4gdm9pZCxcbiAgICAgICAgICAgIHBheW1lbnQ/OiAoKSA9PiBPYnNlcnZhYmxlPHN0cmluZz4sXG4gICAgICAgICAgICBvbkF1dGhvcml6ZT86IChkYXRhOiBJUGF5UGFsUGF5bWVudENvbXBsZXRlRGF0YSwgYWN0aW9uczogYW55KSA9PiBPYnNlcnZhYmxlPHZvaWQ+LFxuICAgICAgICAgICAgY2xpZW50PzogSVBheXBhbENsaWVudCxcbiAgICAgICAgICAgIG9uUGF5bWVudENvbXBsZXRlPzogKGRhdGE6IElQYXlQYWxQYXltZW50Q29tcGxldGVEYXRhLCBhY3Rpb25zOiBhbnkpID0+IHZvaWQsXG4gICAgICAgICAgICB0cmFuc2FjdGlvbnM/OiBJUGF5UGFsVHJhbnNhY3Rpb25bXSxcbiAgICAgICAgICAgIG5vdGVfdG9fcGF5ZXI/OiBzdHJpbmc7XG4gICAgICAgICAgICBleHBlcmllbmNlPzogSVBheVBhbEV4cGVyaWVuY2UsXG4gICAgICAgICAgICBjb21taXQ/OiBib29sZWFuLFxuICAgICAgICAgICAgYnV0dG9uPzogSVBheVBhbEJ1dHRvblN0eWxlLFxuICAgICAgICAgICAgZnVuZGluZz86IElQYXlQYWxGdW5kaW5nXG4gICAgICAgIH0pIHtcbiAgICAgICAgT2JqZWN0LmFzc2lnbih0aGlzLCBjb25maWcpO1xuICAgIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsUGF5bWVudENvbXBsZXRlRGF0YSB7XG4gICAgaW50ZW50OiBzdHJpbmc7XG4gICAgb3JkZXJJRDogc3RyaW5nO1xuICAgIHBheWVySUQ6IHN0cmluZztcbiAgICBwYXltZW50SUQ6IHN0cmluZztcbiAgICBwYXltZW50VG9rZW46IHN0cmluZztcbiAgICByZXR1cm5Vcmw6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsQ2FuY2VsUGF5bWVudCB7XG4gICAgZGF0YTogSVBheVBhbENhbmNlbFBheW1lbnREYXRhO1xuICAgIGFjdGlvbnM6IGFueTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsQ2FuY2VsUGF5bWVudERhdGEge1xuICAgIGJpbGxpbmdJRDogc3RyaW5nO1xuICAgIGNhbmNlbFVybDogc3RyaW5nO1xuICAgIGludGVudDogc3RyaW5nO1xuICAgIHBheW1lbnRJRDogc3RyaW5nO1xuICAgIHBheW1lbnRUb2tlbjogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlwYWxDbGllbnQge1xuICAgIHNhbmRib3g/OiBzdHJpbmc7XG4gICAgcHJvZHVjdGlvbj86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsVHJhbnNhY3Rpb24ge1xuICAgIGFtb3VudDogSVBheVBhbEFtb3VudDtcbiAgICBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgICBjdXN0b20/OiBzdHJpbmc7XG4gICAgcGF5bWVudF9vcHRpb25zPzogSVBheVBhbFRyYW5zYWN0aW9uUGF5bWVudE9wdGlvbnM7XG4gICAgaW52b2ljZV9udW1iZXI/OiBzdHJpbmc7XG4gICAgc29mdF9kZXNjcmlwdG9yPzogc3RyaW5nO1xuICAgIGl0ZW1fbGlzdD86IElQYXlQYWxUcmFuc2FjdGlvbkl0ZW1MaXN0O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxUcmFuc2FjdGlvbkl0ZW1MaXN0IHtcbiAgICBpdGVtcz86IElQYXlQYWxUcmFuc2FjdGlvbkl0ZW1bXTtcbiAgICBzaGlwcGluZ19hZGRyZXNzPzogSVBheVBhbFRyYW5zYWN0aW9uU2hpcHBpbmdBZGRyZXNzO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxUcmFuc2FjdGlvbkl0ZW0ge1xuICAgIG5hbWU6IHN0cmluZztcbiAgICBjdXJyZW5jeTogc3RyaW5nO1xuICAgIHByaWNlOiBudW1iZXI7XG4gICAgcXVhbnRpdHk6IG51bWJlcjtcblxuICAgIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICAgIHRheD86IG51bWJlcjtcbiAgICBza3U/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheVBhbEFtb3VudCB7XG4gICAgdG90YWw6IG51bWJlcjtcbiAgICBjdXJyZW5jeTogc3RyaW5nO1xuICAgIGRldGFpbHM/OiBJUGF5UGFsQW1vdW50RGV0YWlscztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsVHJhbnNhY3Rpb25TaGlwcGluZ0FkZHJlc3Mge1xuICAgIHJlY2lwaWVudF9uYW1lOiBzdHJpbmc7XG4gICAgbGluZTE6IHN0cmluZztcbiAgICBsaW5lMj86IHN0cmluZztcbiAgICBjaXR5OiBzdHJpbmc7XG4gICAgY291bnRyeV9jb2RlOiBzdHJpbmc7XG4gICAgcG9zdGFsX2NvZGU6IHN0cmluZztcbiAgICBwaG9uZTogc3RyaW5nO1xuICAgIHN0YXRlOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheVBhbEFtb3VudERldGFpbHMge1xuICAgIHN1YnRvdGFsOiBudW1iZXI7XG4gICAgdGF4OiBudW1iZXI7XG4gICAgc2hpcHBpbmc6IG51bWJlcjtcbiAgICBoYW5kbGluZ19mZWU6IG51bWJlcjtcbiAgICBzaGlwcGluZ19kaXNjb3VudDogbnVtYmVyO1xuICAgIGluc3VyYW5jZTogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxUcmFuc2FjdGlvblBheW1lbnRPcHRpb25zIHtcbiAgICBhbGxvd2VkX3BheW1lbnRfbWV0aG9kPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxFeHBlcmllbmNlIHtcbiAgICAvKiogSW5kaWNhdGVzIHdoZXRoZXIgUGF5UGFsIGRpc3BsYXlzIHNoaXBwaW5nIGFkZHJlc3MgZmllbGRzIG9uIHRoZSBleHBlcmllbmNlIHBhZ2VzICovXG4gICAgbm9TaGlwcGluZz86IGJvb2xlYW47XG4gICAgLyoqIEEgbGFiZWwgdGhhdCBvdmVycmlkZXMgdGhlIGJ1c2luZXNzIG5hbWUgaW4gdGhlIFBheVBhbCBhY2NvdW50IG9uIHRoZSBQYXlQYWwgcGFnZXMuIE1heCBsZW5ndGg6IDEyNyBjaGFyYWN0ZXJzLiAqL1xuICAgIGJyYW5kTmFtZT86IHN0cmluZztcbiAgICAvKiogVVJMIHRvIHRoZSBsb2dvIGltYWdlIChnaWYsIGpwZywgb3IgcG5nKS4gVGhlIGltYWdlJ3MgbWF4aW11bSB3aWR0aCBpcyAxOTAgcGl4ZWxzIGFuZCBtYXhpbXVtIGhlaWdodCBpcyA2MCBwaXhlbHMuICovXG4gICAgbG9nb0ltYWdlPzogc3RyaW5nO1xuICAgIC8qKiBMb2NhbGUgaW4gd2hpY2ggdG8gZGlzcGxheSBQYXlQYWwgcGFnZSAqL1xuICAgIGxvY2FsZUNvZGU/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheVBhbEJ1dHRvblN0eWxlIHtcbiAgICBsYWJlbD86ICdjaGVja291dCcgfCAncGF5JyB8ICdidXlub3cnIHwgJ3BheXBhbCc7XG4gICAgc2l6ZT86ICdzbWFsbCcgfCAnbWVkaXVtJyB8ICdsYXJnZScgfCAncmVzcG9uc2l2ZSc7XG4gICAgc2hhcGU/OiAncGlsbCcgfCAncmVjdCc7XG4gICAgY29sb3I/OiAnZ29sZCcgfCAnYmx1ZScgfCAnc2lsdmVyJyB8ICdibGFjayc7XG4gICAgbGF5b3V0PzogJ2hvcml6b250YWwnIHwgJ3ZlcnRpY2FsJztcbiAgICB0YWdsaW5lPzogZmFsc2U7XG4gICAgZnVuZGluZ2ljb25zPzogYm9vbGVhbjtcbiAgICBicmFuZGluZz86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheVBhbEZ1bmRpbmcge1xuICAgIGFsbG93ZWQ6IFBheVBhbEZ1bmRpbmdbXTtcbiAgICBkaXNhbGxvd2VkOiBQYXlQYWxGdW5kaW5nW107XG59XG5cbiJdLCJuYW1lcyI6WyJTdWJqZWN0IiwiaW50ZXJ2YWwiLCJ0YWtlVW50aWwiLCJtYXAiLCJDb21wb25lbnQiLCJDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSIsIklucHV0IiwiVmlld0NoaWxkIiwi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