UNPKG

ngx-paypal-with-intent

Version:

Paypal integration for Angular 6, 7 and beyond

506 lines 59.2 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-with-intent', ['exports', '@angular/core', 'rxjs', 'rxjs/operators'], factory) :
    (factory((global['ngx-paypal-with-intent'] = {}),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({
                                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: 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXBheXBhbC13aXRoLWludGVudC51bWQuanMubWFwIiwic291cmNlcyI6WyJuZzovL25neC1wYXlwYWwtd2l0aC1pbnRlbnQvbGliL21vZGVscy9wYXlwYWwtZnVuZGluZy50cyIsIm5nOi8vbmd4LXBheXBhbC13aXRoLWludGVudC9saWIvbW9kZWxzL3BheXBhbC1pbnRlZ3JhdGlvbi50cyIsIm5nOi8vbmd4LXBheXBhbC13aXRoLWludGVudC9saWIvY29tcG9uZW50cy9wYXlwYWwtY29tcG9uZW50LnRzIiwibmc6Ly9uZ3gtcGF5cGFsLXdpdGgtaW50ZW50L2xpYi9uZ3gtcGF5cGFsLm1vZHVsZS50cyIsIm5nOi8vbmd4LXBheXBhbC13aXRoLWludGVudC9saWIvbW9kZWxzL3BheXBhbC1lbnZpcm9ubWVudC50cyIsIm5nOi8vbmd4LXBheXBhbC13aXRoLWludGVudC9saWIvbW9kZWxzL3BheXBhbC1tb2RlbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGVudW0gUGF5UGFsRnVuZGluZyB7XG4gICAgQ2FyZCxcbiAgICBDcmVkaXQsXG4gICAgRWx2XG59XG4iLCJleHBvcnQgZW51bSBQYXlQYWxJbnRlZ3JhdGlvblR5cGUge1xuICAgIENsaWVudFNpZGVSRVNULFxuICAgIFNlcnZlclNpZGVSRVNULFxufVxuIiwiaW1wb3J0IHtcbiAgICBBZnRlclZpZXdJbml0LFxuICAgIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICAgIENvbXBvbmVudCxcbiAgICBFbGVtZW50UmVmLFxuICAgIElucHV0LFxuICAgIE9uQ2hhbmdlcyxcbiAgICBPbkRlc3Ryb3ksXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBWaWV3Q2hpbGQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaW50ZXJ2YWwsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBQYXlQYWxGdW5kaW5nIH0gZnJvbSAnLi4vbW9kZWxzL3BheXBhbC1mdW5kaW5nJztcbmltcG9ydCB7IFBheVBhbEludGVncmF0aW9uVHlwZSB9IGZyb20gJy4uL21vZGVscy9wYXlwYWwtaW50ZWdyYXRpb24nO1xuaW1wb3J0IHsgSVBheXBhbENsaWVudCwgSVBheVBhbFBheW1lbnRDb21wbGV0ZURhdGEsIFBheVBhbENvbmZpZyB9IGZyb20gJy4uL21vZGVscy9wYXlwYWwtbW9kZWxzJztcblxuLyoqXG4gKiBHbG9iYWwgdmFyaWFibGUgd2hlcmUgUGF5UGFsIGlzIGxvYWRlZCB0b1xuICovXG5kZWNsYXJlIHZhciBwYXlwYWw6IGFueTtcblxuQENvbXBvbmVudCh7XG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gICAgc2VsZWN0b3I6ICduZ3gtcGF5cGFsJyxcbiAgICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgI3BheVBhbFNjcmlwdEVsZW0+PC9kaXY+XG4gICAgPGRpdiAjcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbSBbaWRdPVwicGF5UGFsQnV0dG9uQ29udGFpbmVySWRcIj48L2Rpdj5cbiAgICBgXG59KVxuZXhwb3J0IGNsYXNzIE5neFBheXBhbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcblxuICAgIC8qKlxuICAgICAqIENvbmZpZ3VyYXRpb24gZm9yIHBheXBhbC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBjb25maWc6IFBheVBhbENvbmZpZztcblxuICAgIC8qKlxuICAgICAqIEluZGljYXRlcyBpZiBnbG9iYWwgY29uZmlndXJhdGlvbiAocHJvdmlkZWQgdmlhICdmb3JSb290JykgaXMgdXNlZFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHVzZUdsb2JhbENvbmZpZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogQ29udGFpbmVyIGZvciBwYXlwYWwgc2NyaXB0XG4gICAgICovXG4gICAgQFZpZXdDaGlsZCgncGF5UGFsU2NyaXB0RWxlbScpIHBheXBhbFNjcmlwdEVsZW06IEVsZW1lbnRSZWY7XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIGZvciBpbmRpY2F0aW5nIGRlbGF5ZWQgcmVuZGVyZWQgaWYgY29udGFpbmVyIGlzIG5vdCB5ZXQgcmVhZHkgaW4gRE9NXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWdpc3RlclBheVBhbFNjcmlwdFdoZW5Db250YWluZXJJc1JlYWR5ID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBIb2xkcyBjdXJyZW50IGNvbnRhaW5lciBlbGVtZW50XG4gICAgICovXG4gICAgcHJpdmF0ZSBfcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbT86IEVsZW1lbnRSZWY7XG4gICAgQFZpZXdDaGlsZCgncGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbScpIHNldCBwYXlQYWxCdXR0b25Db250YWluZXJFbGVtKGNvbnRlbnQ6IEVsZW1lbnRSZWYpIHtcbiAgICAgICAgaWYgKGNvbnRlbnQpIHtcbiAgICAgICAgICAgIHRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0gPSBjb250ZW50O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUG9sbGluZyBpbnRlcnZhbCBpZiBwYXlwYWwgc2NyaXB0IGlzIHBlbmRpbmdcbiAgICAgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IGRlZmF1bHRQb2xsSW50ZXJ2YWwgPSA1MDtcblxuICAgIC8qKlxuICAgICAqIFBvbGxpbmcgd2lsbCBzdG9wIGFmdGVyIHBvbGxpbmcgcmVhY2hlcyB0aGlzIG51bWJlclxuICAgICAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbWF4aW11bVBvbGxXYWl0VGltZSA9IDUwMDA7XG5cbiAgICAvKipcbiAgICAqIE5hbWUgb2YgdGhlIGdsb2JhbCB2YXJpYWJsZSB3aGVyZSBwYXlwYWwgaXMgc3RvcmVkXG4gICAgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IHBheXBhbFdpbmRvd05hbWUgPSAncGF5cGFsJztcblxuICAgIC8qKlxuICAgICAqIE5hbWUgb2YgdGhlIGdsb2JhbCB2YXJpYWJsZSBpbmRpY2F0aW5nIHRoYXQgc2NyaXB0IHdhcyBpbml0aWF0ZWQgKGFkZGVkIHRvIHBhZ2UpXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBwYXlwYWxXaW5kb3dTY3JpcHRJbml0aWF0ZWQgPSAnbmd4LXBheXBhbC1zY3JpcHQtaW5pdGlhdGVkJztcblxuICAgIC8qKlxuICAgICAqIFBheVBhbCBpbnRlZ3JhdGlvbiBzY3JpcHQgdXJsXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBwYXlwYWxTY3JpcHRVcmwgPSAnaHR0cHM6Ly93d3cucGF5cGFsb2JqZWN0cy5jb20vYXBpL2NoZWNrb3V0LmpzJztcblxuICAgIC8qKlxuICAgICAqIElkIG9mIHRoZSBlbGVtZW50IHdoZXJlIFBheVBhbCBidXR0b24gd2lsbCBiZSByZW5kZXJlZFxuICAgICAqL1xuICAgIHB1YmxpYyBwYXlQYWxCdXR0b25Db250YWluZXJJZD86IHN0cmluZztcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgcGF5UGFsQnV0dG9uQ29udGFpbmVySWRQcmVmaXggPSAnbmd4LXBheXBhbC1idXR0b24tY29udGFpbmVyLSc7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IG5nVW5zdWJzY3JpYmU6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgKSB7XG4gICAgfVxuXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgICAgICAvLyBpbml0IHdoZW4gY29uZmlnIG9uY2UgaXRzIGF2YWlsYWJsZVxuICAgICAgICBpZiAodGhpcy5jb25maWcpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdFBheVBhbCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICAvLyByZWdpc3RlciBzY3JpcHQgaWYgZWxlbWVudCBpcyByZWFkeSBpbiBkb21cbiAgICAgICAgaWYgKHRoaXMucmVnaXN0ZXJQYXlQYWxTY3JpcHRXaGVuQ29udGFpbmVySXNSZWFkeSAmJiB0aGlzLl9wYXlQYWxCdXR0b25Db250YWluZXJFbGVtKSB7XG4gICAgICAgICAgICB0aGlzLnNldHVwU2NyaXB0KCk7XG4gICAgICAgICAgICB0aGlzLnJlZ2lzdGVyUGF5UGFsU2NyaXB0V2hlbkNvbnRhaW5lcklzUmVhZHkgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLm5nVW5zdWJzY3JpYmUubmV4dCgpO1xuICAgICAgICB0aGlzLm5nVW5zdWJzY3JpYmUuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGluaXRQYXlQYWwoKTogdm9pZCB7XG4gICAgICAgIC8vIHNldCB1bmlxdWUgcGF5cGFsIGNvbnRhaW5lciBidXR0b24gaWRcbiAgICAgICAgdGhpcy5wYXlQYWxCdXR0b25Db250YWluZXJJZCA9IGAke3RoaXMucGF5UGFsQnV0dG9uQ29udGFpbmVySWRQcmVmaXh9JHt0aGlzLmdldFBzZXVkb1VuaXF1ZU51bWJlcigpfWA7XG4gICAgICAgIC8vIGNoZWNrIGlmIHBheXBhbCB3YXMgYWxyZWFkeSByZWdpc3RlciBhbmQgaWYgc28sIGRvbid0IGFkZCBpdCB0byBwYWdlIGFnYWluXG4gICAgICAgIGlmICghd2luZG93W3RoaXMucGF5cGFsV2luZG93TmFtZV0pIHtcbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIHNjcmlwdCBpcyBwZW5kaW5nXG4gICAgICAgICAgICBpZiAod2luZG93W3RoaXMucGF5cGFsV2luZG93U2NyaXB0SW5pdGlhdGVkXSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMucG9sbFVudGlsU2NyaXB0QXZhaWxhYmxlKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHJlZ2lzdGVyIHNjcmlwdCBhbmQgc2V0IGdsb2JhbCBmbGFnXG4gICAgICAgICAgICAgICAgd2luZG93W3RoaXMucGF5cGFsV2luZG93U2NyaXB0SW5pdGlhdGVkXSA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5hZGRQYXlQYWxTY3JpcHRUb1BhZ2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8ganVzdCByZWdpc3RlciBwYXltZW50XG4gICAgICAgICAgICB0aGlzLmhhbmRsZVNjcmlwdFJlZ2lzdGVyaW5nKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFBzZXVkb1VuaXF1ZU51bWJlcigpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gbmV3IERhdGUoKS52YWx1ZU9mKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXNlZCB3aGVuIHRoZXJlIGFyZSBtdWx0aXBsZSBwYXlwYWwgY29tcG9uZW50cyBvbiB0aGUgc2FtZSBwYWdlIGJlYWN1c2Ugb25seSAxIG9mIHRoZW1cbiAgICAgKiBtYXkgcmVnaXN0ZXIgcGF5cGFsIHNjcmlwdC4gVGhlIG90aGVyIGhhcyB0byBiZSBwb2xsaW5nIHVudGlsIHBheXBhbCBpcyBhdmFpbGFibGUgb3IgY29tcG9uZW50IGRlc3Ryb3llZFxuICAgICAqL1xuICAgIHByaXZhdGUgcG9sbFVudGlsU2NyaXB0QXZhaWxhYmxlKCk6IHZvaWQge1xuICAgICAgICBjb25zdCBvYnMgPSBpbnRlcnZhbCh0aGlzLmRlZmF1bHRQb2xsSW50ZXJ2YWwpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5uZ1Vuc3Vic2NyaWJlKSxcbiAgICAgICAgICAgICAgICBtYXAoKHgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHggPj0gdGhpcy5tYXhpbXVtUG9sbFdhaXRUaW1lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oYFBheVBhbCBzY3JpcHQgd2FzIG5vdCBsb2FkZWQgYWZ0ZXIgJyR7dGhpcy5tYXhpbXVtUG9sbFdhaXRUaW1lfScgbWF4aW11bSBwb2xsaW5nIHRpbWUuYCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBvYnMudW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIGNoZWNrIGlmIHBheXBhbCBzY3JpcHQgZXhpc3RzXG4gICAgICAgICAgICAgICAgICAgIGlmICh3aW5kb3dbdGhpcy5wYXlwYWxXaW5kb3dOYW1lXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVnaXN0ZXIgc2NyaXB0XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZVNjcmlwdFJlZ2lzdGVyaW5nKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0b3AgZXhlY3V0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICBvYnMudW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhZGRQYXlQYWxTY3JpcHRUb1BhZ2UoKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpO1xuICAgICAgICBzY3JpcHQuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIHNjcmlwdC5zcmMgPSB0aGlzLnBheXBhbFNjcmlwdFVybDtcbiAgICAgICAgc2NyaXB0Lm9ubG9hZCA9ICgpID0+IHRoaXMuaGFuZGxlU2NyaXB0UmVnaXN0ZXJpbmcoKTtcbiAgICAgICAgc2NyaXB0LmFzeW5jID0gdHJ1ZTtcbiAgICAgICAgc2NyaXB0LmRlZmVyID0gdHJ1ZTtcblxuICAgICAgICB0aGlzLnBheXBhbFNjcmlwdEVsZW0ubmF0aXZlRWxlbWVudC5hcHBlbmRDaGlsZChzY3JpcHQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaGFuZGxlU2NyaXB0UmVnaXN0ZXJpbmcoKTogdm9pZCB7XG4gICAgICAgIC8vIGNoZWNrIGlmIGNvbnRhaW5lciB3aXRoIHJlcXVlc3RlZCBpZCBleGlzdHNcbiAgICAgICAgLy8gdGhpcyBpcyBoZXJlIGJlY2F1c2UgZHluYW1pY2FsbHkgc3dpdGNoaW5nIGJldHdlZW4gY29tcG9uZW50cyB3b3VsZCBjYXVzZSBQYXlQYWwgdG9cbiAgICAgICAgLy8gdGhyb3cgYW4gZXJyb3IgaWYgdGhlIGNvbnRhaW5lciBhbHJlYWR5IGV4aXN0ZWQgYmVmb3JlXG4gICAgICAgIGlmICh0aGlzLl9wYXlQYWxCdXR0b25Db250YWluZXJFbGVtICYmIHRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0ubmF0aXZlRWxlbWVudCAmJlxuICAgICAgICAgICAgdGhpcy5fcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbS5uYXRpdmVFbGVtZW50LmlkID09PSB0aGlzLnBheVBhbEJ1dHRvbkNvbnRhaW5lcklkKSB7XG4gICAgICAgICAgICAvLyBjb250YWluZXIgaXMgcmVhZHksIHNldHVwIHNjcmlwdCByaWdodCBhd2F5XG4gICAgICAgICAgICB0aGlzLnNldHVwU2NyaXB0KCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBjb250YWluZXIgaXMgbm90IHJlYWR5LCBkZWxheSByZWdpc3RlcmluZyB1bnRpbCBpdCBpc1xuICAgICAgICAgICAgdGhpcy5yZWdpc3RlclBheVBhbFNjcmlwdFdoZW5Db250YWluZXJJc1JlYWR5ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgc2V0dXBTY3JpcHQoKTogdm9pZCB7XG4gICAgICAgIC8vIGZpcnN0IGNsZWFyIGNvbnRhaW5lclxuICAgICAgICBpZiAoIXRoaXMuX3BheVBhbEJ1dHRvbkNvbnRhaW5lckVsZW0pIHtcbiAgICAgICAgICAgIHRocm93IEVycm9yKGBDYW5ub3Qgc2V0dXAgc2NyaXB0IGJlY2F1c2UgcGF5cGFsIGJ1dHRvbiBjb250YWluZXIgd2l0aCBpZCAnJHt0aGlzLnBheVBhbEJ1dHRvbkNvbnRhaW5lcklkfScgaXMgbm90IHlldCByZWFkeWApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fcGF5UGFsQnV0dG9uQ29udGFpbmVyRWxlbS5uYXRpdmVFbGVtZW50LmlubmVySFRNTCA9ICcnO1xuXG4gICAgICAgIGlmICghd2luZG93W3RoaXMucGF5cGFsV2luZG93TmFtZV0pIHtcbiAgICAgICAgICAgIHRocm93IEVycm9yKCdQYXlQYWwgc2NyaXB0IGlzIG5vdCBhdmFpbGFibGUnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHJlbmRlciBQYXlQYWwgYnV0dG9uIGFzIHBlciB0aGVpciBkb2NzIGF0XG4gICAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLnBheXBhbC5jb20vZG9jcy9pbnRlZ3JhdGlvbi9kaXJlY3QvZXhwcmVzcy1jaGVja291dC9pbnRlZ3JhdGlvbi1qc3Y0L2FkZC1wYXlwYWwtYnV0dG9uL1xuICAgICAgICB3aW5kb3dbdGhpcy5wYXlwYWxXaW5kb3dOYW1lXS5CdXR0b24ucmVuZGVyKHtcbiAgICAgICAgICAgIC8vIHNldCBlbnZpcm9ubWVudFxuICAgICAgICAgICAgZW52OiB0aGlzLmNvbmZpZy5lbnZpcm9ubWVudC50b1N0cmluZygpLFxuXG4gICAgICAgICAgICAvLyBTaG93IHRoZSBidXllciBhICdQYXkgTm93JyBidXR0b24gaW4gdGhlIGNoZWNrb3V0IGZsb3dcbiAgICAgICAgICAgIGNvbW1pdDogdGhpcy5jb25maWcuY29tbWl0LFxuXG4gICAgICAgICAgICAvLyBpbml0IGNsaWVudCBmb3IgY2xpZW50IHNpZGUgaW50ZWdyYXRpb25cbiAgICAgICAgICAgIGNsaWVudDogdGhpcy5nZXRDbGllbnQoKSxcblxuICAgICAgICAgICAgLy8gc2V0IGJ1dHRvbiBjb25maWcgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBzdHlsZTogdGhpcy5jb25maWcuYnV0dG9uLFxuXG4gICAgICAgICAgICAvLyBzZXQgZnVuZGluZyBpZiBhdmFpbGFibGVcbiAgICAgICAgICAgIGZ1bmRpbmc6IHRoaXMuZ2V0RnVuZGluZygpLFxuXG4gICAgICAgICAgICAvLyBwYXltZW50KCkgaXMgY2FsbGVkIHdoZW4gdGhlIGJ1dHRvbiBpcyBjbGlja2VkXG4gICAgICAgICAgICBwYXltZW50OiAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5pbnRlZ3JhdGlvblR5cGUgPT09IFBheVBhbEludGVncmF0aW9uVHlwZS5TZXJ2ZXJTaWRlUkVTVCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBjbGllbnQgbmVlZHMgdG8gY3JlYXRlIHBheW1lbnQgb24gc2VydmVyIHNpZGVcbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5wYXltZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihgWW91IG5lZWQgc2V0IHVwIGEgY3JlYXRlIHBheW1lbnQgbWV0aG9kIGFuZCByZXR1cm5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQYXlQYWwncyBwYXltZW50IGlkIHdoZW4gdXNpbmcgc2VydmVyIHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFBheXBhbCBleHBlY3RzIHByb21pc2Ugd2l0aCBwYXltZW50IGlkIChzdHJpbmcpIHRvIGJlIHJldHVybmVkXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbmZpZy5wYXltZW50KCkudG9Qcm9taXNlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKHBheW1lbnRJZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBheW1lbnRJZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5pbnRlZ3JhdGlvblR5cGUgPT09IFBheVBhbEludGVncmF0aW9uVHlwZS5DbGllbnRTaWRlUkVTVCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuY29uZmlnLnRyYW5zYWN0aW9ucyB8fCAhQXJyYXkuaXNBcnJheSh0aGlzLmNvbmZpZy50cmFuc2FjdGlvbnMpIHx8IHRoaXMuY29uZmlnLnRyYW5zYWN0aW9ucy5sZW5ndGggPD0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoYFlvdSBuZWVkIHRvIHByb3ZpZGUgYXQgbGVhc3QgMSB0cmFuc2FjdGlvbiBmb3IgY2xpZW50IHNpZGUgaW50ZWdyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4cGVyaWVuY2VDb25maWcgPSB0aGlzLmNvbmZpZy5leHBlcmllbmNlO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5wYXltZW50LmNyZWF0ZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXltZW50OiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWxsb3cgdXNlciB0byBzcGVjaWZpZnkgaW50ZW50LCBlbHNlIHVzZSBkZWZhdWx0ICdzYWxlJy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlbnQ6IHRoaXMuY29uZmlnLmludGVudCA/IHRoaXMuY29uZmlnLmludGVudCA6ICdzYWxlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2FjdGlvbnM6IHRoaXMuY29uZmlnLnRyYW5zYWN0aW9uc1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4cGVyaWVuY2U6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dF9maWVsZHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9fc2hpcHBpbmc6IChleHBlcmllbmNlQ29uZmlnICYmIGV4cGVyaWVuY2VDb25maWcubm9TaGlwcGluZykgPyAxIDogMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlc2VudGF0aW9uOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyYW5kX25hbWU6IChleHBlcmllbmNlQ29uZmlnICYmIGV4cGVyaWVuY2VDb25maWcuYnJhbmROYW1lKSA/IGV4cGVyaWVuY2VDb25maWcuYnJhbmROYW1lIDogbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nb19pbWFnZTogKGV4cGVyaWVuY2VDb25maWcgJiYgZXhwZXJpZW5jZUNvbmZpZy5sb2dvSW1hZ2UpID8gZXhwZXJpZW5jZUNvbmZpZy5sb2dvSW1hZ2UgOiBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhbGVfY29kZTogKGV4cGVyaWVuY2VDb25maWcgJiYgZXhwZXJpZW5jZUNvbmZpZy5sb2NhbGVDb2RlKSA/IGV4cGVyaWVuY2VDb25maWcubG9jYWxlQ29kZSA6IG51bGxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIC8vIG9uQXV0aG9yaXplKCkgaXMgY2FsbGVkIHdoZW4gdGhlIGJ1eWVyIGFwcHJvdmVzIHRoZSBwYXltZW50XG4gICAgICAgICAgICBvbkF1dGhvcml6ZTogKGRhdGE6IElQYXlQYWxQYXltZW50Q29tcGxldGVEYXRhLCBhY3Rpb25zOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jb25maWcuaW50ZWdyYXRpb25UeXBlID09PSBQYXlQYWxJbnRlZ3JhdGlvblR5cGUuU2VydmVyU2lkZVJFU1QpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gY2xpZW50IG5lZWRzIHRvIHNlcnZlciB0byBleGVjdXRlIHRoZSBwYXltZW50XG4gICAgICAgICAgICAgICAgICAgIGlmICghdGhpcy5jb25maWcub25BdXRob3JpemUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGBZb3UgbmVlZCBzZXQgdXAgYW4gZXhlY3V0ZSBtZXRob2Qgd2hlbiB1c2luZyBzZXJ2ZXIgc2lkZSBpbnRlZ3JhdGlvbmApO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUGF5cGFsIGV4cGVjdHMgcHJvbWlzZVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5jb25maWcub25BdXRob3JpemUoZGF0YSwgYWN0aW9ucykudG9Qcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLmludGVncmF0aW9uVHlwZSA9PT0gUGF5UGFsSW50ZWdyYXRpb25UeXBlLkNsaWVudFNpZGVSRVNUKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIE1ha2UgYSBjYWxsIHRvIHRoZSBSRVNUIGFwaSB0byBleGVjdXRlIHRoZSBwYXltZW50XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBhY3Rpb25zLnBheW1lbnQuZXhlY3V0ZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5vblBheW1lbnRDb21wbGV0ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGBZb3Ugc2hvdWxkIHByb3ZpZGUgc29tZSBjYWxsYmFjayB3aGVuIHBheW1lbnQgaXMgZmluaXNoZWQgd2hlbiB1c2luZyBjbGllbnQgc2lkZSBpbnRlZ3JhdGlvbmApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcub25QYXltZW50Q29tcGxldGUoZGF0YSwgYWN0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIG9uRXJyb3I6IChlcnIpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jb25maWcub25FcnJvcikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5vbkVycm9yKGVycik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgb25DYW5jZWw6IChkYXRhLCBhY3Rpb25zKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLm9uQ2FuY2VsKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLm9uQ2FuY2VsKGRhdGEsIGFjdGlvbnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkNsaWNrOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLm9uQ2xpY2spIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcub25DbGljaygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB2YWxpZGF0ZTogKGFjdGlvbnMpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jb25maWcudmFsaWRhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcudmFsaWRhdGUoYWN0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LCBgIyR7dGhpcy5wYXlQYWxCdXR0b25Db250YWluZXJJZH1gKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldENsaWVudCgpOiBJUGF5cGFsQ2xpZW50IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmludGVncmF0aW9uVHlwZSA9PT0gUGF5UGFsSW50ZWdyYXRpb25UeXBlLkNsaWVudFNpZGVSRVNUKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuY29uZmlnLmNsaWVudCkge1xuICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGBZb3UgbmVlZCB0byBzZXR1cCBjbGllbnQgaW5mb3JtYXRpb24gd2hlbiB1c2luZyBjbGllbnQgc2lkZSBpbnRlZ3JhdGlvbmApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHByb2R1Y3Rpb246IHRoaXMuY29uZmlnLmNsaWVudC5wcm9kdWN0aW9uLFxuICAgICAgICAgICAgICAgIHNhbmRib3g6IHRoaXMuY29uZmlnLmNsaWVudC5zYW5kYm94XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldEZ1bmRpbmcoKToge1xuICAgICAgICBhbGxvd2VkOiBhbnlbXSxcbiAgICAgICAgZGlzYWxsb3dlZDogYW55W11cbiAgICB9IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgLy8gcmVzb2x2ZSBmdW5kaW5nIHRvIHVzZSBwYXlwYWwncyBwcm9wZXJ0aWVzXG4gICAgICAgIGlmICghdGhpcy5jb25maWcuZnVuZGluZykge1xuICAgICAgICAgICAgLy8gbm8gZnVuZGluZyBwcm92aWRlZFxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGFsbG93ZWQ6IGFueVtdID0gW107XG4gICAgICAgIGNvbnN0IGRpc2FsbG93ZWQ6IGFueVtdID0gW107XG5cbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmZ1bmRpbmcuYWxsb3dlZCkge1xuICAgICAgICAgICAgdGhpcy5jb25maWcuZnVuZGluZy5hbGxvd2VkLmZvckVhY2godHlwZSA9PiB7XG4gICAgICAgICAgICAgICAgYWxsb3dlZC5wdXNoKHRoaXMubWFwRnVuZGluZ1R5cGUodHlwZSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5jb25maWcuZnVuZGluZy5kaXNhbGxvd2VkKSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5mdW5kaW5nLmRpc2FsbG93ZWQuZm9yRWFjaCh0eXBlID0+IHtcbiAgICAgICAgICAgICAgICBkaXNhbGxvd2VkLnB1c2godGhpcy5tYXBGdW5kaW5nVHlwZSh0eXBlKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBhbGxvd2VkOiBhbGxvd2VkLFxuICAgICAgICAgICAgZGlzYWxsb3dlZDogZGlzYWxsb3dlZFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgbWFwRnVuZGluZ1R5cGUodHlwZTogUGF5UGFsRnVuZGluZyk6IGFueSB7XG4gICAgICAgIGlmICh0eXBlID09PSBQYXlQYWxGdW5kaW5nLkNhcmQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXlwYWwuRlVORElORy5DQVJEO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlID09PSBQYXlQYWxGdW5kaW5nLkNyZWRpdCkge1xuICAgICAgICAgICAgcmV0dXJuIHBheXBhbC5GVU5ESU5HLkNSRURJVDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZSA9PT0gUGF5UGFsRnVuZGluZy5FbHYpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXlwYWwuRlVORElORy5FTFY7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgRXJyb3IoYFVuc3VwcG9ydGVkIGZ1bmRpbmcgdHlwZSAnJHt0eXBlfSdgKTtcbiAgICB9XG59XG5cbiIsImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IE5neFBheXBhbENvbXBvbmVudCB9IGZyb20gJy4vY29tcG9uZW50cy9wYXlwYWwtY29tcG9uZW50JztcblxuQE5nTW9kdWxlKHtcbiAgaW1wb3J0czogW1xuICBdLFxuICBkZWNsYXJhdGlvbnM6IFtcbiAgICBOZ3hQYXlwYWxDb21wb25lbnQsXG4gIF0sXG4gIGV4cG9ydHM6IFtcbiAgICBOZ3hQYXlwYWxDb21wb25lbnQsXG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgTmd4UGF5UGFsTW9kdWxlIHtcbn1cblxuXG4iLCJleHBvcnQgZW51bSBQYXlQYWxFbnZpcm9ubWVudCB7XG4gICAgU2FuZGJveCA9ICdzYW5kYm94JyxcbiAgICBQcm9kdWN0aW9uID0gJ3Byb2R1Y3Rpb24nXG59XG4iLCJpbXBvcnQgeyBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IFBheVBhbEZ1bmRpbmcgfSBmcm9tICcuL3BheXBhbC1mdW5kaW5nJztcbmltcG9ydCB7IFBheVBhbEVudmlyb25tZW50IH0gZnJvbSAnLi9wYXlwYWwtZW52aXJvbm1lbnQnO1xuaW1wb3J0IHsgUGF5UGFsSW50ZWdyYXRpb25UeXBlIH0gZnJvbSAnLi9wYXlwYWwtaW50ZWdyYXRpb24nO1xuXG5leHBvcnQgY2xhc3MgUGF5UGFsQ29uZmlnIHtcblxuICAgIC8qKlxuICAgICAqIFNob3cgJ1BheSBOb3cnIGJ1dHRvbiBjb25maWdcbiAgICAgKi9cbiAgICBwdWJsaWMgY29tbWl0ID0gdHJ1ZTtcblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgaW50ZW50IG9mIHRoZSBwYXltZW50LlxuICAgICAqL1xuICAgIHB1YmxpYyBpbnRlbnQgPSAnc2FsZSc7XG5cbiAgICAvKipcbiAgICAgKiBDYWxsZWQgdG8gY3JlYXRlIG5ldyBwYXltZW50IGZvciBzZXJ2ZXIgc2lkZSBpbnRlZ3JhdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBwYXltZW50PzogKCkgPT4gT2JzZXJ2YWJsZTxzdHJpbmc+O1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGVkIHRvIGV4ZWN1dGUgcGF5bWVudCBmb3Igc2VydmVyIHNpZGUgaW50ZWdyYXRpb25cbiAgICAgKi9cbiAgICBwdWJsaWMgb25BdXRob3JpemU/OiAoZGF0YTogSVBheVBhbFBheW1lbnRDb21wbGV0ZURhdGEsIGFjdGlvbnM6IGFueSkgPT4gT2JzZXJ2YWJsZTx2b2lkPjtcblxuICAgIC8qKlxuICAgICAqIENsaWVudCB0b2tlbnMgZm9yIGNsaWVudCBzaWRlIGludGVncmF0aW9uXG4gICAgICovXG4gICAgcHVibGljIGNsaWVudD86IElQYXlwYWxDbGllbnQ7XG5cbiAgICAvKipcbiAgICAgKiBBcnJheSBvZiB0cmFuc2FjdGlvbiwgcmVxdWlyZWQgZm9yIGNsaWVudCBzaWRlIGludGVncmF0aW9uXG4gICAgICovXG4gICAgcHVibGljIHRyYW5zYWN0aW9ucz86IElQYXlQYWxUcmFuc2FjdGlvbltdO1xuXG4gICAgLyoqXG4gICAgICogUGF5bWVudCBFeHBlcmllbmNlIGNvbmZpZ3VyYXRpb25zXG4gICAgICovXG4gICAgcHVibGljIGV4cGVyaWVuY2U/OiBJUGF5UGFsRXhwZXJpZW5jZTtcblxuICAgIC8qKlxuICAgICAqIENhbGxlZCBmb3IgY2xpZW50IHNpZGUgaW50ZWdyYXRpb24gd2hlbiBwYXltZW50IGlzIGV4ZWN1dGVkXG4gICAgICovXG4gICAgcHVibGljIG9uUGF5bWVudENvbXBsZXRlPzogKGRhdGE6IElQYXlQYWxQYXltZW50Q29tcGxldGVEYXRhLCBhY3Rpb25zOiBhbnkpID0+IHZvaWQ7XG5cbiAgICAvKipcbiAgICAgKiBCdXR0b24gY29uZmlndXJhdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBidXR0b24/OiBJUGF5UGFsQnV0dG9uU3R5bGU7XG5cbiAgICAvKipcbiAgICAgKiBQYXlwYWwgZnVuZGluZyBjb25maWd1cmF0aW9uXG4gICAgICovXG4gICAgcHVibGljIGZ1bmRpbmc/OiBJUGF5UGFsRnVuZGluZztcblxuICAgIC8qKlxuICAgICAqIENhbGxlZCB3aGVuIFBheVBhbCBleHBlcmllbmNlcyBhbiBlcnJvclxuICAgICAqL1xuICAgIHB1YmxpYyBvbkVycm9yPzogKGVycjogYW55KSA9PiB2b2lkO1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBoYW5kbGVyIHdpbGwgYmUgY2FsbGVkIGZvciBldmVyeSBjbGljayBvbiB0aGUgUGF5UGFsIGJ1dHRvblxuICAgICAqL1xuICAgIHB1YmxpYyBvbkNsaWNrPzogKCkgPT4gdm9pZDtcblxuICAgIC8qKlxuICAgICAqIENhbGxlZCB3aGVuIHVzZXIgY2FuY2VscyBwYXltZW50XG4gICAgICovXG4gICAgcHVibGljIG9uQ2FuY2VsPzogKGRhdGE6IElQYXlQYWxDYW5jZWxQYXltZW50LCBhY3Rpb25zOiBhbnkpID0+IHZvaWQ7XG5cbiAgICAvKipcbiAgICAgKiBDYW4gYmUgdXNlZCB0byB2YWxpZGF0aW9uIGFzIGNhbiBiZSBzZWVuIGhlcmU6IGh0dHBzOi8vZGV2ZWxvcGVyLnBheXBhbC5jb20vZGVtby9jaGVja291dC8jL3BhdHRlcm4vdmFsaWRhdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyB2YWxpZGF0ZT86IChhY3Rpb25zOiBhbnkpID0+IHZvaWQ7XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFR5cGUgb2YgdGhlIGludGVncmF0aW9uXG4gICAgICAgICAqL1xuICAgICAgICBwdWJsaWMgaW50ZWdyYXRpb25UeXBlOiBQYXlQYWxJbnRlZ3JhdGlvblR5cGUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFbnZpcm9ubWVudFxuICAgICAgICAgKi9cbiAgICAgICAgcHVibGljIGVudmlyb25tZW50OiBQYXlQYWxFbnZpcm9ubWVudCxcbiAgICAgICAgY29uZmlnOiB7XG4gICAgICAgICAgICBvbkVycm9yPzogKGVycjogYW55KSA9PiB2b2lkLFxuICAgICAgICAgICAgb25DbGljaz86ICgpID0+IHZvaWQsXG4gICAgICAgICAgICB2YWxpZGF0ZT86IChhY3Rpb25zOiBhbnkpID0+IHZvaWQ7XG4gICAgICAgICAgICBvbkNhbmNlbD86IChkYXRhOiBJUGF5UGFsQ2FuY2VsUGF5bWVudCwgYWN0aW9uczogYW55KSA9PiB2b2lkLFxuICAgICAgICAgICAgcGF5bWVudD86ICgpID0+IE9ic2VydmFibGU8c3RyaW5nPixcbiAgICAgICAgICAgIGludGVudD86IHN0cmluZyxcbiAgICAgICAgICAgIG9uQXV0aG9yaXplPzogKGRhdGE6IElQYXlQYWxQYXltZW50Q29tcGxldGVEYXRhLCBhY3Rpb25zOiBhbnkpID0+IE9ic2VydmFibGU8dm9pZD4sXG4gICAgICAgICAgICBjbGllbnQ/OiBJUGF5cGFsQ2xpZW50LFxuICAgICAgICAgICAgb25QYXltZW50Q29tcGxldGU/OiAoZGF0YTogSVBheVBhbFBheW1lbnRDb21wbGV0ZURhdGEsIGFjdGlvbnM6IGFueSkgPT4gdm9pZCxcbiAgICAgICAgICAgIHRyYW5zYWN0aW9ucz86IElQYXlQYWxUcmFuc2FjdGlvbltdLFxuICAgICAgICAgICAgbm90ZV90b19wYXllcj86IHN0cmluZztcbiAgICAgICAgICAgIGV4cGVyaWVuY2U/OiBJUGF5UGFsRXhwZXJpZW5jZSxcbiAgICAgICAgICAgIGNvbW1pdD86IGJvb2xlYW4sXG4gICAgICAgICAgICBidXR0b24/OiBJUGF5UGFsQnV0dG9uU3R5bGUsXG4gICAgICAgICAgICBmdW5kaW5nPzogSVBheVBhbEZ1bmRpbmdcbiAgICAgICAgfSkge1xuICAgICAgICBPYmplY3QuYXNzaWduKHRoaXMsIGNvbmZpZyk7XG4gICAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxQYXltZW50Q29tcGxldGVEYXRhIHtcbiAgICBpbnRlbnQ6IHN0cmluZztcbiAgICBvcmRlcklEOiBzdHJpbmc7XG4gICAgcGF5ZXJJRDogc3RyaW5nO1xuICAgIHBheW1lbnRJRDogc3RyaW5nO1xuICAgIHBheW1lbnRUb2tlbjogc3RyaW5nO1xuICAgIHJldHVyblVybDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxDYW5jZWxQYXltZW50IHtcbiAgICBkYXRhOiBJUGF5UGFsQ2FuY2VsUGF5bWVudERhdGE7XG4gICAgYWN0aW9uczogYW55O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxDYW5jZWxQYXltZW50RGF0YSB7XG4gICAgYmlsbGluZ0lEOiBzdHJpbmc7XG4gICAgY2FuY2VsVXJsOiBzdHJpbmc7XG4gICAgaW50ZW50OiBzdHJpbmc7XG4gICAgcGF5bWVudElEOiBzdHJpbmc7XG4gICAgcGF5bWVudFRva2VuOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheXBhbENsaWVudCB7XG4gICAgc2FuZGJveD86IHN0cmluZztcbiAgICBwcm9kdWN0aW9uPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxUcmFuc2FjdGlvbiB7XG4gICAgYW1vdW50OiBJUGF5UGFsQW1vdW50O1xuICAgIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICAgIGN1c3RvbT86IHN0cmluZztcbiAgICBwYXltZW50X29wdGlvbnM/OiBJUGF5UGFsVHJhbnNhY3Rpb25QYXltZW50T3B0aW9ucztcbiAgICBpbnZvaWNlX251bWJlcj86IHN0cmluZztcbiAgICBzb2Z0X2Rlc2NyaXB0b3I/OiBzdHJpbmc7XG4gICAgaXRlbV9saXN0PzogSVBheVBhbFRyYW5zYWN0aW9uSXRlbUxpc3Q7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheVBhbFRyYW5zYWN0aW9uSXRlbUxpc3Qge1xuICAgIGl0ZW1zPzogSVBheVBhbFRyYW5zYWN0aW9uSXRlbVtdO1xuICAgIHNoaXBwaW5nX2FkZHJlc3M/OiBJUGF5UGFsVHJhbnNhY3Rpb25TaGlwcGluZ0FkZHJlc3M7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheVBhbFRyYW5zYWN0aW9uSXRlbSB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIGN1cnJlbmN5OiBzdHJpbmc7XG4gICAgcHJpY2U6IG51bWJlcjtcbiAgICBxdWFudGl0eTogbnVtYmVyO1xuXG4gICAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gICAgdGF4PzogbnVtYmVyO1xuICAgIHNrdT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsQW1vdW50IHtcbiAgICB0b3RhbDogbnVtYmVyO1xuICAgIGN1cnJlbmN5OiBzdHJpbmc7XG4gICAgZGV0YWlscz86IElQYXlQYWxBbW91bnREZXRhaWxzO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQYXlQYWxUcmFuc2FjdGlvblNoaXBwaW5nQWRkcmVzcyB7XG4gICAgcmVjaXBpZW50X25hbWU6IHN0cmluZztcbiAgICBsaW5lMTogc3RyaW5nO1xuICAgIGxpbmUyPzogc3RyaW5nO1xuICAgIGNpdHk6IHN0cmluZztcbiAgICBjb3VudHJ5X2NvZGU6IHN0cmluZztcbiAgICBwb3N0YWxfY29kZTogc3RyaW5nO1xuICAgIHBob25lOiBzdHJpbmc7XG4gICAgc3RhdGU6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsQW1vdW50RGV0YWlscyB7XG4gICAgc3VidG90YWw6IG51bWJlcjtcbiAgICB0YXg6IG51bWJlcjtcbiAgICBzaGlwcGluZzogbnVtYmVyO1xuICAgIGhhbmRsaW5nX2ZlZTogbnVtYmVyO1xuICAgIHNoaXBwaW5nX2Rpc2NvdW50OiBudW1iZXI7XG4gICAgaW5zdXJhbmNlOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheVBhbFRyYW5zYWN0aW9uUGF5bWVudE9wdGlvbnMge1xuICAgIGFsbG93ZWRfcGF5bWVudF9tZXRob2Q/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVBheVBhbEV4cGVyaWVuY2Uge1xuICAgIC8qKiBJbmRpY2F0ZXMgd2hldGhlciBQYXlQYWwgZGlzcGxheXMgc2hpcHBpbmcgYWRkcmVzcyBmaWVsZHMgb24gdGhlIGV4cGVyaWVuY2UgcGFnZXMgKi9cbiAgICBub1NoaXBwaW5nPzogYm9vbGVhbjtcbiAgICAvKiogQSBsYWJlbCB0aGF0IG92ZXJyaWRlcyB0aGUgYnVzaW5lc3MgbmFtZSBpbiB0aGUgUGF5UGFsIGFjY291bnQgb24gdGhlIFBheVBhbCBwYWdlcy4gTWF4IGxlbmd0aDogMTI3IGNoYXJhY3RlcnMuICovXG4gICAgYnJhbmROYW1lPzogc3RyaW5nO1xuICAgIC8qKiBVUkwgdG8gdGhlIGxvZ28gaW1hZ2UgKGdpZiwganBnLCBvciBwbmcpLiBUaGUgaW1hZ2UncyBtYXhpbXVtIHdpZHRoIGlzIDE5MCBwaXhlbHMgYW5kIG1heGltdW0gaGVpZ2h0IGlzIDYwIHBpeGVscy4gKi9cbiAgICBsb2dvSW1hZ2U/OiBzdHJpbmc7XG4gICAgLyoqIExvY2FsZSBpbiB3aGljaCB0byBkaXNwbGF5IFBheVBhbCBwYWdlICovXG4gICAgbG9jYWxlQ29kZT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsQnV0dG9uU3R5bGUge1xuICAgIGxhYmVsPzogJ2NoZWNrb3V0JyB8ICdwYXknIHwgJ2J1eW5vdycgfCAncGF5cGFsJztcbiAgICBzaXplPzogJ3NtYWxsJyB8ICdtZWRpdW0nIHwgJ2xhcmdlJyB8ICdyZXNwb25zaXZlJztcbiAgICBzaGFwZT86ICdwaWxsJyB8ICdyZWN0JztcbiAgICBjb2xvcj86ICdnb2xkJyB8ICdibHVlJyB8ICdzaWx2ZXInIHwgJ2JsYWNrJztcbiAgICBsYXlvdXQ/OiAnaG9yaXpvbnRhbCcgfCAndmVydGljYWwnO1xuICAgIHRhZ2xpbmU/OiBmYWxzZTtcbiAgICBmdW5kaW5naWNvbnM/OiBib29sZWFuO1xuICAgIGJyYW5kaW5nPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUGF5UGFsRnVuZGluZyB7XG4gICAgYWxsb3dlZDogUGF5UGFsRnVuZGluZ1tdO1xuICAgIGRpc2FsbG93ZWQ6IFBheVBhbEZ1bmRpbmdbXTtcbn1cblxuIl0sIm5hbWVzIjpbIlN1YmplY3QiLCJpbnRlcnZhbCIsInRha2VVbnRpbCIsIm1hcCIsIkNvbXBvbmVudCIsIkNoYW5nZURldGVjdGlvblN0cmF0ZWd5IiwiSW5wdXQiLCJWaWV3Q2hpbGQiLCJOZ01vZHVsZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O1FBQ0ksT0FBSTtRQUNKLFNBQU07UUFDTixNQUFHOzs7Ozs7Ozs7Ozs7UUNGSCxpQkFBYztRQUNkLGlCQUFjOzs7Ozs7Ozs7QUNGbEI7UUFpR0k7Ozs7WUF4RFMsb0JBQWUsR0FBRyxLQUFLLENBQUM7Ozs7WUFVekIsNkNBQXdDLEdBQUcsS0FBSyxDQUFDOzs7O1lBZXhDLHdCQUFtQixHQUFHLEVBQUUsQ0FBQzs7OztZQUt6Qix3QkFBbUIsR0FBRyxJQUFJLENBQUM7Ozs7WUFLM0IscUJBQWdCLEdBQUcsUUFBUSxDQUFDOzs7O1lBSzVCLGdDQUEyQixHQUFHLDZCQUE2QixDQUFDOzs7O1lBSzVELG9CQUFlLEdBQUcsK0NBQStDLENBQUM7WUFPbEUsa0NBQTZCLEdBQUcsOEJBQThCLENBQUM7WUFFL0Qsa0JBQWEsR0FBa0IsSUFBSUEsWUFBTyxFQUFRLENBQUM7U0FJbkU7UUExQ0Qsc0JBQTRDLHlEQUF5Qjs7OztnQkFBckUsVUFBc0UsT0FBbUI7Z0JBQ3JGLElBQUksT0FBTyxFQUFFO29CQUNULElBQUksQ0FBQywwQkFBMEIsR0FBRyxPQUFPLENBQUM7aUJBQzdDO2FBQ0o7OztXQUFBOzs7OztRQXdDRCx3Q0FBVzs7OztZQUFYLFVBQVksT0FBc0I7O2dCQUU5QixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUU7b0JBQ2IsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO2lCQUNyQjthQUNKOzs7O1FBRUQsNENBQWU7OztZQUFmOztnQkFFSSxJQUFJLElBQUksQ0FBQyx3Q0FBd0MsSUFBSSxJQUFJLENBQUMsMEJBQTBCLEVBQUU7b0JBQ2xGLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztvQkFDbkIsSUFBSSxDQUFDLHdDQUF3QyxH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