@angular/http
Version:
Angular - the http service
283 lines • 25.5 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,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 { ReadyState, Request } from '@angular/http';
import { ReplaySubject, Subject } from 'rxjs';
import { take } from 'rxjs/operators';
/**
*
* Mock Connection to represent a {\@link Connection} for tests.
*
* \@usageNotes
* ### Example of `mockRespond()`
*
* ```
* var connection;
* backend.connections.subscribe(c => connection = c);
* http.request('data.json').subscribe(res => console.log(res.text()));
* connection.mockRespond(new Response(new ResponseOptions({ body: 'fake response' }))); //logs
* 'fake response'
* ```
*
* ### Example of `mockError()`
*
* ```
* var connection;
* backend.connections.subscribe(c => connection = c);
* http.request('data.json').subscribe(res => res, err => console.log(err)));
* connection.mockError(new Error('error'));
* ```
*
* @deprecated see https://angular.io/guide/http
* \@publicApi
*/
export class MockConnection {
/**
* @param {?} req
*/
constructor(req) {
this.response = (/** @type {?} */ (new ReplaySubject(1).pipe(take(1))));
this.readyState = ReadyState.Open;
this.request = req;
}
/**
* Sends a mock response to the connection. This response is the value that is emitted to the
* {\@link EventEmitter} returned by {\@link Http}.
*
* @param {?} res
* @return {?}
*/
mockRespond(res) {
if (this.readyState === ReadyState.Done || this.readyState === ReadyState.Cancelled) {
throw new Error('Connection has already been resolved');
}
this.readyState = ReadyState.Done;
this.response.next(res);
this.response.complete();
}
/**
* Not yet implemented!
*
* Sends the provided {\@link Response} to the `downloadObserver` of the `Request`
* associated with this connection.
* @param {?} res
* @return {?}
*/
mockDownload(res) {
// this.request.downloadObserver.onNext(res);
// if (res.bytesLoaded === res.totalBytes) {
// this.request.downloadObserver.onCompleted();
// }
}
// TODO(jeffbcross): consider using Response type
/**
* Emits the provided error object as an error to the {\@link Response} {\@link EventEmitter}
* returned
* from {\@link Http}.
*
* @param {?=} err
* @return {?}
*/
mockError(err) {
// Matches ResourceLoader semantics
this.readyState = ReadyState.Done;
this.response.error(err);
}
}
if (false) {
/**
* Describes the state of the connection, based on `XMLHttpRequest.readyState`, but with
* additional states. For example, state 5 indicates an aborted connection.
* @type {?}
*/
MockConnection.prototype.readyState;
/**
* {\@link Request} instance used to create the connection.
* @type {?}
*/
MockConnection.prototype.request;
/**
* {\@link EventEmitter} of {\@link Response}. Can be subscribed to in order to be notified when a
* response is available.
* @type {?}
*/
MockConnection.prototype.response;
}
/**
* A mock backend for testing the {\@link Http} service.
*
* This class can be injected in tests, and should be used to override providers
* to other backends, such as {\@link XHRBackend}.
*
* \@usageNotes
* ### Example
*
* ```
* import {Injectable, Injector} from '\@angular/core';
* import {async, fakeAsync, tick} from '\@angular/core/testing';
* import {BaseRequestOptions, ConnectionBackend, Http, RequestOptions} from '\@angular/http';
* import {Response, ResponseOptions} from '\@angular/http';
* import {MockBackend, MockConnection} from '\@angular/http/testing';
*
* const HERO_ONE = 'HeroNrOne';
* const HERO_TWO = 'WillBeAlwaysTheSecond';
*
* \@Injectable()
* class HeroService {
* constructor(private http: Http) {}
*
* getHeroes(): Promise<String[]> {
* return this.http.get('myservices.de/api/heroes')
* .toPromise()
* .then(response => response.json().data)
* .catch(e => this.handleError(e));
* }
*
* private handleError(error: any): Promise<any> {
* console.error('An error occurred', error);
* return Promise.reject(error.message || error);
* }
* }
*
* describe('MockBackend HeroService Example', () => {
* beforeEach(() => {
* this.injector = Injector.create([
* {provide: ConnectionBackend, useClass: MockBackend},
* {provide: RequestOptions, useClass: BaseRequestOptions},
* Http,
* HeroService,
* ]);
* this.heroService = this.injector.get(HeroService);
* this.backend = this.injector.get(ConnectionBackend) as MockBackend;
* this.backend.connections.subscribe((connection: any) => this.lastConnection = connection);
* });
*
* it('getHeroes() should query current service url', () => {
* this.heroService.getHeroes();
* expect(this.lastConnection).toBeDefined('no http service connection at all?');
* expect(this.lastConnection.request.url).toMatch(/api\/heroes$/, 'url invalid');
* });
*
* it('getHeroes() should return some heroes', fakeAsync(() => {
* let result: String[];
* this.heroService.getHeroes().then((heroes: String[]) => result = heroes);
* this.lastConnection.mockRespond(new Response(new ResponseOptions({
* body: JSON.stringify({data: [HERO_ONE, HERO_TWO]}),
* })));
* tick();
* expect(result.length).toEqual(2, 'should contain given amount of heroes');
* expect(result[0]).toEqual(HERO_ONE, ' HERO_ONE should be the first hero');
* expect(result[1]).toEqual(HERO_TWO, ' HERO_TWO should be the second hero');
* }));
*
* it('getHeroes() while server is down', fakeAsync(() => {
* let result: String[];
* let catchedError: any;
* this.heroService.getHeroes()
* .then((heroes: String[]) => result = heroes)
* .catch((error: any) => catchedError = error);
* this.lastConnection.mockError(new Response(new ResponseOptions({
* status: 404,
* statusText: 'URL not Found',
* })));
* tick();
* expect(result).toBeUndefined();
* expect(catchedError).toBeDefined();
* }));
* });
* ```
*
* @deprecated see https://angular.io/guide/http
* \@publicApi
*/
export class MockBackend {
// Subject<MockConnection>
constructor() {
this.connectionsArray = [];
this.connections = new Subject();
this.connections.subscribe((connection) => this.connectionsArray.push(connection));
this.pendingConnections = new Subject();
}
/**
* Checks all connections, and raises an exception if any connection has not received a response.
*
* This method only exists in the mock implementation, not in real Backends.
* @return {?}
*/
verifyNoPendingRequests() {
/** @type {?} */
let pending = 0;
this.pendingConnections.subscribe((c) => pending++);
if (pending > 0)
throw new Error(`${pending} pending connections to be resolved`);
}
/**
* Can be used in conjunction with `verifyNoPendingRequests` to resolve any not-yet-resolve
* connections, if it's expected that there are connections that have not yet received a response.
*
* This method only exists in the mock implementation, not in real Backends.
* @return {?}
*/
resolveAllConnections() { this.connections.subscribe((c) => c.readyState = 4); }
/**
* Creates a new {\@link MockConnection}. This is equivalent to calling `new
* MockConnection()`, except that it also will emit the new `Connection` to the `connections`
* emitter of this `MockBackend` instance. This method will usually only be used by tests
* against the framework itself, not by end-users.
* @param {?} req
* @return {?}
*/
createConnection(req) {
if (!req || !(req instanceof Request)) {
throw new Error(`createConnection requires an instance of Request, got ${req}`);
}
/** @type {?} */
const connection = new MockConnection(req);
this.connections.next(connection);
return connection;
}
}
MockBackend.decorators = [
{ type: Injectable }
];
/** @nocollapse */
MockBackend.ctorParameters = () => [];
if (false) {
/**
* {\@link EventEmitter}
* of {\@link MockConnection} instances that have been created by this backend. Can be subscribed
* to in order to respond to connections.
*
* This property only exists in the mock implementation, not in real Backends.
* @type {?}
*/
MockBackend.prototype.connections;
/**
* An array representation of `connections`. This array will be updated with each connection that
* is created by this backend.
*
* This property only exists in the mock implementation, not in real Backends.
* @type {?}
*/
MockBackend.prototype.connectionsArray;
/**
* {\@link EventEmitter} of {\@link MockConnection} instances that haven't yet been resolved (i.e.
* with a `readyState`
* less than 4). Used internally to verify that no connections are pending via the
* `verifyNoPendingRequests` method.
*
* This property only exists in the mock implementation, not in real Backends.
* @type {?}
*/
MockBackend.prototype.pendingConnections;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9ja19iYWNrZW5kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvaHR0cC90ZXN0aW5nL3NyYy9tb2NrX2JhY2tlbmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFRQSxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBZ0MsVUFBVSxFQUFFLE9BQU8sRUFBVyxNQUFNLGVBQWUsQ0FBQztBQUMzRixPQUFPLEVBQUMsYUFBYSxFQUFFLE9BQU8sRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUM1QyxPQUFPLEVBQUMsSUFBSSxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUE4QnBDLE1BQU0sT0FBTyxjQUFjOzs7O0lBb0J6QixZQUFZLEdBQVk7UUFDdEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxtQkFBSyxJQUFJLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUEsQ0FBQztRQUN4RCxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUM7UUFDbEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUM7SUFDckIsQ0FBQzs7Ozs7Ozs7SUFPRCxXQUFXLENBQUMsR0FBYTtRQUN2QixJQUFJLElBQUksQ0FBQyxVQUFVLEtBQUssVUFBVSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsVUFBVSxLQUFLLFVBQVUsQ0FBQyxTQUFTLEVBQUU7WUFDbkYsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1NBQ3pEO1FBQ0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hCLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDM0IsQ0FBQzs7Ozs7Ozs7O0lBUUQsWUFBWSxDQUFDLEdBQWE7UUFDeEIsNkNBQTZDO1FBQzdDLDRDQUE0QztRQUM1QyxpREFBaUQ7UUFDakQsSUFBSTtJQUNOLENBQUM7Ozs7Ozs7Ozs7SUFTRCxTQUFTLENBQUMsR0FBVztRQUNuQixtQ0FBbUM7UUFDbkMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzNCLENBQUM7Q0FDRjs7Ozs7OztJQTFEQyxvQ0FBdUI7Ozs7O0lBS3ZCLGlDQUFpQjs7Ozs7O0lBTWpCLGtDQUFrQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUF5SXBDLE1BQU0sT0FBTyxXQUFXOztJQTBCdEI7UUFDRSxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUNqQyxJQUFJLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FDdEIsQ0FBQyxVQUEwQixFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFDNUUsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksT0FBTyxFQUFFLENBQUM7SUFDMUMsQ0FBQzs7Ozs7OztJQU9ELHVCQUF1Qjs7WUFDakIsT0FBTyxHQUFHLENBQUM7UUFDZixJQUFJLENBQUMsa0JBQWtCLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBaUIsRUFBRSxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNwRSxJQUFJLE9BQU8sR0FBRyxDQUFDO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLE9BQU8scUNBQXFDLENBQUMsQ0FBQztJQUNwRixDQUFDOzs7Ozs7OztJQVFELHFCQUFxQixLQUFLLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBaUIsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Ozs7Ozs7OztJQVFoRyxnQkFBZ0IsQ0FBQyxHQUFZO1FBQzNCLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsWUFBWSxPQUFPLENBQUMsRUFBRTtZQUNyQyxNQUFNLElBQUksS0FBSyxDQUFDLHlEQUF5RCxHQUFHLEVBQUUsQ0FBQyxDQUFDO1NBQ2pGOztjQUNLLFVBQVUsR0FBRyxJQUFJLGNBQWMsQ0FBQyxHQUFHLENBQUM7UUFDMUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDbEMsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQzs7O1lBbkVGLFVBQVU7Ozs7Ozs7Ozs7Ozs7SUFTVCxrQ0FBaUI7Ozs7Ozs7O0lBUWpCLHVDQUFtQzs7Ozs7Ozs7OztJQVNuQyx5Q0FBd0IiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7SW5qZWN0YWJsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge0Nvbm5lY3Rpb24sIENvbm5lY3Rpb25CYWNrZW5kLCBSZWFkeVN0YXRlLCBSZXF1ZXN0LCBSZXNwb25zZX0gZnJvbSAnQGFuZ3VsYXIvaHR0cCc7XG5pbXBvcnQge1JlcGxheVN1YmplY3QsIFN1YmplY3R9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHt0YWtlfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cblxuLyoqXG4gKlxuICogTW9jayBDb25uZWN0aW9uIHRvIHJlcHJlc2VudCBhIHtAbGluayBDb25uZWN0aW9ufSBmb3IgdGVzdHMuXG4gKlxuICogQHVzYWdlTm90ZXNcbiAqICMjIyBFeGFtcGxlIG9mIGBtb2NrUmVzcG9uZCgpYFxuICpcbiAqIGBgYFxuICogdmFyIGNvbm5lY3Rpb247XG4gKiBiYWNrZW5kLmNvbm5lY3Rpb25zLnN1YnNjcmliZShjID0+IGNvbm5lY3Rpb24gPSBjKTtcbiAqIGh0dHAucmVxdWVzdCgnZGF0YS5qc29uJykuc3Vic2NyaWJlKHJlcyA9PiBjb25zb2xlLmxvZyhyZXMudGV4dCgpKSk7XG4gKiBjb25uZWN0aW9uLm1vY2tSZXNwb25kKG5ldyBSZXNwb25zZShuZXcgUmVzcG9uc2VPcHRpb25zKHsgYm9keTogJ2Zha2UgcmVzcG9uc2UnIH0pKSk7IC8vbG9nc1xuICogJ2Zha2UgcmVzcG9uc2UnXG4gKiBgYGBcbiAqXG4gKiAjIyMgRXhhbXBsZSBvZiBgbW9ja0Vycm9yKClgXG4gKlxuICogYGBgXG4gKiB2YXIgY29ubmVjdGlvbjtcbiAqIGJhY2tlbmQuY29ubmVjdGlvbnMuc3Vic2NyaWJlKGMgPT4gY29ubmVjdGlvbiA9IGMpO1xuICogaHR0cC5yZXF1ZXN0KCdkYXRhLmpzb24nKS5zdWJzY3JpYmUocmVzID0+IHJlcywgZXJyID0+IGNvbnNvbGUubG9nKGVycikpKTtcbiAqIGNvbm5lY3Rpb24ubW9ja0Vycm9yKG5ldyBFcnJvcignZXJyb3InKSk7XG4gKiBgYGBcbiAqXG4gKiBAZGVwcmVjYXRlZCBzZWUgaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2h0dHBcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGNsYXNzIE1vY2tDb25uZWN0aW9uIGltcGxlbWVudHMgQ29ubmVjdGlvbiB7XG4gIC8vIFRPRE86IE5hbWUgYHJlYWR5U3RhdGVgIHNob3VsZCBjaGFuZ2UgdG8gYmUgbW9yZSBnZW5lcmljLCBhbmQgc3RhdGVzIGNvdWxkIGJlIG1hZGUgdG8gYmUgbW9yZVxuICAvLyBkZXNjcmlwdGl2ZSB0aGFuIFJlc291cmNlTG9hZGVyIHN0YXRlcy5cbiAgLyoqXG4gICAqIERlc2NyaWJlcyB0aGUgc3RhdGUgb2YgdGhlIGNvbm5lY3Rpb24sIGJhc2VkIG9uIGBYTUxIdHRwUmVxdWVzdC5yZWFkeVN0YXRlYCwgYnV0IHdpdGhcbiAgICogYWRkaXRpb25hbCBzdGF0ZXMuIEZvciBleGFtcGxlLCBzdGF0ZSA1IGluZGljYXRlcyBhbiBhYm9ydGVkIGNvbm5lY3Rpb24uXG4gICAqL1xuICByZWFkeVN0YXRlOiBSZWFkeVN0YXRlO1xuXG4gIC8qKlxuICAgKiB7QGxpbmsgUmVxdWVzdH0gaW5zdGFuY2UgdXNlZCB0byBjcmVhdGUgdGhlIGNvbm5lY3Rpb24uXG4gICAqL1xuICByZXF1ZXN0OiBSZXF1ZXN0O1xuXG4gIC8qKlxuICAgKiB7QGxpbmsgRXZlbnRFbWl0dGVyfSBvZiB7QGxpbmsgUmVzcG9uc2V9LiBDYW4gYmUgc3Vic2NyaWJlZCB0byBpbiBvcmRlciB0byBiZSBub3RpZmllZCB3aGVuIGFcbiAgICogcmVzcG9uc2UgaXMgYXZhaWxhYmxlLlxuICAgKi9cbiAgcmVzcG9uc2U6IFJlcGxheVN1YmplY3Q8UmVzcG9uc2U+O1xuXG4gIGNvbnN0cnVjdG9yKHJlcTogUmVxdWVzdCkge1xuICAgIHRoaXMucmVzcG9uc2UgPSA8YW55Pm5ldyBSZXBsYXlTdWJqZWN0KDEpLnBpcGUodGFrZSgxKSk7XG4gICAgdGhpcy5yZWFkeVN0YXRlID0gUmVhZHlTdGF0ZS5PcGVuO1xuICAgIHRoaXMucmVxdWVzdCA9IHJlcTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kcyBhIG1vY2sgcmVzcG9uc2UgdG8gdGhlIGNvbm5lY3Rpb24uIFRoaXMgcmVzcG9uc2UgaXMgdGhlIHZhbHVlIHRoYXQgaXMgZW1pdHRlZCB0byB0aGVcbiAgICoge0BsaW5rIEV2ZW50RW1pdHRlcn0gcmV0dXJuZWQgYnkge0BsaW5rIEh0dHB9LlxuICAgKlxuICAgKi9cbiAgbW9ja1Jlc3BvbmQocmVzOiBSZXNwb25zZSkge1xuICAgIGlmICh0aGlzLnJlYWR5U3RhdGUgPT09IFJlYWR5U3RhdGUuRG9uZSB8fCB0aGlzLnJlYWR5U3RhdGUgPT09IFJlYWR5U3RhdGUuQ2FuY2VsbGVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nvbm5lY3Rpb24gaGFzIGFscmVhZHkgYmVlbiByZXNvbHZlZCcpO1xuICAgIH1cbiAgICB0aGlzLnJlYWR5U3RhdGUgPSBSZWFkeVN0YXRlLkRvbmU7XG4gICAgdGhpcy5yZXNwb25zZS5uZXh0KHJlcyk7XG4gICAgdGhpcy5yZXNwb25zZS5jb21wbGV0ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vdCB5ZXQgaW1wbGVtZW50ZWQhXG4gICAqXG4gICAqIFNlbmRzIHRoZSBwcm92aWRlZCB7QGxpbmsgUmVzcG9uc2V9IHRvIHRoZSBgZG93bmxvYWRPYnNlcnZlcmAgb2YgdGhlIGBSZXF1ZXN0YFxuICAgKiBhc3NvY2lhdGVkIHdpdGggdGhpcyBjb25uZWN0aW9uLlxuICAgKi9cbiAgbW9ja0Rvd25sb2FkKHJlczogUmVzcG9uc2UpIHtcbiAgICAvLyB0aGlzLnJlcXVlc3QuZG93bmxvYWRPYnNlcnZlci5vbk5leHQocmVzKTtcbiAgICAvLyBpZiAocmVzLmJ5dGVzTG9hZGVkID09PSByZXMudG90YWxCeXRlcykge1xuICAgIC8vICAgdGhpcy5yZXF1ZXN0LmRvd25sb2FkT2JzZXJ2ZXIub25Db21wbGV0ZWQoKTtcbiAgICAvLyB9XG4gIH1cblxuICAvLyBUT0RPKGplZmZiY3Jvc3MpOiBjb25zaWRlciB1c2luZyBSZXNwb25zZSB0eXBlXG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgcHJvdmlkZWQgZXJyb3Igb2JqZWN0IGFzIGFuIGVycm9yIHRvIHRoZSB7QGxpbmsgUmVzcG9uc2V9IHtAbGluayBFdmVudEVtaXR0ZXJ9XG4gICAqIHJldHVybmVkXG4gICAqIGZyb20ge0BsaW5rIEh0dHB9LlxuICAgKlxuICAgKi9cbiAgbW9ja0Vycm9yKGVycj86IEVycm9yKSB7XG4gICAgLy8gTWF0Y2hlcyBSZXNvdXJjZUxvYWRlciBzZW1hbnRpY3NcbiAgICB0aGlzLnJlYWR5U3RhdGUgPSBSZWFkeVN0YXRlLkRvbmU7XG4gICAgdGhpcy5yZXNwb25zZS5lcnJvcihlcnIpO1xuICB9XG59XG5cbi8qKlxuICogQSBtb2NrIGJhY2tlbmQgZm9yIHRlc3RpbmcgdGhlIHtAbGluayBIdHRwfSBzZXJ2aWNlLlxuICpcbiAqIFRoaXMgY2xhc3MgY2FuIGJlIGluamVjdGVkIGluIHRlc3RzLCBhbmQgc2hvdWxkIGJlIHVzZWQgdG8gb3ZlcnJpZGUgcHJvdmlkZXJzXG4gKiB0byBvdGhlciBiYWNrZW5kcywgc3VjaCBhcyB7QGxpbmsgWEhSQmFja2VuZH0uXG4gKlxuICogQHVzYWdlTm90ZXNcbiAqICMjIyBFeGFtcGxlXG4gKlxuICogYGBgXG4gKiBpbXBvcnQge0luamVjdGFibGUsIEluamVjdG9yfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbiAqIGltcG9ydCB7YXN5bmMsIGZha2VBc3luYywgdGlja30gZnJvbSAnQGFuZ3VsYXIvY29yZS90ZXN0aW5nJztcbiAqIGltcG9ydCB7QmFzZVJlcXVlc3RPcHRpb25zLCBDb25uZWN0aW9uQmFja2VuZCwgSHR0cCwgUmVxdWVzdE9wdGlvbnN9IGZyb20gJ0Bhbmd1bGFyL2h0dHAnO1xuICogaW1wb3J0IHtSZXNwb25zZSwgUmVzcG9uc2VPcHRpb25zfSBmcm9tICdAYW5ndWxhci9odHRwJztcbiAqIGltcG9ydCB7TW9ja0JhY2tlbmQsIE1vY2tDb25uZWN0aW9ufSBmcm9tICdAYW5ndWxhci9odHRwL3Rlc3RpbmcnO1xuICpcbiAqIGNvbnN0IEhFUk9fT05FID0gJ0hlcm9Ock9uZSc7XG4gKiBjb25zdCBIRVJPX1RXTyA9ICdXaWxsQmVBbHdheXNUaGVTZWNvbmQnO1xuICpcbiAqIEBJbmplY3RhYmxlKClcbiAqIGNsYXNzIEhlcm9TZXJ2aWNlIHtcbiAqICAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOiBIdHRwKSB7fVxuICpcbiAqICAgZ2V0SGVyb2VzKCk6IFByb21pc2U8U3RyaW5nW10+IHtcbiAqICAgICByZXR1cm4gdGhpcy5odHRwLmdldCgnbXlzZXJ2aWNlcy5kZS9hcGkvaGVyb2VzJylcbiAqICAgICAgICAgLnRvUHJvbWlzZSgpXG4gKiAgICAgICAgIC50aGVuKHJlc3BvbnNlID0+IHJlc3BvbnNlLmpzb24oKS5kYXRhKVxuICogICAgICAgICAuY2F0Y2goZSA9PiB0aGlzLmhhbmRsZUVycm9yKGUpKTtcbiAqICAgfVxuICpcbiAqICAgcHJpdmF0ZSBoYW5kbGVFcnJvcihlcnJvcjogYW55KTogUHJvbWlzZTxhbnk+IHtcbiAqICAgICBjb25zb2xlLmVycm9yKCdBbiBlcnJvciBvY2N1cnJlZCcsIGVycm9yKTtcbiAqICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyb3IubWVzc2FnZSB8fCBlcnJvcik7XG4gKiAgIH1cbiAqIH1cbiAqXG4gKiBkZXNjcmliZSgnTW9ja0JhY2tlbmQgSGVyb1NlcnZpY2UgRXhhbXBsZScsICgpID0+IHtcbiAqICAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gKiAgICAgdGhpcy5pbmplY3RvciA9IEluamVjdG9yLmNyZWF0ZShbXG4gKiAgICAgICB7cHJvdmlkZTogQ29ubmVjdGlvbkJhY2tlbmQsIHVzZUNsYXNzOiBNb2NrQmFja2VuZH0sXG4gKiAgICAgICB7cHJvdmlkZTogUmVxdWVzdE9wdGlvbnMsIHVzZUNsYXNzOiBCYXNlUmVxdWVzdE9wdGlvbnN9LFxuICogICAgICAgSHR0cCxcbiAqICAgICAgIEhlcm9TZXJ2aWNlLFxuICogICAgIF0pO1xuICogICAgIHRoaXMuaGVyb1NlcnZpY2UgPSB0aGlzLmluamVjdG9yLmdldChIZXJvU2VydmljZSk7XG4gKiAgICAgdGhpcy5iYWNrZW5kID0gdGhpcy5pbmplY3Rvci5nZXQoQ29ubmVjdGlvbkJhY2tlbmQpIGFzIE1vY2tCYWNrZW5kO1xuICogICAgIHRoaXMuYmFja2VuZC5jb25uZWN0aW9ucy5zdWJzY3JpYmUoKGNvbm5lY3Rpb246IGFueSkgPT4gdGhpcy5sYXN0Q29ubmVjdGlvbiA9IGNvbm5lY3Rpb24pO1xuICogICB9KTtcbiAqXG4gKiAgIGl0KCdnZXRIZXJvZXMoKSBzaG91bGQgcXVlcnkgY3VycmVudCBzZXJ2aWNlIHVybCcsICgpID0+IHtcbiAqICAgICB0aGlzLmhlcm9TZXJ2aWNlLmdldEhlcm9lcygpO1xuICogICAgIGV4cGVjdCh0aGlzLmxhc3RDb25uZWN0aW9uKS50b0JlRGVmaW5lZCgnbm8gaHR0cCBzZXJ2aWNlIGNvbm5lY3Rpb24gYXQgYWxsPycpO1xuICogICAgIGV4cGVjdCh0aGlzLmxhc3RDb25uZWN0aW9uLnJlcXVlc3QudXJsKS50b01hdGNoKC9hcGlcXC9oZXJvZXMkLywgJ3VybCBpbnZhbGlkJyk7XG4gKiAgIH0pO1xuICpcbiAqICAgaXQoJ2dldEhlcm9lcygpIHNob3VsZCByZXR1cm4gc29tZSBoZXJvZXMnLCBmYWtlQXN5bmMoKCkgPT4ge1xuICogICAgICAgIGxldCByZXN1bHQ6IFN0cmluZ1tdO1xuICogICAgICAgIHRoaXMuaGVyb1NlcnZpY2UuZ2V0SGVyb2VzKCkudGhlbigoaGVyb2VzOiBTdHJpbmdbXSkgPT4gcmVzdWx0ID0gaGVyb2VzKTtcbiAqICAgICAgICB0aGlzLmxhc3RDb25uZWN0aW9uLm1vY2tSZXNwb25kKG5ldyBSZXNwb25zZShuZXcgUmVzcG9uc2VPcHRpb25zKHtcbiAqICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtkYXRhOiBbSEVST19PTkUsIEhFUk9fVFdPXX0pLFxuICogICAgICAgIH0pKSk7XG4gKiAgICAgICAgdGljaygpO1xuICogICAgICAgIGV4cGVjdChyZXN1bHQubGVuZ3RoKS50b0VxdWFsKDIsICdzaG91bGQgY29udGFpbiBnaXZlbiBhbW91bnQgb2YgaGVyb2VzJyk7XG4gKiAgICAgICAgZXhwZWN0KHJlc3VsdFswXSkudG9FcXVhbChIRVJPX09ORSwgJyBIRVJPX09ORSBzaG91bGQgYmUgdGhlIGZpcnN0IGhlcm8nKTtcbiAqICAgICAgICBleHBlY3QocmVzdWx0WzFdKS50b0VxdWFsKEhFUk9fVFdPLCAnIEhFUk9fVFdPIHNob3VsZCBiZSB0aGUgc2Vjb25kIGhlcm8nKTtcbiAqICAgICAgfSkpO1xuICpcbiAqICAgaXQoJ2dldEhlcm9lcygpIHdoaWxlIHNlcnZlciBpcyBkb3duJywgZmFrZUFzeW5jKCgpID0+IHtcbiAqICAgICAgICBsZXQgcmVzdWx0OiBTdHJpbmdbXTtcbiAqICAgICAgICBsZXQgY2F0Y2hlZEVycm9yOiBhbnk7XG4gKiAgICAgICAgdGhpcy5oZXJvU2VydmljZS5nZXRIZXJvZXMoKVxuICogICAgICAgICAgICAudGhlbigoaGVyb2VzOiBTdHJpbmdbXSkgPT4gcmVzdWx0ID0gaGVyb2VzKVxuICogICAgICAgICAgICAuY2F0Y2goKGVycm9yOiBhbnkpID0+IGNhdGNoZWRFcnJvciA9IGVycm9yKTtcbiAqICAgICAgICB0aGlzLmxhc3RDb25uZWN0aW9uLm1vY2tFcnJvcihuZXcgUmVzcG9uc2UobmV3IFJlc3BvbnNlT3B0aW9ucyh7XG4gKiAgICAgICAgICBzdGF0dXM6IDQwNCxcbiAqICAgICAgICAgIHN0YXR1c1RleHQ6ICdVUkwgbm90IEZvdW5kJyxcbiAqICAgICAgICB9KSkpO1xuICogICAgICAgIHRpY2soKTtcbiAqICAgICAgICBleHBlY3QocmVzdWx0KS50b0JlVW5kZWZpbmVkKCk7XG4gKiAgICAgICAgZXhwZWN0KGNhdGNoZWRFcnJvcikudG9CZURlZmluZWQoKTtcbiAqICAgICAgfSkpO1xuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBAZGVwcmVjYXRlZCBzZWUgaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2h0dHBcbiAqIEBwdWJsaWNBcGlcbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIE1vY2tCYWNrZW5kIGltcGxlbWVudHMgQ29ubmVjdGlvbkJhY2tlbmQge1xuICAvKipcbiAgICoge0BsaW5rIEV2ZW50RW1pdHRlcn1cbiAgICogb2Yge0BsaW5rIE1vY2tDb25uZWN0aW9ufSBpbnN0YW5jZXMgdGhhdCBoYXZlIGJlZW4gY3JlYXRlZCBieSB0aGlzIGJhY2tlbmQuIENhbiBiZSBzdWJzY3JpYmVkXG4gICAqIHRvIGluIG9yZGVyIHRvIHJlc3BvbmQgdG8gY29ubmVjdGlvbnMuXG4gICAqXG4gICAqIFRoaXMgcHJvcGVydHkgb25seSBleGlzdHMgaW4gdGhlIG1vY2sgaW1wbGVtZW50YXRpb24sIG5vdCBpbiByZWFsIEJhY2tlbmRzLlxuICAgKi9cbiAgY29ubmVjdGlvbnM6IGFueTsgIC8vPE1vY2tDb25uZWN0aW9uPlxuXG4gIC8qKlxuICAgKiBBbiBhcnJheSByZXByZXNlbnRhdGlvbiBvZiBgY29ubmVjdGlvbnNgLiBUaGlzIGFycmF5IHdpbGwgYmUgdXBkYXRlZCB3aXRoIGVhY2ggY29ubmVjdGlvbiB0aGF0XG4gICAqIGlzIGNyZWF0ZWQgYnkgdGhpcyBiYWNrZW5kLlxuICAgKlxuICAgKiBUaGlzIHByb3BlcnR5IG9ubHkgZXhpc3RzIGluIHRoZSBtb2NrIGltcGxlbWVudGF0aW9uLCBub3QgaW4gcmVhbCBCYWNrZW5kcy5cbiAgICovXG4gIGNvbm5lY3Rpb25zQXJyYXk6IE1vY2tDb25uZWN0aW9uW107XG4gIC8qKlxuICAgKiB7QGxpbmsgRXZlbnRFbWl0dGVyfSBvZiB7QGxpbmsgTW9ja0Nvbm5lY3Rpb259IGluc3RhbmNlcyB0aGF0IGhhdmVuJ3QgeWV0IGJlZW4gcmVzb2x2ZWQgKGkuZS5cbiAgICogd2l0aCBhIGByZWFkeVN0YXRlYFxuICAgKiBsZXNzIHRoYW4gNCkuIFVzZWQgaW50ZXJuYWxseSB0byB2ZXJpZnkgdGhhdCBubyBjb25uZWN0aW9ucyBhcmUgcGVuZGluZyB2aWEgdGhlXG4gICAqIGB2ZXJpZnlOb1BlbmRpbmdSZXF1ZXN0c2AgbWV0aG9kLlxuICAgKlxuICAgKiBUaGlzIHByb3BlcnR5IG9ubHkgZXhpc3RzIGluIHRoZSBtb2NrIGltcGxlbWVudGF0aW9uLCBub3QgaW4gcmVhbCBCYWNrZW5kcy5cbiAgICovXG4gIHBlbmRpbmdDb25uZWN0aW9uczogYW55OyAgLy8gU3ViamVjdDxNb2NrQ29ubmVjdGlvbj5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uc0FycmF5ID0gW107XG4gICAgdGhpcy5jb25uZWN0aW9ucyA9IG5ldyBTdWJqZWN0KCk7XG4gICAgdGhpcy5jb25uZWN0aW9ucy5zdWJzY3JpYmUoXG4gICAgICAgIChjb25uZWN0aW9uOiBNb2NrQ29ubmVjdGlvbikgPT4gdGhpcy5jb25uZWN0aW9uc0FycmF5LnB1c2goY29ubmVjdGlvbikpO1xuICAgIHRoaXMucGVuZGluZ0Nvbm5lY3Rpb25zID0gbmV3IFN1YmplY3QoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgYWxsIGNvbm5lY3Rpb25zLCBhbmQgcmFpc2VzIGFuIGV4Y2VwdGlvbiBpZiBhbnkgY29ubmVjdGlvbiBoYXMgbm90IHJlY2VpdmVkIGEgcmVzcG9uc2UuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIG9ubHkgZXhpc3RzIGluIHRoZSBtb2NrIGltcGxlbWVudGF0aW9uLCBub3QgaW4gcmVhbCBCYWNrZW5kcy5cbiAgICovXG4gIHZlcmlmeU5vUGVuZGluZ1JlcXVlc3RzKCkge1xuICAgIGxldCBwZW5kaW5nID0gMDtcbiAgICB0aGlzLnBlbmRpbmdDb25uZWN0aW9ucy5zdWJzY3JpYmUoKGM6IE1vY2tDb25uZWN0aW9uKSA9PiBwZW5kaW5nKyspO1xuICAgIGlmIChwZW5kaW5nID4gMCkgdGhyb3cgbmV3IEVycm9yKGAke3BlbmRpbmd9IHBlbmRpbmcgY29ubmVjdGlvbnMgdG8gYmUgcmVzb2x2ZWRgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYW4gYmUgdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIGB2ZXJpZnlOb1BlbmRpbmdSZXF1ZXN0c2AgdG8gcmVzb2x2ZSBhbnkgbm90LXlldC1yZXNvbHZlXG4gICAqIGNvbm5lY3Rpb25zLCBpZiBpdCdzIGV4cGVjdGVkIHRoYXQgdGhlcmUgYXJlIGNvbm5lY3Rpb25zIHRoYXQgaGF2ZSBub3QgeWV0IHJlY2VpdmVkIGEgcmVzcG9uc2UuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIG9ubHkgZXhpc3RzIGluIHRoZSBtb2NrIGltcGxlbWVudGF0aW9uLCBub3QgaW4gcmVhbCBCYWNrZW5kcy5cbiAgICovXG4gIHJlc29sdmVBbGxDb25uZWN0aW9ucygpIHsgdGhpcy5jb25uZWN0aW9ucy5zdWJzY3JpYmUoKGM6IE1vY2tDb25uZWN0aW9uKSA9PiBjLnJlYWR5U3RhdGUgPSA0KTsgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IHtAbGluayBNb2NrQ29ubmVjdGlvbn0uIFRoaXMgaXMgZXF1aXZhbGVudCB0byBjYWxsaW5nIGBuZXdcbiAgICogTW9ja0Nvbm5lY3Rpb24oKWAsIGV4Y2VwdCB0aGF0IGl0IGFsc28gd2lsbCBlbWl0IHRoZSBuZXcgYENvbm5lY3Rpb25gIHRvIHRoZSBgY29ubmVjdGlvbnNgXG4gICAqIGVtaXR0ZXIgb2YgdGhpcyBgTW9ja0JhY2tlbmRgIGluc3RhbmNlLiBUaGlzIG1ldGhvZCB3aWxsIHVzdWFsbHkgb25seSBiZSB1c2VkIGJ5IHRlc3RzXG4gICAqIGFnYWluc3QgdGhlIGZyYW1ld29yayBpdHNlbGYsIG5vdCBieSBlbmQtdXNlcnMuXG4gICAqL1xuICBjcmVhdGVDb25uZWN0aW9uKHJlcTogUmVxdWVzdCk6IE1vY2tDb25uZWN0aW9uIHtcbiAgICBpZiAoIXJlcSB8fCAhKHJlcSBpbnN0YW5jZW9mIFJlcXVlc3QpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGNyZWF0ZUNvbm5lY3Rpb24gcmVxdWlyZXMgYW4gaW5zdGFuY2Ugb2YgUmVxdWVzdCwgZ290ICR7cmVxfWApO1xuICAgIH1cbiAgICBjb25zdCBjb25uZWN0aW9uID0gbmV3IE1vY2tDb25uZWN0aW9uKHJlcSk7XG4gICAgdGhpcy5jb25uZWN0aW9ucy5uZXh0KGNvbm5lY3Rpb24pO1xuICAgIHJldHVybiBjb25uZWN0aW9uO1xuICB9XG59XG4iXX0=