@iotize/ionic
Version:
Iotize specific building blocks on top of @ionic/angular.
240 lines • 34.5 kB
JavaScript
import { Injectable } from '@angular/core';
import { Tap } from '@iotize/tap';
import { ConnectionState } from '@iotize/tap/protocol/api';
import { defer, Observable } from 'rxjs';
import { catchError, map, shareReplay, switchMap, tap } from 'rxjs/operators';
import { CurrentDeviceService, LONG_RANGE_PROTOCOL_FILTER, } from './current-device.service';
import { debug } from './logger';
import { ProtocolFactoryService } from './protocol-factory.service';
import * as i0 from "@angular/core";
import * as i1 from "./current-device.service";
import * as i2 from "./protocol-factory.service";
const TAG = 'TapConnectionService';
export const TAP_CONNECTION_OPTIONS_PROVIDER = 'TapConnectionOptions';
export var TapRegisterProtocolsMethod;
(function (TapRegisterProtocolsMethod) {
/**
* Only register altertive protocol when connecting with nfc using ndef
*/
TapRegisterProtocolsMethod["NDEF_ONLY"] = "NDEF_ONLY";
/**
* Register alternative protocols using NDEF if present or service if not
*/
TapRegisterProtocolsMethod["NDEF_OR_SERVICE"] = "NDEF_OR_SERVICE";
/**
* Register alternative protocols using service (even if ndef is available)
*/
TapRegisterProtocolsMethod["SERVICE_ONLY"] = "SERVICE_ONLY";
})(TapRegisterProtocolsMethod || (TapRegisterProtocolsMethod = {}));
/**
* User can the replace with its own service
*/
export class TapConnectionService {
constructor(tapService, protocolFactory) {
this.tapService = tapService;
this.protocolFactory = protocolFactory;
this.tapFactory = (protocol) => {
return Tap.fromProtocol(protocol);
};
}
/**
* Create a Tap connection Observable shared stream
*/
connect(meta, config) {
return new Observable((emitter) => {
const subscription = this.createConnectionObservable(meta, config, emitter).subscribe({
error: async (err) => {
console.warn(`Tap connection failed with error`, err);
await this.tapService
.remove(false)
.catch((err) => console.warn('ignored error', err));
emitter.error(err);
},
complete: () => emitter.complete(),
});
return () => {
subscription.unsubscribe();
};
}).pipe(shareReplay(1));
}
createConnectionObservable(protocolMeta, config, emitter) {
let connectObservable = defer(async () => {
const protocol = await this.protocolFactory.create(protocolMeta);
const tap = this.tapFactory(protocol);
emitter.next({
message: `Initialize Tap from ${protocolMeta.type}...`,
tap,
});
return tap;
});
if (config.encryption) {
const encryptionOptions = config.encryption;
connectObservable = connectObservable.pipe(switchMap(async (tap) => {
emitter.next({
message: `Enable encryption...`,
tap,
});
if (encryptionOptions.keys) {
debug(TAG, 'Set encryption keys: ', encryptionOptions.keys);
tap.encryption.setEncryptionKeys(encryptionOptions.keys);
}
if (encryptionOptions.encryption) {
if (!tap.encryption.sessionKey && !tap.isConnected()) {
await tap.connect();
}
tap.encryption.resume();
debug(TAG, 'Enable encryption: ', encryptionOptions.encryption);
}
if (encryptionOptions.frameCounter != undefined) {
tap.encryption.setEncryptedFrameCounter(encryptionOptions.frameCounter);
}
return tap;
}));
}
connectObservable = connectObservable.pipe(switchMap(async (tap) => {
if (this.tapService.hasTap) {
await this.tapService.remove();
}
this.tapService.setTapFromEvent({
protocolMeta: protocolMeta,
tap: tap,
}, {
emit: false, // We emit only at the end of initialisation
});
tap.keepAlive.stop();
return tap;
}));
if (protocolMeta.type === 'nfc') {
if (config.nfcPairing) {
connectObservable = connectObservable.pipe(switchMap(async (tap) => {
emitter.next({
message: `NFC pairing...`,
tap,
});
debug(TAG, 'nfcPairing');
await tap.connect();
await tap.nfcPairing();
return tap;
}));
}
}
if (config.registerProtocolsMethod !== false) {
connectObservable = connectObservable.pipe(switchMap(async (tap) => {
if (!tap.isConnected()) {
emitter.next({
message: `Connecting with ${protocolMeta.type}...`,
tap,
});
await tap.connect();
}
emitter.next({
message: `Initializing protocols...`,
tap,
});
await this.registerAlternativeProtocols(config.registerProtocolsMethod, protocolMeta);
return tap;
}));
}
const switchProtocol = config.switchProtocol;
if (protocolMeta.type === 'nfc') {
connectObservable = connectObservable.pipe(switchMap(async (tap) => {
if (switchProtocol) {
const protocolMeta = this.tapService.availableProtocols.find(LONG_RANGE_PROTOCOL_FILTER);
if (protocolMeta) {
debug(TAG, 'Using long range protocol: ', protocolMeta);
emitter.next({
message: `Switch to ${protocolMeta.type}`,
tap,
});
await this.tapService.useProtocolFromMeta(protocolMeta);
}
}
else {
debug(TAG, 'keep NFC protocol');
const nfcProtocol = tap.protocol;
// for NFC connection
await nfcProtocol._connect().toPromise();
nfcProtocol.setConnectionState(ConnectionState.CONNECTED);
}
return tap;
}));
}
if (config.refreshSessionState) {
connectObservable = connectObservable.pipe(switchMap(async (tap) => {
debug(TAG, 'refreshSessionState');
emitter.next({
message: 'Refreshing user session...',
tap,
});
await tap.auth.refreshSessionState();
return tap;
}));
}
if (config.keepAlive !== false) {
connectObservable = connectObservable.pipe(tap((tap) => {
tap.keepAlive.start();
}));
}
return connectObservable.pipe(map((tap) => {
this.tapService.notifyNewTap();
return tap;
}), catchError((originalError) => {
console.warn(`Tap connection failed with error`, originalError);
return defer(async () => {
await this.tapService
.remove(false)
.catch((err) => console.warn('ignored error', err));
throw originalError;
});
}));
}
async registerAlternativeProtocols(registerAlternativeProtocolMethod, initialProtocolMeta) {
if (registerAlternativeProtocolMethod === false) {
return;
}
registerAlternativeProtocolMethod =
registerAlternativeProtocolMethod ||
TapRegisterProtocolsMethod.NDEF_OR_SERVICE;
debug(TAG, `Register alternative protocols with method: ${registerAlternativeProtocolMethod}`);
const tap = this.tapService.tap;
switch (registerAlternativeProtocolMethod) {
case TapRegisterProtocolsMethod.NDEF_OR_SERVICE:
let registeredProtocolMeta;
if (!tap.isConnected()) {
await tap.connect();
}
if (initialProtocolMeta.type === 'nfc') {
registeredProtocolMeta =
await this.tapService.registerProtocolsFromTag(initialProtocolMeta.info.tag);
}
else {
await this.tapService.registerProtocolsFromTap().catch((err) => {
console.warn('Failed to register protocols from tap', err);
});
}
break;
case TapRegisterProtocolsMethod.SERVICE_ONLY:
if (!tap.isConnected()) {
await tap.connect();
}
await this.tapService.registerProtocolsFromTap().catch((err) => {
console.warn('Failed to register protocols from tap', err);
});
break;
case TapRegisterProtocolsMethod.NDEF_ONLY:
if (initialProtocolMeta.type === 'nfc') {
await this.tapService.registerProtocolsFromTag(initialProtocolMeta.info.tag);
}
break;
}
}
}
/** @nocollapse */ TapConnectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConnectionService, deps: [{ token: i1.CurrentDeviceService }, { token: i2.ProtocolFactoryService }], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ TapConnectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConnectionService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConnectionService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: function () { return [{ type: i1.CurrentDeviceService }, { type: i2.ProtocolFactoryService }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLWNvbm5lY3Rpb24uc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9zcmMvbGliL3RhcC1jb25uZWN0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRWxDLE9BQU8sRUFBZSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN4RSxPQUFPLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBYyxNQUFNLE1BQU0sQ0FBQztBQUNyRCxPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTlFLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsMEJBQTBCLEdBQzNCLE1BQU0sMEJBQTBCLENBQUM7QUFFbEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNqQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7OztBQUVwRSxNQUFNLEdBQUcsR0FBRyxzQkFBc0IsQ0FBQztBQUVuQyxNQUFNLENBQUMsTUFBTSwrQkFBK0IsR0FBRyxzQkFBc0IsQ0FBQztBQUV0RSxNQUFNLENBQU4sSUFBWSwwQkFlWDtBQWZELFdBQVksMEJBQTBCO0lBQ3BDOztPQUVHO0lBQ0gscURBQXVCLENBQUE7SUFFdkI7O09BRUc7SUFDSCxpRUFBbUMsQ0FBQTtJQUVuQzs7T0FFRztJQUNILDJEQUE2QixDQUFBO0FBQy9CLENBQUMsRUFmVywwQkFBMEIsS0FBMUIsMEJBQTBCLFFBZXJDO0FBOENEOztHQUVHO0FBSUgsTUFBTSxPQUFPLG9CQUFvQjtJQUsvQixZQUNVLFVBQWdDLEVBQ2hDLGVBQXVDO1FBRHZDLGVB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SUFuUVUsb0JBQW9CO3lJQUFwQixvQkFBb0IsY0FGbkIsTUFBTTs0RkFFUCxvQkFBb0I7a0JBSGhDLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTkZDQ29tUHJvdG9jb2wgfSBmcm9tICdAaW90aXplL2RldmljZS1jb20tbmZjLmNvcmRvdmEnO1xuaW1wb3J0IHsgVGFwIH0gZnJvbSAnQGlvdGl6ZS90YXAnO1xuaW1wb3J0IHsgRW5jcnlwdGlvbk9wdGlvbnMgfSBmcm9tICdAaW90aXplL3RhcC9hdXRoJztcbmltcG9ydCB7IENvbVByb3RvY29sLCBDb25uZWN0aW9uU3RhdGUgfSBmcm9tICdAaW90aXplL3RhcC9wcm90b2NvbC9hcGknO1xuaW1wb3J0IHsgZGVmZXIsIE9ic2VydmFibGUsIFN1YnNjcmliZXIgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGNhdGNoRXJyb3IsIG1hcCwgc2hhcmVSZXBsYXksIHN3aXRjaE1hcCwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQge1xuICBDdXJyZW50RGV2aWNlU2VydmljZSxcbiAgTE9OR19SQU5HRV9QUk9UT0NPTF9GSUxURVIsXG59IGZyb20gJy4vY3VycmVudC1kZXZpY2Uuc2VydmljZSc7XG5pbXBvcnQgeyBQcm90b2NvbE1ldGEgfSBmcm9tICcuL2V4dGVuc2lvbnMvcHJvdG9jb2wtaW5mbyc7XG5pbXBvcnQgeyBkZWJ1ZyB9IGZyb20gJy4vbG9nZ2VyJztcbmltcG9ydCB7IFByb3RvY29sRmFjdG9yeVNlcnZpY2UgfSBmcm9tICcuL3Byb3RvY29sLWZhY3Rvcnkuc2VydmljZSc7XG5cbmNvbnN0IFRBRyA9ICdUYXBDb25uZWN0aW9uU2VydmljZSc7XG5cbmV4cG9ydCBjb25zdCBUQVBfQ09OTkVDVElPTl9PUFRJT05TX1BST1ZJREVSID0gJ1RhcENvbm5lY3Rpb25PcHRpb25zJztcblxuZXhwb3J0IGVudW0gVGFwUmVnaXN0ZXJQcm90b2NvbHNNZXRob2Qge1xuICAvKipcbiAgICogT25seSByZWdpc3RlciBhbHRlcnRpdmUgcHJvdG9jb2wgd2hlbiBjb25uZWN0aW5nIHdpdGggbmZjIHVzaW5nIG5kZWZcbiAgICovXG4gIE5ERUZfT05MWSA9ICdOREVGX09OTFknLFxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhbHRlcm5hdGl2ZSBwcm90b2NvbHMgdXNpbmcgTkRFRiBpZiBwcmVzZW50IG9yIHNlcnZpY2UgaWYgbm90XG4gICAqL1xuICBOREVGX09SX1NFUlZJQ0UgPSAnTkRFRl9PUl9TRVJWSUNFJyxcblxuICAvKipcbiAgICogUmVnaXN0ZXIgYWx0ZXJuYXRpdmUgcHJvdG9jb2xzIHVzaW5nIHNlcnZpY2UgKGV2ZW4gaWYgbmRlZiBpcyBhdmFpbGFibGUpXG4gICAqL1xuICBTRVJWSUNFX09OTFkgPSAnU0VSVklDRV9PTkxZJyxcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUYXBDb25uZWN0aW9uT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBTZXQgdG8gdHJ1ZSBpZiB5b3Ugd2FudCB0byBhdXRvbWF0aWNhbGx5IGNvbm5lY3Qgd2l0aCBhIGxvbmcgcmFuZ2UgcHJvdG9jb2wgd2hlbiBjb25uZWN0aW5nIHdpdGggTkZDXG4gICAqL1xuICBzd2l0Y2hQcm90b2NvbD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIENvbmZpZ3VyZSByZWdpc3RlciBhbHRlcm5hdGl2ZSBwcm90b2NvbCBtZXRob2Qgd2hlbiB3ZSBhcmUgY29ubmVjdGlvbiB0byB0aGUgdGFwXG4gICAqIFRoaXMgd2lsbCBwZXJmb3JtcyBhZGRpdGlvbmFsIHJlcXVlc3RzIGxlYWRpbmcgdG8gYSBzbG93ZXIgY29ubmVjdGlvblxuICAgKi9cbiAgcmVnaXN0ZXJQcm90b2NvbHNNZXRob2Q/OiBUYXBSZWdpc3RlclByb3RvY29sc01ldGhvZCB8IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBTZXQgdG8gdHJ1ZSB0byByZWZyZXNoIHNlc3Npb24gc3RhdGUgYWZ0ZXIgY29ubmVjdGlvblxuICAgKi9cbiAgcmVmcmVzaFNlc3Npb25TdGF0ZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRydWUgdG8gcGVyZm9ybSBORkMgcGFpcmluZyBvbiBjb25uZWN0aW9uXG4gICAqL1xuICBuZmNQYWlyaW5nPzogYm9vbGVhbjtcblxuICAvLyAvKipcbiAgLy8gICogVHJ1ZSB0byBlbmFibGUgZW5jcnlwdGlvbiB3aGlsZSB1c2luZyBORkMgcHJvdG9jb2xcbiAgLy8gICovXG4gIC8vIG5mY0VuYWJsZUVuY3J5cHRpb24/OiBib29sZWFuXG5cbiAgLyoqXG4gICAqIEVuY3J5cHRpb24ga2V5cyBmb3IgdGFwIGluaXRpYWxpemF0aW9uXG4gICAqL1xuICBlbmNyeXB0aW9uPzogRW5jcnlwdGlvbk9wdGlvbnM7XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGtlZXAgYWxpdmUgKGlmIHRydWUgb3IgdW5kZWZpbmVkKVxuICAgKiBJZiBmYWxzZSwga2VlcCBhbGl2ZSBpcyBub3Qgc3RhcnRlZFxuICAgKi9cbiAga2VlcEFsaXZlPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb25uZWN0aW9uRXZlbnQge1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIHRhcDogVGFwO1xufVxuXG4vKipcbiAqIFVzZXIgY2FuIHRoZSByZXBsYWNlIHdpdGggaXRzIG93biBzZXJ2aWNlXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBUYXBDb25uZWN0aW9uU2VydmljZSB7XG4gIHByaXZhdGUgdGFwRmFjdG9yeTogKHByb3RvY29sOiBDb21Qcm90b2NvbCkgPT4gVGFwID0gKHByb3RvY29sKSA9PiB7XG4gICAgcmV0dXJuIFRhcC5mcm9tUHJvdG9jb2wocHJvdG9jb2wpO1xuICB9O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgdGFwU2VydmljZTogQ3VycmVudERldmljZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBwcm90b2NvbEZhY3Rvcnk6IFByb3RvY29sRmFjdG9yeVNlcnZpY2VcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBUYXAgY29ubmVjdGlvbiBPYnNlcnZhYmxlIHNoYXJlZCBzdHJlYW1cbiAgICovXG4gIGNvbm5lY3QoXG4gICAgbWV0YTogUHJvdG9jb2xNZXRhLFxuICAgIGNvbmZpZzogVGFwQ29ubmVjdGlvbk9wdGlvbnNcbiAgKTogT2JzZXJ2YWJsZTxDb25uZWN0aW9uRXZlbnQ+IHtcbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGUoKGVtaXR0ZXI6IFN1YnNjcmliZXI8Q29ubmVjdGlvbkV2ZW50PikgPT4ge1xuICAgICAgY29uc3Qgc3Vic2NyaXB0aW9uID0gdGhpcy5jcmVhdGVDb25uZWN0aW9uT2JzZXJ2YWJsZShcbiAgICAgICAgbWV0YSxcbiAgICAgICAgY29uZmlnLFxuICAgICAgICBlbWl0dGVyXG4gICAgICApLnN1YnNjcmliZSh7XG4gICAgICAgIGVycm9yOiBhc3luYyAoZXJyKSA9PiB7XG4gICAgICAgICAgY29uc29sZS53YXJuKGBUYXAgY29ubmVjdGlvbiBmYWlsZWQgd2l0aCBlcnJvcmAsIGVycik7XG4gICAgICAgICAgYXdhaXQgdGhpcy50YXBTZXJ2aWNlXG4gICAgICAgICAgICAucmVtb3ZlKGZhbHNlKVxuICAgICAgICAgICAgLmNhdGNoKChlcnIpID0+IGNvbnNvbGUud2FybignaWdub3JlZCBlcnJvcicsIGVycikpO1xuICAgICAgICAgIGVtaXR0ZXIuZXJyb3IoZXJyKTtcbiAgICAgICAgfSxcbiAgICAgICAgY29tcGxldGU6ICgpID0+IGVtaXR0ZXIuY29tcGxldGUoKSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuICgpID0+IHtcbiAgICAgICAgc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICB9O1xuICAgIH0pLnBpcGUoc2hhcmVSZXBsYXkoMSkpO1xuICB9XG5cbiAgY3JlYXRlQ29ubmVjdGlvbk9ic2VydmFibGUoXG4gICAgcHJvdG9jb2xNZXRhOiBQcm90b2NvbE1ldGEsXG4gICAgY29uZmlnOiBUYXBDb25uZWN0aW9uT3B0aW9ucyxcbiAgICBlbWl0dGVyOiBTdWJzY3JpYmVyPENvbm5lY3Rpb25FdmVudD5cbiAgKSB7XG4gICAgbGV0IGNvbm5lY3RPYnNlcnZhYmxlID0gZGVmZXIoYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcHJvdG9jb2wgPSBhd2FpdCB0aGlzLnByb3RvY29sRmFjdG9yeS5jcmVhdGUocHJvdG9jb2xNZXRhKTtcbiAgICAgIGNvbnN0IHRhcCA9IHRoaXMudGFwRmFjdG9yeShwcm90b2NvbCk7XG4gICAgICBlbWl0dGVyLm5leHQoe1xuICAgICAgICBtZXNzYWdlOiBgSW5pdGlhbGl6ZSBUYXAgZnJvbSAke3Byb3RvY29sTWV0YS50eXBlfS4uLmAsXG4gICAgICAgIHRhcCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHRhcDtcbiAgICB9KTtcblxuICAgIGlmIChjb25maWcuZW5jcnlwdGlvbikge1xuICAgICAgY29uc3QgZW5jcnlwdGlvbk9wdGlvbnMgPSBjb25maWcuZW5jcnlwdGlvbjtcbiAgICAgIGNvbm5lY3RPYnNlcnZhYmxlID0gY29ubmVjdE9ic2VydmFibGUucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKGFzeW5jICh0YXApID0+IHtcbiAgICAgICAgICBlbWl0dGVyLm5leHQoe1xuICAgICAgICAgICAgbWVzc2FnZTogYEVuYWJsZSBlbmNyeXB0aW9uLi4uYCxcbiAgICAgICAgICAgIHRhcCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAoZW5jcnlwdGlvbk9wdGlvbnMua2V5cykge1xuICAgICAgICAgICAgZGVidWcoVEFHLCAnU2V0IGVuY3J5cHRpb24ga2V5czogJywgZW5jcnlwdGlvbk9wdGlvbnMua2V5cyk7XG4gICAgICAgICAgICB0YXAuZW5jcnlwdGlvbi5zZXRFbmNyeXB0aW9uS2V5cyhlbmNyeXB0aW9uT3B0aW9ucy5rZXlzKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGVuY3J5cHRpb25PcHRpb25zLmVuY3J5cHRpb24pIHtcbiAgICAgICAgICAgIGlmICghdGFwLmVuY3J5cHRpb24uc2Vzc2lvbktleSAmJiAhdGFwLmlzQ29ubmVjdGVkKCkpIHtcbiAgICAgICAgICAgICAgYXdhaXQgdGFwLmNvbm5lY3QoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRhcC5lbmNyeXB0aW9uLnJlc3VtZSgpO1xuICAgICAgICAgICAgZGVidWcoVEFHLCAnRW5hYmxlIGVuY3J5cHRpb246ICcsIGVuY3J5cHRpb25PcHRpb25zLmVuY3J5cHRpb24pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZW5jcnlwdGlvbk9wdGlvbnMuZnJhbWVDb3VudGVyICE9IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGFwLmVuY3J5cHRpb24uc2V0RW5jcnlwdGVkRnJhbWVDb3VudGVyKFxuICAgICAgICAgICAgICBlbmNyeXB0aW9uT3B0aW9ucy5mcmFtZUNvdW50ZXJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0YXA7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbm5lY3RPYnNlcnZhYmxlID0gY29ubmVjdE9ic2VydmFibGUucGlwZShcbiAgICAgIHN3aXRjaE1hcChhc3luYyAodGFwKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLnRhcFNlcnZpY2UuaGFzVGFwKSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy50YXBTZXJ2aWNlLnJlbW92ZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudGFwU2VydmljZS5zZXRUYXBGcm9tRXZlbnQoXG4gICAgICAgICAge1xuICAgICAgICAgICAgcHJvdG9jb2xNZXRhOiBwcm90b2NvbE1ldGEsXG4gICAgICAgICAgICB0YXA6IHRhcCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGVtaXQ6IGZhbHNlLCAvLyBXZSBlbWl0IG9ubHkgYXQgdGhlIGVuZCBvZiBpbml0aWFsaXNhdGlvblxuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgdGFwLmtlZXBBbGl2ZS5zdG9wKCk7XG4gICAgICAgIHJldHVybiB0YXA7XG4gICAgICB9KVxuICAgICk7XG5cbiAgICBpZiAocHJvdG9jb2xNZXRhLnR5cGUgPT09ICduZmMnKSB7XG4gICAgICBpZiAoY29uZmlnLm5mY1BhaXJpbmcpIHtcbiAgICAgICAgY29ubmVjdE9ic2VydmFibGUgPSBjb25uZWN0T2JzZXJ2YWJsZS5waXBlKFxuICAgICAgICAgIHN3aXRjaE1hcChhc3luYyAodGFwKSA9PiB7XG4gICAgICAgICAgICBlbWl0dGVyLm5leHQoe1xuICAgICAgICAgICAgICBtZXNzYWdlOiBgTkZDIHBhaXJpbmcuLi5gLFxuICAgICAgICAgICAgICB0YXAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGRlYnVnKFRBRywgJ25mY1BhaXJpbmcnKTtcbiAgICAgICAgICAgIGF3YWl0IHRhcC5jb25uZWN0KCk7XG4gICAgICAgICAgICBhd2FpdCB0YXAubmZjUGFpcmluZygpO1xuICAgICAgICAgICAgcmV0dXJuIHRhcDtcbiAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjb25maWcucmVnaXN0ZXJQcm90b2NvbHNNZXRob2QgIT09IGZhbHNlKSB7XG4gICAgICBjb25uZWN0T2JzZXJ2YWJsZSA9IGNvbm5lY3RPYnNlcnZhYmxlLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcChhc3luYyAodGFwKSA9PiB7XG4gICAgICAgICAgaWYgKCF0YXAuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgICAgICAgZW1pdHRlci5uZXh0KHtcbiAgICAgICAgICAgICAgbWVzc2FnZTogYENvbm5lY3Rpbmcgd2l0aCAke3Byb3RvY29sTWV0YS50eXBlfS4uLmAsXG4gICAgICAgICAgICAgIHRhcCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgYXdhaXQgdGFwLmNvbm5lY3QoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgZW1pdHRlci5uZXh0KHtcbiAgICAgICAgICAgIG1lc3NhZ2U6IGBJbml0aWFsaXppbmcgcHJvdG9jb2xzLi4uYCxcbiAgICAgICAgICAgIHRhcCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBhd2FpdCB0aGlzLnJlZ2lzdGVyQWx0ZXJuYXRpdmVQcm90b2NvbHMoXG4gICAgICAgICAgICBjb25maWcucmVnaXN0ZXJQcm90b2NvbHNNZXRob2QsXG4gICAgICAgICAgICBwcm90b2NvbE1ldGFcbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiB0YXA7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHN3aXRjaFByb3RvY29sID0gY29uZmlnLnN3aXRjaFByb3RvY29sO1xuICAgIGlmIChwcm90b2NvbE1ldGEudHlwZSA9PT0gJ25mYycpIHtcbiAgICAgIGNvbm5lY3RPYnNlcnZhYmxlID0gY29ubmVjdE9ic2VydmFibGUucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKGFzeW5jICh0YXApID0+IHtcbiAgICAgICAgICBpZiAoc3dpdGNoUHJvdG9jb2wpIHtcbiAgICAgICAgICAgIGNvbnN0IHByb3RvY29sTWV0YSA9IHRoaXMudGFwU2VydmljZS5hdmFpbGFibGVQcm90b2NvbHMuZmluZChcbiAgICAgICAgICAgICAgTE9OR19SQU5HRV9QUk9UT0NPTF9GSUxURVJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAocHJvdG9jb2xNZXRhKSB7XG4gICAgICAgICAgICAgIGRlYnVnKFRBRywgJ1VzaW5nIGxvbmcgcmFuZ2UgcHJvdG9jb2w6ICcsIHByb3RvY29sTWV0YSk7XG4gICAgICAgICAgICAgIGVtaXR0ZXIubmV4dCh7XG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN3aXRjaCB0byAke3Byb3RvY29sTWV0YS50eXBlfWAsXG4gICAgICAgICAgICAgICAgdGFwLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgYXdhaXQgdGhpcy50YXBTZXJ2aWNlLnVzZVByb3RvY29sRnJvbU1ldGEocHJvdG9jb2xNZXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGVidWcoVEFHLCAna2VlcCBORkMgcHJvdG9jb2wnKTtcbiAgICAgICAgICAgIGNvbnN0IG5mY1Byb3RvY29sID0gdGFwLnByb3RvY29sIGFzIE5GQ0NvbVByb3RvY29sO1xuICAgICAgICAgICAgLy8gZm9yIE5GQyBjb25uZWN0aW9uXG4gICAgICAgICAgICBhd2FpdCBuZmNQcm90b2NvbC5fY29ubmVjdCgpLnRvUHJvbWlzZSgpO1xuICAgICAgICAgICAgbmZjUHJvdG9jb2wuc2V0Q29ubmVjdGlvblN0YXRlKENvbm5lY3Rpb25TdGF0ZS5DT05ORUNURUQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdGFwO1xuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoY29uZmlnLnJlZnJlc2hTZXNzaW9uU3RhdGUpIHtcbiAgICAgIGNvbm5lY3RPYnNlcnZhYmxlID0gY29ubmVjdE9ic2VydmFibGUucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKGFzeW5jICh0YXApID0+IHtcbiAgICAgICAgICBkZWJ1ZyhUQUcsICdyZWZyZXNoU2Vzc2lvblN0YXRlJyk7XG4gICAgICAgICAgZW1pdHRlci5uZXh0KHtcbiAgICAgICAgICAgIG1lc3NhZ2U6ICdSZWZyZXNoaW5nIHVzZXIgc2Vzc2lvbi4uLicsXG4gICAgICAgICAgICB0YXAsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgYXdhaXQgdGFwLmF1dGgucmVmcmVzaFNlc3Npb25TdGF0ZSgpO1xuICAgICAgICAgIHJldHVybiB0YXA7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChjb25maWcua2VlcEFsaXZlICE9PSBmYWxzZSkge1xuICAgICAgY29ubmVjdE9ic2VydmFibGUgPSBjb25uZWN0T2JzZXJ2YWJsZS5waXBlKFxuICAgICAgICB0YXAoKHRhcCkgPT4ge1xuICAgICAgICAgIHRhcC5rZWVwQWxpdmUuc3RhcnQoKTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbm5lY3RPYnNlcnZhYmxlLnBpcGUoXG4gICAgICBtYXAoKHRhcCkgPT4ge1xuICAgICAgICB0aGlzLnRhcFNlcnZpY2Uubm90aWZ5TmV3VGFwKCk7XG4gICAgICAgIHJldHVybiB0YXA7XG4gICAgICB9KSxcbiAgICAgIGNhdGNoRXJyb3IoKG9yaWdpbmFsRXJyb3IpID0+IHtcbiAgICAgICAgY29uc29sZS53YXJuKGBUYXAgY29ubmVjdGlvbiBmYWlsZWQgd2l0aCBlcnJvcmAsIG9yaWdpbmFsRXJyb3IpO1xuICAgICAgICByZXR1cm4gZGVmZXIoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGF3YWl0IHRoaXMudGFwU2VydmljZVxuICAgICAgICAgICAgLnJlbW92ZShmYWxzZSlcbiAgICAgICAgICAgIC5jYXRjaCgoZXJyKSA9PiBjb25zb2xlLndhcm4oJ2lnbm9yZWQgZXJyb3InLCBlcnIpKTtcbiAgICAgICAgICB0aHJvdyBvcmlnaW5hbEVycm9yO1xuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIHJlZ2lzdGVyQWx0ZXJuYXRpdmVQcm90b2NvbHMoXG4gICAgcmVnaXN0ZXJBbHRlcm5hdGl2ZVByb3RvY29sTWV0aG9kOlxuICAgICAgfCBUYXBSZWdpc3RlclByb3RvY29sc01ldGhvZFxuICAgICAgfCBmYWxzZVxuICAgICAgfCB1bmRlZmluZWQsXG4gICAgaW5pdGlhbFByb3RvY29sTWV0YTogUHJvdG9jb2xNZXRhXG4gICkge1xuICAgIGlmIChyZWdpc3RlckFsdGVybmF0aXZlUHJvdG9jb2xNZXRob2QgPT09IGZhbHNlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJlZ2lzdGVyQWx0ZXJuYXRpdmVQcm90b2NvbE1ldGhvZCA9XG4gICAgICByZWdpc3RlckFsdGVybmF0aXZlUHJvdG9jb2xNZXRob2QgfHxcbiAgICAgIFRhcFJlZ2lzdGVyUHJvdG9jb2xzTWV0aG9kLk5ERUZfT1JfU0VSVklDRTtcbiAgICBkZWJ1ZyhcbiAgICAgIFRBRyxcbiAgICAgIGBSZWdpc3RlciBhbHRlcm5hdGl2ZSBwcm90b2NvbHMgd2l0aCBtZXRob2Q6ICR7cmVnaXN0ZXJBbHRlcm5hdGl2ZVByb3RvY29sTWV0aG9kfWBcbiAgICApO1xuICAgIGNvbnN0IHRhcCA9IHRoaXMudGFwU2VydmljZS50YXA7XG4gICAgc3dpdGNoIChyZWdpc3RlckFsdGVybmF0aXZlUHJvdG9jb2xNZXRob2QpIHtcbiAgICAgIGNhc2UgVGFwUmVnaXN0ZXJQcm90b2NvbHNNZXRob2QuTkRFRl9PUl9TRVJWSUNFOlxuICAgICAgICBsZXQgcmVnaXN0ZXJlZFByb3RvY29sTWV0YTogUHJvdG9jb2xNZXRhIHwgdW5kZWZpbmVkO1xuICAgICAgICBpZiAoIXRhcC5pc0Nvbm5lY3RlZCgpKSB7XG4gICAgICAgICAgYXdhaXQgdGFwLmNvbm5lY3QoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaW5pdGlhbFByb3RvY29sTWV0YS50eXBlID09PSAnbmZjJykge1xuICAgICAgICAgIHJlZ2lzdGVyZWRQcm90b2NvbE1ldGEgPVxuICAgICAgICAgICAgYXdhaXQgdGhpcy50YXBTZXJ2aWNlLnJlZ2lzdGVyUHJvdG9jb2xzRnJvbVRhZyhcbiAgICAgICAgICAgICAgaW5pdGlhbFByb3RvY29sTWV0YS5pbmZvLnRhZ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnRhcFNlcnZpY2UucmVnaXN0ZXJQcm90b2NvbHNGcm9tVGFwKCkuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdGYWlsZWQgdG8gcmVnaXN0ZXIgcHJvdG9jb2xzIGZyb20gdGFwJywgZXJyKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgVGFwUmVnaXN0ZXJQcm90b2NvbHNNZXRob2QuU0VSVklDRV9PTkxZOlxuICAgICAgICBpZiAoIXRhcC5pc0Nvbm5lY3RlZCgpKSB7XG4gICAgICAgICAgYXdhaXQgdGFwLmNvbm5lY3QoKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLnRhcFNlcnZpY2UucmVnaXN0ZXJQcm90b2NvbHNGcm9tVGFwKCkuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgIGNvbnNvbGUud2FybignRmFpbGVkIHRvIHJlZ2lzdGVyIHByb3RvY29scyBmcm9tIHRhcCcsIGVycik7XG4gICAgICAgIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgVGFwUmVnaXN0ZXJQcm90b2NvbHNNZXRob2QuTkRFRl9PTkxZOlxuICAgICAgICBpZiAoaW5pdGlhbFByb3RvY29sTWV0YS50eXBlID09PSAnbmZjJykge1xuICAgICAgICAgIGF3YWl0IHRoaXMudGFwU2VydmljZS5yZWdpc3RlclByb3RvY29sc0Zyb21UYWcoXG4gICAgICAgICAgICBpbml0aWFsUHJvdG9jb2xNZXRhLmluZm8udGFnXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cbn1cbiJdfQ==