@secrethub/ngx-stripe
Version:
The core package for ngx-stripe, for using stripe.js in your application
772 lines (758 loc) • 77.5 kB
JavaScript
(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('@secrethub/ngx-stripe', ['exports', '@angular/core', 'rxjs', 'rxjs/operators'], factory) :
(factory((global.secrethub = global.secrethub || {}, global.secrethub['ngx-stripe'] = {}),global.ng.core,global.rxjs,global.rxjs.operators));
}(this, (function (exports,i0,rxjs,operators) { 'use strict';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* The public key that should be used for connecting to Stripe
* @type {?}
*/
var STRIPE_PUBLIC_KEY = new i0.InjectionToken('Stripe public key');
/**
* Extra configuration options that can be used to further configure Stripe
* @type {?}
*/
var STRIPE_OPTIONS = new i0.InjectionToken('Optional configuration options');
/**
* The version of stripe that should be used
* @type {?}
*/
var STRIPE_VERSION = new i0.InjectionToken('Stripe version to use');
/**
* The location of the stripe javascript file
* @type {?}
*/
var STRIPE_SCRIPT_LOCATION = 'https://js.stripe.com/';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @enum {string} */
var SupportedVersions = {
V3: 'v3',
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var NgxStripeModule = /** @class */ (function () {
function 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=SupportedVersions.V3] - The version of Stripe that should be used
*/
/**
* 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 {?}
*/
NgxStripeModule.forRoot = /**
* 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 {?}
*/
function (key, options, version) {
if (version === void 0) {
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: i0.NgModule, args: [{
imports: [],
},] }
];
return NgxStripeModule;
}());
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
function __awaiter(thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function () { if (t[0] & 1)
throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f)
throw new TypeError("Generator is already executing.");
while (_)
try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done)
return t;
if (y = 0, t)
op = [op[0] & 2, t.value];
switch (op[0]) {
case 0:
case 1:
t = op;
break;
case 4:
_.label++;
return { value: op[1], done: false };
case 5:
_.label++;
y = op[1];
op = [0];
continue;
case 7:
op = _.ops.pop();
_.trys.pop();
continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
_ = 0;
continue;
}
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
_.label = op[1];
break;
}
if (op[0] === 6 && _.label < t[1]) {
_.label = t[1];
t = op;
break;
}
if (t && _.label < t[2]) {
_.label = t[2];
_.ops.push(op);
break;
}
if (t[2])
_.ops.pop();
_.trys.pop();
continue;
}
op = body.call(thisArg, _);
}
catch (e) {
op = [6, e];
y = 0;
}
finally {
f = t = 0;
}
if (op[0] & 5)
throw op[1];
return { value: op[0] ? op[1] : void 0, done: true };
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var StripeLoader = /** @class */ (function () {
function StripeLoader(version, options, key) {
this.version = version;
this.options = options;
this.key = key;
}
/**
* Fetches the stripe instance from the DOM
*
* @return The Stripe instance or null if it is not yet registered
*/
/**
* Fetches the stripe instance from the DOM
*
* @param {?} key
* @param {?} options
* @return {?} The Stripe instance or null if it is not yet registered
*/
StripeLoader.getStripeInstance = /**
* Fetches the stripe instance from the DOM
*
* @param {?} key
* @param {?} options
* @return {?} The Stripe instance or null if it is not yet registered
*/
function (key, options) {
/** @type {?} */
var stripeInstance = window[StripeLoader.STRIPE_WINDOW_KEY];
if (stripeInstance) {
return stripeInstance(key, options);
}
return null;
};
/**
* Checks whether or not StripeJS has been loaded
*/
/**
* Checks whether or not StripeJS has been loaded
* @return {?}
*/
StripeLoader.isStripeLoaded = /**
* Checks whether or not StripeJS has been loaded
* @return {?}
*/
function () {
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
*/
/**
* 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
*/
StripeLoader.prototype.loadScript = /**
* 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
*/
function () {
var _this = this;
return new rxjs.Observable(function (observer) {
if (!StripeLoader.isStripeLoaded()) {
/** @type {?} */
var script = StripeLoader.constructScript(_this.getStripeScriptUrl());
script.onload = (function () {
observer.next(StripeLoader.getStripeInstance(_this.key, _this.options));
observer.complete();
});
script.onerror = function () {
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
*/
/**
* Constructs the url that should be used for loading the Stripe script
* @return {?} URL to stripe script location
*/
StripeLoader.prototype.getStripeScriptUrl = /**
* Constructs the url that should be used for loading the Stripe script
* @return {?} URL to stripe script location
*/
function () {
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
*/
/**
* 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
*/
StripeLoader.constructScript = /**
* 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
*/
function (url) {
/** @type {?} */
var 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: i0.Injectable, args: [{
providedIn: 'root',
},] }
];
StripeLoader.ctorParameters = function () {
return [
{ type: SupportedVersions, decorators: [{ type: i0.Inject, args: [STRIPE_VERSION,] }] },
{ type: undefined, decorators: [{ type: i0.Inject, args: [STRIPE_OPTIONS,] }] },
{ type: String, decorators: [{ type: i0.Inject, args: [STRIPE_PUBLIC_KEY,] }] }
];
};
/** @nocollapse */ StripeLoader.ngInjectableDef = i0.defineInjectable({ factory: function StripeLoader_Factory() { return new StripeLoader(i0.inject(STRIPE_VERSION), i0.inject(STRIPE_OPTIONS), i0.inject(STRIPE_PUBLIC_KEY)); }, token: StripeLoader, providedIn: "root" });
return StripeLoader;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var StripeService = /** @class */ (function () {
/**
* Lazy load the StripeJS javascript file on first usage of the service
* @param loader - The loader that should be used for loading StripeJS
*/
function StripeService(loader) {
var _this = this;
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 rxjs.BehaviorSubject(null);
loader.loadScript()
.subscribe(function (stripe) { return _this.stripe$.next(stripe); }, function () {
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
*/
/**
* 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 {?}
*/
StripeService.prototype.changeKey = /**
* 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 {?}
*/
function (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] - Any configuration options for the Elements object
* @param [isIETFLocaleTag] - Whether or not the options `locale` is formatted as a IETFLocaleTag.
* If true the locale will be formatted by this function
*
* @return Observable that resolves in an StripeJS ElementsCreator
*/
/**
* 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
*/
StripeService.prototype.getElementFactory = /**
* 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
*/
function (options, isIETFLocaleTag) {
if (isIETFLocaleTag === void 0) {
isIETFLocaleTag = false;
}
return __awaiter(this, void 0, void 0, function () {
var stripe;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (isIETFLocaleTag && options && options.locale) {
options.locale = options.locale.split('-')[0]; // Only use the first part of the locale 'en' for example
}
return [4 /*yield*/, this.getStripe()];
case 1:
stripe = _a.sent();
return [2 /*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
*/
/**
* 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
*/
StripeService.prototype.makePaymentRequest = /**
* 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
*/
function (options) {
return __awaiter(this, void 0, void 0, function () {
var stripe;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getStripe()];
case 1:
stripe = _a.sent();
return [2 /*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] - an object containing additional payment information you might have collected
*
* @return A promise that resolves in a token or a rejection if the creation of the token failed
*/
/**
* 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
*/
StripeService.prototype.createTokenFromElement = /**
* 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
*/
function (element, data) {
return __awaiter(this, void 0, void 0, function () {
var stripe;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getStripe()];
case 1:
stripe = _a.sent();
return [2 /*return*/, stripe.createToken(element, data).then(function (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
*/
/**
* 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
*/
StripeService.prototype.createTokenFromBankAccount = /**
* 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
*/
function (data) {
return __awaiter(this, void 0, void 0, function () {
var stripe;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getStripe()];
case 1:
stripe = _a.sent();
return [2 /*return*/, stripe.createToken('bank_account', data).then(function (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
*/
/**
* 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
*/
StripeService.prototype.createTokenFromPii = /**
* 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
*/
function (data) {
return __awaiter(this, void 0, void 0, function () {
var stripe;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getStripe()];
case 1:
stripe = _a.sent();
return [2 /*return*/, stripe.createToken('pii', data).then(function (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
*/
/**
* 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
*/
StripeService.prototype.createSourceFromElement = /**
* 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
*/
function (element, data) {
return __awaiter(this, void 0, void 0, function () {
var stripe;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getStripe()];
case 1:
stripe = _a.sent();
return [2 /*return*/, stripe.createSource(element, data).then(function (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
*/
/**
* 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
*/
StripeService.prototype.createSourceFromData = /**
* 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
*/
function (data) {
return __awaiter(this, void 0, void 0, function () {
var stripe;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getStripe()];
case 1:
stripe = _a.sent();
return [2 /*return*/, stripe.createSource(data).then(function (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
*/
/**
* 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
*/
StripeService.prototype.getSource = /**
* 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
*/
function (id, client_secret) {
return __awaiter(this, void 0, void 0, function () {
var stripe;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getStripe()];
case 1:
stripe = _a.sent();
return [2 /*return*/, stripe.retrieveSource({ id: id, client_secret: client_secret }).then(function (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)
*/
/**
* Fetches the StripeJS instance
* NOTE: Use the instance for token generation
*
* @return {?} The StripeJS instance when it is available (since StripeJS is loaded Async)
*/
StripeService.prototype.getStripe = /**
* Fetches the StripeJS instance
* NOTE: Use the instance for token generation
*
* @return {?} The StripeJS instance when it is available (since StripeJS is loaded Async)
*/
function () {
return this.stripe$.pipe(operators.filter(function (stripe) { return !!stripe; }), operators.first()).toPromise().then(function (stripe) { return stripe; });
};
StripeService.decorators = [
{ type: i0.Injectable, args: [{
providedIn: 'root',
},] }
];
StripeService.ctorParameters = function () {
return [
{ type: StripeLoader }
];
};
/** @nocollapse */ StripeService.ngInjectableDef = i0.defineInjectable({ factory: function StripeService_Factory() { return new StripeService(i0.inject(StripeLoader)); }, token: StripeService, providedIn: "root" });
return StripeService;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
exports.NgxStripeModule = NgxStripeModule;
exports.StripeService = StripeService;
exports.StripeLoader = StripeLoader;
exports.SupportedVersions = SupportedVersions;
exports.ɵb = STRIPE_OPTIONS;
exports.ɵa = STRIPE_PUBLIC_KEY;
exports.ɵc = STRIPE_VERSION;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjcmV0aHViLW5neC1zdHJpcGUudW1kLmpzLm1hcCIsInNvdXJjZXMiOlsibmc6Ly9Ac2VjcmV0aHViL25neC1zdHJpcGUvbGliL21vZGVsL3N0cmlwZS5jb25zdGFudC50cyIsIm5nOi8vQHNlY3JldGh1Yi9uZ3gtc3RyaXBlL2xpYi9tb2RlbC9TdXBwb3J0ZWRWZXJzaW9ucy50cyIsIm5nOi8vQHNlY3JldGh1Yi9uZ3gtc3RyaXBlL2xpYi9uZ3gtc3RyaXBlLm1vZHVsZS50cyIsIm5vZGVfbW9kdWxlcy90c2xpYi90c2xpYi5lczYuanMiLCJuZzovL0BzZWNyZXRodWIvbmd4LXN0cmlwZS9saWIvc2VydmljZXMvc3RyaXBlLWxvYWRlci5zZXJ2aWNlLnRzIiwibmc6Ly9Ac2VjcmV0aHViL25neC1zdHJpcGUvbGliL3NlcnZpY2VzL3N0cmlwZS5zZXJ2aWNlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7SW5qZWN0aW9uVG9rZW59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtTdXBwb3J0ZWRWZXJzaW9uc30gZnJvbSAnLi9TdXBwb3J0ZWRWZXJzaW9ucyc7XG5pbXBvcnQge1N0cmlwZUNvbmZpZ09wdGlvbnN9IGZyb20gJ3N0cmlwZWpzJztcblxuLyoqXG4gKiBUaGUgcHVibGljIGtleSB0aGF0IHNob3VsZCBiZSB1c2VkIGZvciBjb25uZWN0aW5nIHRvIFN0cmlwZVxuICovXG5leHBvcnQgY29uc3QgU1RSSVBFX1BVQkxJQ19LRVkgPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nPignU3RyaXBlIHB1YmxpYyBrZXknKTtcblxuLyoqXG4gKiBFeHRyYSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdGhhdCBjYW4gYmUgdXNlZCB0byBmdXJ0aGVyIGNvbmZpZ3VyZSBTdHJpcGVcbiAqL1xuZXhwb3J0IGNvbnN0IFNUUklQRV9PUFRJT05TID0gbmV3IEluamVjdGlvblRva2VuPFN0cmlwZUNvbmZpZ09wdGlvbnM+KCdPcHRpb25hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMnKTtcblxuLyoqXG4gKiBUaGUgdmVyc2lvbiBvZiBzdHJpcGUgdGhhdCBzaG91bGQgYmUgdXNlZFxuICovXG5leHBvcnQgY29uc3QgU1RSSVBFX1ZFUlNJT04gPSBuZXcgSW5qZWN0aW9uVG9rZW48U3VwcG9ydGVkVmVyc2lvbnM+KCdTdHJpcGUgdmVyc2lvbiB0byB1c2UnKTtcblxuLyoqXG4gKiBUaGUgbG9jYXRpb24gb2YgdGhlIHN0cmlwZSBqYXZhc2NyaXB0IGZpbGVcbiAqL1xuZXhwb3J0IGNvbnN0IFNUUklQRV9TQ1JJUFRfTE9DQVRJT04gPSAnaHR0cHM6Ly9qcy5zdHJpcGUuY29tLyc7XG4iLCIvKipcbiAqIEFsbCB0aGUgU3RyaXBlIHZlcnNpb25zIHRoYXQgYXJlIHN1cHBvcnRlZCBieSB0aGlzIGxpYnJhcnlcbiAqL1xuZXhwb3J0IGVudW0gU3VwcG9ydGVkVmVyc2lvbnMge1xuICBWMyA9ICd2MycsXG59XG4iLCJpbXBvcnQge01vZHVsZVdpdGhQcm92aWRlcnMsIE5nTW9kdWxlfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtTVFJJUEVfT1BUSU9OUywgU1RSSVBFX1BVQkxJQ19LRVksIFNUUklQRV9WRVJTSU9OfSBmcm9tICcuL21vZGVsL3N0cmlwZS5jb25zdGFudCc7XHJcbmltcG9ydCB7U3VwcG9ydGVkVmVyc2lvbnN9IGZyb20gJy4vbW9kZWwvU3VwcG9ydGVkVmVyc2lvbnMnO1xyXG5pbXBvcnQge1N0cmlwZUNvbmZpZ09wdGlvbnN9IGZyb20gJ3N0cmlwZWpzJztcclxuXHJcbkBOZ01vZHVsZSh7XHJcbiAgaW1wb3J0czogW10sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOZ3hTdHJpcGVNb2R1bGUge1xyXG5cclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgbmV3IGluc3RhbmNlIG9mIHRoZSBOZ3hTdHJpcGVNb2R1bGVcclxuICAgKiBAcGFyYW0ga2V5IC0gVGhlIHB1YmxpYyBrZXkgdGhhdCBzaG91bGQgYmUgdXNlZCB0byBjb21tdW5pY2F0ZSB3aXRoIFN0cmlwZVxyXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gQW55IG9wdGlvbnMgdG8gY29uZmlndXJlIFN0cmlwZUpTXHJcbiAgICogQHBhcmFtIFt2ZXJzaW9uPVN1cHBvcnRlZFZlcnNpb25zLlYzXSAtIFRoZSB2ZXJzaW9uIG9mIFN0cmlwZSB0aGF0IHNob3VsZCBiZSB1c2VkXHJcbiAgICovXHJcbiAgcHVibGljIHN0YXRpYyBmb3JSb290KGtleTogc3RyaW5nLCBvcHRpb25zPzogU3RyaXBlQ29uZmlnT3B0aW9ucywgdmVyc2lvbiA9IFN1cHBvcnRlZFZlcnNpb25zLlYzKTogTW9kdWxlV2l0aFByb3ZpZGVycyB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBuZ01vZHVsZTogTmd4U3RyaXBlTW9kdWxlLFxyXG4gICAgICBwcm92aWRlcnM6IFtcclxuICAgICAgICB7cHJvdmlkZTogU1RSSVBFX1BVQkxJQ19LRVksIHVzZVZhbHVlOiBrZXl9LFxyXG4gICAgICAgIHtwcm92aWRlOiBTVFJJUEVfT1BUSU9OUywgdXNlVmFsdWU6IG9wdGlvbnN9LFxyXG4gICAgICAgIHtwcm92aWRlOiBTVFJJUEVfVkVSU0lPTiwgdXNlVmFsdWU6IHZlcnNpb259LFxyXG4gICAgICBdLFxyXG4gICAgfTtcclxuICB9XHJcbn1cclxuIiwiLyohICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbkNvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxyXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpOyB5b3UgbWF5IG5vdCB1c2VcclxudGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGVcclxuTGljZW5zZSBhdCBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcclxuXHJcblRISVMgQ09ERSBJUyBQUk9WSURFRCBPTiBBTiAqQVMgSVMqIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTllcclxuS0lORCwgRUlUSEVSIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIFdJVEhPVVQgTElNSVRBVElPTiBBTlkgSU1QTElFRFxyXG5XQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgVElUTEUsIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLFxyXG5NRVJDSEFOVEFCTElUWSBPUiBOT04tSU5GUklOR0VNRU5ULlxyXG5cclxuU2VlIHRoZSBBcGFjaGUgVmVyc2lvbiAyLjAgTGljZW5zZSBmb3Igc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zXHJcbmFuZCBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogKi9cclxuLyogZ2xvYmFsIFJlZmxlY3QsIFByb21pc2UgKi9cclxuXHJcbnZhciBleHRlbmRTdGF0aWNzID0gZnVuY3Rpb24oZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyA9IE9iamVjdC5zZXRQcm90b3R5cGVPZiB8fFxyXG4gICAgICAgICh7IF9fcHJvdG9fXzogW10gfSBpbnN0YW5jZW9mIEFycmF5ICYmIGZ1bmN0aW9uIChkLCBiKSB7IGQuX19wcm90b19fID0gYjsgfSkgfHxcclxuICAgICAgICBmdW5jdGlvbiAoZCwgYikgeyBmb3IgKHZhciBwIGluIGIpIGlmIChiLmhhc093blByb3BlcnR5KHApKSBkW3BdID0gYltwXTsgfTtcclxuICAgIHJldHVybiBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG4gICAgZnVuY3Rpb24gX18oKSB7IHRoaXMuY29uc3RydWN0b3IgPSBkOyB9XHJcbiAgICBkLnByb3RvdHlwZSA9IGIgPT09IG51bGwgPyBPYmplY3QuY3JlYXRlKGIpIDogKF9fLnByb3RvdHlwZSA9IGIucHJvdG90eXBlLCBuZXcgX18oKSk7XHJcbn1cclxuXHJcbmV4cG9ydCB2YXIgX19hc3NpZ24gPSBmdW5jdGlvbigpIHtcclxuICAgIF9fYXNzaWduID0gT2JqZWN0LmFzc2lnbiB8fCBmdW5jdGlvbiBfX2Fzc2lnbih0KSB7XHJcbiAgICAgICAgZm9yICh2YXIgcywgaSA9IDEsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XHJcbiAgICAgICAgICAgIHMgPSBhcmd1bWVudHNbaV07XHJcbiAgICAgICAgICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSkgdFtwXSA9IHNbcF07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0O1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3Jlc3QocywgZSkge1xyXG4gICAgdmFyIHQgPSB7fTtcclxuICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKVxyXG4gICAgICAgIHRbcF0gPSBzW3BdO1xyXG4gICAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKVxyXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBwID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhzKTsgaSA8IHAubGVuZ3RoOyBpKyspIGlmIChlLmluZGV4T2YocFtpXSkgPCAwKVxyXG4gICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgIHJldHVybiB0O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYykge1xyXG4gICAgdmFyIGMgPSBhcmd1bWVudHMubGVuZ3RoLCByID0gYyA8IDMgPyB0YXJnZXQgOiBkZXNjID09PSBudWxsID8gZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBrZXkpIDogZGVzYywgZDtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSA9PT0gXCJmdW5jdGlvblwiKSByID0gUmVmbGVjdC5kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYyk7XHJcbiAgICBlbHNlIGZvciAodmFyIGkgPSBkZWNvcmF0b3JzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSBpZiAoZCA9IGRlY29yYXRvcnNbaV0pIHIgPSAoYyA8IDMgPyBkKHIpIDogYyA+IDMgPyBkKHRhcmdldCwga2V5LCByKSA6IGQodGFyZ2V0LCBrZXkpKSB8fCByO1xyXG4gICAgcmV0dXJuIGMgPiAzICYmIHIgJiYgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwga2V5LCByKSwgcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcGFyYW0ocGFyYW1JbmRleCwgZGVjb3JhdG9yKSB7XHJcbiAgICByZXR1cm4gZnVuY3Rpb24gKHRhcmdldCwga2V5KSB7IGRlY29yYXRvcih0YXJnZXQsIGtleSwgcGFyYW1JbmRleCk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fbWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpIHtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5tZXRhZGF0YSA9PT0gXCJmdW5jdGlvblwiKSByZXR1cm4gUmVmbGVjdC5tZXRhZGF0YShtZXRhZGF0YUtleSwgbWV0YWRhdGFWYWx1ZSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0ZXIodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHJlc3VsdC52YWx1ZSk7IH0pLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZ2VuZXJhdG9yKHRoaXNBcmcsIGJvZHkpIHtcclxuICAgIHZhciBfID0geyBsYWJlbDogMCwgc2VudDogZnVuY3Rpb24oKSB7IGlmICh0WzBdICYgMSkgdGhyb3cgdFsxXTsgcmV0dXJuIHRbMV07IH0sIHRyeXM6IFtdLCBvcHM6IFtdIH0sIGYsIHksIHQsIGc7XHJcbiAgICByZXR1cm4gZyA9IHsgbmV4dDogdmVyYigwKSwgXCJ0aHJvd1wiOiB2ZXJiKDEpLCBcInJldHVyblwiOiB2ZXJiKDIpIH0sIHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiAoZ1tTeW1ib2wuaXRlcmF0b3JdID0gZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzOyB9KSwgZztcclxuICAgIGZ1bmN0aW9uIHZlcmIobikgeyByZXR1cm4gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIHN0ZXAoW24sIHZdKTsgfTsgfVxyXG4gICAgZnVuY3Rpb24gc3RlcChvcCkge1xyXG4gICAgICAgIGlmIChmKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLlwiKTtcclxuICAgICAgICB3aGlsZSAoXykgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKGYgPSAxLCB5ICYmICh0ID0gb3BbMF0gJiAyID8geVtcInJldHVyblwiXSA6IG9wWzBdID8geVtcInRocm93XCJdIHx8ICgodCA9IHlbXCJyZXR1cm5cIl0pICYmIHQuY2FsbCh5KSwgMCkgOiB5Lm5leHQpICYmICEodCA9IHQuY2FsbCh5LCBvcFsxXSkpLmRvbmUpIHJldHVybiB0O1xyXG4gICAgICAgICAgICBpZiAoeSA9IDAsIHQpIG9wID0gW29wWzBdICYgMiwgdC52YWx1ZV07XHJcbiAgICAgICAgICAgIHN3aXRjaCAob3BbMF0pIHtcclxuICAgICAgICAgICAgICAgIGNhc2UgMDogY2FzZSAxOiB0ID0gb3A7IGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSA0OiBfLmxhYmVsKys7IHJldHVybiB7IHZhbHVlOiBvcFsxXSwgZG9uZTogZmFsc2UgfTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNTogXy5sYWJlbCsrOyB5ID0gb3BbMV07IG9wID0gWzBdOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNzogb3AgPSBfLm9wcy5wb3AoKTsgXy50cnlzLnBvcCgpOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEodCA9IF8udHJ5cywgdCA9IHQubGVuZ3RoID4gMCAmJiB0W3QubGVuZ3RoIC0gMV0pICYmIChvcFswXSA9PT0gNiB8fCBvcFswXSA9PT0gMikpIHsgXyA9IDA7IGNvbnRpbnVlOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSAzICYmICghdCB8fCAob3BbMV0gPiB0WzBdICYmIG9wWzFdIDwgdFszXSkpKSB7IF8ubGFiZWwgPSBvcFsxXTsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAob3BbMF0gPT09IDYgJiYgXy5sYWJlbCA8IHRbMV0pIHsgXy5sYWJlbCA9IHRbMV07IHQgPSBvcDsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAodCAmJiBfLmxhYmVsIDwgdFsyXSkgeyBfLmxhYmVsID0gdFsyXTsgXy5vcHMucHVzaChvcCk7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRbMl0pIF8ub3BzLnBvcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgb3AgPSBib2R5LmNhbGwodGhpc0FyZywgXyk7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkgeyBvcCA9IFs2LCBlXTsgeSA9IDA7IH0gZmluYWxseSB7IGYgPSB0ID0gMDsgfVxyXG4gICAgICAgIGlmIChvcFswXSAmIDUpIHRocm93IG9wWzFdOyByZXR1cm4geyB2YWx1ZTogb3BbMF0gPyBvcFsxXSA6IHZvaWQgMCwgZG9uZTogdHJ1ZSB9O1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19leHBvcnRTdGFyKG0sIGV4cG9ydHMpIHtcclxuICAgIGZvciAodmFyIHAgaW4gbSkgaWYgKCFleHBvcnRzLmhhc093blByb3BlcnR5KHApKSBleHBvcnRzW3BdID0gbVtwXTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fdmFsdWVzKG8pIHtcclxuICAgIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9bU3ltYm9sLml0ZXJhdG9yXSwgaSA9IDA7XHJcbiAgICBpZiAobSkgcmV0dXJuIG0uY2FsbChvKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgICAgbmV4dDogZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAobyAmJiBpID49IG8ubGVuZ3RoKSBvID0gdm9pZCAwO1xyXG4gICAgICAgICAgICByZXR1cm4geyB2YWx1ZTogbyAmJiBvW2krK10sIGRvbmU6ICFvIH07XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVhZChvLCBuKSB7XHJcbiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl07XHJcbiAgICBpZiAoIW0pIHJldHVybiBvO1xyXG4gICAgdmFyIGkgPSBtLmNhbGwobyksIHIsIGFyID0gW10sIGU7XHJcbiAgICB0cnkge1xyXG4gICAgICAgIHdoaWxlICgobiA9PT0gdm9pZCAwIHx8IG4tLSA+IDApICYmICEociA9IGkubmV4dCgpKS5kb25lKSBhci5wdXNoKHIudmFsdWUpO1xyXG4gICAgfVxyXG4gICAgY2F0Y2ggKGVycm9yKSB7IGUgPSB7IGVycm9yOiBlcnJvciB9OyB9XHJcbiAgICBmaW5hbGx5IHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBpZiAociAmJiAhci5kb25lICYmIChtID0gaVtcInJldHVyblwiXSkpIG0uY2FsbChpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZmluYWxseSB7IGlmIChlKSB0aHJvdyBlLmVycm9yOyB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gYXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3NwcmVhZCgpIHtcclxuICAgIGZvciAodmFyIGFyID0gW10sIGkgPSAwOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIGFyID0gYXIuY29uY2F0KF9fcmVhZChhcmd1bWVudHNbaV0pKTtcclxuICAgIHJldHVybiBhcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fYXdhaXQodikge1xyXG4gICAgcmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBfX2F3YWl0ID8gKHRoaXMudiA9IHYsIHRoaXMpIDogbmV3IF9fYXdhaXQodik7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2FzeW5jR2VuZXJhdG9yKHRoaXNBcmcsIF9hcmd1bWVudHMsIGdlbmVyYXRvcikge1xyXG4gICAgaWYgKCFTeW1ib2wuYXN5bmNJdGVyYXRvcikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLlwiKTtcclxuICAgIHZhciBnID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pLCBpLCBxID0gW107XHJcbiAgICByZXR1cm4gaSA9IHt9LCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIpLCB2ZXJiKFwicmV0dXJuXCIpLCBpW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXM7IH0sIGk7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4pIHsgaWYgKGdbbl0pIGlbbl0gPSBmdW5jdGlvbiAodikgeyByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKGEsIGIpIHsgcS5wdXNoKFtuLCB2LCBhLCBiXSkgPiAxIHx8IHJlc3VtZShuLCB2KTsgfSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHJlc3VtZShuLCB2KSB7IHRyeSB7IHN0ZXAoZ1tuXSh2KSk7IH0gY2F0Y2ggKGUpIHsgc2V0dGxlKHFbMF1bM10sIGUpOyB9IH1cclxuICAgIGZ1bmN0aW9uIHN0ZXAocikgeyByLnZhbHVlIGluc3RhbmNlb2YgX19hd2FpdCA/IFByb21pc2UucmVzb2x2ZShyLnZhbHVlLnYpLnRoZW4oZnVsZmlsbCwgcmVqZWN0KSA6IHNldHRsZShxWzBdWzJdLCByKTsgfVxyXG4gICAgZnVuY3Rpb24gZnVsZmlsbCh2YWx1ZSkgeyByZXN1bWUoXCJuZXh0XCIsIHZhbHVlKTsgfVxyXG4gICAgZnVuY3Rpb24gcmVqZWN0KHZhbHVlKSB7IHJlc3VtZShcInRocm93XCIsIHZhbHVlKTsgfVxyXG4gICAgZnVuY3Rpb24gc2V0dGxlKGYsIHYpIHsgaWYgKGYodiksIHEuc2hpZnQoKSwgcS5sZW5ndGgpIHJlc3VtZShxWzBdWzBdLCBxWzBdWzFdKTsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY0RlbGVnYXRvcihvKSB7XHJcbiAgICB2YXIgaSwgcDtcclxuICAgIHJldHVybiBpID0ge30sIHZlcmIoXCJuZXh0XCIpLCB2ZXJiKFwidGhyb3dcIiwgZnVuY3Rpb24gKGUpIHsgdGhyb3cgZTsgfSksIHZlcmIoXCJyZXR1cm5cIiksIGlbU3ltYm9sLml0ZXJhdG9yXSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXM7IH0sIGk7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4sIGYpIHsgaVtuXSA9IG9bbl0gPyBmdW5jdGlvbiAodikgeyByZXR1cm4gKHAgPSAhcCkgPyB7IHZhbHVlOiBfX2F3YWl0KG9bbl0odikpLCBkb25lOiBuID09PSBcInJldHVyblwiIH0gOiBmID8gZih2KSA6IHY7IH0gOiBmOyB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2FzeW5jVmFsdWVzKG8pIHtcclxuICAgIGlmICghU3ltYm9sLmFzeW5jSXRlcmF0b3IpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC5cIik7XHJcbiAgICB2YXIgbSA9IG9bU3ltYm9sLmFzeW5jSXRlcmF0b3JdLCBpO1xyXG4gICAgcmV0dXJuIG0gPyBtLmNhbGwobykgOiAobyA9IHR5cGVvZiBfX3ZhbHVlcyA9PT0gXCJmdW5jdGlvblwiID8gX192YWx1ZXMobykgOiBvW1N5bWJvbC5pdGVyYXRvcl0oKSwgaSA9IHt9LCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIpLCB2ZXJiKFwicmV0dXJuXCIpLCBpW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXM7IH0sIGkpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuKSB7IGlbbl0gPSBvW25dICYmIGZ1bmN0aW9uICh2KSB7IHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7IHYgPSBvW25dKHYpLCBzZXR0bGUocmVzb2x2ZSwgcmVqZWN0LCB2LmRvbmUsIHYudmFsdWUpOyB9KTsgfTsgfVxyXG4gICAgZnVuY3Rpb24gc2V0dGxlKHJlc29sdmUsIHJlamVjdCwgZCwgdikgeyBQcm9taXNlLnJlc29sdmUodikudGhlbihmdW5jdGlvbih2KSB7IHJlc29sdmUoeyB2YWx1ZTogdiwgZG9uZTogZCB9KTsgfSwgcmVqZWN0KTsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19tYWtlVGVtcGxhdGVPYmplY3QoY29va2VkLCByYXcpIHtcclxuICAgIGlmIChPYmplY3QuZGVmaW5lUHJvcGVydHkpIHsgT2JqZWN0LmRlZmluZVByb3BlcnR5KGNvb2tlZCwgXCJyYXdcIiwgeyB2YWx1ZTogcmF3IH0pOyB9IGVsc2UgeyBjb29rZWQucmF3ID0gcmF3OyB9XHJcbiAgICByZXR1cm4gY29va2VkO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9faW1wb3J0U3Rhcihtb2QpIHtcclxuICAgIGlmIChtb2QgJiYgbW9kLl9fZXNNb2R1bGUpIHJldHVybiBtb2Q7XHJcbiAgICB2YXIgcmVzdWx0ID0ge307XHJcbiAgICBpZiAobW9kICE9IG51bGwpIGZvciAodmFyIGsgaW4gbW9kKSBpZiAoT2JqZWN0Lmhhc093blByb3BlcnR5LmNhbGwobW9kLCBrKSkgcmVzdWx0W2tdID0gbW9kW2tdO1xyXG4gICAgcmVzdWx0LmRlZmF1bHQgPSBtb2Q7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19pbXBvcnREZWZhdWx0KG1vZCkge1xyXG4gICAgcmV0dXJuIChtb2QgJiYgbW9kLl9fZXNNb2R1bGUpID8gbW9kIDogeyBkZWZhdWx0OiBtb2Qg