UNPKG

@secrethub/ngx-stripe

Version:

The core package for ngx-stripe, for using stripe.js in your application

388 lines (379 loc) 38 kB
import { InjectionToken, NgModule, Inject, Injectable, defineInjectable, inject } from '@angular/core'; import { Observable, BehaviorSubject } from 'rxjs'; import { __awaiter } from 'tslib'; import { filter, first } from 'rxjs/operators'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * The public key that should be used for connecting to Stripe * @type {?} */ const STRIPE_PUBLIC_KEY = new InjectionToken('Stripe public key'); /** * Extra configuration options that can be used to further configure Stripe * @type {?} */ const STRIPE_OPTIONS = new InjectionToken('Optional configuration options'); /** * The version of stripe that should be used * @type {?} */ const STRIPE_VERSION = new InjectionToken('Stripe version to use'); /** * The location of the stripe javascript file * @type {?} */ const STRIPE_SCRIPT_LOCATION = 'https://js.stripe.com/'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** @enum {string} */ const SupportedVersions = { V3: 'v3', }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ class NgxStripeModule { /** * Creates a new instance of the NgxStripeModule * @param {?} key - The public key that should be used to communicate with Stripe * @param {?=} options - Any options to configure StripeJS * @param {?=} version * @return {?} */ static forRoot(key, options, version = SupportedVersions.V3) { return { ngModule: NgxStripeModule, providers: [ { provide: STRIPE_PUBLIC_KEY, useValue: key }, { provide: STRIPE_OPTIONS, useValue: options }, { provide: STRIPE_VERSION, useValue: version }, ], }; } } NgxStripeModule.decorators = [ { type: NgModule, args: [{ imports: [], },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ class StripeLoader { /** * @param {?} version * @param {?} options * @param {?} key */ constructor(version, options, key) { this.version = version; this.options = options; this.key = key; } /** * Fetches the stripe instance from the DOM * * @param {?} key * @param {?} options * @return {?} The Stripe instance or null if it is not yet registered */ static getStripeInstance(key, options) { /** @type {?} */ const stripeInstance = window[StripeLoader.STRIPE_WINDOW_KEY]; if (stripeInstance) { return stripeInstance(key, options); } return null; } /** * Checks whether or not StripeJS has been loaded * @return {?} */ static isStripeLoaded() { return !!window[StripeLoader.STRIPE_WINDOW_KEY]; } /** * Injects the script tag into the body of the page in order to lazy * load the Stripe script * * @return {?} Observable to indicate when the script has finished loading */ loadScript() { return new Observable((observer) => { if (!StripeLoader.isStripeLoaded()) { /** @type {?} */ const script = StripeLoader.constructScript(this.getStripeScriptUrl()); script.onload = (() => { observer.next(StripeLoader.getStripeInstance(this.key, this.options)); observer.complete(); }); script.onerror = () => { observer.error('Failed to load the Stripe script!'); observer.complete(); }; document.body.appendChild(script); } else { observer.next(StripeLoader.getStripeInstance(this.key, this.options)); observer.complete(); } }); } /** * Constructs the url that should be used for loading the Stripe script * @return {?} URL to stripe script location */ getStripeScriptUrl() { return STRIPE_SCRIPT_LOCATION + this.version + '/'; } /** * Constructs a script element that loads javascript from the given url * @param {?} url - The URL from which the javascript should be loaded * * @return {?} A script element that can be attached to the DOM */ static constructScript(url) { /** @type {?} */ const script = document.createElement('script'); script.type = 'text/javascript'; script.async = true; script.defer = true; script.src = url; return script; } } /** * The key under which the stripe script is placed in the * window object * * @default 'Stripe' */ StripeLoader.STRIPE_WINDOW_KEY = 'Stripe'; StripeLoader.decorators = [ { type: Injectable, args: [{ providedIn: 'root', },] } ]; StripeLoader.ctorParameters = () => [ { type: SupportedVersions, decorators: [{ type: Inject, args: [STRIPE_VERSION,] }] }, { type: undefined, decorators: [{ type: Inject, args: [STRIPE_OPTIONS,] }] }, { type: String, decorators: [{ type: Inject, args: [STRIPE_PUBLIC_KEY,] }] } ]; /** @nocollapse */ StripeLoader.ngInjectableDef = defineInjectable({ factory: function StripeLoader_Factory() { return new StripeLoader(inject(STRIPE_VERSION), inject(STRIPE_OPTIONS), inject(STRIPE_PUBLIC_KEY)); }, token: StripeLoader, providedIn: "root" }); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ class StripeService { /** * Lazy load the StripeJS javascript file on first usage of the service * @param {?} loader - The loader that should be used for loading StripeJS */ constructor(loader) { this.loader = loader; /** * A BehaviorSubject containing the StripeJS object * * Since the script is loaded Async we need an options for all our functions * to wait for stripe to have been loaded */ this.stripe$ = new BehaviorSubject(null); loader.loadScript() .subscribe((stripe) => this.stripe$.next(stripe), () => { throw new Error('Stripe could not be loaded!'); }); } /** * Creates a new stripe instance with the given key * @param {?} key - The public key that should be used to communicate with Stripe * @param {?=} options - Any options to configure StripeJS * @return {?} */ changeKey(key, options) { this.stripe$.next(StripeLoader.getStripeInstance(key, options)); } /** * Configures the `Elements` object from StripeJS with the given options * @see https://stripe.com/docs/stripe-js/elements/quickstart#create-form * @param {?=} options * @param {?=} isIETFLocaleTag * @return {?} Observable that resolves in an StripeJS ElementsCreator */ getElementFactory(options, isIETFLocaleTag = false) { return __awaiter(this, void 0, void 0, function* () { if (isIETFLocaleTag && options && options.locale) { options.locale = options.locale.split('-')[0]; // Only use the first part of the locale 'en' for example } /** @type {?} */ const stripe = yield this.getStripe(); return stripe.elements(options); }); } /** * Create a payment request * NOTE: This is NOT supported for Firefox * @see https://stripe.com/docs/payment-request-api * * @param {?} options - Payment information that should be used by Stripe * * @return {?} the created request */ makePaymentRequest(options) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const stripe = yield this.getStripe(); return stripe.paymentRequest(options); }); } /** * Creates a token from the given element * * @param {?} element - The element from which the data needs to be extracted * @param {?=} data * @return {?} A promise that resolves in a token or a rejection if the creation of the token failed */ createTokenFromElement(element, data) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const stripe = yield this.getStripe(); return stripe.createToken(element, data).then((result) => { if (result.error) { Promise.reject(result.error); } return result.token; }); }); } /** * Creates a token from a bank account * * @param {?} data - The data from the bank account that should be used for the token * * @return {?} A promise that resolves in a token or a rejection if the creation of the token failed */ createTokenFromBankAccount(data) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const stripe = yield this.getStripe(); return stripe.createToken('bank_account', data).then((result) => { if (result.error) { Promise.reject(result.error); } return result.token; }); }); } /** * Creates a token from the personal information of a customer * * @param {?} data - The personal information that should be used for the creation of the token * * @return {?} A promise that resolves in a token or a rejection if the creation of the token failed */ createTokenFromPii(data) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const stripe = yield this.getStripe(); return stripe.createToken('pii', data).then((result) => { if (result.error) { Promise.reject(result.error); } return result.token; }); }); } /** * Creates a source object from the given element and data * * @param {?} element - The element from which the data needs to be extracted * @param {?} data - An object containing the type of Source you want to create and any additional payment source information * * @return {?} A promise that resolves in a source object or a rejection if the creation of the source failed */ createSourceFromElement(element, data) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const stripe = yield this.getStripe(); return stripe.createSource(element, data).then((result) => { if (result.error) { Promise.reject(result.error); } return result.source; }); }); } /** * Creates a source object from only data * * @param {?} data - The data that should be used for the creation of the source object * * @return {?} A promise that resolves in a source object or a rejection if the creation of the source failed */ createSourceFromData(data) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const stripe = yield this.getStripe(); return stripe.createSource(data).then((result) => { if (result.error) { Promise.reject(result.error); } return result.source; }); }); } /** * Fetches an existing source based on the given parameters * * @param {?} id - The unique identifier of the source * @param {?} client_secret - A secret available to the web client that created the Source * * @return {?} A promise that resolves in a source object or a rejection if the creation of the source failed */ getSource(id, client_secret) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const stripe = yield this.getStripe(); return stripe.retrieveSource({ id, client_secret }).then((result) => { if (result.error) { Promise.reject(result.error); } return result.source; }); }); } /** * Fetches the StripeJS instance * NOTE: Use the instance for token generation * * @return {?} The StripeJS instance when it is available (since StripeJS is loaded Async) */ getStripe() { return this.stripe$.pipe(filter((stripe) => !!stripe), first()).toPromise().then((stripe) => stripe); } } StripeService.decorators = [ { type: Injectable, args: [{ providedIn: 'root', },] } ]; StripeService.ctorParameters = () => [ { type: StripeLoader } ]; /** @nocollapse */ StripeService.ngInjectableDef = defineInjectable({ factory: function StripeService_Factory() { return new StripeService(inject(StripeLoader)); }, token: StripeService, providedIn: "root" }); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ export { NgxStripeModule, StripeService, StripeLoader, SupportedVersions, STRIPE_OPTIONS as ɵb, STRIPE_PUBLIC_KEY as ɵa, STRIPE_VERSION as ɵc }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjcmV0aHViLW5neC1zdHJpcGUuanMubWFwIiwic291cmNlcyI6WyJuZzovL0BzZWNyZXRodWIvbmd4LXN0cmlwZS9saWIvbW9kZWwvc3RyaXBlLmNvbnN0YW50LnRzIiwibmc6Ly9Ac2VjcmV0aHViL25neC1zdHJpcGUvbGliL21vZGVsL1N1cHBvcnRlZFZlcnNpb25zLnRzIiwibmc6Ly9Ac2VjcmV0aHViL25neC1zdHJpcGUvbGliL25neC1zdHJpcGUubW9kdWxlLnRzIiwibmc6Ly9Ac2VjcmV0aHViL25neC1zdHJpcGUvbGliL3NlcnZpY2VzL3N0cmlwZS1sb2FkZXIuc2VydmljZS50cyIsIm5nOi8vQHNlY3JldGh1Yi9uZ3gtc3RyaXBlL2xpYi9zZXJ2aWNlcy9zdHJpcGUuc2VydmljZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0luamVjdGlvblRva2VufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7U3VwcG9ydGVkVmVyc2lvbnN9IGZyb20gJy4vU3VwcG9ydGVkVmVyc2lvbnMnO1xuaW1wb3J0IHtTdHJpcGVDb25maWdPcHRpb25zfSBmcm9tICdzdHJpcGVqcyc7XG5cbi8qKlxuICogVGhlIHB1YmxpYyBrZXkgdGhhdCBzaG91bGQgYmUgdXNlZCBmb3IgY29ubmVjdGluZyB0byBTdHJpcGVcbiAqL1xuZXhwb3J0IGNvbnN0IFNUUklQRV9QVUJMSUNfS0VZID0gbmV3IEluamVjdGlvblRva2VuPHN0cmluZz4oJ1N0cmlwZSBwdWJsaWMga2V5Jyk7XG5cbi8qKlxuICogRXh0cmEgY29uZmlndXJhdGlvbiBvcHRpb25zIHRoYXQgY2FuIGJlIHVzZWQgdG8gZnVydGhlciBjb25maWd1cmUgU3RyaXBlXG4gKi9cbmV4cG9ydCBjb25zdCBTVFJJUEVfT1BUSU9OUyA9IG5ldyBJbmplY3Rpb25Ub2tlbjxTdHJpcGVDb25maWdPcHRpb25zPignT3B0aW9uYWwgY29uZmlndXJhdGlvbiBvcHRpb25zJyk7XG5cbi8qKlxuICogVGhlIHZlcnNpb24gb2Ygc3RyaXBlIHRoYXQgc2hvdWxkIGJlIHVzZWRcbiAqL1xuZXhwb3J0IGNvbnN0IFNUUklQRV9WRVJTSU9OID0gbmV3IEluamVjdGlvblRva2VuPFN1cHBvcnRlZFZlcnNpb25zPignU3RyaXBlIHZlcnNpb24gdG8gdXNlJyk7XG5cbi8qKlxuICogVGhlIGxvY2F0aW9uIG9mIHRoZSBzdHJpcGUgamF2YXNjcmlwdCBmaWxlXG4gKi9cbmV4cG9ydCBjb25zdCBTVFJJUEVfU0NSSVBUX0xPQ0FUSU9OID0gJ2h0dHBzOi8vanMuc3RyaXBlLmNvbS8nO1xuIiwiLyoqXG4gKiBBbGwgdGhlIFN0cmlwZSB2ZXJzaW9ucyB0aGF0IGFyZSBzdXBwb3J0ZWQgYnkgdGhpcyBsaWJyYXJ5XG4gKi9cbmV4cG9ydCBlbnVtIFN1cHBvcnRlZFZlcnNpb25zIHtcbiAgVjMgPSAndjMnLFxufVxuIiwiaW1wb3J0IHtNb2R1bGVXaXRoUHJvdmlkZXJzLCBOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7U1RSSVBFX09QVElPTlMsIFNUUklQRV9QVUJMSUNfS0VZLCBTVFJJUEVfVkVSU0lPTn0gZnJvbSAnLi9tb2RlbC9zdHJpcGUuY29uc3RhbnQnO1xyXG5pbXBvcnQge1N1cHBvcnRlZFZlcnNpb25zfSBmcm9tICcuL21vZGVsL1N1cHBvcnRlZFZlcnNpb25zJztcclxuaW1wb3J0IHtTdHJpcGVDb25maWdPcHRpb25zfSBmcm9tICdzdHJpcGVqcyc7XHJcblxyXG5ATmdNb2R1bGUoe1xyXG4gIGltcG9ydHM6IFtdLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTmd4U3RyaXBlTW9kdWxlIHtcclxuXHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyBpbnN0YW5jZSBvZiB0aGUgTmd4U3RyaXBlTW9kdWxlXHJcbiAgICogQHBhcmFtIGtleSAtIFRoZSBwdWJsaWMga2V5IHRoYXQgc2hvdWxkIGJlIHVzZWQgdG8gY29tbXVuaWNhdGUgd2l0aCBTdHJpcGVcclxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIEFueSBvcHRpb25zIHRvIGNvbmZpZ3VyZSBTdHJpcGVKU1xyXG4gICAqIEBwYXJhbSBbdmVyc2lvbj1TdXBwb3J0ZWRWZXJzaW9ucy5WM10gLSBUaGUgdmVyc2lvbiBvZiBTdHJpcGUgdGhhdCBzaG91bGQgYmUgdXNlZFxyXG4gICAqL1xyXG4gIHB1YmxpYyBzdGF0aWMgZm9yUm9vdChrZXk6IHN0cmluZywgb3B0aW9ucz86IFN0cmlwZUNvbmZpZ09wdGlvbnMsIHZlcnNpb24gPSBTdXBwb3J0ZWRWZXJzaW9ucy5WMyk6IE1vZHVsZVdpdGhQcm92aWRlcnMge1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgbmdNb2R1bGU6IE5neFN0cmlwZU1vZHVsZSxcclxuICAgICAgcHJvdmlkZXJzOiBbXHJcbiAgICAgICAge3Byb3ZpZGU6IFNUUklQRV9QVUJMSUNfS0VZLCB1c2VWYWx1ZToga2V5fSxcclxuICAgICAgICB7cHJvdmlkZTogU1RSSVBFX09QVElPTlMsIHVzZVZhbHVlOiBvcHRpb25zfSxcclxuICAgICAgICB7cHJvdmlkZTogU1RSSVBFX1ZFUlNJT04sIHVzZVZhbHVlOiB2ZXJzaW9ufSxcclxuICAgICAgXSxcclxuICAgIH07XHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7T2JzZXJ2YWJsZSwgU3Vic2NyaWJlcn0gZnJvbSAncnhqcyc7XG5pbXBvcnQge0luamVjdCwgSW5qZWN0YWJsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1NUUklQRV9PUFRJT05TLCBTVFJJUEVfUFVCTElDX0tFWSwgU1RSSVBFX1NDUklQVF9MT0NBVElPTiwgU1RSSVBFX1ZFUlNJT059IGZyb20gJy4uL21vZGVsL3N0cmlwZS5jb25zdGFudCc7XG5pbXBvcnQge1N1cHBvcnRlZFZlcnNpb25zfSBmcm9tICcuLi9tb2RlbC9TdXBwb3J0ZWRWZXJzaW9ucyc7XG5pbXBvcnQge1N0cmlwZUNvbmZpZ09wdGlvbnMsIFN0cmlwZUpTfSBmcm9tICdzdHJpcGVqcyc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBTdHJpcGVMb2FkZXIge1xuXG4gIC8qKlxuICAgKiBUaGUga2V5IHVuZGVyIHdoaWNoIHRoZSBzdHJpcGUgc2NyaXB0IGlzIHBsYWNlZCBpbiB0aGVcbiAgICogd2luZG93IG9iamVjdFxuICAgKlxuICAgKiBAZGVmYXVsdCAnU3RyaXBlJ1xuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgU1RSSVBFX1dJTkRPV19LRVkgPSAnU3RyaXBlJztcblxuICBjb25zdHJ1Y3RvcihASW5qZWN0KFNUUklQRV9WRVJTSU9OKSBwcml2YXRlIHZlcnNpb246IFN1cHBvcnRlZFZlcnNpb25zLFxuICAgICAgICAgICAgICBASW5qZWN0KFNUUklQRV9PUFRJT05TKSBwcml2YXRlIG9wdGlvbnM6IFN0cmlwZUNvbmZpZ09wdGlvbnMsXG4gICAgICAgICAgICAgIEBJbmplY3QoU1RSSVBFX1BVQkxJQ19LRVkpIHByaXZhdGUga2V5OiBzdHJpbmcpIHtcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaGVzIHRoZSBzdHJpcGUgaW5zdGFuY2UgZnJvbSB0aGUgRE9NXG4gICAqXG4gICAqIEByZXR1cm4gVGhlIFN0cmlwZSBpbnN0YW5jZSBvciBudWxsIGlmIGl0IGlzIG5vdCB5ZXQgcmVnaXN0ZXJlZFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBnZXRTdHJpcGVJbnN0YW5jZShrZXk6IHN0cmluZywgb3B0aW9uczogU3RyaXBlQ29uZmlnT3B0aW9ucyk6IFN0cmlwZUpTIHwgbnVsbCB7XG4gICAgY29uc3Qgc3RyaXBlSW5zdGFuY2UgPSB3aW5kb3dbU3RyaXBlTG9hZGVyLlNUUklQRV9XSU5ET1dfS0VZXTtcbiAgICBpZiAoc3RyaXBlSW5zdGFuY2UpIHtcbiAgICAgIHJldHVybiBzdHJpcGVJbnN0YW5jZShrZXksIG9wdGlvbnMpO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciBvciBub3QgU3RyaXBlSlMgaGFzIGJlZW4gbG9hZGVkXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGlzU3RyaXBlTG9hZGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIXdpbmRvd1tTdHJpcGVMb2FkZXIuU1RSSVBFX1dJTkRPV19LRVldO1xuICB9XG5cbiAgLyoqXG4gICAqIEluamVjdHMgdGhlIHNjcmlwdCB0YWcgaW50byB0aGUgYm9keSBvZiB0aGUgcGFnZSBpbiBvcmRlciB0byBsYXp5XG4gICAqIGxvYWQgdGhlIFN0cmlwZSBzY3JpcHRcbiAgICpcbiAgICogQHJldHVybiBPYnNlcnZhYmxlIHRvIGluZGljYXRlIHdoZW4gdGhlIHNjcmlwdCBoYXMgZmluaXNoZWQgbG9hZGluZ1xuICAgKi9cbiAgcHVibGljIGxvYWRTY3JpcHQoKTogT2JzZXJ2YWJsZTxTdHJpcGVKUz4ge1xuICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZTxTdHJpcGVKUz4oKG9ic2VydmVyOiBTdWJzY3JpYmVyPFN0cmlwZUpTPikgPT4ge1xuICAgICAgaWYgKCFTdHJpcGVMb2FkZXIuaXNTdHJpcGVMb2FkZWQoKSkge1xuICAgICAgICBjb25zdCBzY3JpcHQgPSBTdHJpcGVMb2FkZXIuY29uc3RydWN0U2NyaXB0KHRoaXMuZ2V0U3RyaXBlU2NyaXB0VXJsKCkpO1xuXG4gICAgICAgIHNjcmlwdC5vbmxvYWQgPSAoKCkgPT4ge1xuICAgICAgICAgIG9ic2VydmVyLm5leHQoU3RyaXBlTG9hZGVyLmdldFN0cmlwZUluc3RhbmNlKHRoaXMua2V5LCB0aGlzLm9wdGlvbnMpKTtcbiAgICAgICAgICBvYnNlcnZlci5jb21wbGV0ZSgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzY3JpcHQub25lcnJvciA9ICgpID0+IHtcbiAgICAgICAgICBvYnNlcnZlci5lcnJvcignRmFpbGVkIHRvIGxvYWQgdGhlIFN0cmlwZSBzY3JpcHQhJyk7XG4gICAgICAgICAgb2JzZXJ2ZXIuY29tcGxldGUoKTtcbiAgICAgICAgfTtcblxuICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHNjcmlwdCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBvYnNlcnZlci5uZXh0KFN0cmlwZUxvYWRlci5nZXRTdHJpcGVJbnN0YW5jZSh0aGlzLmtleSwgdGhpcy5vcHRpb25zKSk7XG4gICAgICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ29uc3RydWN0cyB0aGUgdXJsIHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIGxvYWRpbmcgdGhlIFN0cmlwZSBzY3JpcHRcbiAgICogQHJldHVybiBVUkwgdG8gc3RyaXBlIHNjcmlwdCBsb2NhdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBnZXRTdHJpcGVTY3JpcHRVcmwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gU1RSSVBFX1NDUklQVF9MT0NBVElPTiArIHRoaXMudmVyc2lvbiArICcvJztcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgc2NyaXB0IGVsZW1lbnQgdGhhdCBsb2FkcyBqYXZhc2NyaXB0IGZyb20gdGhlIGdpdmVuIHVybFxuICAgKiBAcGFyYW0gdXJsIC0gVGhlIFVSTCBmcm9tIHdoaWNoIHRoZSBqYXZhc2NyaXB0IHNob3VsZCBiZSBsb2FkZWRcbiAgICpcbiAgICogQHJldHVybiBBIHNjcmlwdCBlbGVtZW50IHRoYXQgY2FuIGJlIGF0dGFjaGVkIHRvIHRoZSBET01cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGNvbnN0cnVjdFNjcmlwdCh1cmw6IHN0cmluZyk6IEhUTUxTY3JpcHRFbGVtZW50IHtcbiAgICBjb25zdCBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtcbiAgICBzY3JpcHQudHlwZSA9ICd0ZXh0L2phdmFzY3JpcHQnO1xuICAgIHNjcmlwdC5hc3luYyA9IHRydWU7XG4gICAgc2NyaXB0LmRlZmVyID0gdHJ1ZTtcbiAgICBzY3JpcHQuc3JjID0gdXJsO1xuXG4gICAgcmV0dXJuIHNjcmlwdDtcbiAgfVxufVxuIiwiaW1wb3J0IHtJbmplY3RhYmxlfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtTdHJpcGVKUywgU3RyaXBlQ29uZmlnT3B0aW9uc30gZnJvbSAnc3RyaXBlanMnO1xyXG5pbXBvcnQge1N0cmlwZUVsZW1lbnQsIEVsZW1lbnRGYWN0b3J5LCBFbGVtZW50Q3JlYXRvck9wdGlvbnN9IGZyb20gJ3N0cmlwZWpzL2VsZW1lbnQnO1xyXG5pbXBvcnQge1N0cmlwZVBheW1lbnRPcHRpb25zLCBTdHJpcGVQYXltZW50UmVxdWVzdH0gZnJvbSAnc3RyaXBlanMvcGF5bWVudCc7XHJcbmltcG9ydCB7QmFua1Rva2VuRGF0YSwgSUJBTlRva2VuRGF0YSwgUGlpVG9rZW5EYXRhLCBUb2tlbiwgVG9rZW5EYXRhLCBUb2tlblJlc3VsdH0gZnJvbSAnc3RyaXBlanMvdG9rZW4nO1xyXG5pbXBvcnQge1NvdXJjZSwgU291cmNlRGF0YSwgU291cmNlUmVzdWx0fSBmcm9tICdzdHJpcGVqcy9zb3VyY2UnO1xyXG5pbXBvcnQge0JlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZX0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7ZmlsdGVyLCBmaXJzdH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQge1N0cmlwZUxvYWRlcn0gZnJvbSAnLi9zdHJpcGUtbG9hZGVyLnNlcnZpY2UnO1xyXG5cclxuQEluamVjdGFibGUoe1xyXG4gIHByb3ZpZGVkSW46ICdyb290JyxcclxufSlcclxuZXhwb3J0IGNsYXNzIFN0cmlwZVNlcnZpY2Uge1xyXG4gIC8qKlxyXG4gICAqIEEgQmVoYXZpb3JTdWJqZWN0IGNvbnRhaW5pbmcgdGhlIFN0cmlwZUpTIG9iamVjdFxyXG4gICAqXHJcbiAgICogU2luY2UgdGhlIHNjcmlwdCBpcyBsb2FkZWQgQXN5bmMgd2UgbmVlZCBhbiBvcHRpb25zIGZvciBhbGwgb3VyIGZ1bmN0aW9uc1xyXG4gICAqIHRvIHdhaXQgZm9yIHN0cmlwZSB0byBoYXZlIGJlZW4gbG9hZGVkXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzdHJpcGUkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxTdHJpcGVKUyB8IG51bGw+KG51bGwpO1xyXG5cclxuICAvKipcclxuICAgKiBMYXp5IGxvYWQgdGhlIFN0cmlwZUpTIGphdmFzY3JpcHQgZmlsZSBvbiBmaXJzdCB1c2FnZSBvZiB0aGUgc2VydmljZVxyXG4gICAqIEBwYXJhbSBsb2FkZXIgLSBUaGUgbG9hZGVyIHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIGxvYWRpbmcgU3RyaXBlSlNcclxuICAgKi9cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGxvYWRlcjogU3RyaXBlTG9hZGVyKSB7XHJcbiAgICBsb2FkZXIubG9hZFNjcmlwdCgpXHJcbiAgICAgIC5zdWJzY3JpYmUoXHJcbiAgICAgICAgKHN0cmlwZTogU3RyaXBlSlMpID0+IHRoaXMuc3RyaXBlJC5uZXh0KHN0cmlwZSksXHJcbiAgICAgICAgKCkgPT4ge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTdHJpcGUgY291bGQgbm90IGJlIGxvYWRlZCEnKTtcclxuICAgICAgICB9LFxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyBzdHJpcGUgaW5zdGFuY2Ugd2l0aCB0aGUgZ2l2ZW4ga2V5XHJcbiAgICogQHBhcmFtIGtleSAtIFRoZSBwdWJsaWMga2V5IHRoYXQgc2hvdWxkIGJlIHVzZWQgdG8gY29tbXVuaWNhdGUgd2l0aCBTdHJpcGVcclxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIEFueSBvcHRpb25zIHRvIGNvbmZpZ3VyZSBTdHJpcGVKU1xyXG4gICAqL1xyXG4gIHB1YmxpYyBjaGFuZ2VLZXkoa2V5OiBzdHJpbmcsIG9wdGlvbnM/OiBTdHJpcGVDb25maWdPcHRpb25zKTogdm9pZCB7XHJcbiAgICB0aGlzLnN0cmlwZSQubmV4dChTdHJpcGVMb2FkZXIuZ2V0U3RyaXBlSW5zdGFuY2Uoa2V5LCBvcHRpb25zKSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDb25maWd1cmVzIHRoZSBgRWxlbWVudHNgIG9iamVjdCBmcm9tIFN0cmlwZUpTIHdpdGggdGhlIGdpdmVuIG9wdGlvbnNcclxuICAgKiBAc2VlIGh0dHBzOi8vc3RyaXBlLmNvbS9kb2NzL3N0cmlwZS1qcy9lbGVtZW50cy9xdWlja3N0YXJ0I2NyZWF0ZS1mb3JtXHJcbiAgICogQHBhcmFtIFtvcHRpb25zXSAtIEFueSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBFbGVtZW50cyBvYmplY3RcclxuICAgKiBAcGFyYW0gW2lzSUVURkxvY2FsZVRhZ10gLSBXaGV0aGVyIG9yIG5vdCB0aGUgb3B0aW9ucyBgbG9jYWxlYCBpcyBmb3JtYXR0ZWQgYXMgYSBJRVRGTG9jYWxlVGFnLlxyXG4gICAqIElmIHRydWUgdGhlIGxvY2FsZSB3aWxsIGJlIGZvcm1hdHRlZCBieSB0aGlzIGZ1bmN0aW9uXHJcbiAgICpcclxuICAgKiBAcmV0dXJuIE9ic2VydmFibGUgdGhhdCByZXNvbHZlcyBpbiBhbiBTdHJpcGVKUyBFbGVtZW50c0NyZWF0b3JcclxuICAgKi9cclxuICBwdWJsaWMgYXN5bmMgZ2V0RWxlbWVudEZhY3Rvcnkob3B0aW9ucz86IEVsZW1lbnRDcmVhdG9yT3B0aW9ucywgaXNJRVRGTG9jYWxlVGFnID0gZmFsc2UpOiBQcm9taXNlPEVsZW1lbnRGYWN0b3J5PiB7XHJcbiAgICBpZiAoaXNJRVRGTG9jYWxlVGFnICYmIG9wdGlvbnMgJiYgb3B0aW9ucy5sb2NhbGUpIHtcclxuICAgICAgb3B0aW9ucy5sb2NhbGUgPSBvcHRpb25zLmxvY2FsZS5zcGxpdCgnLScpWzBdOyAvLyBPbmx5IHVzZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgbG9jYWxlICdlbicgZm9yIGV4YW1wbGVcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBzdHJpcGUgPSBhd2FpdCB0aGlzLmdldFN0cmlwZSgpO1xyXG4gICAgcmV0dXJuIHN0cmlwZS5lbGVtZW50cyhvcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENyZWF0ZSBhIHBheW1lbnQgcmVxdWVzdFxyXG4gICAqIE5PVEU6IFRoaXMgaXMgTk9UIHN1cHBvcnRlZCBmb3IgRmlyZWZveFxyXG4gICAqIEBzZWUgaHR0cHM6Ly9zdHJpcGUuY29tL2RvY3MvcGF5bWVudC1yZXF1ZXN0LWFwaVxyXG4gICAqXHJcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBQYXltZW50IGluZm9ybWF0aW9uIHRoYXQgc2hvdWxkIGJlIHVzZWQgYnkgU3RyaXBlXHJcbiAgICpcclxuICAgKiBAcmV0dXJuIHRoZSBjcmVhdGVkIHJlcXVlc3RcclxuICAgKi9cclxuICBwdWJsaWMgYXN5bmMgbWFrZVBheW1lbnRSZXF1ZXN0KG9wdGlvbnM6IFN0cmlwZVBheW1lbnRPcHRpb25zKTogUHJvbWlzZTxTdHJpcGVQYXltZW50UmVxdWVzdD4ge1xyXG4gICAgY29uc3Qgc3RyaXBlID0gYXdhaXQgdGhpcy5nZXRTdHJpcGUoKTtcclxuICAgIHJldHVybiBzdHJpcGUucGF5bWVudFJlcXVlc3Qob3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgdG9rZW4gZnJvbSB0aGUgZ2l2ZW4gZWxlbWVudFxyXG4gICAqXHJcbiAgICogQHBhcmFtIGVsZW1lbnQgLSBUaGUgZWxlbWVudCBmcm9tIHdoaWNoIHRoZSBkYXRhIG5lZWRzIHRvIGJlIGV4dHJhY3RlZFxyXG4gICAqIEBwYXJhbSBbZGF0YV0gLSBhbiBvYmplY3QgY29udGFpbmluZyBhZGRpdGlvbmFsIHBheW1lbnQgaW5mb3JtYXRpb24geW91IG1pZ2h0IGhhdmUgY29sbGVjdGVkXHJcbiAgICpcclxuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGluIGEgdG9rZW4gb3IgYSByZWplY3Rpb24gaWYgdGhlIGNyZWF0aW9uIG9mIHRoZSB0b2tlbiBmYWlsZWRcclxuICAgKi9cclxuICBwdWJsaWMgYXN5bmMgY3JlYXRlVG9rZW5Gcm9tRWxlbWVudChlbGVtZW50OiBTdHJpcGVFbGVtZW50LCBkYXRhPzogVG9rZW5EYXRhIHwgSUJBTlRva2VuRGF0YSk6IFByb21pc2U8VG9rZW4+IHtcclxuICAgIGNvbnN0IHN0cmlwZSA9IGF3YWl0IHRoaXMuZ2V0U3RyaXBlKCk7XHJcbiAgICByZXR1cm4gc3RyaXBlLmNyZWF0ZVRva2VuKGVsZW1lbnQsIGRhdGEpLnRoZW4oKHJlc3VsdDogVG9rZW5SZXN1bHQpID0+IHtcclxuICAgICAgaWYgKHJlc3VsdC5lcnJvcikge1xyXG4gICAgICAgIFByb21pc2UucmVqZWN0KHJlc3VsdC5lcnJvcik7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHJlc3VsdC50b2tlbjtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIHRva2VuIGZyb20gYSBiYW5rIGFjY291bnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSBkYXRhIC0gVGhlIGRhdGEgZnJvbSB0aGUgYmFuayBhY2NvdW50IHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIHRoZSB0b2tlblxyXG4gICAqXHJcbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBpbiBhIHRva2VuIG9yIGEgcmVqZWN0aW9uIGlmIHRoZSBjcmVhdGlvbiBvZiB0aGUgdG9rZW4gZmFpbGVkXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIGNyZWF0ZVRva2VuRnJvbUJhbmtBY2NvdW50KGRhdGE6IEJhbmtUb2tlbkRhdGEpOiBQcm9taXNlPFRva2VuPiB7XHJcbiAgICBjb25zdCBzdHJpcGUgPSBhd2FpdCB0aGlzLmdldFN0cmlwZSgpO1xyXG4gICAgcmV0dXJuIHN0cmlwZS5jcmVhdGVUb2tlbignYmFua19hY2NvdW50JywgZGF0YSkudGhlbigocmVzdWx0OiBUb2tlblJlc3VsdCkgPT4ge1xyXG4gICAgICBpZiAocmVzdWx0LmVycm9yKSB7XHJcbiAgICAgICAgUHJvbWlzZS5yZWplY3QocmVzdWx0LmVycm9yKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gcmVzdWx0LnRva2VuO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgdG9rZW4gZnJvbSB0aGUgcGVyc29uYWwgaW5mb3JtYXRpb24gb2YgYSBjdXN0b21lclxyXG4gICAqXHJcbiAgICogQHBhcmFtIGRhdGEgLSBUaGUgcGVyc29uYWwgaW5mb3JtYXRpb24gdGhhdCBzaG91bGQgYmUgdXNlZCBmb3IgdGhlIGNyZWF0aW9uIG9mIHRoZSB0b2tlblxyXG4gICAqXHJcbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBpbiBhIHRva2VuIG9yIGEgcmVqZWN0aW9uIGlmIHRoZSBjcmVhdGlvbiBvZiB0aGUgdG9rZW4gZmFpbGVkXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIGNyZWF0ZVRva2VuRnJvbVBpaShkYXRhOiBQaWlUb2tlbkRhdGEpOiBQcm9taXNlPFRva2VuPiB7XHJcbiAgICBjb25zdCBzdHJpcGUgPSBhd2FpdCB0aGlzLmdldFN0cmlwZSgpO1xyXG4gICAgcmV0dXJuIHN0cmlwZS5jcmVhdGVUb2tlbigncGlpJywgZGF0YSkudGhlbigocmVzdWx0OiBUb2tlblJlc3VsdCkgPT4ge1xyXG4gICAgICBpZiAocmVzdWx0LmVycm9yKSB7XHJcbiAgICAgICAgUHJvbWlzZS5yZWplY3QocmVzdWx0LmVycm9yKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gcmVzdWx0LnRva2VuO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgc291cmNlIG9iamVjdCBmcm9tIHRoZSBnaXZlbiBlbGVtZW50IGFuZCBkYXRhXHJcbiAgICpcclxuICAgKiBAcGFyYW0gZWxlbWVudCAtIFRoZSBlbGVtZW50IGZyb20gd2hpY2ggdGhlIGRhdGEgbmVlZHMgdG8gYmUgZXh0cmFjdGVkXHJcbiAgICogQHBhcmFtIGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgdHlwZSBvZiBTb3VyY2UgeW91IHdhbnQgdG8gY3JlYXRlIGFuZCBhbnkgYWRkaXRpb25hbCBwYXltZW50IHNvdXJjZSBpbmZvcm1hdGlvblxyXG4gICAqXHJcbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBpbiBhIHNvdXJjZSBvYmplY3Qgb3IgYSByZWplY3Rpb24gaWYgdGhlIGNyZWF0aW9uIG9mIHRoZSBzb3VyY2UgZmFpbGVkXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIGNyZWF0ZVNvdXJjZUZyb21FbGVtZW50KGVsZW1lbnQ6IFN0cmlwZUVsZW1lbnQsIGRhdGE6IFNvdXJjZURhdGEpOiBQcm9taXNlPFNvdXJjZT4ge1xyXG4gICAgY29uc3Qgc3RyaXBlID0gYXdhaXQgdGhpcy5nZXRTdHJpcGUoKTtcclxuICAgIHJldHVybiBzdHJpcGUuY3JlYXRlU291cmNlKGVsZW1lbnQsIGRhdGEpLnRoZW4oKHJlc3VsdDogU291cmNlUmVzdWx0KSA9PiB7XHJcbiAgICAgIGlmIChyZXN1bHQuZXJyb3IpIHtcclxuICAgICAgICBQcm9taXNlLnJlamVjdChyZXN1bHQuZXJyb3IpO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiByZXN1bHQuc291cmNlO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgc291cmNlIG9iamVjdCBmcm9tIG9ubHkgZGF0YVxyXG4gICAqXHJcbiAgICogQHBhcmFtIGRhdGEgLSBUaGUgZGF0YSB0aGF0IHNob3VsZCBiZSB1c2VkIGZvciB0aGUgY3JlYXRpb24gb2YgdGhlIHNvdXJjZSBvYmplY3RcclxuICAgKlxyXG4gICAqIEByZXR1cm4gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgaW4gYSBzb3VyY2Ugb2JqZWN0IG9yIGEgcmVqZWN0aW9uIGlmIHRoZSBjcmVhdGlvbiBvZiB0aGUgc291cmNlIGZhaWxlZFxyXG4gICAqL1xyXG4gIHB1YmxpYyBhc3luYyBjcmVhdGVTb3VyY2VGcm9tRGF0YShkYXRhOiBTb3VyY2VEYXRhKTogUHJvbWlzZTxTb3VyY2U+IHtcclxuICAgIGNvbnN0IHN0cmlwZSA9IGF3YWl0IHRoaXMuZ2V0U3RyaXBlKCk7XHJcbiAgICByZXR1cm4gc3RyaXBlLmNyZWF0ZVNvdXJjZShkYXRhKS50aGVuKChyZXN1bHQ6IFNvdXJjZVJlc3VsdCkgPT4ge1xyXG4gICAgICBpZiAocmVzdWx0LmVycm9yKSB7XHJcbiAgICAgICAgUHJvbWlzZS5yZWplY3QocmVzdWx0LmVycm9yKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gcmVzdWx0LnNvdXJjZTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRmV0Y2hlcyBhbiBleGlzdGluZyBzb3VyY2UgYmFzZWQgb24gdGhlIGdpdmVuIHBhcmFtZXRlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSBpZCAtIFRoZSB1bmlxdWUgaWRlbnRpZmllciBvZiB0aGUgc291cmNlXHJcbiAgICogQHBhcmFtIGNsaWVudF9zZWNyZXQgLSBBIHNlY3JldCBhdmFpbGFibGUgdG8gdGhlIHdlYiBjbGllbnQgdGhhdCBjcmVhdGVkIHRoZSBTb3VyY2VcclxuICAgKlxyXG4gICAqIEByZXR1cm4gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgaW4gYSBzb3VyY2Ugb2JqZWN0IG9yIGEgcmVqZWN0aW9uIGlmIHRoZSBjcmVhdGlvbiBvZiB0aGUgc291cmNlIGZhaWxlZFxyXG4gICAqL1xyXG4gIHB1YmxpYyBhc3luYyBnZXRTb3VyY2UoaWQ6IHN0cmluZywgY2xpZW50X3NlY3JldDogc3RyaW5nKTogUHJvbWlzZTxTb3VyY2U+IHtcclxuICAgIGNvbnN0IHN0cmlwZSA9IGF3YWl0IHRoaXMuZ2V0U3RyaXBlKCk7XHJcbiAgICByZXR1cm4gc3RyaXBlLnJldHJpZXZlU291cmNlKHtpZCwgY2xpZW50X3NlY3JldH0pLnRoZW4oKHJlc3VsdDogU291cmNlUmVzdWx0KSA9PiB7XHJcbiAgICAgIGlmIChyZXN1bHQuZXJyb3IpIHtcclxuICAgICAgICBQcm9taXNlLnJlamVjdChyZXN1bHQuZXJyb3IpO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiByZXN1bHQuc291cmNlO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBGZXRjaGVzIHRoZSBTdHJpcGVKUyBpbnN0YW5jZVxyXG4gICAqIE5PVEU6IFVzZSB0aGUgaW5zdGFuY2UgZm9yIHRva2VuIGdlbmVyYXRpb25cclxuICAgKlxyXG4gICAqIEByZXR1cm4gVGhlIFN0cmlwZUpTIGluc3RhbmNlIHdoZW4gaXQgaXMgYXZhaWxhYmxlIChzaW5jZSBTdHJpcGVKUyBpcyBsb2FkZWQgQXN5bmMpXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRTdHJpcGUoKTogUHJvbWlzZTxTdHJpcGVKUz4ge1xyXG4gICAgcmV0dXJuIHRoaXMuc3RyaXBlJC5waXBlKFxyXG4gICAgICBmaWx0ZXIoKHN0cmlwZTogU3RyaXBlSlMgfCBudWxsKSA9PiAhIXN0cmlwZSksXHJcbiAgICAgIGZpcnN0KCksXHJcbiAgICApLnRvUHJvbWlzZSgpLnRoZW4oKHN0cmlwZTogU3RyaXBlSlMpID0+IHN0cmlwZSk7XHJcbiAgfVxyXG59XHJcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQTs7OztBQU9BLE1BQWEsaUJBQWlCLEdBQUcsSUFBSSxjQUFjLENBQVMsbUJBQW1CLENBQUM7Ozs7O0FBS2hGLE1BQWEsY0FBYyxHQUFHLElBQUksY0FBYyxDQUFzQixnQ0FBZ0MsQ0FBQzs7Ozs7QUFLdkcsTUFBYSxjQUFjLEdBQUcsSUFBSSxjQUFjLENBQW9CLHVCQUF1QixDQUFDOzs7OztBQUs1RixNQUFhLHNCQUFzQixHQUFHLHdCQUF3Qjs7Ozs7Ozs7SUNsQjVELElBQUssSUFBSTs7Ozs7OztBQ0pYOzs7Ozs7OztJQWdCUyxPQUFPLE9BQU8sQ0FBQyxHQUFXLEVBQUUsT0FBNkIsRUFBRSxPQUFPLEdBQUcsaUJBQWlCLENBQUMsRUFBRTtRQUM5RixPQUFPO1lBQ0wsUUFBUSxF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