@angular/common
Version:
Angular - commonly needed directives and services
377 lines • 154 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { concatMap, filter, map } from 'rxjs/operators';
import { HttpHandler } from './backend';
import { HttpHeaders } from './headers';
import { HttpParams } from './params';
import { HttpRequest } from './request';
import { HttpResponse } from './response';
/**
* Constructs an instance of `HttpRequestOptions<T>` from a source `HttpMethodOptions` and
* the given `body`. This function clones the object and adds the body.
* @template T
* @param {?} options
* @param {?} body
* @return {?}
*/
function addBody(options, body) {
return {
body,
headers: options.headers,
observe: options.observe,
params: options.params,
reportProgress: options.reportProgress,
responseType: options.responseType,
withCredentials: options.withCredentials,
};
}
/**
* Performs HTTP requests.
*
* This service is available as an injectable class, with methods to perform HTTP requests.
* Each request method has multiple signatures, and the return type varies based on
* the signature that is called (mainly the values of `observe` and `responseType`).
*
* \@usageNotes
* Sample HTTP requests for the [Tour of Heroes](/tutorial/toh-pt0) application.
*
* ### HTTP Request Example
*
* ```
* // GET heroes whose name contains search term
* searchHeroes(term: string): observable<Hero[]>{
*
* const params = new HttpParams({fromString: 'name=term'});
* return this.httpClient.request('GET', this.heroesUrl, {responseType:'json', params});
* }
* ```
* ### JSONP Example
* ```
* requestJsonp(url, callback = 'callback') {
* return this.httpClient.jsonp(this.heroesURL, callback);
* }
* ```
*
* ### PATCH Example
* ```
* // PATCH one of the heroes' name
* patchHero (id: number, heroName: string): Observable<{}> {
* const url = `${this.heroesUrl}/${id}`; // PATCH api/heroes/42
* return this.httpClient.patch(url, {name: heroName}, httpOptions)
* .pipe(catchError(this.handleError('patchHero')));
* }
* ```
*
* @see [HTTP Guide](guide/http)
*
* \@publicApi
*/
export class HttpClient {
/**
* @param {?} handler
*/
constructor(handler) {
this.handler = handler;
}
/**
* Constructs an observable for a generic HTTP request that, when subscribed,
* fires the request through the chain of registered interceptors and on to the
* server.
*
* You can pass an `HttpRequest` directly as the only parameter. In this case,
* the call returns an observable of the raw `HttpEvent` stream.
*
* Alternatively you can pass an HTTP method as the first parameter,
* a URL string as the second, and an options hash containing the request body as the third.
* See `addBody()`. In this case, the specified `responseType` and `observe` options determine the
* type of returned observable.
* * The `responseType` value determines how a successful response body is parsed.
* * If `responseType` is the default `json`, you can pass a type interface for the resulting
* object as a type parameter to the call.
*
* The `observe` value determines the return type, according to what you are interested in
* observing.
* * An `observe` value of events returns an observable of the raw `HttpEvent` stream, including
* progress events by default.
* * An `observe` value of response returns an observable of `HttpResponse<T>`,
* where the `T` parameter depends on the `responseType` and any optionally provided type
* parameter.
* * An `observe` value of body returns an observable of `<T>` with the same `T` body type.
*
* @param {?} first
* @param {?=} url
* @param {?=} options
* @return {?}
*/
request(first, url, options = {}) {
/** @type {?} */
let req;
// First, check whether the primary argument is an instance of `HttpRequest`.
if (first instanceof HttpRequest) {
// It is. The other arguments must be undefined (per the signatures) and can be
// ignored.
req = (/** @type {?} */ (first));
}
else {
// It's a string, so it represents a URL. Construct a request based on it,
// and incorporate the remaining arguments (assuming `GET` unless a method is
// provided.
// Figure out the headers.
/** @type {?} */
let headers = undefined;
if (options.headers instanceof HttpHeaders) {
headers = options.headers;
}
else {
headers = new HttpHeaders(options.headers);
}
// Sort out parameters.
/** @type {?} */
let params = undefined;
if (!!options.params) {
if (options.params instanceof HttpParams) {
params = options.params;
}
else {
params = new HttpParams((/** @type {?} */ ({ fromObject: options.params })));
}
}
// Construct the request.
req = new HttpRequest(first, (/** @type {?} */ (url)), (options.body !== undefined ? options.body : null), {
headers,
params,
reportProgress: options.reportProgress,
// By default, JSON is assumed to be returned for all calls.
responseType: options.responseType || 'json',
withCredentials: options.withCredentials,
});
}
// Start with an Observable.of() the initial request, and run the handler (which
// includes all interceptors) inside a concatMap(). This way, the handler runs
// inside an Observable chain, which causes interceptors to be re-run on every
// subscription (this also makes retries re-run the handler, including interceptors).
/** @type {?} */
const events$ = of(req).pipe(concatMap((/**
* @param {?} req
* @return {?}
*/
(req) => this.handler.handle(req))));
// If coming via the API signature which accepts a previously constructed HttpRequest,
// the only option is to get the event stream. Otherwise, return the event stream if
// that is what was requested.
if (first instanceof HttpRequest || options.observe === 'events') {
return events$;
}
// The requested stream contains either the full response or the body. In either
// case, the first step is to filter the event stream to extract a stream of
// responses(s).
/** @type {?} */
const res$ = (/** @type {?} */ (events$.pipe(filter((/**
* @param {?} event
* @return {?}
*/
(event) => event instanceof HttpResponse)))));
// Decide which stream to return.
switch (options.observe || 'body') {
case 'body':
// The requested stream is the body. Map the response stream to the response
// body. This could be done more simply, but a misbehaving interceptor might
// transform the response body into a different format and ignore the requested
// responseType. Guard against this by validating that the response is of the
// requested type.
switch (req.responseType) {
case 'arraybuffer':
return res$.pipe(map((/**
* @param {?} res
* @return {?}
*/
(res) => {
// Validate that the body is an ArrayBuffer.
if (res.body !== null && !(res.body instanceof ArrayBuffer)) {
throw new Error('Response is not an ArrayBuffer.');
}
return res.body;
})));
case 'blob':
return res$.pipe(map((/**
* @param {?} res
* @return {?}
*/
(res) => {
// Validate that the body is a Blob.
if (res.body !== null && !(res.body instanceof Blob)) {
throw new Error('Response is not a Blob.');
}
return res.body;
})));
case 'text':
return res$.pipe(map((/**
* @param {?} res
* @return {?}
*/
(res) => {
// Validate that the body is a string.
if (res.body !== null && typeof res.body !== 'string') {
throw new Error('Response is not a string.');
}
return res.body;
})));
case 'json':
default:
// No validation needed for JSON responses, as they can be of any type.
return res$.pipe(map((/**
* @param {?} res
* @return {?}
*/
(res) => res.body)));
}
case 'response':
// The response stream was requested directly, so return it.
return res$;
default:
// Guard against new future observe types being added.
throw new Error(`Unreachable: unhandled observe type ${options.observe}}`);
}
}
/**
* Constructs an observable that, when subscribed, causes the configured
* `DELETE` request to execute on the server. See the individual overloads for
* details on the return type.
*
* @param {?} url The endpoint URL.
* @param {?=} options The HTTP options to send with the request.
*
* @return {?}
*/
delete(url, options = {}) {
return this.request('DELETE', url, (/** @type {?} */ (options)));
}
/**
* Constructs an observable that, when subscribed, causes the configured
* `GET` request to execute on the server. See the individual overloads for
* details on the return type.
* @param {?} url
* @param {?=} options
* @return {?}
*/
get(url, options = {}) {
return this.request('GET', url, (/** @type {?} */ (options)));
}
/**
* Constructs an observable that, when subscribed, causes the configured
* `HEAD` request to execute on the server. The `HEAD` method returns
* meta information about the resource without transferring the
* resource itself. See the individual overloads for
* details on the return type.
* @param {?} url
* @param {?=} options
* @return {?}
*/
head(url, options = {}) {
return this.request('HEAD', url, (/** @type {?} */ (options)));
}
/**
* Constructs an `Observable` that, when subscribed, causes a request with the special method
* `JSONP` to be dispatched via the interceptor pipeline.
* The [JSONP pattern](https://en.wikipedia.org/wiki/JSONP) works around limitations of certain
* API endpoints that don't support newer,
* and preferable [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) protocol.
* JSONP treats the endpoint API as a JavaScript file and tricks the browser to process the
* requests even if the API endpoint is not located on the same domain (origin) as the client-side
* application making the request.
* The endpoint API must support JSONP callback for JSONP requests to work.
* The resource API returns the JSON response wrapped in a callback function.
* You can pass the callback function name as one of the query parameters.
* Note that JSONP requests can only be used with `GET` requests.
*
* @template T
* @param {?} url The resource URL.
* @param {?} callbackParam The callback function name.
*
* @return {?}
*/
jsonp(url, callbackParam) {
return this.request('JSONP', url, {
params: new HttpParams().append(callbackParam, 'JSONP_CALLBACK'),
observe: 'body',
responseType: 'json',
});
}
/**
* Constructs an `Observable` that, when subscribed, causes the configured
* `OPTIONS` request to execute on the server. This method allows the client
* to determine the supported HTTP methods and other capabilites of an endpoint,
* without implying a resource action. See the individual overloads for
* details on the return type.
* @param {?} url
* @param {?=} options
* @return {?}
*/
options(url, options = {}) {
return this.request('OPTIONS', url, (/** @type {?} */ (options)));
}
/**
* Constructs an observable that, when subscribed, causes the configured
* `PATCH` request to execute on the server. See the individual overloads for
* details on the return type.
* @param {?} url
* @param {?} body
* @param {?=} options
* @return {?}
*/
patch(url, body, options = {}) {
return this.request('PATCH', url, addBody(options, body));
}
/**
* Constructs an observable that, when subscribed, causes the configured
* `POST` request to execute on the server. The server responds with the location of
* the replaced resource. See the individual overloads for
* details on the return type.
* @param {?} url
* @param {?} body
* @param {?=} options
* @return {?}
*/
post(url, body, options = {}) {
return this.request('POST', url, addBody(options, body));
}
/**
* Constructs an observable that, when subscribed, causes the configured
* `PUT` request to execute on the server. The `PUT` method replaces an existing resource
* with a new set of values.
* See the individual overloads for details on the return type.
* @param {?} url
* @param {?} body
* @param {?=} options
* @return {?}
*/
put(url, body, options = {}) {
return this.request('PUT', url, addBody(options, body));
}
}
HttpClient.decorators = [
{ type: Injectable }
];
/** @nocollapse */
HttpClient.ctorParameters = () => [
{ type: HttpHandler }
];
if (false) {
/**
* @type {?}
* @private
*/
HttpClient.prototype.handler;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29tbW9uL2h0dHAvc3JjL2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFhLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNyQyxPQUFPLEVBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUV0RCxPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sV0FBVyxDQUFDO0FBQ3RDLE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFDdEMsT0FBTyxFQUFDLFVBQVUsRUFBb0IsTUFBTSxVQUFVLENBQUM7QUFDdkQsT0FBTyxFQUFDLFdBQVcsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUN0QyxPQUFPLEVBQVksWUFBWSxFQUFDLE1BQU0sWUFBWSxDQUFDOzs7Ozs7Ozs7QUFPbkQsU0FBUyxPQUFPLENBQ1osT0FPQyxFQUNELElBQWM7SUFDaEIsT0FBTztRQUNMLElBQUk7UUFDSixPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU87UUFDeEIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO1FBQ3hCLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTTtRQUN0QixjQUFjLEVBQUUsT0FBTyxDQUFDLGNBQWM7UUFDdEMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxZQUFZO1FBQ2xDLGVBQWUsRUFBRSxPQUFPLENBQUMsZUFBZTtLQUN6QyxDQUFDO0FBQ0osQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBOENELE1BQU0sT0FBTyxVQUFVOzs7O0lBQ3JCLFlBQW9CLE9BQW9CO1FBQXBCLFlBQU8sR0FBUCxPQUFPLENBQWE7SUFBRyxDQUFDOzs7Ozs7Ozs7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Ozs7Ozs7Ozs7O0lBaVNELElBQUksQ0FBQyxHQUFXLEVBQUUsSUFBYyxFQUFFLFVBTzlCLEVBQUU7UUFDSixPQUFPLElBQUksQ0FBQyxPQUFPLENBQU0sTUFBTSxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDaEUsQ0FBQzs7Ozs7Ozs7Ozs7SUEyUkQsR0FBRyxDQUFDLEdBQVcsRUFBRSxJQUFjLEVBQUUsVUFPN0IsRUFBRTtRQUNKLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBTSxLQUFLLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUMvRCxDQUFDOzs7WUE3L0VGLFVBQVU7Ozs7WUEzRUgsV0FBVzs7Ozs7OztJQTZFTCw2QkFBNEIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7SW5qZWN0YWJsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge09ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge2NvbmNhdE1hcCwgZmlsdGVyLCBtYXB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHtIdHRwSGFuZGxlcn0gZnJvbSAnLi9iYWNrZW5kJztcbmltcG9ydCB7SHR0cEhlYWRlcnN9IGZyb20gJy4vaGVhZGVycyc7XG5pbXBvcnQge0h0dHBQYXJhbXMsIEh0dHBQYXJhbXNPcHRpb25zfSBmcm9tICcuL3BhcmFtcyc7XG5pbXBvcnQge0h0dHBSZXF1ZXN0fSBmcm9tICcuL3JlcXVlc3QnO1xuaW1wb3J0IHtIdHRwRXZlbnQsIEh0dHBSZXNwb25zZX0gZnJvbSAnLi9yZXNwb25zZSc7XG5cblxuLyoqXG4gKiBDb25zdHJ1Y3RzIGFuIGluc3RhbmNlIG9mIGBIdHRwUmVxdWVzdE9wdGlvbnM8VD5gIGZyb20gYSBzb3VyY2UgYEh0dHBNZXRob2RPcHRpb25zYCBhbmRcbiAqIHRoZSBnaXZlbiBgYm9keWAuIFRoaXMgZnVuY3Rpb24gY2xvbmVzIHRoZSBvYmplY3QgYW5kIGFkZHMgdGhlIGJvZHkuXG4gKi9cbmZ1bmN0aW9uIGFkZEJvZHk8VD4oXG4gICAgb3B0aW9uczoge1xuICAgICAgaGVhZGVycz86IEh0dHBIZWFkZXJzIHwge1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICAgIG9ic2VydmU/OiBIdHRwT2JzZXJ2ZSxcbiAgICAgIHBhcmFtcz86IEh0dHBQYXJhbXMgfCB7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sXG4gICAgICByZXNwb25zZVR5cGU/OiAnYXJyYXlidWZmZXInIHwgJ2Jsb2InIHwgJ2pzb24nIHwgJ3RleHQnLFxuICAgICAgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgICB9LFxuICAgIGJvZHk6IFQgfCBudWxsKTogYW55IHtcbiAgcmV0dXJuIHtcbiAgICBib2R5LFxuICAgIGhlYWRlcnM6IG9wdGlvbnMuaGVhZGVycyxcbiAgICBvYnNlcnZlOiBvcHRpb25zLm9ic2VydmUsXG4gICAgcGFyYW1zOiBvcHRpb25zLnBhcmFtcyxcbiAgICByZXBvcnRQcm9ncmVzczogb3B0aW9ucy5yZXBvcnRQcm9ncmVzcyxcbiAgICByZXNwb25zZVR5cGU6IG9wdGlvbnMucmVzcG9uc2VUeXBlLFxuICAgIHdpdGhDcmVkZW50aWFsczogb3B0aW9ucy53aXRoQ3JlZGVudGlhbHMsXG4gIH07XG59XG5cbmV4cG9ydCB0eXBlIEh0dHBPYnNlcnZlID0gJ2JvZHknIHwgJ2V2ZW50cycgfCAncmVzcG9uc2UnO1xuXG4vKipcbiAqIFBlcmZvcm1zIEhUVFAgcmVxdWVzdHMuXG4gKlxuICogVGhpcyBzZXJ2aWNlIGlzIGF2YWlsYWJsZSBhcyBhbiBpbmplY3RhYmxlIGNsYXNzLCB3aXRoIG1ldGhvZHMgdG8gcGVyZm9ybSBIVFRQIHJlcXVlc3RzLlxuICogRWFjaCByZXF1ZXN0IG1ldGhvZCBoYXMgbXVsdGlwbGUgc2lnbmF0dXJlcywgYW5kIHRoZSByZXR1cm4gdHlwZSB2YXJpZXMgYmFzZWQgb25cbiAqIHRoZSBzaWduYXR1cmUgdGhhdCBpcyBjYWxsZWQgKG1haW5seSB0aGUgdmFsdWVzIG9mIGBvYnNlcnZlYCBhbmQgYHJlc3BvbnNlVHlwZWApLlxuICpcbiAqIEB1c2FnZU5vdGVzXG4gKiBTYW1wbGUgSFRUUCByZXF1ZXN0cyBmb3IgdGhlIFtUb3VyIG9mIEhlcm9lc10oL3R1dG9yaWFsL3RvaC1wdDApIGFwcGxpY2F0aW9uLlxuICpcbiAqICMjIyBIVFRQIFJlcXVlc3QgRXhhbXBsZVxuICpcbiAqIGBgYFxuICogIC8vIEdFVCBoZXJvZXMgd2hvc2UgbmFtZSBjb250YWlucyBzZWFyY2ggdGVybVxuICogc2VhcmNoSGVyb2VzKHRlcm06IHN0cmluZyk6IG9ic2VydmFibGU8SGVyb1tdPntcbiAqXG4gKiAgY29uc3QgcGFyYW1zID0gbmV3IEh0dHBQYXJhbXMoe2Zyb21TdHJpbmc6ICduYW1lPXRlcm0nfSk7XG4gKiAgICByZXR1cm4gdGhpcy5odHRwQ2xpZW50LnJlcXVlc3QoJ0dFVCcsIHRoaXMuaGVyb2VzVXJsLCB7cmVzcG9uc2VUeXBlOidqc29uJywgcGFyYW1zfSk7XG4gKiB9XG4gKiBgYGBcbiAqICMjIyBKU09OUCBFeGFtcGxlXG4gKiBgYGBcbiAqIHJlcXVlc3RKc29ucCh1cmwsIGNhbGxiYWNrID0gJ2NhbGxiYWNrJykge1xuICogIHJldHVybiB0aGlzLmh0dHBDbGllbnQuanNvbnAodGhpcy5oZXJvZXNVUkwsIGNhbGxiYWNrKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqICMjIyBQQVRDSCBFeGFtcGxlXG4gKiBgYGBcbiAqIC8vIFBBVENIIG9uZSBvZiB0aGUgaGVyb2VzJyBuYW1lXG4gKiBwYXRjaEhlcm8gKGlkOiBudW1iZXIsIGhlcm9OYW1lOiBzdHJpbmcpOiBPYnNlcnZhYmxlPHt9PiB7XG4gKiBjb25zdCB1cmwgPSBgJHt0aGlzLmhlcm9lc1VybH0vJHtpZH1gOyAgIC8vIFBBVENIIGFwaS9oZXJvZXMvNDJcbiAqICByZXR1cm4gdGhpcy5odHRwQ2xpZW50LnBhdGNoKHVybCwge25hbWU6IGhlcm9OYW1lfSwgaHR0cE9wdGlvbnMpXG4gKiAgICAucGlwZShjYXRjaEVycm9yKHRoaXMuaGFuZGxlRXJyb3IoJ3BhdGNoSGVybycpKSk7XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAc2VlIFtIVFRQIEd1aWRlXShndWlkZS9odHRwKVxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEh0dHBDbGllbnQge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGhhbmRsZXI6IEh0dHBIYW5kbGVyKSB7fVxuXG4gIC8qKlxuICAgKiBTZW5kcyBhbiBgSFRUUFJlcXVlc3RgIGFuZCByZXR1cm5zIGEgc3RyZWFtIG9mIGBIVFRQRXZlbnRzYC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIHJlc3BvbnNlLCB3aXRoIHRoZSByZXNwb25zZSBib2R5IGFzIGEgc3RyZWFtIG9mIGBIVFRQRXZlbnRzYC5cbiAgICovXG4gIHJlcXVlc3Q8Uj4ocmVxOiBIdHRwUmVxdWVzdDxhbnk+KTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8Uj4+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB0aGF0IGludGVycHJldHMgdGhlIGJvZHkgYXMgYW4gYEFycmF5QnVmZmVyYCBhbmQgcmV0dXJucyB0aGUgcmVzcG9uc2UgaW4gYW5cbiAgICogYEFycmF5QnVmZmVyYC5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIHJlc3BvbnNlLCB3aXRoIHRoZSByZXNwb25zZSBib2R5IGFzIGFuIGBBcnJheUJ1ZmZlcmAuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgb2JzZXJ2ZT86ICdib2R5JyxcbiAgICBwYXJhbXM/OiBIdHRwUGFyYW1zfHtbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sXG4gICAgcmVzcG9uc2VUeXBlOiAnYXJyYXlidWZmZXInLCB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxBcnJheUJ1ZmZlcj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHRoYXQgaW50ZXJwcmV0cyB0aGUgYm9keSBhcyBhIGJsb2IgYW5kIHJldHVybnNcbiAgICogdGhlIHJlc3BvbnNlIGFzIGEgYmxvYi5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIHJlc3BvbnNlLCB3aXRoIHRoZSByZXNwb25zZSBib2R5IG9mIHR5cGUgYEJsb2JgLlxuICAgKi9cbiAgcmVxdWVzdChtZXRob2Q6IHN0cmluZywgdXJsOiBzdHJpbmcsIG9wdGlvbnM6IHtcbiAgICBib2R5PzogYW55LFxuICAgIGhlYWRlcnM/OiBIdHRwSGVhZGVyc3x7W2hlYWRlcjogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIG9ic2VydmU/OiAnYm9keScsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3x7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIHJlc3BvbnNlVHlwZTogJ2Jsb2InLCB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxCbG9iPjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3QgdGhhdCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGEgdGV4dCBzdHJpbmcgYW5kXG4gICAqIHJldHVybnMgYSBzdHJpbmcgdmFsdWUuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIHRoZSByZXNwb25zZSwgd2l0aCB0aGUgcmVzcG9uc2UgYm9keSBvZiB0eXBlIHN0cmluZy5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBvYnNlcnZlPzogJ2JvZHknLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8e1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbixcbiAgICByZXNwb25zZVR5cGU6ICd0ZXh0Jywgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8c3RyaW5nPjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3QgdGhhdCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGFuIGBBcnJheUJ1ZmZlcmAgYW5kIHJldHVybnMgdGhlXG4gICAqIHRoZSBmdWxsIGV2ZW50IHN0cmVhbS5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIHJlc3BvbnNlLCB3aXRoIHRoZSByZXNwb25zZSBib2R5IGFzIGFuIGFycmF5IG9mIGBIVFRQRXZlbnRzYCBmb3IgdGhlXG4gICAqIHJlcXVlc3QuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3x7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgb2JzZXJ2ZTogJ2V2ZW50cycsIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbixcbiAgICByZXNwb25zZVR5cGU6ICdhcnJheWJ1ZmZlcicsIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxBcnJheUJ1ZmZlcj4+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB0aGF0IGludGVycHJldHMgdGhlIGJvZHkgYXMgYSBgQmxvYmAgYW5kIHJldHVybnNcbiAgICogdGhlIGZ1bGwgZXZlbnQgc3RyZWFtLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIEFuIGBPYnNlcnZhYmxlYCBvZiBvZiBhbGwgYEh0dHBFdmVudHNgIGZvciB0aGUgcmVxdWVzdCxcbiAgICogd2l0aCB0aGUgcmVzcG9uc2UgYm9keSBvZiB0eXBlIGBCbG9iYC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBvYnNlcnZlOiAnZXZlbnRzJyxcbiAgICBwYXJhbXM/OiBIdHRwUGFyYW1zfHtbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sXG4gICAgcmVzcG9uc2VUeXBlOiAnYmxvYicsIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxCbG9iPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSB0ZXh0IHN0cmluZyBhbmQgcmV0dXJucyB0aGUgZnVsbCBldmVudCBzdHJlYW0uXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIGFsbCBgSHR0cEV2ZW50c2AgZm9yIHRoZSByZXF1ZXMsXG4gICAqIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBzdHJpbmcuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgb2JzZXJ2ZTogJ2V2ZW50cycsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3x7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIHJlc3BvbnNlVHlwZTogJ3RleHQnLCB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8c3RyaW5nPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSBKU09OIG9iamVjdCBhbmQgcmV0dXJucyB0aGUgZnVsbCBldmVudCBzdHJlYW0uXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlICByZXF1ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIEFuIGBPYnNlcnZhYmxlYCBvZiBhbGwgYEh0dHBFdmVudHNgIGZvciB0aGUgcmVxdWVzdCxcbiAgICogIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgT2JqZWN0YC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sXG4gICAgb2JzZXJ2ZTogJ2V2ZW50cycsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3x7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVzcG9uc2VUeXBlPzogJ2pzb24nLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxhbnk+PjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3Qgd2hpY2ggaW50ZXJwcmV0cyB0aGUgYm9keSBhcyBhIEpTT04gb2JqZWN0IGFuZCByZXR1cm5zIHRoZSBmdWxsIGV2ZW50IHN0cmVhbS5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgYWxsIGBIdHRwRXZlbnRzYCBmb3IgdGhlIHJlcXVlc3QsXG4gICAqIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgUmAuXG4gICAqL1xuICByZXF1ZXN0PFI+KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIG9ic2VydmU6ICdldmVudHMnLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8e1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIHJlc3BvbnNlVHlwZT86ICdqc29uJyxcbiAgICB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8Uj4+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB3aGljaCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGFuIGBBcnJheUJ1ZmZlcmBcbiAgICogYW5kIHJldHVybnMgdGhlIGZ1bGwgYEhUVFBSZXNwb25zZWAuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIHRoZSBgSFRUUFJlc3BvbnNlYCwgd2l0aCB0aGUgcmVzcG9uc2UgYm9keSBhcyBhbiBgQXJyYXlCdWZmZXJgLlxuICAgKi9cbiAgcmVxdWVzdChtZXRob2Q6IHN0cmluZywgdXJsOiBzdHJpbmcsIG9wdGlvbnM6IHtcbiAgICBib2R5PzogYW55LFxuICAgIGhlYWRlcnM/OiBIdHRwSGVhZGVyc3x7W2hlYWRlcjogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIG9ic2VydmU6ICdyZXNwb25zZScsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3x7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIHJlc3BvbnNlVHlwZTogJ2FycmF5YnVmZmVyJywgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8SHR0cFJlc3BvbnNlPEFycmF5QnVmZmVyPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSBgQmxvYmAgYW5kIHJldHVybnMgdGhlIGZ1bGwgYEhUVFBSZXNwb25zZWAuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIHRoZSBgSFRUUFJlc3BvbnNlYCwgd2l0aCB0aGUgcmVzcG9uc2UgYm9keSBvZiB0eXBlIGBCbG9iYC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBvYnNlcnZlOiAncmVzcG9uc2UnLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8e1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbixcbiAgICByZXNwb25zZVR5cGU6ICdibG9iJywgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8SHR0cFJlc3BvbnNlPEJsb2I+PjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3Qgd2hpY2ggaW50ZXJwcmV0cyB0aGUgYm9keSBhcyBhIHRleHQgc3RyZWFtIGFuZCByZXR1cm5zIHRoZSBmdWxsIGBIVFRQUmVzcG9uc2VgLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIEFuIGBPYnNlcnZhYmxlYCBvZiB0aGUgSFRUUCByZXNwb25zZSwgd2l0aCB0aGUgcmVzcG9uc2UgYm9keSBvZiB0eXBlIHN0cmluZy5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBvYnNlcnZlOiAncmVzcG9uc2UnLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8e1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbixcbiAgICByZXNwb25zZVR5cGU6ICd0ZXh0Jywgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8SHR0cFJlc3BvbnNlPHN0cmluZz4+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB3aGljaCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGEgSlNPTiBvYmplY3QgYW5kIHJldHVybnMgdGhlIGZ1bGwgYEhUVFBSZXNwb25zZWAuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIHRoZSBmdWxsIGBIVFRQUmVzcG9uc2VgLFxuICAgKiB3aXRoIHRoZSByZXNwb25zZSBib2R5IG9mIHR5cGUgYE9iamVjdGAuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIG9ic2VydmU6ICdyZXNwb25zZScsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3x7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVzcG9uc2VUeXBlPzogJ2pzb24nLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEh0dHBSZXNwb25zZTxPYmplY3Q+PjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3Qgd2hpY2ggaW50ZXJwcmV0cyB0aGUgYm9keSBhcyBhIEpTT04gb2JqZWN0IGFuZCByZXR1cm5zXG4gICAqIHRoZSBmdWxsIGBIVFRQUmVzcG9uc2VgIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgaW4gdGhlIHJlcXVlc3RlZCB0eXBlLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuICBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIGZ1bGwgYEhUVFBSZXNwb25zZWAsIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgUmAuXG4gICAqL1xuICByZXF1ZXN0PFI+KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIG9ic2VydmU6ICdyZXNwb25zZScsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3x7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcmVzcG9uc2VUeXBlPzogJ2pzb24nLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEh0dHBSZXNwb25zZTxSPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSBKU09OIG9iamVjdCBhbmQgcmV0dXJucyB0aGUgZnVsbFxuICAgKiBgSFRUUFJlc3BvbnNlYCBhcyBhIEpTT04gb2JqZWN0LlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIEFuIGBPYnNlcnZhYmxlYCBvZiB0aGUgYEhUVFBSZXNwb25zZWAsIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgT2JqZWN0YC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zPzoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgb2JzZXJ2ZT86ICdib2R5JyxcbiAgICBwYXJhbXM/OiBIdHRwUGFyYW1zfHtbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICByZXNwb25zZVR5cGU/OiAnanNvbicsXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPE9iamVjdD47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSBKU09OIG9iamVjdFxuICAgKiB3aXRoIHRoZSByZXNwb25zZSBib2R5IG9mIHRoZSByZXF1ZXN0ZWQgdHlwZS5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIGBIVFRQUmVzcG9uc2VgLCB3aXRoIHRoZSByZXNwb25zZSBib2R5IG9mIHR5cGUgYFJgLlxuICAgKi9cbiAgcmVxdWVzdDxSPihtZXRob2Q6IHN0cmluZywgdXJsOiBzdHJpbmcsIG9wdGlvbnM/OiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBvYnNlcnZlPzogJ2JvZHknLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8e1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIHJlc3BvbnNlVHlwZT86ICdqc29uJyxcbiAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sXG4gICAgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8Uj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoZXJlIHJlc3BvbnNlIHR5cGUgYW5kIHJlcXVlc3RlZCBvYnNlcnZhYmxlIGFyZSBub3Qga25vd24gc3RhdGljYWxseS5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIHJldWVzdGVkIHJlc3BvbnNlLCB3dXRoIGJvZHkgb2YgdHlwZSBgYW55YC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zPzoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3x7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgb2JzZXJ2ZT86IEh0dHBPYnNlcnZlLFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbixcbiAgICByZXNwb25zZVR5cGU/OiAnYXJyYXlidWZmZXInfCdibG9iJ3wnanNvbid8J3RleHQnLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPGFueT47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYW4gb2JzZXJ2YWJsZSBmb3IgYSBnZW5lcmljIEhUVFAgcmVxdWVzdCB0aGF0LCB3aGVuIHN1YnNjcmliZWQsXG4gICAqIGZpcmVzIHRoZSByZXF1ZXN0IHRocm91Z2ggdGhlIGNoYWluIG9mIHJlZ2lzdGVyZWQgaW50ZXJjZXB0b3JzIGFuZCBvbiB0byB0aGVcbiAgICogc2VydmVyLlxuICAgKlxuICAgKiBZb3UgY2FuIHBhc3MgYW4gYEh0dHBSZXF1ZXN0YCBkaXJlY3RseSBhcyB0aGUgb25seSBwYXJhbWV0ZXIuIEluIHRoaXMgY2FzZSxcbiAgICogdGhlIGNhbGwgcmV0dXJucyBhbiBvYnNlcnZhYmxlIG9mIHRoZSByYXcgYEh0dHBFdmVudGAgc3RyZWFtLlxuICAgKlxuICAgKiBBbHRlcm5hdGl2ZWx5IHlvdSBjYW4gcGFzcyBhbiBIVFRQIG1ldGhvZCBhcyB0aGUgZmlyc3QgcGFyYW1ldGVyLFxuICAgKiBhIFVSTCBzdHJpbmcgYXMgdGhlIHNlY29uZCwgYW5kIGFuIG9wdGlvbnMgaGFzaCBjb250YWluaW5nIHRoZSByZXF1ZXN0IGJvZHkgYXMgdGhlIHRoaXJkLlxuICAgKiBTZWUgYGFkZEJvZHkoKWAuIEluIHRoaXMgY2FzZSwgdGhlIHNwZWNpZmllZCBgcmVzcG9uc2VUeXBlYCBhbmQgYG9ic2VydmVgIG9wdGlvbnMgZGV0ZXJtaW5lIHRoZVxuICAgKiB0eXBlIG9mIHJldHVybmVkIG9ic2VydmFibGUuXG4gICAqICAgKiBUaGUgYHJlc3BvbnNlVHlwZWAgdmFsdWUgZGV0ZXJtaW5lcyBob3cgYSBzdWNjZXNzZnVsIHJlc3BvbnNlIGJvZHkgaXMgcGFyc2VkLlxuICAgKiAgICogSWYgYHJlc3BvbnNlVHlwZWAgaXMgdGhlIGRlZmF1bHQgYGpzb25gLCB5b3UgY2FuIHBhc3MgYSB0eXBlIGludGVyZmFjZSBmb3IgdGhlIHJlc3VsdGluZ1xuICAgKiBvYmplY3QgYXMgYSB0eXBlIHBhcmFtZXRlciB0byB0aGUgY2FsbC5cbiAgICpcbiAgICogVGhlIGBvYnNlcnZlYCB2YWx1ZSBkZXRlcm1pbmVzIHRoZSByZXR1cm4gdHlwZSwgYWNjb3JkaW5nIHRvIHdoYXQgeW91IGFyZSBpbnRlcmVzdGVkIGluXG4gICAqIG9ic2VydmluZy5cbiAgICogICAqIEFuIGBvYnNlcnZlYCB2YWx1ZSBvZiBldmVudHMgcmV0dXJucyBhbiBvYnNlcnZhYmxlIG9mIHRoZSByYXcgYEh0dHBFdmVudGAgc3RyZWFtLCBpbmNsdWRpbmdcbiAgICogcHJvZ3Jlc3MgZXZlbnRzIGJ5IGRlZmF1bHQuXG4gICAqICAgKiBBbiBgb2JzZXJ2ZWAgdmFsdWUgb2YgcmVzcG9uc2UgcmV0dXJucyBhbiBvYnNlcnZhYmxlIG9mIGBIdHRwUmVzcG9uc2U8VD5gLFxuICAgKiB3aGVyZSB0aGUgYFRgIHBhcmFtZXRlciBkZXBlbmRzIG9uIHRoZSBgcmVzcG9uc2VUeXBlYCBhbmQgYW55IG9wdGlvbmFsbHkgcHJvdmlkZWQgdHlwZVxuICAgKiBwYXJhbWV0ZXIuXG4gICAqICAgKiBBbiBgb2JzZXJ2ZWAgdmFsdWUgb2YgYm9keSByZXR1cm5zIGFuIG9ic2VydmFibGUgb2YgYDxUPmAgd2l0aCB0aGUgc2FtZSBgVGAgYm9keSB0eXBlLlxuICAgKlxuICAgKi9cbiAgcmVxdWVzdChmaXJzdDogc3RyaW5nfEh0dHBSZXF1ZXN0PGFueT4sIHVybD86IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgb2JzZXJ2ZT86IEh0dHBPYnNlcnZlLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8e1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbixcbiAgICByZXNwb25zZVR5cGU/OiAnYXJyYXlidWZmZXInfCdibG9iJ3wnanNvbid8J3RleHQnLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0gPSB7fSk6IE9ic2VydmFibGU8YW55PiB7XG4gICAgbGV0IHJlcTogSHR0cFJlcXVlc3Q8YW55PjtcbiAgICAvLyBGaXJzdCwgY2hlY2sgd2hldGhlciB0aGUgcHJpbWFyeSBhcmd1bWVudCBpcyBhbiBpbnN0YW5jZSBvZiBgSHR0cFJlcXVlc3RgLlxuICAgIGlmIChmaXJzdCBpbnN0YW5jZW9mIEh0dHBSZXF1ZXN0KSB7XG4gICAgICAvLyBJdCBpcy4gVGhlIG90aGVyIGFyZ3VtZW50cyBtdXN0IGJlIHVuZGVmaW5lZCAocGVyIHRoZSBzaWduYXR1cmVzKSBhbmQgY2FuIGJlXG4gICAgICAvLyBpZ25vcmVkLlxuICAgICAgcmVxID0gZmlyc3QgYXMgSHR0cFJlcXVlc3Q8YW55PjtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gSXQncyBhIHN0cmluZywgc28gaXQgcmVwcmVzZW50cyBhIFVSTC4gQ29uc3RydWN0IGEgcmVxdWVzdCBiYXNlZCBvbiBpdCxcbiAgICAgIC8vIGFuZCBpbmNvcnBvcmF0ZSB0aGUgcmVtYWluaW5nIGFyZ3VtZW50cyAoYXNzdW1pbmcgYEdFVGAgdW5sZXNzIGEgbWV0aG9kIGlzXG4gICAgICAvLyBwcm92aWRlZC5cblxuICAgICAgLy8gRmlndXJlIG91dCB0aGUgaGVhZGVycy5cbiAgICAgIGxldCBoZWFkZXJzOiBIdHRwSGVhZGVyc3x1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gICAgICBpZiAob3B0aW9ucy5oZWFkZXJzIGluc3RhbmNlb2YgSHR0cEhlYWRlcnMpIHtcbiAgICAgICAgaGVhZGVycyA9IG9wdGlvbnMuaGVhZGVycztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGhlYWRlcnMgPSBuZXcgSHR0cEhlYWRlcnMob3B0aW9ucy5oZWFkZXJzKTtcbiAgICAgIH1cblxuICAgICAgLy8gU29ydCBvdXQgcGFyYW1ldGVycy5cbiAgICAgIGxldCBwYXJhbXM6IEh0dHBQYXJhbXN8dW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgICAgaWYgKCEhb3B0aW9ucy5wYXJhbXMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMucGFyYW1zIGluc3RhbmNlb2YgSHR0cFBhcmFtcykge1xuICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1zO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBhcmFtcyA9IG5ldyBIdHRwUGFyYW1zKHsgZnJvbU9iamVjdDogb3B0aW9ucy5wYXJhbXMgfSBhcyBIdHRwUGFyYW1zT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gQ29uc3RydWN0IHRoZSByZXF1ZXN0LlxuICAgICAgcmVxID0gbmV3IEh0dHBSZXF1ZXN0KGZpcnN0LCB1cmwgISwgKG9wdGlvbnMuYm9keSAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5ib2R5IDogbnVsbCksIHtcbiAgICAgICAgaGVhZGVycyxcbiAgICAgICAgcGFyYW1zLFxuICAgICAgICByZXBvcnRQcm9ncmVzczogb3B0aW9ucy5yZXBvcnRQcm9ncmVzcyxcbiAgICAgICAgLy8gQnkgZGVmYXVsdCwgSlNPTiBpcyBhc3N1bWVkIHRvIGJlIHJldHVybmVkIGZvciBhbGwgY2FsbHMuXG4gICAgICAgIHJlc3BvbnNlVHlwZTogb3B0aW9ucy5yZXNwb25zZVR5cGUgfHwgJ2pzb24nLFxuICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IG9wdGlvbnMud2l0aENyZWRlbnRpYWxzLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gU3RhcnQgd2l0aCBhbiBPYnNlcnZhYmxlLm9mKCkgdGhlIGluaXRpYWwgcmVxdWVzdCwgYW5kIHJ1biB0aGUgaGFuZGxlciAod2hpY2hcbiAgICAvLyBpbmNsdWRlcyBhbGwgaW50ZXJjZXB0b3JzKSBpbnNpZGUgYSBjb25jYXRNYXAoKS4gVGhpcyB3YXksIHRoZSBoYW5kbGVyIHJ1bnNcbiAgICAvLyBpbnNpZGUgYW4gT2JzZXJ2YWJsZSBjaGFpbiwgd2hpY2ggY2F1c2VzIGludGVyY2VwdG9ycyB0byBiZSByZS1ydW4gb24gZXZlcnlcbiAgICAvLyBzdWJzY3JpcHRpb24gKHRoaXMgYWxzbyBtYWtlcyByZXRyaWVzIHJlLXJ1biB0aGUgaGFuZGxlciwgaW5jbHVkaW5nIGludGVyY2VwdG9ycykuXG4gICAgY29uc3QgZXZlbnRzJDogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8YW55Pj4gPVxuICAgICAgICBvZiAocmVxKS5waXBlKGNvbmNhdE1hcCgocmVxOiBIdHRwUmVxdWVzdDxhbnk+KSA9PiB0aGlzLmhhbmRsZXIuaGFuZGxlKHJlcSkpKTtcblxuICAgIC8vIElmIGNvbWluZyB2aWEgdGhlIEFQSSBzaWduYXR1cmUgd2hpY2ggYWNjZXB0cyBhIHByZXZpb3VzbHkgY29uc3RydWN0ZWQgSHR0cFJlcXVlc3QsXG4gICAgLy8gdGhlIG9ubHkgb3B0aW9uIGlzIHRvIGdldCB0aGUgZXZlbnQgc3RyZWFtLiBPdGhlcndpc2UsIHJldHVybiB0aGUgZXZlbnQgc3RyZWFtIGlmXG4gICAgLy8gdGhhdCBpcyB3aGF0IHdhcyByZXF1ZXN0ZWQuXG4gICAgaWYgKGZpcnN0IGluc3RhbmNlb2YgSHR0cFJlcXVlc3QgfHwgb3B0aW9ucy5vYnNlcnZlID09PSAnZXZlbnRzJykge1xuICAgICAgcmV0dXJuIGV2ZW50cyQ7XG4gICAgfVxuXG4gICAgLy8gVGhlIHJlcXVlc3RlZCBzdHJlYW0gY29udGFpbnMgZWl0aGVyIHRoZSBmdWxsIHJlc3BvbnNlIG9yIHRoZSBib2R5LiBJbiBlaXRoZXJcbiAgICAvLyBjYXNlLCB0aGUgZmlyc3Qgc3RlcCBpcyB0byBmaWx0ZXIgdGhlIGV2ZW50IHN0cmVhbSB0byBleHRyYWN0IGEgc3RyZWFtIG9mXG4gICAgLy8gcmVzcG9uc2VzKHMpLlxuICAgIGNvbnN0IHJlcyQ6IE9ic2VydmFibGU8SHR0cFJlc3BvbnNlPGFueT4+ID0gPE9ic2VydmFibGU8SHR0cFJlc3BvbnNlPGFueT4+PmV2ZW50cyQucGlwZShcbiAgICAgICAgZmlsdGVyKChldmVudDogSHR0cEV2ZW50PGFueT4pID0+IGV2ZW50IGluc3RhbmNlb2YgSHR0cFJlc3BvbnNlKSk7XG5cbiAgICAvLyBEZWNpZGUgd2hpY2ggc3RyZWFtIHRvIHJldHVybi5cbiAgICBzd2l0Y2ggKG9wdGlvbnMub2JzZXJ2ZSB8fCAnYm9keScpIHtcbiAgICAgIGNhc2UgJ2JvZHknOlxuICAgICAgICAvLyBUaGUgcmVxdWVzdGVkIHN0cmVhbSBpcyB0aGUgYm9keS4gTWFwIHRoZSByZXNwb25zZSBzdHJlYW0gdG8gdGhlIHJlc3BvbnNlXG4gICAgICAgIC8vIGJvZHkuIFRoaXMgY291bGQgYmUgZG9uZSBtb3JlIHNpbXBseSwgYnV0IGEgbWlzYmVoYXZpbmcgaW50ZXJjZXB0b3IgbWlnaHRcbiAgICAgICAgLy8gdHJhbnNmb3JtIHRoZSByZXNwb25zZSBib2R5IGludG8gYSBkaWZmZXJlbnQgZm9ybWF0IGFuZCBpZ25vcmUgdGhlIHJlcXVlc3RlZFxuICAgICAgICAvLyByZXNwb25zZVR5cGUuIEd1YXJkIGFnYWluc3QgdGhpcyBieSB2YWxpZGF0aW5nIHRoYXQgdGhlIHJlc3BvbnNlIGlzIG9mIHRoZVxuICAgICAgICAvLyByZXF1ZXN0ZWQgdHlwZS5cbiAgICAgICAgc3dpdGNoIChyZXEucmVzcG9uc2VUeXBlKSB7XG4gICAgICAgICAgY2FzZSAnYXJyYXlidWZmZXInOlxuICAgICAgICAgICAgcmV0dXJuIHJlcyQucGlwZShtYXAoKHJlczogSHR0cFJlc3BvbnNlPGFueT4pID0+IHtcbiAgICAgICAgICAgICAgLy8gVmFsaWRhdGUgdGhhdCB0aGUgYm9keSBpcyBhbiBBcnJheUJ1ZmZlci5cbiAgICAgICAgICAgICAgaWYgKHJlcy5ib2R5ICE9PSBudWxsICYmICEocmVzLmJvZHkgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Jlc3BvbnNlIGlzIG5vdCBhbiBBcnJheUJ1ZmZlci4nKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gcmVzLmJvZHk7XG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgY2FzZSAnYmxvYic6XG4gICAgICAgICAgICByZXR1cm4gcmVzJC5waXBlKG1hcCgocmVzOiBIdHRwUmVzcG9uc2U8YW55PikgPT4ge1xuICAgICAgICAgICAgICAvLyBWYWxpZGF0ZSB0aGF0IHRoZSBib2R5IGlzIGEgQmxvYi5cbiAgICAgICAgICAgICAgaWYgKHJlcy5ib2R5ICE9PSBudWxsICYmICEocmVzLmJvZHkgaW5zdGFuY2VvZiBCbG9iKSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUmVzcG9uc2UgaXMgbm90IGEgQmxvYi4nKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gcmVzLmJvZHk7XG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgY2FzZSAndGV4dCc6XG4gICAgICAgICAgICByZXR1cm4gcmVzJC5waXBlKG1hcCgocmVzOiBIdHRwUmVzcG9uc2U8YW55PikgPT4ge1xuICAgICAgICAgICAgICAvLyBWYWxpZGF0ZSB0aGF0IHRoZSBib2R5IGlzIGEgc3RyaW5nLlxuICAgICAgICAgICAgICBpZiAocmVzLmJvZHkgIT09IG51bGwgJiYgdHlwZW9mIHJlcy5ib2R5ICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUmVzcG9uc2UgaXMgbm90IGEgc3RyaW5nLicpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiByZXMuYm9keTtcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICBjYXNlICdqc29uJzpcbiAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLy8gTm8gdmFsaWRhdGlvbiBuZWVkZWQgZm9yIEpTT04gcmVzcG9uc2VzLCBhcyB0aGV5IGNhbiBiZSBvZiBhbnkgdHlwZS5cbiAgICAgICAgICAgIHJldHVybiByZXMkLnBpcGUobWFwKChyZXM6IEh0dHBSZXNwb25zZTxhbnk+KSA9PiByZXMuYm9keSkpO1xuICAgICAgICB9XG4gICAgICBjYXNlICdyZXNwb25zZSc6XG4gICAgICAgIC8vIFRoZSByZXNwb25zZSBzdHJlYW0gd2FzIHJlcXVlc3RlZCBkaXJlY3RseSwgc28gcmV0dXJuIGl0LlxuICAgICAgICByZXR1cm4gcmVzJDtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIC8vIEd1YXJkIGFnYWluc3QgbmV3IGZ1dHVyZSBvYnNlcnZlIHR5cGVzIGJlaW5nIG