UNPKG

@iotize/ionic

Version:

Iotize specific building blocks on top of @ionic/angular.

252 lines 36.1 kB
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 { tapService; protocolFactory; tapFactory = (protocol) => { return Tap.fromProtocol(protocol); }; constructor(tapService, protocolFactory) { this.tapService = tapService; this.protocolFactory = protocolFactory; } /** * 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) => { if (!tap.isConnected()) { emitter.next({ message: `Connecting with ${protocolMeta.type}...`, tap, }); await tap.connect(); } debug(TAG, 'refreshSessionState'); emitter.next({ message: 'Refreshing user session...', tap, }); await tap.auth.refreshSessionState(); return tap; })); } if (config.keepAlive !== false && config.keepAlive !== 0) { connectObservable = connectObservable.pipe(tap((tap) => { if (typeof config.keepAlive === 'number') { tap.keepAlive.period = config.keepAlive; } 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 */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TapConnectionService, deps: [{ token: i1.CurrentDeviceService }, { token: i2.ProtocolFactoryService }], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TapConnectionService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TapConnectionService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: () => [{ type: i1.CurrentDeviceService }, { type: i2.ProtocolFactoryService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLWNvbm5lY3Rpb24uc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9zcmMvbGliL3RhcC1jb25uZWN0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRWxDLE9BQU8sRUFBZSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN4RSxPQUFPLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBYyxNQUFNLE1BQU0sQ0FBQztBQUNyRCxPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTlFLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsMEJBQTBCLEdBQzNCLE1BQU0sMEJBQTBCLENBQUM7QUFFbEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNqQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7OztBQUVwRSxNQUFNLEdBQUcsR0FBRyxzQkFBc0IsQ0FBQztBQUVuQyxNQUFNLENBQUMsTUFBTSwrQkFBK0IsR0FBRyxzQkFBc0IsQ0FBQztBQUV0RSxNQUFNLENBQU4sSUFBWSwwQkFlWDtBQWZELFdBQVksMEJBQTBCO0lBQ3BDOztPQUVHO0lBQ0gscURBQXVCLENBQUE7SUFFdkI7O09BRUc7SUFDSCxpRUFBbUMsQ0FBQTtJQUVuQzs7T0FFRztJQUNILDJEQUE2QixDQUFBO0FBQy9CLENBQUMsRUFmVywwQkFBMEIsS0FBMUIsMEJBQTBCLFFBZXJDO0FBZ0REOztHQUVHO0FBSUgsTUFBTSxPQUFPLG9CQUFvQjtJQU1yQjtJQUNBO0lBTkYsVUFBVSxHQUFtQyxDQUFDLFFBQVEs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T0FBTyxDQUFDLElBQUksQ0FBQyx1Q0FBdUMsRUFBRSxHQUFHLENBQUMsQ0FBQztvQkFDN0QsQ0FBQyxDQUFDLENBQUM7Z0JBQ0wsQ0FBQztnQkFDRCxNQUFNO1lBQ1IsS0FBSywwQkFBMEIsQ0FBQyxZQUFZO2dCQUMxQyxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7b0JBQ3ZCLE1BQU0sR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUN0QixDQUFDO2dCQUNELE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyx3QkFBd0IsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO29CQUM3RCxPQUFPLENBQUMsSUFBSSxDQUFDLHVDQUF1QyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUM3RCxDQUFDLENBQUMsQ0FBQztnQkFDSCxNQUFNO1lBQ1IsS0FBSywwQkFBMEIsQ0FBQyxTQUFTO2dCQUN2QyxJQUFJLG1CQUFtQixDQUFDLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQztvQkFDdkMsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLHdCQUF3QixDQUM1QyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUM3QixDQUFDO2dCQUNKLENBQUM7Z0JBQ0QsTUFBTTtRQUNWLENBQUM7SUFDSCxDQUFDOzJIQTdRVSxvQkFBb0I7K0hBQXBCLG9CQUFvQixjQUZuQixNQUFNOzs0RkFFUCxvQkFBb0I7a0JBSGhDLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTkZDQ29tUHJvdG9jb2wgfSBmcm9tICdAaW90aXplL2RldmljZS1jb20tbmZjLmNvcmRvdmEnO1xuaW1wb3J0IHsgVGFwIH0gZnJvbSAnQGlvdGl6ZS90YXAnO1xuaW1wb3J0IHsgRW5jcnlwdGlvbk9wdGlvbnMgfSBmcm9tICdAaW90aXplL3RhcC9hdXRoJztcbmltcG9ydCB7IENvbVByb3RvY29sLCBDb25uZWN0aW9uU3RhdGUgfSBmcm9tICdAaW90aXplL3RhcC9wcm90b2NvbC9hcGknO1xuaW1wb3J0IHsgZGVmZXIsIE9ic2VydmFibGUsIFN1YnNjcmliZXIgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGNhdGNoRXJyb3IsIG1hcCwgc2hhcmVSZXBsYXksIHN3aXRjaE1hcCwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQge1xuICBDdXJyZW50RGV2aWNlU2VydmljZSxcbiAgTE9OR19SQU5HRV9QUk9UT0NPTF9GSUxURVIsXG59IGZyb20gJy4vY3VycmVudC1kZXZpY2Uuc2VydmljZSc7XG5pbXBvcnQgeyBQcm90b2NvbE1ldGEgfSBmcm9tICcuL2V4dGVuc2lvbnMvcHJvdG9jb2wtaW5mbyc7XG5pbXBvcnQgeyBkZWJ1ZyB9IGZyb20gJy4vbG9nZ2VyJztcbmltcG9ydCB7IFByb3RvY29sRmFjdG9yeVNlcnZpY2UgfSBmcm9tICcuL3Byb3RvY29sLWZhY3Rvcnkuc2VydmljZSc7XG5cbmNvbnN0IFRBRyA9ICdUYXBDb25uZWN0aW9uU2VydmljZSc7XG5cbmV4cG9ydCBjb25zdCBUQVBfQ09OTkVDVElPTl9PUFRJT05TX1BST1ZJREVSID0gJ1RhcENvbm5lY3Rpb25PcHRpb25zJztcblxuZXhwb3J0IGVudW0gVGFwUmVnaXN0ZXJQcm90b2NvbHNNZXRob2Qge1xuICAvKipcbiAgICogT25seSByZWdpc3RlciBhbHRlcnRpdmUgcHJvdG9jb2wgd2hlbiBjb25uZWN0aW5nIHdpdGggbmZjIHVzaW5nIG5kZWZcbiAgICovXG4gIE5ERUZfT05MWSA9ICdOREVGX09OTFknLFxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhbHRlcm5hdGl2ZSBwcm90b2NvbHMgdXNpbmcgTkRFRiBpZiBwcmVzZW50IG9yIHNlcnZpY2UgaWYgbm90XG4gICAqL1xuICBOREVGX09SX1NFUlZJQ0UgPSAnTkRFRl9PUl9TRVJWSUNFJyxcblxuICAvKipcbiAgICogUmVnaXN0ZXIgYWx0ZXJuYXRpdmUgcHJvdG9jb2xzIHVzaW5nIHNlcnZpY2UgKGV2ZW4gaWYgbmRlZiBpcyBhdmFpbGFibGUpXG4gICAqL1xuICBTRVJWSUNFX09OTFkgPSAnU0VSVklDRV9PTkxZJyxcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUYXBDb25uZWN0aW9uT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBTZXQgdG8gdHJ1ZSBpZiB5b3Ugd2FudCB0byBhdXRvbWF0aWNhbGx5IGNvbm5lY3Qgd2l0aCBhIGxvbmcgcmFuZ2UgcHJvdG9jb2wgd2hlbiBjb25uZWN0aW5nIHdpdGggTkZDXG4gICAqL1xuICBzd2l0Y2hQcm90b2NvbD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIENvbmZpZ3VyZSByZWdpc3RlciBhbHRlcm5hdGl2ZSBwcm90b2NvbCBtZXRob2Qgd2hlbiB3ZSBhcmUgY29ubmVjdGlvbiB0byB0aGUgdGFwXG4gICAqIFRoaXMgd2lsbCBwZXJmb3JtcyBhZGRpdGlvbmFsIHJlcXVlc3RzIGxlYWRpbmcgdG8gYSBzbG93ZXIgY29ubmVjdGlvblxuICAgKi9cbiAgcmVnaXN0ZXJQcm90b2NvbHNNZXRob2Q/OiBUYXBSZWdpc3RlclByb3RvY29sc01ldGhvZCB8IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBTZXQgdG8gdHJ1ZSB0byByZWZyZXNoIHNlc3Npb24gc3RhdGUgYWZ0ZXIgY29ubmVjdGlvblxuICAgKi9cbiAgcmVmcmVzaFNlc3Npb25TdGF0ZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRydWUgdG8gcGVyZm9ybSBORkMgcGFpcmluZyBvbiBjb25uZWN0aW9uXG4gICAqL1xuICBuZmNQYWlyaW5nPzogYm9vbGVhbjtcblxuICAvLyAvKipcbiAgLy8gICogVHJ1ZSB0byBlbmFibGUgZW5jcnlwdGlvbiB3aGlsZSB1c2luZyBORkMgcHJvdG9jb2xcbiAgLy8gICovXG4gIC8vIG5mY0VuYWJsZUVuY3J5cHRpb24/OiBib29sZWFuXG5cbiAgLyoqXG4gICAqIEVuY3J5cHRpb24ga2V5cyBmb3IgdGFwIGluaXRpYWxpemF0aW9uXG4gICAqL1xuICBlbmNyeXB0aW9uPzogRW5jcnlwdGlvbk9wdGlvbnM7XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGtlZXAgYWxpdmUgKGlmIHRydWUgb3IgdW5kZWZpbmVkKVxuICAgKiBJZiBmYWxzZSwga2VlcCBhbGl2ZSBpcyBub3Qgc3RhcnRlZFxuICAgKiBJZiB0cnVlLCBpdCBpcyBzdGFydGVkIHdpdGggZGVmYXVsdCBwZXJpb2RcbiAgICogSWYgbnVtYmVyID4gMCB0aGlzIGlzIHRoZSBrZWVwIGFsaXZlIHBlcmlvZCB0byB1c2UgaW4gbWlsbGlzZWNvbmRzXG4gICAqL1xuICBrZWVwQWxpdmU/OiBib29sZWFuIHwgbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3Rpb25FdmVudCB7XG4gIG1lc3NhZ2U6IHN0cmluZztcbiAgdGFwOiBUYXA7XG59XG5cbi8qKlxuICogVXNlciBjYW4gdGhlIHJlcGxhY2Ugd2l0aCBpdHMgb3duIHNlcnZpY2VcbiAqL1xuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCcsXG59KVxuZXhwb3J0IGNsYXNzIFRhcENvbm5lY3Rpb25TZXJ2aWNlIHtcbiAgcHJpdmF0ZSB0YXBGYWN0b3J5OiAocHJvdG9jb2w6IENvbVByb3RvY29sKSA9PiBUYXAgPSAocHJvdG9jb2wpID0+IHtcbiAgICByZXR1cm4gVGFwLmZyb21Qcm90b2NvbChwcm90b2NvbCk7XG4gIH07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSB0YXBTZXJ2aWNlOiBDdXJyZW50RGV2aWNlU2VydmljZSxcbiAgICBwcml2YXRlIHByb3RvY29sRmFjdG9yeTogUHJvdG9jb2xGYWN0b3J5U2VydmljZVxuICApIHt9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIFRhcCBjb25uZWN0aW9uIE9ic2VydmFibGUgc2hhcmVkIHN0cmVhbVxuICAgKi9cbiAgY29ubmVjdChcbiAgICBtZXRhOiBQcm90b2NvbE1ldGEsXG4gICAgY29uZmlnOiBUYXBDb25uZWN0aW9uT3B0aW9uc1xuICApOiBPYnNlcnZhYmxlPENvbm5lY3Rpb25FdmVudD4ge1xuICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZSgoZW1pdHRlcjogU3Vic2NyaWJlcjxDb25uZWN0aW9uRXZlbnQ+KSA9PiB7XG4gICAgICBjb25zdCBzdWJzY3JpcHRpb24gPSB0aGlzLmNyZWF0ZUNvbm5lY3Rpb25PYnNlcnZhYmxlKFxuICAgICAgICBtZXRhLFxuICAgICAgICBjb25maWcsXG4gICAgICAgIGVtaXR0ZXJcbiAgICAgICkuc3Vic2NyaWJlKHtcbiAgICAgICAgZXJyb3I6IGFzeW5jIChlcnIpID0+IHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oYFRhcCBjb25uZWN0aW9uIGZhaWxlZCB3aXRoIGVycm9yYCwgZXJyKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLnRhcFNlcnZpY2VcbiAgICAgICAgICAgIC5yZW1vdmUoZmFsc2UpXG4gICAgICAgICAgICAuY2F0Y2goKGVycikgPT4gY29uc29sZS53YXJuKCdpZ25vcmVkIGVycm9yJywgZXJyKSk7XG4gICAgICAgICAgZW1pdHRlci5lcnJvcihlcnIpO1xuICAgICAgICB9LFxuICAgICAgICBjb21wbGV0ZTogKCkgPT4gZW1pdHRlci5jb21wbGV0ZSgpLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgIH07XG4gICAgfSkucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gIH1cblxuICBjcmVhdGVDb25uZWN0aW9uT2JzZXJ2YWJsZShcbiAgICBwcm90b2NvbE1ldGE6IFByb3RvY29sTWV0YSxcbiAgICBjb25maWc6IFRhcENvbm5lY3Rpb25PcHRpb25zLFxuICAgIGVtaXR0ZXI6IFN1YnNjcmliZXI8Q29ubmVjdGlvbkV2ZW50PlxuICApIHtcbiAgICBsZXQgY29ubmVjdE9ic2VydmFibGUgPSBkZWZlcihhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBwcm90b2NvbCA9IGF3YWl0IHRoaXMucHJvdG9jb2xGYWN0b3J5LmNyZWF0ZShwcm90b2NvbE1ldGEpO1xuICAgICAgY29uc3QgdGFwID0gdGhpcy50YXBGYWN0b3J5KHByb3RvY29sKTtcbiAgICAgIGVtaXR0ZXIubmV4dCh7XG4gICAgICAgIG1lc3NhZ2U6IGBJbml0aWFsaXplIFRhcCBmcm9tICR7cHJvdG9jb2xNZXRhLnR5cGV9Li4uYCxcbiAgICAgICAgdGFwLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gdGFwO1xuICAgIH0pO1xuXG4gICAgaWYgKGNvbmZpZy5lbmNyeXB0aW9uKSB7XG4gICAgICBjb25zdCBlbmNyeXB0aW9uT3B0aW9ucyA9IGNvbmZpZy5lbmNyeXB0aW9uO1xuICAgICAgY29ubmVjdE9ic2VydmFibGUgPSBjb25uZWN0T2JzZXJ2YWJsZS5waXBlKFxuICAgICAgICBzd2l0Y2hNYXAoYXN5bmMgKHRhcCkgPT4ge1xuICAgICAgICAgIGVtaXR0ZXIubmV4dCh7XG4gICAgICAgICAgICBtZXNzYWdlOiBgRW5hYmxlIGVuY3J5cHRpb24uLi5gLFxuICAgICAgICAgICAgdGFwLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGlmIChlbmNyeXB0aW9uT3B0aW9ucy5rZXlzKSB7XG4gICAgICAgICAgICBkZWJ1ZyhUQUcsICdTZXQgZW5jcnlwdGlvbiBrZXlzOiAnLCBlbmNyeXB0aW9uT3B0aW9ucy5rZXlzKTtcbiAgICAgICAgICAgIHRhcC5lbmNyeXB0aW9uLnNldEVuY3J5cHRpb25LZXlzKGVuY3J5cHRpb25PcHRpb25zLmtleXMpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZW5jcnlwdGlvbk9wdGlvbnMuZW5jcnlwdGlvbikge1xuICAgICAgICAgICAgaWYgKCF0YXAuZW5jcnlwdGlvbi5zZXNzaW9uS2V5ICYmICF0YXAuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgICAgICAgICBhd2FpdCB0YXAuY29ubmVjdCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGFwLmVuY3J5cHRpb24ucmVzdW1lKCk7XG4gICAgICAgICAgICBkZWJ1ZyhUQUcsICdFbmFibGUgZW5jcnlwdGlvbjogJywgZW5jcnlwdGlvbk9wdGlvbnMuZW5jcnlwdGlvbik7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChlbmNyeXB0aW9uT3B0aW9ucy5mcmFtZUNvdW50ZXIgIT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0YXAuZW5jcnlwdGlvbi5zZXRFbmNyeXB0ZWRGcmFtZUNvdW50ZXIoXG4gICAgICAgICAgICAgIGVuY3J5cHRpb25PcHRpb25zLmZyYW1lQ291bnRlclxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHRhcDtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29ubmVjdE9ic2VydmFibGUgPSBjb25uZWN0T2JzZXJ2YWJsZS5waXBlKFxuICAgICAgc3dpdGNoTWFwKGFzeW5jICh0YXApID0+IHtcbiAgICAgICAgaWYgKHRoaXMudGFwU2VydmljZS5oYXNUYXApIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnRhcFNlcnZpY2UucmVtb3ZlKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50YXBTZXJ2aWNlLnNldFRhcEZyb21FdmVudChcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwcm90b2NvbE1ldGE6IHByb3RvY29sTWV0YSxcbiAgICAgICAgICAgIHRhcDogdGFwLFxuICAgICAgICAgIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgZW1pdDogZmFsc2UsIC8vIFdlIGVtaXQgb25seSBhdCB0aGUgZW5kIG9mIGluaXRpYWxpc2F0aW9uXG4gICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgICB0YXAua2VlcEFsaXZlLnN0b3AoKTtcbiAgICAgICAgcmV0dXJuIHRhcDtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGlmIChwcm90b2NvbE1ldGEudHlwZSA9PT0gJ25mYycpIHtcbiAgICAgIGlmIChjb25maWcubmZjUGFpcmluZykge1xuICAgICAgICBjb25uZWN0T2JzZXJ2YWJsZSA9IGNvbm5lY3RPYnNlcnZhYmxlLnBpcGUoXG4gICAgICAgICAgc3dpdGNoTWFwKGFzeW5jICh0YXApID0+IHtcbiAgICAgICAgICAgIGVtaXR0ZXIubmV4dCh7XG4gICAgICAgICAgICAgIG1lc3NhZ2U6IGBORkMgcGFpcmluZy4uLmAsXG4gICAgICAgICAgICAgIHRhcCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZGVidWcoVEFHLCAnbmZjUGFpcmluZycpO1xuICAgICAgICAgICAgYXdhaXQgdGFwLmNvbm5lY3QoKTtcbiAgICAgICAgICAgIGF3YWl0IHRhcC5uZmNQYWlyaW5nKCk7XG4gICAgICAgICAgICByZXR1cm4gdGFwO1xuICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGNvbmZpZy5yZWdpc3RlclByb3RvY29sc01ldGhvZCAhPT0gZmFsc2UpIHtcbiAgICAgIGNvbm5lY3RPYnNlcnZhYmxlID0gY29ubmVjdE9ic2VydmFibGUucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKGFzeW5jICh0YXApID0+IHtcbiAgICAgICAgICBpZiAoIXRhcC5pc0Nvbm5lY3RlZCgpKSB7XG4gICAgICAgICAgICBlbWl0dGVyLm5leHQoe1xuICAgICAgICAgICAgICBtZXNzYWdlOiBgQ29ubmVjdGluZyB3aXRoICR7cHJvdG9jb2xNZXRhLnR5cGV9Li4uYCxcbiAgICAgICAgICAgICAgdGFwLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBhd2FpdCB0YXAuY29ubmVjdCgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBlbWl0dGVyLm5leHQoe1xuICAgICAgICAgICAgbWVzc2FnZTogYEluaXRpYWxpemluZyBwcm90b2NvbHMuLi5gLFxuICAgICAgICAgICAgdGFwLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGF3YWl0IHRoaXMucmVnaXN0ZXJBbHRlcm5hdGl2ZVByb3RvY29scyhcbiAgICAgICAgICAgIGNvbmZpZy5yZWdpc3RlclByb3RvY29sc01ldGhvZCxcbiAgICAgICAgICAgIHByb3RvY29sTWV0YVxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIHRhcDtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3Qgc3dpdGNoUHJvdG9jb2wgPSBjb25maWcuc3dpdGNoUHJvdG9jb2w7XG4gICAgaWYgKHByb3RvY29sTWV0YS50eXBlID09PSAnbmZjJykge1xuICAgICAgY29ubmVjdE9ic2VydmFibGUgPSBjb25uZWN0T2JzZXJ2YWJsZS5waXBlKFxuICAgICAgICBzd2l0Y2hNYXAoYXN5bmMgKHRhcCkgPT4ge1xuICAgICAgICAgIGlmIChzd2l0Y2hQcm90b2NvbCkge1xuICAgICAgICAgICAgY29uc3QgcHJvdG9jb2xNZXRhID0gdGhpcy50YXBTZXJ2aWNlLmF2YWlsYWJsZVByb3RvY29scy5maW5kKFxuICAgICAgICAgICAgICBMT05HX1JBTkdFX1BST1RPQ09MX0ZJTFRFUlxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChwcm90b2NvbE1ldGEpIHtcbiAgICAgICAgICAgICAgZGVidWcoVEFHLCAnVXNpbmcgbG9uZyByYW5nZSBwcm90b2NvbDogJywgcHJvdG9jb2xNZXRhKTtcbiAgICAgICAgICAgICAgZW1pdHRlci5uZXh0KHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3dpdGNoIHRvICR7cHJvdG9jb2xNZXRhLnR5cGV9YCxcbiAgICAgICAgICAgICAgICB0YXAsXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICBhd2FpdCB0aGlzLnRhcFNlcnZpY2UudXNlUHJvdG9jb2xGcm9tTWV0YShwcm90b2NvbE1ldGEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkZWJ1ZyhUQUcsICdrZWVwIE5GQyBwcm90b2NvbCcpO1xuICAgICAgICAgICAgY29uc3QgbmZjUHJvdG9jb2wgPSB0YXAucHJvdG9jb2wgYXMgTkZDQ29tUHJvdG9jb2w7XG4gICAgICAgICAgICAvLyBmb3IgTkZDIGNvbm5lY3Rpb25cbiAgICAgICAgICAgIGF3YWl0IG5mY1Byb3RvY29sLl9jb25uZWN0KCkudG9Qcm9taXNlKCk7XG4gICAgICAgICAgICBuZmNQcm90b2NvbC5zZXRDb25uZWN0aW9uU3RhdGUoQ29ubmVjdGlvblN0YXRlLkNPTk5FQ1RFRCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0YXA7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChjb25maWcucmVmcmVzaFNlc3Npb25TdGF0ZSkge1xuICAgICAgY29ubmVjdE9ic2VydmFibGUgPSBjb25uZWN0T2JzZXJ2YWJsZS5waXBlKFxuICAgICAgICBzd2l0Y2hNYXAoYXN5bmMgKHRhcCkgPT4ge1xuICAgICAgICAgIGlmICghdGFwLmlzQ29ubmVjdGVkKCkpIHtcbiAgICAgICAgICAgIGVtaXR0ZXIubmV4dCh7XG4gICAgICAgICAgICAgIG1lc3NhZ2U6IGBDb25uZWN0aW5nIHdpdGggJHtwcm90b2NvbE1ldGEudHlwZX0uLi5gLFxuICAgICAgICAgICAgICB0YXAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGF3YWl0IHRhcC5jb25uZWN0KCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGRlYnVnKFRBRywgJ3JlZnJlc2hTZXNzaW9uU3RhdGUnKTtcbiAgICAgICAgICBlbWl0dGVyLm5leHQoe1xuICAgICAgICAgICAgbWVzc2FnZTogJ1JlZnJlc2hpbmcgdXNlciBzZXNzaW9uLi4uJyxcbiAgICAgICAgICAgIHRhcCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBhd2FpdCB0YXAuYXV0aC5yZWZyZXNoU2Vzc2lvblN0YXRlKCk7XG4gICAgICAgICAgcmV0dXJuIHRhcDtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKGNvbmZpZy5rZWVwQWxpdmUgIT09IGZhbHNlICYmIGNvbmZpZy5rZWVwQWxpdmUgIT09IDApIHtcbiAgICAgIGNvbm5lY3RPYnNlcnZhYmxlID0gY29ubmVjdE9ic2VydmFibGUucGlwZShcbiAgICAgICAgdGFwKCh0YXApID0+IHtcbiAgICAgICAgICBpZiAodHlwZW9mIGNvbmZpZy5rZWVwQWxpdmUgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICB0YXAua2VlcEFsaXZlLnBlcmlvZCA9IGNvbmZpZy5rZWVwQWxpdmU7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRhcC5rZWVwQWxpdmUuc3RhcnQoKTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbm5lY3RPYnNlcnZhYmxlLnBpcGUoXG4gICAgICBtYXAoKHRhcCkgPT4ge1xuICAgICAgICB0aGlzLnRhcFNlcnZpY2Uubm90aWZ5TmV3VGFwKCk7XG4gICAgICAgIHJldHVybiB0YXA7XG4gICAgICB9KSxcbiAgICAgIGNhdGNoRXJyb3IoKG9yaWdpbmFsRXJyb3IpID0+IHtcbiAgICAgICAgY29uc29sZS53YXJuKGBUYXAgY29ubmVjdGlvbiBmYWlsZWQgd2l0aCBlcnJvcmAsIG9yaWdpbmFsRXJyb3IpO1xuICAgICAgICByZXR1cm4gZGVmZXIoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGF3YWl0IHRoaXMudGFwU2VydmljZVxuICAgICAgICAgICAgLnJlbW92ZShmYWxzZSlcbiAgICAgICAgICAgIC5jYXRjaCgoZXJyKSA9PiBjb25zb2xlLndhcm4oJ2lnbm9yZWQgZXJyb3InLCBlcnIpKTtcbiAgICAgICAgICB0aHJvdyBvcmlnaW5hbEVycm9yO1xuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIHJlZ2lzdGVyQWx0ZXJuYXRpdmVQcm90b2NvbHMoXG4gICAgcmVnaXN0ZXJBbHRlcm5hdGl2ZVByb3RvY29sTWV0aG9kOlxuICAgICAgfCBUYXBSZWdpc3RlclByb3RvY29sc01ldGhvZFxuICAgICAgfCBmYWxzZVxuICAgICAgfCB1bmRlZmluZWQsXG4gICAgaW5pdGlhbFByb3RvY29sTWV0YTogUHJvdG9jb2xNZXRhXG4gICkge1xuICAgIGlmIChyZWdpc3RlckFsdGVybmF0aXZlUHJvdG9jb2xNZXRob2QgPT09IGZhbHNlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJlZ2lzdGVyQWx0ZXJuYXRpdmVQcm90b2NvbE1ldGhvZCA9XG4gICAgICByZWdpc3RlckFsdGVybmF0aXZlUHJvdG9jb2xNZXRob2QgfHxcbiAgICAgIFRhcFJlZ2lzdGVyUHJvdG9jb2xzTWV0aG9kLk5ERUZfT1JfU0VSVklDRTtcbiAgICBkZWJ1ZyhcbiAgICAgIFRBRyxcbiAgICAgIGBSZWdpc3RlciBhbHRlcm5hdGl2ZSBwcm90b2NvbHMgd2l0aCBtZXRob2Q6ICR7cmVnaXN0ZXJBbHRlcm5hdGl2ZVByb3RvY29sTWV0aG9kfWBcbiAgICApO1xuICAgIGNvbnN0IHRhcCA9IHRoaXMudGFwU2VydmljZS50YXA7XG4gICAgc3dpdGNoIChyZWdpc3RlckFsdGVybmF0aXZlUHJvdG9jb2xNZXRob2QpIHtcbiAgICAgIGNhc2UgVGFwUmVnaXN0ZXJQcm90b2NvbHNNZXRob2QuTkRFRl9PUl9TRVJWSUNFOlxuICAgICAgICBsZXQgcmVnaXN0ZXJlZFByb3RvY29sTWV0YTogUHJvdG9jb2xNZXRhIHwgdW5kZWZpbmVkO1xuICAgICAgICBpZiAoIXRhcC5pc0Nvbm5lY3RlZCgpKSB7XG4gICAgICAgICAgYXdhaXQgdGFwLmNvbm5lY3QoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaW5pdGlhbFByb3RvY29sTWV0YS50eXBlID09PSAnbmZjJykge1xuICAgICAgICAgIHJlZ2lzdGVyZWRQcm90b2NvbE1ldGEgPVxuICAgICAgICAgICAgYXdhaXQgdGhpcy50YXBTZXJ2aWNlLnJlZ2lzdGVyUHJvdG9jb2xzRnJvbVRhZyhcbiAgICAgICAgICAgICAgaW5pdGlhbFByb3RvY29sTWV0YS5pbmZvLnRhZ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnRhcFNlcnZpY2UucmVnaXN0ZXJQcm90b2NvbHNGcm9tVGFwKCkuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdGYWlsZWQgdG8gcmVnaXN0ZXIgcHJvdG9jb2xzIGZyb20gdGFwJywgZXJyKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgVGFwUmVnaXN0ZXJQcm90b2NvbHNNZXRob2QuU0VSVklDRV9PTkxZOlxuICAgICAgICBpZiAoIXRhcC5pc0Nvbm5lY3RlZCgpKSB7XG4gICAgICAgICAgYXdhaXQgdGFwLmNvbm5lY3QoKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLnRhcFNlcnZpY2UucmVnaXN0ZXJQcm90b2NvbHNGcm9tVGFwKCkuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgIGNvbnNvbGUud2FybignRmFpbGVkIHRvIHJlZ2lzdGVyIHByb3RvY29scyBmcm9tIHRhcCcsIGVycik7XG4gICAgICAgIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgVGFwUmVnaXN0ZXJQcm90b2NvbHNNZXRob2QuTkRFRl9PTkxZOlxuICAgICAgICBpZiAoaW5pdGlhbFByb3RvY29sTWV0YS50eXBlID09PSAnbmZjJykge1xuICAgICAgICAgIGF3YWl0IHRoaXMudGFwU2VydmljZS5yZWdpc3RlclByb3RvY29sc0Zyb21UYWcoXG4gICAgICAgICAgICBpbml0aWFsUHJvdG9jb2xNZXRhLmluZm8udGFnXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cbn1cbiJdfQ==