UNPKG

@angular/common

Version:

Angular - commonly needed directives and services

325 lines (324 loc) 170 kB
/** * @license * Copyright Google LLC 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'; import * as i0 from "@angular/core"; import * as i1 from "./backend"; /** * Constructs an instance of `HttpRequestOptions<T>` from a source `HttpMethodOptions` and * the given `body`. This function clones the object and adds the body. * * Note that the `responseType` *options* value is a String that identifies the * single data type of the response. * A single overload version of the method handles each response type. * The value of `responseType` cannot be a union, as the combined signature could imply. * */ function addBody(options, body) { return { body, headers: options.headers, context: options.context, 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`). * * Note that the `responseType` *options* value is a String that identifies the * single data type of the response. * A single overload version of the method handles each response type. * The value of `responseType` cannot be a union, as the combined signature could imply. * * @usageNotes * Sample HTTP requests for the [Tour of Heroes](/tutorial/tour-of-heroes/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}); * } * ``` * * Alternatively, the parameter string can be used without invoking HttpParams * by directly joining to the URL. * ``` * this.httpClient.request('GET', this.heroesUrl + '?' + 'name=term', {responseType:'json'}); * ``` * * * ### 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) * @see [HTTP Request](api/common/http/HttpRequest) * * @publicApi */ class HttpClient { 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. * */ request(first, url, options = {}) { 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 = 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. let headers = undefined; if (options.headers instanceof HttpHeaders) { headers = options.headers; } else { headers = new HttpHeaders(options.headers); } // Sort out parameters. let params = undefined; if (!!options.params) { if (options.params instanceof HttpParams) { params = options.params; } else { params = new HttpParams({ fromObject: options.params }); } } // Construct the request. req = new HttpRequest(first, url, (options.body !== undefined ? options.body : null), { headers, context: options.context, 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). const events$ = of(req).pipe(concatMap((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). const res$ = events$.pipe(filter((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((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((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((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((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. * */ delete(url, options = {}) { return this.request('DELETE', url, 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. */ get(url, options = {}) { return this.request('GET', url, 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. */ head(url, options = {}) { return this.request('HEAD', url, 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. * * @param url The resource URL. * @param callbackParam The callback function name. * */ 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 capabilities of an endpoint, * without implying a resource action. See the individual overloads for * details on the return type. */ options(url, options = {}) { return this.request('OPTIONS', url, 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. */ 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. */ 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. */ put(url, body, options = {}) { return this.request('PUT', url, addBody(options, body)); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: HttpClient, deps: [{ token: i1.HttpHandler }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: HttpClient }); } } export { HttpClient }; i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: HttpClient, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1.HttpHandler }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29tbW9uL2h0dHAvc3JjL2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBYSxFQUFFLEVBQUMsTUFBTSxNQUFNLENBQUM7QUFDcEMsT0FBTyxFQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFFdEQsT0FBTyxFQUFDLFdBQVcsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUV0QyxPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sV0FBVyxDQUFDO0FBQ3RDLE9BQU8sRUFBQyxVQUFVLEVBQW9CLE1BQU0sVUFBVSxDQUFDO0FBQ3ZELE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFDdEMsT0FBTyxFQUFZLFlBQVksRUFBQyxNQUFNLFlBQVksQ0FBQzs7O0FBR25EOzs7Ozs7Ozs7R0FTRztBQUNILFNBQVMsT0FBTyxDQUNaLE9BU0MsRUFDRCxJQUFZO0lBQ2QsT0FBTztRQUNMLElBQUk7UUFDSixPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU87UUFDeEIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO1FBQ3hCLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztRQUN4QixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU07UUFDdEIsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjO1FBQ3RDLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtRQUNsQyxlQUFlLEVBQUUsT0FBTyxDQUFDLGVBQWU7S0FDekMsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0RHO0FBQ0gsTUFDYSxVQUFVO0lB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TyxDQUFNLFNBQVMsRUFBRSxHQUFHLEVBQUUsT0FBYyxDQUFDLENBQUM7SUFDM0QsQ0FBQztJQXVURDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLEdBQVcsRUFBRSxJQUFjLEVBQUUsVUFTL0IsRUFBRTtRQUNKLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBTSxPQUFPLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBcVREOzs7OztPQUtHO0lBQ0gsSUFBSSxDQUFDLEdBQVcsRUFBRSxJQUFjLEVBQUUsVUFTOUIsRUFBRTtRQUNKLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBTSxNQUFNLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNoRSxDQUFDO0lBb1REOzs7OztPQUtHO0lBQ0gsR0FBRyxDQUFDLEdBQVcsRUFBRSxJQUFjLEVBQUUsVUFTN0IsRUFBRTtRQUNKLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBTSxLQUFLLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUMvRCxDQUFDO3lIQTV0RlUsVUFBVTs2SEFBVixVQUFVOztTQUFWLFVBQVU7c0dBQVYsVUFBVTtrQkFEdEIsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge0luamVjdGFibGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtPYnNlcnZhYmxlLCBvZn0gZnJvbSAncnhqcyc7XG5pbXBvcnQge2NvbmNhdE1hcCwgZmlsdGVyLCBtYXB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHtIdHRwSGFuZGxlcn0gZnJvbSAnLi9iYWNrZW5kJztcbmltcG9ydCB7SHR0cENvbnRleHR9IGZyb20gJy4vY29udGV4dCc7XG5pbXBvcnQge0h0dHBIZWFkZXJzfSBmcm9tICcuL2hlYWRlcnMnO1xuaW1wb3J0IHtIdHRwUGFyYW1zLCBIdHRwUGFyYW1zT3B0aW9uc30gZnJvbSAnLi9wYXJhbXMnO1xuaW1wb3J0IHtIdHRwUmVxdWVzdH0gZnJvbSAnLi9yZXF1ZXN0JztcbmltcG9ydCB7SHR0cEV2ZW50LCBIdHRwUmVzcG9uc2V9IGZyb20gJy4vcmVzcG9uc2UnO1xuXG5cbi8qKlxuICogQ29uc3RydWN0cyBhbiBpbnN0YW5jZSBvZiBgSHR0cFJlcXVlc3RPcHRpb25zPFQ+YCBmcm9tIGEgc291cmNlIGBIdHRwTWV0aG9kT3B0aW9uc2AgYW5kXG4gKiB0aGUgZ2l2ZW4gYGJvZHlgLiBUaGlzIGZ1bmN0aW9uIGNsb25lcyB0aGUgb2JqZWN0IGFuZCBhZGRzIHRoZSBib2R5LlxuICpcbiAqIE5vdGUgdGhhdCB0aGUgYHJlc3BvbnNlVHlwZWAgKm9wdGlvbnMqIHZhbHVlIGlzIGEgU3RyaW5nIHRoYXQgaWRlbnRpZmllcyB0aGVcbiAqIHNpbmdsZSBkYXRhIHR5cGUgb2YgdGhlIHJlc3BvbnNlLlxuICogQSBzaW5nbGUgb3ZlcmxvYWQgdmVyc2lvbiBvZiB0aGUgbWV0aG9kIGhhbmRsZXMgZWFjaCByZXNwb25zZSB0eXBlLlxuICogVGhlIHZhbHVlIG9mIGByZXNwb25zZVR5cGVgIGNhbm5vdCBiZSBhIHVuaW9uLCBhcyB0aGUgY29tYmluZWQgc2lnbmF0dXJlIGNvdWxkIGltcGx5LlxuICpcbiAqL1xuZnVuY3Rpb24gYWRkQm9keTxUPihcbiAgICBvcHRpb25zOiB7XG4gICAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICAgIGNvbnRleHQ/OiBIdHRwQ29udGV4dCxcbiAgICAgIG9ic2VydmU/OiAnYm9keSd8J2V2ZW50cyd8J3Jlc3BvbnNlJyxcbiAgICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8XG4gICAgICAgICAgICB7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgUmVhZG9ubHlBcnJheTxzdHJpbmd8bnVtYmVyfGJvb2xlYW4+fSxcbiAgICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbixcbiAgICAgIHJlc3BvbnNlVHlwZT86ICdhcnJheWJ1ZmZlcid8J2Jsb2InfCdqc29uJ3wndGV4dCcsXG4gICAgICB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICAgIH0sXG4gICAgYm9keTogVHxudWxsKTogYW55IHtcbiAgcmV0dXJuIHtcbiAgICBib2R5LFxuICAgIGhlYWRlcnM6IG9wdGlvbnMuaGVhZGVycyxcbiAgICBjb250ZXh0OiBvcHRpb25zLmNvbnRleHQsXG4gICAgb2JzZXJ2ZTogb3B0aW9ucy5vYnNlcnZlLFxuICAgIHBhcmFtczogb3B0aW9ucy5wYXJhbXMsXG4gICAgcmVwb3J0UHJvZ3Jlc3M6IG9wdGlvbnMucmVwb3J0UHJvZ3Jlc3MsXG4gICAgcmVzcG9uc2VUeXBlOiBvcHRpb25zLnJlc3BvbnNlVHlwZSxcbiAgICB3aXRoQ3JlZGVudGlhbHM6IG9wdGlvbnMud2l0aENyZWRlbnRpYWxzLFxuICB9O1xufVxuXG4vKipcbiAqIFBlcmZvcm1zIEhUVFAgcmVxdWVzdHMuXG4gKiBUaGlzIHNlcnZpY2UgaXMgYXZhaWxhYmxlIGFzIGFuIGluamVjdGFibGUgY2xhc3MsIHdpdGggbWV0aG9kcyB0byBwZXJmb3JtIEhUVFAgcmVxdWVzdHMuXG4gKiBFYWNoIHJlcXVlc3QgbWV0aG9kIGhhcyBtdWx0aXBsZSBzaWduYXR1cmVzLCBhbmQgdGhlIHJldHVybiB0eXBlIHZhcmllcyBiYXNlZCBvblxuICogdGhlIHNpZ25hdHVyZSB0aGF0IGlzIGNhbGxlZCAobWFpbmx5IHRoZSB2YWx1ZXMgb2YgYG9ic2VydmVgIGFuZCBgcmVzcG9uc2VUeXBlYCkuXG4gKlxuICogTm90ZSB0aGF0IHRoZSBgcmVzcG9uc2VUeXBlYCAqb3B0aW9ucyogdmFsdWUgaXMgYSBTdHJpbmcgdGhhdCBpZGVudGlmaWVzIHRoZVxuICogc2luZ2xlIGRhdGEgdHlwZSBvZiB0aGUgcmVzcG9uc2UuXG4gKiBBIHNpbmdsZSBvdmVybG9hZCB2ZXJzaW9uIG9mIHRoZSBtZXRob2QgaGFuZGxlcyBlYWNoIHJlc3BvbnNlIHR5cGUuXG4gKiBUaGUgdmFsdWUgb2YgYHJlc3BvbnNlVHlwZWAgY2Fubm90IGJlIGEgdW5pb24sIGFzIHRoZSBjb21iaW5lZCBzaWduYXR1cmUgY291bGQgaW1wbHkuXG5cbiAqXG4gKiBAdXNhZ2VOb3Rlc1xuICogU2FtcGxlIEhUVFAgcmVxdWVzdHMgZm9yIHRoZSBbVG91ciBvZiBIZXJvZXNdKC90dXRvcmlhbC90b3VyLW9mLWhlcm9lcy90b2gtcHQwKSBhcHBsaWNhdGlvbi5cbiAqXG4gKiAjIyMgSFRUUCBSZXF1ZXN0IEV4YW1wbGVcbiAqXG4gKiBgYGBcbiAqICAvLyBHRVQgaGVyb2VzIHdob3NlIG5hbWUgY29udGFpbnMgc2VhcmNoIHRlcm1cbiAqIHNlYXJjaEhlcm9lcyh0ZXJtOiBzdHJpbmcpOiBvYnNlcnZhYmxlPEhlcm9bXT57XG4gKlxuICogIGNvbnN0IHBhcmFtcyA9IG5ldyBIdHRwUGFyYW1zKHtmcm9tU3RyaW5nOiAnbmFtZT10ZXJtJ30pO1xuICogICAgcmV0dXJuIHRoaXMuaHR0cENsaWVudC5yZXF1ZXN0KCdHRVQnLCB0aGlzLmhlcm9lc1VybCwge3Jlc3BvbnNlVHlwZTonanNvbicsIHBhcmFtc30pO1xuICogfVxuICogYGBgXG4gKlxuICogQWx0ZXJuYXRpdmVseSwgdGhlIHBhcmFtZXRlciBzdHJpbmcgY2FuIGJlIHVzZWQgd2l0aG91dCBpbnZva2luZyBIdHRwUGFyYW1zXG4gKiBieSBkaXJlY3RseSBqb2luaW5nIHRvIHRoZSBVUkwuXG4gKiBgYGBcbiAqIHRoaXMuaHR0cENsaWVudC5yZXF1ZXN0KCdHRVQnLCB0aGlzLmhlcm9lc1VybCArICc/JyArICduYW1lPXRlcm0nLCB7cmVzcG9uc2VUeXBlOidqc29uJ30pO1xuICogYGBgXG4gKlxuICpcbiAqICMjIyBKU09OUCBFeGFtcGxlXG4gKiBgYGBcbiAqIHJlcXVlc3RKc29ucCh1cmwsIGNhbGxiYWNrID0gJ2NhbGxiYWNrJykge1xuICogIHJldHVybiB0aGlzLmh0dHBDbGllbnQuanNvbnAodGhpcy5oZXJvZXNVUkwsIGNhbGxiYWNrKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqICMjIyBQQVRDSCBFeGFtcGxlXG4gKiBgYGBcbiAqIC8vIFBBVENIIG9uZSBvZiB0aGUgaGVyb2VzJyBuYW1lXG4gKiBwYXRjaEhlcm8gKGlkOiBudW1iZXIsIGhlcm9OYW1lOiBzdHJpbmcpOiBPYnNlcnZhYmxlPHt9PiB7XG4gKiBjb25zdCB1cmwgPSBgJHt0aGlzLmhlcm9lc1VybH0vJHtpZH1gOyAgIC8vIFBBVENIIGFwaS9oZXJvZXMvNDJcbiAqICByZXR1cm4gdGhpcy5odHRwQ2xpZW50LnBhdGNoKHVybCwge25hbWU6IGhlcm9OYW1lfSwgaHR0cE9wdGlvbnMpXG4gKiAgICAucGlwZShjYXRjaEVycm9yKHRoaXMuaGFuZGxlRXJyb3IoJ3BhdGNoSGVybycpKSk7XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAc2VlIFtIVFRQIEd1aWRlXShndWlkZS9odHRwKVxuICogQHNlZSBbSFRUUCBSZXF1ZXN0XShhcGkvY29tbW9uL2h0dHAvSHR0cFJlcXVlc3QpXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgSHR0cENsaWVudCB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgaGFuZGxlcjogSHR0cEhhbmRsZXIpIHt9XG5cbiAgLyoqXG4gICAqIFNlbmRzIGFuIGBIdHRwUmVxdWVzdGAgYW5kIHJldHVybnMgYSBzdHJlYW0gb2YgYEh0dHBFdmVudGBzLlxuICAgKlxuICAgKiBAcmV0dXJuIEFuIGBPYnNlcnZhYmxlYCBvZiB0aGUgcmVzcG9uc2UsIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgYXMgYSBzdHJlYW0gb2YgYEh0dHBFdmVudGBzLlxuICAgKi9cbiAgcmVxdWVzdDxSPihyZXE6IEh0dHBSZXF1ZXN0PGFueT4pOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxSPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHRoYXQgaW50ZXJwcmV0cyB0aGUgYm9keSBhcyBhbiBgQXJyYXlCdWZmZXJgIGFuZCByZXR1cm5zIHRoZSByZXNwb25zZSBpblxuICAgKiBhbiBgQXJyYXlCdWZmZXJgLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKlxuICAgKiBAcmV0dXJuIEFuIGBPYnNlcnZhYmxlYCBvZiB0aGUgcmVzcG9uc2UsIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgYXMgYW4gYEFycmF5QnVmZmVyYC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBjb250ZXh0PzogSHR0cENvbnRleHQsXG4gICAgb2JzZXJ2ZT86ICdib2R5JyxcbiAgICBwYXJhbXM/OiBIdHRwUGFyYW1zfFxuICAgICAgICAgIHtbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBSZWFkb25seUFycmF5PHN0cmluZ3xudW1iZXJ8Ym9vbGVhbj59LFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbiwgcmVzcG9uc2VUeXBlOiAnYXJyYXlidWZmZXInLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEFycmF5QnVmZmVyPjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3QgdGhhdCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGEgYmxvYiBhbmQgcmV0dXJuc1xuICAgKiB0aGUgcmVzcG9uc2UgYXMgYSBibG9iLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIEFuIGBPYnNlcnZhYmxlYCBvZiB0aGUgcmVzcG9uc2UsIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgQmxvYmAuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgY29udGV4dD86IEh0dHBDb250ZXh0LFxuICAgIG9ic2VydmU/OiAnYm9keScsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3xcbiAgICAgICAgICB7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgUmVhZG9ubHlBcnJheTxzdHJpbmd8bnVtYmVyfGJvb2xlYW4+fSxcbiAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sIHJlc3BvbnNlVHlwZTogJ2Jsb2InLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEJsb2I+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB0aGF0IGludGVycHJldHMgdGhlIGJvZHkgYXMgYSB0ZXh0IHN0cmluZyBhbmRcbiAgICogcmV0dXJucyBhIHN0cmluZyB2YWx1ZS5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIHJlc3BvbnNlLCB3aXRoIHRoZSByZXNwb25zZSBib2R5IG9mIHR5cGUgc3RyaW5nLlxuICAgKi9cbiAgcmVxdWVzdChtZXRob2Q6IHN0cmluZywgdXJsOiBzdHJpbmcsIG9wdGlvbnM6IHtcbiAgICBib2R5PzogYW55LFxuICAgIGhlYWRlcnM/OiBIdHRwSGVhZGVyc3x7W2hlYWRlcjogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIGNvbnRleHQ/OiBIdHRwQ29udGV4dCxcbiAgICBvYnNlcnZlPzogJ2JvZHknLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8XG4gICAgICAgICAge1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IFJlYWRvbmx5QXJyYXk8c3RyaW5nfG51bWJlcnxib29sZWFuPn0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLCByZXNwb25zZVR5cGU6ICd0ZXh0JyxcbiAgICB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxzdHJpbmc+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB0aGF0IGludGVycHJldHMgdGhlIGJvZHkgYXMgYW4gYEFycmF5QnVmZmVyYCBhbmQgcmV0dXJucyB0aGVcbiAgICogdGhlIGZ1bGwgZXZlbnQgc3RyZWFtLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuIEFuIGBPYnNlcnZhYmxlYCBvZiB0aGUgcmVzcG9uc2UsIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgYXMgYW4gYXJyYXkgb2YgYEh0dHBFdmVudGBzIGZvclxuICAgKiB0aGUgcmVxdWVzdC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBjb250ZXh0PzogSHR0cENvbnRleHQsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3xcbiAgICAgICAgICB7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgUmVhZG9ubHlBcnJheTxzdHJpbmd8bnVtYmVyfGJvb2xlYW4+fSxcbiAgICAgICAgICBvYnNlcnZlOiAnZXZlbnRzJyxcbiAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sIHJlc3BvbnNlVHlwZTogJ2FycmF5YnVmZmVyJyxcbiAgICB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8QXJyYXlCdWZmZXI+PjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3QgdGhhdCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGEgYEJsb2JgIGFuZCByZXR1cm5zXG4gICAqIHRoZSBmdWxsIGV2ZW50IHN0cmVhbS5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgYWxsIGBIdHRwRXZlbnRgcyBmb3IgdGhlIHJlcXVlc3QsXG4gICAqIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgQmxvYmAuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sIG9ic2VydmU6ICdldmVudHMnLFxuICAgIGNvbnRleHQ/OiBIdHRwQ29udGV4dCxcbiAgICBwYXJhbXM/OiBIdHRwUGFyYW1zfFxuICAgICAgICAgIHtbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBSZWFkb25seUFycmF5PHN0cmluZ3xudW1iZXJ8Ym9vbGVhbj59LFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbiwgcmVzcG9uc2VUeXBlOiAnYmxvYicsXG4gICAgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8SHR0cEV2ZW50PEJsb2I+PjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3Qgd2hpY2ggaW50ZXJwcmV0cyB0aGUgYm9keSBhcyBhIHRleHQgc3RyaW5nIGFuZCByZXR1cm5zIHRoZSBmdWxsIGV2ZW50XG4gICAqIHN0cmVhbS5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgYWxsIGBIdHRwRXZlbnRgcyBmb3IgdGhlIHJlcXVlc3QsXG4gICAqIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBzdHJpbmcuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sIG9ic2VydmU6ICdldmVudHMnLFxuICAgIGNvbnRleHQ/OiBIdHRwQ29udGV4dCxcbiAgICBwYXJhbXM/OiBIdHRwUGFyYW1zfFxuICAgICAgICAgIHtbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBSZWFkb25seUFycmF5PHN0cmluZ3xudW1iZXJ8Ym9vbGVhbj59LFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbiwgcmVzcG9uc2VUeXBlOiAndGV4dCcsXG4gICAgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8SHR0cEV2ZW50PHN0cmluZz4+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB3aGljaCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGEgSmF2YVNjcmlwdCBvYmplY3QgYW5kIHJldHVybnMgdGhlIGZ1bGxcbiAgICogZXZlbnQgc3RyZWFtLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSAgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgYWxsIGBIdHRwRXZlbnRgcyBmb3IgdGhlIHJlcXVlc3QsXG4gICAqIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgT2JqZWN0YC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBjb250ZXh0PzogSHR0cENvbnRleHQsXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLCBvYnNlcnZlOiAnZXZlbnRzJyxcbiAgICBwYXJhbXM/OiBIdHRwUGFyYW1zfFxuICAgICAgICAgIHtbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBSZWFkb25seUFycmF5PHN0cmluZ3xudW1iZXJ8Ym9vbGVhbj59LFxuICAgIHJlc3BvbnNlVHlwZT86ICdqc29uJyxcbiAgICB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8YW55Pj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSBKYXZhU2NyaXB0IG9iamVjdCBhbmQgcmV0dXJucyB0aGUgZnVsbFxuICAgKiBldmVudCBzdHJlYW0uXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIGFsbCBgSHR0cEV2ZW50YHMgZm9yIHRoZSByZXF1ZXN0LFxuICAgKiB3aXRoIHRoZSByZXNwb25zZSBib2R5IG9mIHR5cGUgYFJgLlxuICAgKi9cbiAgcmVxdWVzdDxSPihtZXRob2Q6IHN0cmluZywgdXJsOiBzdHJpbmcsIG9wdGlvbnM6IHtcbiAgICBib2R5PzogYW55LFxuICAgIGhlYWRlcnM/OiBIdHRwSGVhZGVyc3x7W2hlYWRlcjogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIGNvbnRleHQ/OiBIdHRwQ29udGV4dCxcbiAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sIG9ic2VydmU6ICdldmVudHMnLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8XG4gICAgICAgICAge1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IFJlYWRvbmx5QXJyYXk8c3RyaW5nfG51bWJlcnxib29sZWFuPn0sXG4gICAgcmVzcG9uc2VUeXBlPzogJ2pzb24nLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxSPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYW4gYEFycmF5QnVmZmVyYFxuICAgKiBhbmQgcmV0dXJucyB0aGUgZnVsbCBgSHR0cFJlc3BvbnNlYC5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIGBIdHRwUmVzcG9uc2VgLCB3aXRoIHRoZSByZXNwb25zZSBib2R5IGFzIGFuIGBBcnJheUJ1ZmZlcmAuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sIG9ic2VydmU6ICdyZXNwb25zZScsXG4gICAgY29udGV4dD86IEh0dHBDb250ZXh0LFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8XG4gICAgICAgICAge1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IFJlYWRvbmx5QXJyYXk8c3RyaW5nfG51bWJlcnxib29sZWFuPn0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLCByZXNwb25zZVR5cGU6ICdhcnJheWJ1ZmZlcicsXG4gICAgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8SHR0cFJlc3BvbnNlPEFycmF5QnVmZmVyPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSBgQmxvYmAgYW5kIHJldHVybnMgdGhlIGZ1bGwgYEh0dHBSZXNwb25zZWAuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIHRoZSBgSHR0cFJlc3BvbnNlYCwgd2l0aCB0aGUgcmVzcG9uc2UgYm9keSBvZiB0eXBlIGBCbG9iYC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSwgb2JzZXJ2ZTogJ3Jlc3BvbnNlJyxcbiAgICBjb250ZXh0PzogSHR0cENvbnRleHQsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3xcbiAgICAgICAgICB7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgUmVhZG9ubHlBcnJheTxzdHJpbmd8bnVtYmVyfGJvb2xlYW4+fSxcbiAgICByZXBvcnRQcm9ncmVzcz86IGJvb2xlYW4sIHJlc3BvbnNlVHlwZTogJ2Jsb2InLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEh0dHBSZXNwb25zZTxCbG9iPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSB0ZXh0IHN0cmVhbSBhbmQgcmV0dXJucyB0aGUgZnVsbFxuICAgKiBgSHR0cFJlc3BvbnNlYC5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIEhUVFAgcmVzcG9uc2UsIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBzdHJpbmcuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sIG9ic2VydmU6ICdyZXNwb25zZScsXG4gICAgY29udGV4dD86IEh0dHBDb250ZXh0LFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8XG4gICAgICAgICAge1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IFJlYWRvbmx5QXJyYXk8c3RyaW5nfG51bWJlcnxib29sZWFuPn0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLCByZXNwb25zZVR5cGU6ICd0ZXh0JyxcbiAgICB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxIdHRwUmVzcG9uc2U8c3RyaW5nPj47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSByZXF1ZXN0IHdoaWNoIGludGVycHJldHMgdGhlIGJvZHkgYXMgYSBKYXZhU2NyaXB0IG9iamVjdCBhbmQgcmV0dXJucyB0aGUgZnVsbFxuICAgKiBgSHR0cFJlc3BvbnNlYC5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIGZ1bGwgYEh0dHBSZXNwb25zZWAsXG4gICAqIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgT2JqZWN0YC5cbiAgICovXG4gIHJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBjb250ZXh0PzogSHR0cENvbnRleHQsXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLCBvYnNlcnZlOiAncmVzcG9uc2UnLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8XG4gICAgICAgICAge1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IFJlYWRvbmx5QXJyYXk8c3RyaW5nfG51bWJlcnxib29sZWFuPn0sXG4gICAgcmVzcG9uc2VUeXBlPzogJ2pzb24nLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPEh0dHBSZXNwb25zZTxPYmplY3Q+PjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIHJlcXVlc3Qgd2hpY2ggaW50ZXJwcmV0cyB0aGUgYm9keSBhcyBhIEphdmFTY3JpcHQgb2JqZWN0IGFuZCByZXR1cm5zXG4gICAqIHRoZSBmdWxsIGBIdHRwUmVzcG9uc2VgIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgaW4gdGhlIHJlcXVlc3RlZCB0eXBlLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0aG9kICBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB1cmwgICAgIFRoZSBlbmRwb2ludCBVUkwuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBIVFRQIG9wdGlvbnMgdG8gc2VuZCB3aXRoIHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKiBAcmV0dXJuICBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIGZ1bGwgYEh0dHBSZXNwb25zZWAsIHdpdGggdGhlIHJlc3BvbnNlIGJvZHkgb2YgdHlwZSBgUmAuXG4gICAqL1xuICByZXF1ZXN0PFI+KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9uczoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgY29udGV4dD86IEh0dHBDb250ZXh0LFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbiwgb2JzZXJ2ZTogJ3Jlc3BvbnNlJyxcbiAgICBwYXJhbXM/OiBIdHRwUGFyYW1zfFxuICAgICAgICAgIHtbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBSZWFkb25seUFycmF5PHN0cmluZ3xudW1iZXJ8Ym9vbGVhbj59LFxuICAgIHJlc3BvbnNlVHlwZT86ICdqc29uJyxcbiAgICB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxIdHRwUmVzcG9uc2U8Uj4+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB3aGljaCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGEgSmF2YVNjcmlwdCBvYmplY3QgYW5kIHJldHVybnMgdGhlIGZ1bGxcbiAgICogYEh0dHBSZXNwb25zZWAgYXMgYSBKYXZhU2NyaXB0IG9iamVjdC5cbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCAgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0gdXJsICAgICBUaGUgZW5kcG9pbnQgVVJMLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgSFRUUCBvcHRpb25zIHRvIHNlbmQgd2l0aCB0aGUgcmVxdWVzdC5cbiAgICpcbiAgICogQHJldHVybiBBbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIGBIdHRwUmVzcG9uc2VgLCB3aXRoIHRoZSByZXNwb25zZSBib2R5IG9mIHR5cGUgYE9iamVjdGAuXG4gICAqL1xuICByZXF1ZXN0KG1ldGhvZDogc3RyaW5nLCB1cmw6IHN0cmluZywgb3B0aW9ucz86IHtcbiAgICBib2R5PzogYW55LFxuICAgIGhlYWRlcnM/OiBIdHRwSGVhZGVyc3x7W2hlYWRlcjogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW119LFxuICAgIGNvbnRleHQ/OiBIdHRwQ29udGV4dCxcbiAgICBvYnNlcnZlPzogJ2JvZHknLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8XG4gICAgICAgICAge1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IFJlYWRvbmx5QXJyYXk8c3RyaW5nfG51bWJlcnxib29sZWFuPn0sXG4gICAgcmVzcG9uc2VUeXBlPzogJ2pzb24nLFxuICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbixcbiAgICB3aXRoQ3JlZGVudGlhbHM/OiBib29sZWFuLFxuICB9KTogT2JzZXJ2YWJsZTxPYmplY3Q+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB3aGljaCBpbnRlcnByZXRzIHRoZSBib2R5IGFzIGEgSmF2YVNjcmlwdCBvYmplY3RcbiAgICogd2l0aCB0aGUgcmVzcG9uc2UgYm9keSBvZiB0aGUgcmVxdWVzdGVkIHR5cGUuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIHRoZSBgSHR0cFJlc3BvbnNlYCwgd2l0aCB0aGUgcmVzcG9uc2UgYm9keSBvZiB0eXBlIGBSYC5cbiAgICovXG4gIHJlcXVlc3Q8Uj4obWV0aG9kOiBzdHJpbmcsIHVybDogc3RyaW5nLCBvcHRpb25zPzoge1xuICAgIGJvZHk/OiBhbnksXG4gICAgaGVhZGVycz86IEh0dHBIZWFkZXJzfHtbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXX0sXG4gICAgY29udGV4dD86IEh0dHBDb250ZXh0LFxuICAgIG9ic2VydmU/OiAnYm9keScsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3xcbiAgICAgICAgICB7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgUmVhZG9ubHlBcnJheTxzdHJpbmd8bnVtYmVyfGJvb2xlYW4+fSxcbiAgICByZXNwb25zZVR5cGU/OiAnanNvbicsXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW4sXG4gIH0pOiBPYnNlcnZhYmxlPFI+O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgcmVxdWVzdCB3aGVyZSByZXNwb25zZSB0eXBlIGFuZCByZXF1ZXN0ZWQgb2JzZXJ2YWJsZSBhcmUgbm90IGtub3duIHN0YXRpY2FsbHkuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHVybCAgICAgVGhlIGVuZHBvaW50IFVSTC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIEhUVFAgb3B0aW9ucyB0byBzZW5kIHdpdGggdGhlIHJlcXVlc3QuXG4gICAqXG4gICAqIEByZXR1cm4gQW4gYE9ic2VydmFibGVgIG9mIHRoZSByZXF1ZXN0ZWQgcmVzcG9uc2UsIHdpdGggYm9keSBvZiB0eXBlIGBhbnlgLlxuICAgKi9cbiAgcmVxdWVzdChtZXRob2Q6IHN0cmluZywgdXJsOiBzdHJpbmcsIG9wdGlvbnM/OiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBjb250ZXh0PzogSHR0cENvbnRleHQsXG4gICAgcGFyYW1zPzogSHR0cFBhcmFtc3xcbiAgICAgICAgICB7W3BhcmFtOiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgUmVhZG9ubHlBcnJheTxzdHJpbmd8bnVtYmVyfGJvb2xlYW4+fSxcbiAgICBvYnNlcnZlPzogJ2JvZHknfCdldmVudHMnfCdyZXNwb25zZScsXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIHJlc3BvbnNlVHlwZT86ICdhcnJheWJ1ZmZlcid8J2Jsb2InfCdqc29uJ3wndGV4dCcsXG4gICAgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSk6IE9ic2VydmFibGU8YW55PjtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhbiBvYnNlcnZhYmxlIGZvciBhIGdlbmVyaWMgSFRUUCByZXF1ZXN0IHRoYXQsIHdoZW4gc3Vic2NyaWJlZCxcbiAgICogZmlyZXMgdGhlIHJlcXVlc3QgdGhyb3VnaCB0aGUgY2hhaW4gb2YgcmVnaXN0ZXJlZCBpbnRlcmNlcHRvcnMgYW5kIG9uIHRvIHRoZVxuICAgKiBzZXJ2ZXIuXG4gICAqXG4gICAqIFlvdSBjYW4gcGFzcyBhbiBgSHR0cFJlcXVlc3RgIGRpcmVjdGx5IGFzIHRoZSBvbmx5IHBhcmFtZXRlci4gSW4gdGhpcyBjYXNlLFxuICAgKiB0aGUgY2FsbCByZXR1cm5zIGFuIG9ic2VydmFibGUgb2YgdGhlIHJhdyBgSHR0cEV2ZW50YCBzdHJlYW0uXG4gICAqXG4gICAqIEFsdGVybmF0aXZlbHkgeW91IGNhbiBwYXNzIGFuIEhUVFAgbWV0aG9kIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXIsXG4gICAqIGEgVVJMIHN0cmluZyBhcyB0aGUgc2Vjb25kLCBhbmQgYW4gb3B0aW9ucyBoYXNoIGNvbnRhaW5pbmcgdGhlIHJlcXVlc3QgYm9keSBhcyB0aGUgdGhpcmQuXG4gICAqIFNlZSBgYWRkQm9keSgpYC4gSW4gdGhpcyBjYXNlLCB0aGUgc3BlY2lmaWVkIGByZXNwb25zZVR5cGVgIGFuZCBgb2JzZXJ2ZWAgb3B0aW9ucyBkZXRlcm1pbmUgdGhlXG4gICAqIHR5cGUgb2YgcmV0dXJuZWQgb2JzZXJ2YWJsZS5cbiAgICogICAqIFRoZSBgcmVzcG9uc2VUeXBlYCB2YWx1ZSBkZXRlcm1pbmVzIGhvdyBhIHN1Y2Nlc3NmdWwgcmVzcG9uc2UgYm9keSBpcyBwYXJzZWQuXG4gICAqICAgKiBJZiBgcmVzcG9uc2VUeXBlYCBpcyB0aGUgZGVmYXVsdCBganNvbmAsIHlvdSBjYW4gcGFzcyBhIHR5cGUgaW50ZXJmYWNlIGZvciB0aGUgcmVzdWx0aW5nXG4gICAqIG9iamVjdCBhcyBhIHR5cGUgcGFyYW1ldGVyIHRvIHRoZSBjYWxsLlxuICAgKlxuICAgKiBUaGUgYG9ic2VydmVgIHZhbHVlIGRldGVybWluZXMgdGhlIHJldHVybiB0eXBlLCBhY2NvcmRpbmcgdG8gd2hhdCB5b3UgYXJlIGludGVyZXN0ZWQgaW5cbiAgICogb2JzZXJ2aW5nLlxuICAgKiAgICogQW4gYG9ic2VydmVgIHZhbHVlIG9mIGV2ZW50cyByZXR1cm5zIGFuIG9ic2VydmFibGUgb2YgdGhlIHJhdyBgSHR0cEV2ZW50YCBzdHJlYW0sIGluY2x1ZGluZ1xuICAgKiBwcm9ncmVzcyBldmVudHMgYnkgZGVmYXVsdC5cbiAgICogICAqIEFuIGBvYnNlcnZlYCB2YWx1ZSBvZiByZXNwb25zZSByZXR1cm5zIGFuIG9ic2VydmFibGUgb2YgYEh0dHBSZXNwb25zZTxUPmAsXG4gICAqIHdoZXJlIHRoZSBgVGAgcGFyYW1ldGVyIGRlcGVuZHMgb24gdGhlIGByZXNwb25zZVR5cGVgIGFuZCBhbnkgb3B0aW9uYWxseSBwcm92aWRlZCB0eXBlXG4gICAqIHBhcmFtZXRlci5cbiAgICogICAqIEFuIGBvYnNlcnZlYCB2YWx1ZSBvZiBib2R5IHJldHVybnMgYW4gb2JzZXJ2YWJsZSBvZiBgPFQ+YCB3aXRoIHRoZSBzYW1lIGBUYCBib2R5IHR5cGUuXG4gICAqXG4gICAqL1xuICByZXF1ZXN0KGZpcnN0OiBzdHJpbmd8SHR0cFJlcXVlc3Q8YW55PiwgdXJsPzogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgYm9keT86IGFueSxcbiAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnN8e1toZWFkZXI6IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdfSxcbiAgICBjb250ZXh0PzogSHR0cENvbnRleHQsXG4gICAgb2JzZXJ2ZT86ICdib2R5J3wnZXZlbnRzJ3wncmVzcG9uc2UnLFxuICAgIHBhcmFtcz86IEh0dHBQYXJhbXN8XG4gICAgICAgICAge1twYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IFJlYWRvbmx5QXJyYXk8c3RyaW5nfG51bWJlcnxib29sZWFuPn0sXG4gICAgcmVwb3J0UHJvZ3Jlc3M/OiBib29sZWFuLFxuICAgIHJlc3BvbnNlVHlwZT86ICdhcnJheWJ1ZmZlcid8J2Jsb2InfCdqc29uJ3wndGV4dCcsXG4gICAgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbixcbiAgfSA9IHt9KTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICBsZXQgcmVxOiBIdHRwUmVxdWVzdDxhbnk+O1xuICAgIC8vIEZpcnN0LCBjaGVjayB3aGV0aGVyIHRoZSBwcmltYXJ5IGFyZ3VtZW50IGlzIGFuIGluc3RhbmNlIG9mIGBIdHRwUmVxdWVzdGAuXG4gICAgaWYgKGZpcnN0IGluc3RhbmNlb2YgSHR0cFJlcXVlc3QpIHtcbiAgICAgIC8vIEl0IGlzLiBUaGUgb3RoZXIgYXJndW1lbnRzIG11c3QgYmUgdW5kZWZpbmVkIChwZXIgdGhlIHNpZ25hdHVyZXMpIGFuZCBjYW4gYmVcbiAgICAgIC8vIGlnbm9yZWQuXG4gICAgICByZXEgPSBmaXJzdDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gSXQncyBhIHN0cmluZywgc28gaXQgcmVwcmVzZW50cyBhIFVSTC4gQ29uc3RydWN0IGEgcmVxdWVzdCBiYXNlZCBvbiBpdCxcbiAgICAgIC8vIGFuZCBpbmNvcnBvcmF0ZSB0aGUgcmVtYWluaW5nIGFyZ3VtZW50cyAoYXNzdW1pbmcgYEdFVGAgdW5sZXNzIGEgbWV0aG9kIGlzXG4gICAgICAvLyBwcm92aWRlZC5cblxuICAgICAgLy8gRmlndXJlIG91dCB0aGUgaGVhZGVycy5cbiAgICAgIGxldCBoZWFkZXJzOiBIdHRwSGVhZGVyc3x1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gICAgICBpZiAob3B0aW9ucy5oZWFkZXJzIGluc3RhbmNlb2YgSHR0cEhlYWRlcnMpIHtcbiAgICAgICAgaGVhZGVycyA9IG9wdGlvbnMuaGVhZGVycztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGhlYWRlcnMgPSBuZXcgSHR0cEhlYWRlcnMob3B0aW9ucy5oZWFkZXJzKTtcbiAgICAgIH1cblxuICAgICAgLy8gU29ydCBvdXQgcGFyYW1ldGVycy5cbiAgICAgIGxldCBwYXJhbXM6IEh0dHBQYXJhbXN8dW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgICAgaWYgKCEhb3B0aW9ucy5wYXJhbXMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMucGFyYW1zIGluc3RhbmNlb2YgSHR0cFBhcmFtcykge1xuICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1zO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBhcmFtcyA9IG5ldyBIdHRwUGFyYW1zKHtmcm9tT2JqZWN0OiBvcHRpb25zLnBhcmFtc30gYXMgSHR0cFBhcmFtc09wdGlvbnMpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIENvbnN0cnVjdCB0aGUgcmVxdWVzdC5cbiAgICAgIHJlcSA9IG5ldyBIdHRwUmVxdWVzdChmaXJzdCwgdXJsISwgKG9wdGlvbnMuYm9keSAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5ib2R5IDogbnVsbCksIHtcbiAgICAgICAgaGVhZGVycyxcbiAgICAgICAgY29udGV4dDogb3B0aW9ucy5jb250ZXh0LFxuICAgICAgICBwYXJhbXMsXG4gICAgICAgIHJlcG9ydFByb2dyZXNzOiBvcHRpb25zLnJlcG9ydFByb2dyZXNzLFxuICAgICAgICAvLyBCeSBkZWZhdWx0LCBKU09OIGlzIGFzc3VtZWQgdG8gYmUgcmV0dXJuZWQgZm9yIGFsbCBjYWxscy5cbiAgICAgICAgcmVzcG9uc2VUeXBlOiBvcHRpb25zLnJlc3BvbnNlVHlwZSB8fCAnanNvbicsXG4gICAgICAgIHdpdGhDcmVkZW50aWFsczogb3B0aW9ucy53aXRoQ3JlZGVudGlhbHMsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBTdGFydCB3aXRoIGFuIE9ic2VydmFibGUub2YoKSB0aGUgaW5pdGlhbCByZXF1ZXN0LCBhbmQgcnVuIHRoZSBoYW5kbGVyICh3aGljaFxuICAgIC8vIGluY2x1ZGVzIGFsbCBpbnRlcmNlcHRvcnMpIGluc2lkZSBhIGNvbmNhdE1hcCgpLiBUaGlzIHdheSwgdGhlIGhhbmRsZXIgcnVuc1xuICAgIC8vIGluc2lkZSBhbiBPYnNlcnZhYmxlIGNoYWluLCB3aGljaCBjYXVzZXMgaW50ZXJjZXB0b3JzIHRvIGJlIHJlLXJ1biBvbiBldmVyeVxuICAgIC8vIHN1YnNjcmlwdGlvbiAodGhpcyBhbHNvIG1ha2VzIHJldHJpZXMgcmUtcnVuIHRoZSBoYW5kbGVyLCBpbmNsdWRpbmcgaW50ZXJjZXB0b3JzKS5cbiAgICBjb25zdCBldmVudHMkOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxhbnk+PiA9XG4gICAgICAgIG9mKHJlcSkucGlwZShjb25jYXRNYXAoKHJlcTogSHR0cFJlcXVlc3Q8YW55PikgPT4gdGhpcy5oYW5kbGVyLmhhbmRsZShyZXEpKSk7XG5cbiAgICAvLyBJZiBjb21pbmcgdmlhIHRoZSBBUEkgc2lnbmF0dXJlIHdoaWNoIGFjY2VwdHMgYSBwcmV2aW91c2x5IGNvbnN0cnVjdGVkIEh0dHBSZXF1ZXN0LFxuICAgIC8vIHRoZSBvbmx5IG9wdGlvbiBpcyB0byBnZXQgdGhlIGV2ZW50IHN0cmVhbS4gT3RoZXJ3aXNlLCByZXR1cm4gdGhlIGV2ZW50IHN0cmVhbSBpZlxuICAgIC8vIHRoYXQgaXMgd2hhdCB3YXMgcmVxdWVzdGVkLlxuICAgIGlmIChmaXJzdCBpbnN0YW5jZW9mIEh0dHBSZXF1ZXN0IHx8IG9wdGlvbnMub2JzZXJ2ZSA9PT0gJ2V2ZW50cycpIHtcbiAgICAgIHJldHVybiBldmVudHMkO1xuICAgIH1cblxuICAgIC8vIFR