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