UNPKG

@hsaadawy/ngx-chat

Version:
225 lines 39 kB
import { jid as parseJid, xml } from '@xmpp/client'; import { Presence } from '../../../../core/presence'; import { ContactSubscription } from '../../../../core/subscription'; import { AbstractXmppPlugin } from './abstract-xmpp-plugin'; /** * https://xmpp.org/rfcs/rfc6121.html#roster-add-success */ export class RosterPlugin extends AbstractXmppPlugin { constructor(chatService, logService) { super(); this.chatService = chatService; this.logService = logService; } handleStanza(stanza) { if (this.isCapabilitiesStanza(stanza)) { return false; } if (this.isRosterPushStanza(stanza)) { return this.handleRosterPushStanza(stanza); } else if (this.isPresenceStanza(stanza)) { return this.handlePresenceStanza(stanza); } return false; } isRosterPushStanza(stanza) { return stanza.name === 'iq' && stanza.attrs.type === 'set' && stanza.getChild('query', 'jabber:iq:roster'); } isPresenceStanza(stanza) { return stanza.name === 'presence' && !stanza.getChild('x', 'http://jabber.org/protocol/muc#user'); } isCapabilitiesStanza(stanza) { const child = stanza.getChild('c', 'http://jabber.org/protocol/caps'); return !!child; } handleRosterPushStanza(stanza) { // TODO: // Security Warning: Traditionally, a roster push included no 'from' address, with the result that all roster pushes were sent // implicitly from the bare JID of the account itself. However, this specification allows entities other than the user's server // to maintain roster information, which means that a roster push might include a 'from' address other than the bare JID of the // user's account. Therefore, the client MUST check the 'from' address to verify that the sender of the roster push is authorized // to update the roster. If the client receives a roster push from an unauthorized entity, it MUST NOT process the pushed data; in // addition, the client can either return a stanza error of <service-unavailable/> error or refuse to return a stanza error at all // (the latter behavior overrides a MUST-level requirement from [XMPP‑CORE] for the purpose of preventing a presence leak). const itemChild = stanza.getChild('query').getChild('item'); const contact = this.chatService.getOrCreateContactById(itemChild.attrs.jid, itemChild.attrs.name || itemChild.attrs.jid); contact.pendingOut$.next(itemChild.attrs.ask === 'subscribe'); const subscriptionStatus = itemChild.attrs.subscription || 'none'; this.chatService.chatConnectionService.sendIqAckResult(stanza.attrs.id); let handled = false; if (subscriptionStatus === 'remove') { contact.pendingOut$.next(false); contact.subscription$.next(ContactSubscription.none); handled = true; } else if (subscriptionStatus === 'none') { contact.subscription$.next(ContactSubscription.none); handled = true; } else if (subscriptionStatus === 'to') { contact.subscription$.next(ContactSubscription.to); handled = true; } else if (subscriptionStatus === 'from') { contact.subscription$.next(ContactSubscription.from); handled = true; } else if (subscriptionStatus === 'both') { contact.subscription$.next(ContactSubscription.both); handled = true; } if (handled) { const existingContacts = this.chatService.contacts$.getValue(); this.chatService.contacts$.next(existingContacts); } return handled; } handlePresenceStanza(stanza) { const fromAsContact = this.chatService.getOrCreateContactById(stanza.attrs.from); const isAddressedToMe = this.chatService.chatConnectionService.userJid.bare().equals(parseJid(stanza.attrs.to).bare()); if (isAddressedToMe) { if (!stanza.attrs.type) { // https://xmpp.org/rfcs/rfc3921.html#stanzas-presence-children-show const show = stanza.getChildText('show'); const presenceMapping = { chat: Presence.present, null: Presence.present, away: Presence.away, dnd: Presence.away, xa: Presence.away, }; const presence = presenceMapping[show]; if (presence) { fromAsContact.updateResourcePresence(stanza.attrs.from, presence); } else { this.logService.error('illegal presence:', stanza.attrs.from, show); } return true; } else if (stanza.attrs.type === 'unavailable') { fromAsContact.updateResourcePresence(stanza.attrs.from, Presence.unavailable); return true; } else if (stanza.attrs.type === 'subscribe') { if (fromAsContact.isSubscribed() || fromAsContact.pendingOut$.getValue()) { // subscriber is already a contact of us, approve subscription fromAsContact.pendingIn$.next(false); this.sendAcceptPresenceSubscriptionRequest(stanza.attrs.from); fromAsContact.subscription$.next(this.transitionSubscriptionRequestReceivedAccepted(fromAsContact.subscription$.getValue())); this.chatService.contacts$.next(this.chatService.contacts$.getValue()); return true; } else if (fromAsContact) { // subscriber is known but not subscribed or pending fromAsContact.pendingIn$.next(true); this.chatService.contacts$.next(this.chatService.contacts$.getValue()); return true; } } else if (stanza.attrs.type === 'subscribed') { fromAsContact.pendingOut$.next(false); fromAsContact.subscription$.next(this.transitionSubscriptionRequestSentAccepted(fromAsContact.subscription$.getValue())); this.chatService.contacts$.next(this.chatService.contacts$.getValue()); return true; } else if (stanza.attrs.type === 'unsubscribed') { // TODO: handle unsubscribed } else if (stanza.attrs.type === 'unsubscribe') { // TODO: handle unsubscribe } } return false; } transitionSubscriptionRequestReceivedAccepted(subscription) { switch (subscription) { case ContactSubscription.none: return ContactSubscription.from; case ContactSubscription.to: return ContactSubscription.both; default: return subscription; } } transitionSubscriptionRequestSentAccepted(subscription) { switch (subscription) { case ContactSubscription.none: return ContactSubscription.to; case ContactSubscription.from: return ContactSubscription.both; default: return subscription; } } sendAcceptPresenceSubscriptionRequest(jid) { const contact = this.chatService.getOrCreateContactById(jid); contact.pendingIn$.next(false); this.chatService.chatConnectionService.send(xml('presence', { to: jid, type: 'subscribed', id: this.chatService.chatConnectionService.getNextIqId() })); } onBeforeOnline() { return this.refreshRosterContacts(); } getRosterContacts() { return new Promise((resolve) => this.chatService.chatConnectionService.sendIq(xml('iq', { type: 'get' }, xml('query', { xmlns: 'jabber:iq:roster' }))).then((responseStanza) => resolve(this.convertToContacts(responseStanza)), (responseStanza) => { this.logService.error('error converting roster contact push', responseStanza.toString()); resolve([]); })); } convertToContacts(responseStanza) { return responseStanza.getChild('query').getChildElements() .map(rosterElement => { const contact = this.chatService.getOrCreateContactById(rosterElement.attrs.jid, rosterElement.attrs.name || rosterElement.attrs.jid); contact.subscription$.next(this.parseSubscription(rosterElement.attrs.subscription)); contact.pendingOut$.next(rosterElement.attrs.ask === 'subscribe'); return contact; }); } parseSubscription(subscription) { switch (subscription) { case 'to': return ContactSubscription.to; case 'from': return ContactSubscription.from; case 'both': return ContactSubscription.both; case 'none': default: return ContactSubscription.none; } } addRosterContact(jid) { this.sendAcceptPresenceSubscriptionRequest(jid); this.sendAddToRoster(jid); this.sendSubscribeToPresence(jid); } sendAddToRoster(jid) { return this.chatService.chatConnectionService.sendIq(xml('iq', { type: 'set' }, xml('query', { xmlns: 'jabber:iq:roster' }, xml('item', { jid })))); } sendSubscribeToPresence(jid) { this.chatService.chatConnectionService.send(xml('presence', { id: this.chatService.chatConnectionService.getNextIqId(), to: jid, type: 'subscribe' })); } removeRosterContact(jid) { const contact = this.chatService.getContactById(jid); if (contact) { contact.subscription$.next(ContactSubscription.none); contact.pendingOut$.next(false); contact.pendingIn$.next(false); this.sendRemoveFromRoster(jid); this.sendWithdrawPresenceSubscription(jid); } } sendRemoveFromRoster(jid) { this.chatService.chatConnectionService.sendIq(xml('iq', { type: 'set' }, xml('query', { xmlns: 'jabber:iq:roster' }, xml('item', { jid, subscription: 'remove' })))); } sendWithdrawPresenceSubscription(jid) { this.chatService.chatConnectionService.send(xml('presence', { id: this.chatService.chatConnectionService.getNextIqId(), to: jid, type: 'unsubscribed' })); } refreshRosterContacts() { return this.getRosterContacts(); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9zdGVyLnBsdWdpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3BhenpuZXR3b3JrL25neC1jaGF0L3NyYy9saWIvc2VydmljZXMvYWRhcHRlcnMveG1wcC9wbHVnaW5zL3Jvc3Rlci5wbHVnaW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEdBQUcsSUFBSSxRQUFRLEVBQUUsR0FBRyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRXBELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUVyRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUdwRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUU1RDs7R0FFRztBQUNILE1BQU0sT0FBTyxZQUFhLFNBQVEsa0JBQWtCO0lBRWhELFlBQ1ksV0FBNEIsRUFDNUIsVUFBc0I7UUFFOUIsS0FBSyxFQUFFLENBQUM7UUFIQSxnQkFBVyxHQUFYLFdBQVcsQ0FBaUI7UUFDNUIsZUFBVSxHQUFWLFVBQVUsQ0FBWTtJQUdsQyxDQUFDO0lBRUQsWUFBWSxDQUFDLE1BQWM7UUFDdkIsSUFBSSxJQUFJLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDbkMsT0FBTyxLQUFLLENBQUM7U0FDaEI7UUFDRCxJQUFJLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUNqQyxPQUFPLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztTQUM5QzthQUFNLElBQUksSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQ3RDLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1NBQzVDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDakIsQ0FBQztJQUVPLGtCQUFrQixDQUFD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TyxvQkFBb0IsQ0FBQyxHQUFXO1FBQ3BDLElBQUksQ0FBQyxXQUFXLENBQUMscUJBQXFCLENBQUMsTUFBTSxDQUN6QyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUMsSUFBSSxFQUFFLEtBQUssRUFBQyxFQUNuQixHQUFHLENBQUMsT0FBTyxFQUFFLEVBQUMsS0FBSyxFQUFFLGtCQUFrQixFQUFDLEVBQ3BDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsRUFBQyxHQUFHLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVPLGdDQUFnQyxDQUFDLEdBQVc7UUFDaEQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQ3ZDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsRUFBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxxQkFBcUIsQ0FBQyxXQUFXLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxjQUFjLEVBQUMsQ0FBQyxDQUM3RyxDQUFDO0lBQ04sQ0FBQztJQUVELHFCQUFxQjtRQUNqQixPQUFPLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO0lBQ3BDLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGppZCBhcyBwYXJzZUppZCwgeG1sIH0gZnJvbSAnQHhtcHAvY2xpZW50JztcclxuaW1wb3J0IHsgQ29udGFjdCB9IGZyb20gJy4uLy4uLy4uLy4uL2NvcmUvY29udGFjdCc7XHJcbmltcG9ydCB7IFByZXNlbmNlIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9wcmVzZW5jZSc7XHJcbmltcG9ydCB7IFByZXNlbmNlU3RhbnphLCBTdGFuemEgfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL3N0YW56YSc7XHJcbmltcG9ydCB7IENvbnRhY3RTdWJzY3JpcHRpb24gfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL3N1YnNjcmlwdGlvbic7XHJcbmltcG9ydCB7IExvZ1NlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9sb2cuc2VydmljZSc7XHJcbmltcG9ydCB7IFhtcHBDaGF0QWRhcHRlciB9IGZyb20gJy4uL3htcHAtY2hhdC1hZGFwdGVyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBBYnN0cmFjdFhtcHBQbHVnaW4gfSBmcm9tICcuL2Fic3RyYWN0LXhtcHAtcGx1Z2luJztcclxuXHJcbi8qKlxyXG4gKiBodHRwczovL3htcHAub3JnL3JmY3MvcmZjNjEyMS5odG1sI3Jvc3Rlci1hZGQtc3VjY2Vzc1xyXG4gKi9cclxuZXhwb3J0IGNsYXNzIFJvc3RlclBsdWdpbiBleHRlbmRzIEFic3RyYWN0WG1wcFBsdWdpbiB7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHJpdmF0ZSBjaGF0U2VydmljZTogWG1wcENoYXRBZGFwdGVyLFxyXG4gICAgICAgIHByaXZhdGUgbG9nU2VydmljZTogTG9nU2VydmljZSxcclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaGFuZGxlU3RhbnphKHN0YW56YTogU3RhbnphKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuaXNDYXBhYmlsaXRpZXNTdGFuemEoc3RhbnphKSkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh0aGlzLmlzUm9zdGVyUHVzaFN0YW56YShzdGFuemEpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmhhbmRsZVJvc3RlclB1c2hTdGFuemEoc3RhbnphKTtcclxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuaXNQcmVzZW5jZVN0YW56YShzdGFuemEpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmhhbmRsZVByZXNlbmNlU3RhbnphKHN0YW56YSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGlzUm9zdGVyUHVzaFN0YW56YShzdGFuemE6IFN0YW56YSkge1xyXG4gICAgICAgIHJldHVybiBzdGFuemEubmFtZSA9PT0gJ2lxJ1xyXG4gICAgICAgICAgICAmJiBzdGFuemEuYXR0cnMudHlwZSA9PT0gJ3NldCdcclxuICAgICAgICAgICAgJiYgc3RhbnphLmdldENoaWxkKCdxdWVyeScsICdqYWJiZXI6aXE6cm9zdGVyJyk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBpc1ByZXNlbmNlU3RhbnphKHN0YW56YTogU3RhbnphKTogc3RhbnphIGlzIFByZXNlbmNlU3RhbnphIHtcclxuICAgICAgICByZXR1cm4gc3RhbnphLm5hbWUgPT09ICdwcmVzZW5jZScgJiYgIXN0YW56YS5nZXRDaGlsZCgneCcsICdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjdXNlcicpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgaXNDYXBhYmlsaXRpZXNTdGFuemEoc3RhbnphOiBTdGFuemEpIHtcclxuICAgICAgICBjb25zdCBjaGlsZCA9IHN0YW56YS5nZXRDaGlsZCgnYycsICdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9jYXBzJyk7XHJcbiAgICAgICAgcmV0dXJuICEhY2hpbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBoYW5kbGVSb3N0ZXJQdXNoU3RhbnphKHN0YW56YTogU3RhbnphKSB7XHJcblxyXG4gICAgICAgIC8vIFRPRE86XHJcbiAgICAgICAgLy8gU2VjdXJpdHkgV2FybmluZzogVHJhZGl0aW9uYWxseSwgYSByb3N0ZXIgcHVzaCBpbmNsdWRlZCBubyAnZnJvbScgYWRkcmVzcywgd2l0aCB0aGUgcmVzdWx0IHRoYXQgYWxsIHJvc3RlciBwdXNoZXMgd2VyZSBzZW50XHJcbiAgICAgICAgLy8gaW1wbGljaXRseSBmcm9tIHRoZSBiYXJlIEpJRCBvZiB0aGUgYWNjb3VudCBpdHNlbGYuIEhvd2V2ZXIsIHRoaXMgc3BlY2lmaWNhdGlvbiBhbGxvd3MgZW50aXRpZXMgb3RoZXIgdGhhbiB0aGUgdXNlcidzIHNlcnZlclxyXG4gICAgICAgIC8vIHRvIG1haW50YWluIHJvc3RlciBpbmZvcm1hdGlvbiwgd2hpY2ggbWVhbnMgdGhhdCBhIHJvc3RlciBwdXNoIG1pZ2h0IGluY2x1ZGUgYSAnZnJvbScgYWRkcmVzcyBvdGhlciB0aGFuIHRoZSBiYXJlIEpJRCBvZiB0aGVcclxuICAgICAgICAvLyB1c2VyJ3MgYWNjb3VudC4gVGhlcmVmb3JlLCB0aGUgY2xpZW50IE1VU1QgY2hlY2sgdGhlICdmcm9tJyBhZGRyZXNzIHRvIHZlcmlmeSB0aGF0IHRoZSBzZW5kZXIgb2YgdGhlIHJvc3RlciBwdXNoIGlzIGF1dGhvcml6ZWRcclxuICAgICAgICAvLyB0byB1cGRhdGUgdGhlIHJvc3Rlci4gSWYgdGhlIGNsaWVudCByZWNlaXZlcyBhIHJvc3RlciBwdXNoIGZyb20gYW4gdW5hdXRob3JpemVkIGVudGl0eSwgaXQgTVVTVCBOT1QgcHJvY2VzcyB0aGUgcHVzaGVkIGRhdGE7IGluXHJcbiAgICAgICAgLy8gYWRkaXRpb24sIHRoZSBjbGllbnQgY2FuIGVpdGhlciByZXR1cm4gYSBzdGFuemEgZXJyb3Igb2YgPHNlcnZpY2UtdW5hdmFpbGFibGUvPiBlcnJvciBvciByZWZ1c2UgdG8gcmV0dXJuIGEgc3RhbnphIGVycm9yIGF0IGFsbFxyXG4gICAgICAgIC8vICh0aGUgbGF0dGVyIGJlaGF2aW9yIG92ZXJyaWRlcyBhIE1VU1QtbGV2ZWwgcmVxdWlyZW1lbnQgZnJvbSBbWE1QUOKAkUNPUkVdIGZvciB0aGUgcHVycG9zZSBvZiBwcmV2ZW50aW5nIGEgcHJlc2VuY2UgbGVhaykuXHJcblxyXG4gICAgICAgIGNvbnN0IGl0ZW1DaGlsZCA9IHN0YW56YS5nZXRDaGlsZCgncXVlcnknKS5nZXRDaGlsZCgnaXRlbScpO1xyXG4gICAgICAgIGNvbnN0IGNvbnRhY3QgPSB0aGlzLmNoYXRTZXJ2aWNlLmdldE9yQ3JlYXRlQ29udGFjdEJ5SWQoaXRlbUNoaWxkLmF0dHJzLmppZCwgaXRlbUNoaWxkLmF0dHJzLm5hbWUgfHwgaXRlbUNoaWxkLmF0dHJzLmppZCk7XHJcbiAgICAgICAgY29udGFjdC5wZW5kaW5nT3V0JC5uZXh0KGl0ZW1DaGlsZC5hdHRycy5hc2sgPT09ICdzdWJzY3JpYmUnKTtcclxuICAgICAgICBjb25zdCBzdWJzY3JpcHRpb25TdGF0dXMgPSBpdGVtQ2hpbGQuYXR0cnMuc3Vic2NyaXB0aW9uIHx8ICdub25lJztcclxuXHJcbiAgICAgICAgdGhpcy5jaGF0U2VydmljZS5jaGF0Q29ubmVjdGlvblNlcnZpY2Uuc2VuZElxQWNrUmVzdWx0KHN0YW56YS5hdHRycy5pZCk7XHJcblxyXG4gICAgICAgIGxldCBoYW5kbGVkID0gZmFsc2U7XHJcblxyXG4gICAgICAgIGlmIChzdWJzY3JpcHRpb25TdGF0dXMgPT09ICdyZW1vdmUnKSB7XHJcbiAgICAgICAgICAgIGNvbnRhY3QucGVuZGluZ091dCQubmV4dChmYWxzZSk7XHJcbiAgICAgICAgICAgIGNvbnRhY3Quc3Vic2NyaXB0aW9uJC5uZXh0KENvbnRhY3RTdWJzY3JpcHRpb24ubm9uZSk7XHJcbiAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoc3Vic2NyaXB0aW9uU3RhdHVzID09PSAnbm9uZScpIHtcclxuICAgICAgICAgICAgY29udGFjdC5zdWJzY3JpcHRpb24kLm5leHQoQ29udGFjdFN1YnNjcmlwdGlvbi5ub25lKTtcclxuICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgfSBlbHNlIGlmIChzdWJzY3JpcHRpb25TdGF0dXMgPT09ICd0bycpIHtcclxuICAgICAgICAgICAgY29udGFjdC5zdWJzY3JpcHRpb24kLm5leHQoQ29udGFjdFN1YnNjcmlwdGlvbi50byk7XHJcbiAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoc3Vic2NyaXB0aW9uU3RhdHVzID09PSAnZnJvbScpIHtcclxuICAgICAgICAgICAgY29udGFjdC5zdWJzY3JpcHRpb24kLm5leHQoQ29udGFjdFN1YnNjcmlwdGlvbi5mcm9tKTtcclxuICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgfSBlbHNlIGlmIChzdWJzY3JpcHRpb25TdGF0dXMgPT09ICdib3RoJykge1xyXG4gICAgICAgICAgICBjb250YWN0LnN1YnNjcmlwdGlvbiQubmV4dChDb250YWN0U3Vic2NyaXB0aW9uLmJvdGgpO1xyXG4gICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChoYW5kbGVkKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGV4aXN0aW5nQ29udGFjdHMgPSB0aGlzLmNoYXRTZXJ2aWNlLmNvbnRhY3RzJC5nZXRWYWx1ZSgpO1xyXG4gICAgICAgICAgICB0aGlzLmNoYXRTZXJ2aWNlLmNvbnRhY3RzJC5uZXh0KGV4aXN0aW5nQ29udGFjdHMpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIGhhbmRsZWQ7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBoYW5kbGVQcmVzZW5jZVN0YW56YShzdGFuemE6IFByZXNlbmNlU3RhbnphKSB7XHJcbiAgICAgICAgY29uc3QgZnJvbUFzQ29udGFjdCA9IHRoaXMuY2hhdFNlcnZpY2UuZ2V0T3JDcmVhdGVDb250YWN0QnlJZChzdGFuemEuYXR0cnMuZnJvbSk7XHJcbiAgICAgICAgY29uc3QgaXNBZGRyZXNzZWRUb01lID0gdGhpcy5jaGF0U2VydmljZS5jaGF0Q29ubmVjdGlvblNlcnZpY2UudXNlckppZC5iYXJlKCkuZXF1YWxzKHBhcnNlSmlkKHN0YW56YS5hdHRycy50bykuYmFyZSgpKTtcclxuICAgICAgICBpZiAoaXNBZGRyZXNzZWRUb01lKSB7XHJcbiAgICAgICAgICAgIGlmICghc3RhbnphLmF0dHJzLnR5cGUpIHtcclxuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8veG1wcC5vcmcvcmZjcy9yZmMzOTIxLmh0bWwjc3Rhbnphcy1wcmVzZW5jZS1jaGlsZHJlbi1zaG93XHJcbiAgICAgICAgICAgICAgICBjb25zdCBzaG93ID0gc3RhbnphLmdldENoaWxkVGV4dCgnc2hvdycpO1xyXG4gICAgICAgICAgICAgICAgY29uc3QgcHJlc2VuY2VNYXBwaW5nOiB7IFtrZXk6IHN0cmluZ106IFByZXNlbmNlIH0gPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY2hhdDogUHJlc2VuY2UucHJlc2VudCxcclxuICAgICAgICAgICAgICAgICAgICBudWxsOiBQcmVzZW5jZS5wcmVzZW50LFxyXG4gICAgICAgICAgICAgICAgICAgIGF3YXk6IFByZXNlbmNlLmF3YXksXHJcbiAgICAgICAgICAgICAgICAgICAgZG5kOiBQcmVzZW5jZS5hd2F5LFxyXG4gICAgICAgICAgICAgICAgICAgIHhhOiBQcmVzZW5jZS5hd2F5LFxyXG4gICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHByZXNlbmNlID0gcHJlc2VuY2VNYXBwaW5nW3Nob3ddO1xyXG4gICAgICAgICAgICAgICAgaWYgKHByZXNlbmNlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgZnJvbUFzQ29udGFjdC51cGRhdGVSZXNvdXJjZVByZXNlbmNlKHN0YW56YS5hdHRycy5mcm9tLCBwcmVzZW5jZSk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nU2VydmljZS5lcnJvcignaWxsZWdhbCBwcmVzZW5jZTonLCBzdGFuemEuYXR0cnMuZnJvbSwgc2hvdyk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChzdGFuemEuYXR0cnMudHlwZSA9PT0gJ3VuYXZhaWxhYmxlJykge1xyXG4gICAgICAgICAgICAgICAgZnJvbUFzQ29udGFjdC51cGRhdGVSZXNvdXJjZVByZXNlbmNlKHN0YW56YS5hdHRycy5mcm9tLCBQcmVzZW5jZS51bmF2YWlsYWJsZSk7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChzdGFuemEuYXR0cnMudHlwZSA9PT0gJ3N1YnNjcmliZScpIHtcclxuICAgICAgICAgICAgICAgIGlmIChmcm9tQXNDb250YWN0LmlzU3Vic2NyaWJlZCgpIHx8IGZyb21Bc0NvbnRhY3QucGVuZGluZ091dCQuZ2V0VmFsdWUoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIHN1YnNjcmliZXIgaXMgYWxyZWFkeSBhIGNvbnRhY3Qgb2YgdXMsIGFwcHJvdmUgc3Vic2NyaXB0aW9uXHJcbiAgICAgICAgICAgICAgICAgICAgZnJvbUFzQ29udGFjdC5wZW5kaW5nSW4kLm5leHQoZmFsc2UpO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VuZEFjY2VwdFByZXNlbmNlU3Vic2NyaXB0aW9uUmVxdWVzdChzdGFuemEuYXR0cnMuZnJvbSk7XHJcbiAgICAgICAgICAgICAgICAgICAgZnJvbUFzQ29udGFjdC5zdWJzY3JpcHRpb24kLm5leHQoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudHJhbnNpdGlvblN1YnNjcmlwdGlvblJlcXVlc3RSZWNlaXZlZEFjY2VwdGVkKGZyb21Bc0NvbnRhY3Quc3Vic2NyaXB0aW9uJC5nZXRWYWx1ZSgpKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jaGF0U2VydmljZS5jb250YWN0cyQubmV4dCh0aGlzLmNoYXRTZXJ2aWNlLmNvbnRhY3RzJC5nZXRWYWx1ZSgpKTtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZnJvbUFzQ29udGFjdCkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIHN1YnNjcmliZXIgaXMga25vd24gYnV0IG5vdCBzdWJzY3JpYmVkIG9yIHBlbmRpbmdcclxuICAgICAgICAgICAgICAgICAgICBmcm9tQXNDb250YWN0LnBlbmRpbmdJbiQubmV4dCh0cnVlKTtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNoYXRTZXJ2aWNlLmNvbnRhY3RzJC5uZXh0KHRoaXMuY2hhdFNlcnZpY2UuY29udGFjdHMkLmdldFZhbHVlKCkpO1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKHN0YW56YS5hdHRycy50eXBlID09PSAnc3Vic2NyaWJlZCcpIHtcclxuICAgICAgICAgICAgICAgIGZyb21Bc0NvbnRhY3QucGVuZGluZ091dCQubmV4dChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICBmcm9tQXNDb250YWN0LnN1YnNjcmlwdGlvbiQubmV4dCh0aGlzLnRyYW5zaXRpb25TdWJzY3JpcHRpb25SZXF1ZXN0U2VudEFjY2VwdGVkKGZyb21Bc0NvbnRhY3Quc3Vic2NyaXB0aW9uJC5nZXRWYWx1ZSgpKSk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmNoYXRTZXJ2aWNlLmNvbnRhY3RzJC5uZXh0KHRoaXMuY2hhdFNlcnZpY2UuY29udGFjdHMkLmdldFZhbHVlKCkpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoc3RhbnphLmF0dHJzLnR5cGUgPT09ICd1bnN1YnNjcmliZWQnKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBoYW5kbGUgdW5zdWJzY3JpYmVkXHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoc3RhbnphLmF0dHJzLnR5cGUgPT09ICd1bnN1YnNjcmliZScpIHtcclxuICAgICAgICAgICAgICAgIC8vIFRPRE86IGhhbmRsZSB1bnN1YnNjcmliZVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHRyYW5zaXRpb25TdWJzY3JpcHRpb25SZXF1ZXN0UmVjZWl2ZWRBY2NlcHRlZChzdWJzY3JpcHRpb246IENvbnRhY3RTdWJzY3JpcHRpb24pIHtcclxuICAgICAgICBzd2l0Y2ggKHN1YnNjcmlwdGlvbikge1xyXG4gICAgICAgICAgICBjYXNlIENvbnRhY3RTdWJzY3JpcHRpb24ubm9uZTpcclxuICAgICAgICAgICAgICAgIHJldHVybiBDb250YWN0U3Vic2NyaXB0aW9uLmZyb207XHJcbiAgICAgICAgICAgIGNhc2UgQ29udGFjdFN1YnNjcmlwdGlvbi50bzpcclxuICAgICAgICAgICAgICAgIHJldHVybiBDb250YWN0U3Vic2NyaXB0aW9uLmJvdGg7XHJcbiAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gc3Vic2NyaXB0aW9uO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHRyYW5zaXRpb25TdWJzY3JpcHRpb25SZXF1ZXN0U2VudEFjY2VwdGVkKHN1YnNjcmlwdGlvbjogQ29udGFjdFN1YnNjcmlwdGlvbikge1xyXG4gICAgICAgIHN3aXRjaCAoc3Vic2NyaXB0aW9uKSB7XHJcbiAgICAgICAgICAgIGNhc2UgQ29udGFjdFN1YnNjcmlwdGlvbi5ub25lOlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIENvbnRhY3RTdWJzY3JpcHRpb24udG87XHJcbiAgICAgICAgICAgIGNhc2UgQ29udGFjdFN1YnNjcmlwdGlvbi5mcm9tOlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIENvbnRhY3RTdWJzY3JpcHRpb24uYm90aDtcclxuICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgIHJldHVybiBzdWJzY3JpcHRpb247XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgc2VuZEFjY2VwdFByZXNlbmNlU3Vic2NyaXB0aW9uUmVxdWVzdChqaWQ6IHN0cmluZykge1xyXG4gICAgICAgIGNvbnN0IGNvbnRhY3QgPSB0aGlzLmNoYXRTZXJ2aWNlLmdldE9yQ3JlYXRlQ29udGFjdEJ5SWQoamlkKTtcclxuICAgICAgICBjb250YWN0LnBlbmRpbmdJbiQubmV4dChmYWxzZSk7XHJcbiAgICAgICAgdGhpcy5jaGF0U2VydmljZS5jaGF0Q29ubmVjdGlvblNlcnZpY2Uuc2VuZChcclxuICAgICAgICAgICAgeG1sKCdwcmVzZW5jZScsIHt0bzogamlkLCB0eXBlOiAnc3Vic2NyaWJlZCcsIGlkOiB0aGlzLmNoYXRTZXJ2aWNlLmNoYXRDb25uZWN0aW9uU2VydmljZS5nZXROZXh0SXFJZCgpfSlcclxuICAgICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbkJlZm9yZU9ubGluZSgpOiBQcm9taXNlTGlrZTxhbnk+IHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yZWZyZXNoUm9zdGVyQ29udGFjdHMoKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXRSb3N0ZXJDb250YWN0cygpOiBQcm9taXNlPENvbnRhY3RbXT4ge1xyXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT5cclxuICAgICAgICAgICAgdGhpcy5jaGF0U2VydmljZS5jaGF0Q29ubmVjdGlvblNlcnZpY2Uuc2VuZElxKFxyXG4gICAgICAgICAgICAgICAgeG1sKCdpcScsIHt0eXBlOiAnZ2V0J30sXHJcbiAgICAgICAgICAgICAgICAgICAgeG1sKCdxdWVyeScsIHt4bWxuczogJ2phYmJlcjppcTpyb3N0ZXInfSlcclxuICAgICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgKS50aGVuKFxyXG4gICAgICAgICAgICAgICAgKHJlc3BvbnNlU3RhbnphOiBTdGFuemEpID0+IHJlc29sdmUodGhpcy5jb252ZXJ0VG9Db250YWN0cyhyZXNwb25zZVN0YW56YSkpLFxyXG4gICAgICAgICAgICAgICAgKHJlc3BvbnNlU3RhbnphOiBTdGFuemEpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZ1NlcnZpY2UuZXJyb3IoJ2Vycm9yIGNvbnZlcnRpbmcgcm9zdGVyIGNvbnRhY3QgcHVzaCcsIHJlc3BvbnNlU3RhbnphLnRvU3RyaW5nKCkpO1xyXG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoW10pO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNvbnZlcnRUb0NvbnRhY3RzKHJlc3BvbnNlU3RhbnphOiBTdGFuemEpOiBDb250YWN0W10ge1xyXG4gICAgICAgIHJldHVybiByZXNwb25zZVN0YW56YS5nZXRDaGlsZCgncXVlcnknKS5nZXRDaGlsZEVsZW1lbnRzKClcclxuICAgICAgICAgICAgLm1hcChyb3N0ZXJFbGVtZW50ID0+IHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGNvbnRhY3QgPSB0aGlzLmNoYXRTZXJ2aWNlLmdldE9yQ3JlYXRlQ29udGFjdEJ5SWQocm9zdGVyRWxlbWVudC5hdHRycy5qaWQsXHJcbiAgICAgICAgICAgICAgICAgICAgcm9zdGVyRWxlbWVudC5hdHRycy5uYW1lIHx8IHJvc3RlckVsZW1lbnQuYXR0cnMuamlkKTtcclxuICAgICAgICAgICAgICAgIGNvbnRhY3Quc3Vic2NyaXB0aW9uJC5uZXh0KHRoaXMucGFyc2VTdWJzY3JpcHRpb24ocm9zdGVyRWxlbWVudC5hdHRycy5zdWJzY3JpcHRpb24pKTtcclxuICAgICAgICAgICAgICAgIGNvbnRhY3QucGVuZGluZ091dCQubmV4dChyb3N0ZXJFbGVtZW50LmF0dHJzLmFzayA9PT0gJ3N1YnNjcmliZScpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRhY3Q7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgcGFyc2VTdWJzY3JpcHRpb24oc3Vic2NyaXB0aW9uOiBzdHJpbmcpOiBDb250YWN0U3Vic2NyaXB0aW9uIHtcclxuICAgICAgICBzd2l0Y2ggKHN1YnNjcmlwdGlvbikge1xyXG4gICAgICAgICAgICBjYXNlICd0byc6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gQ29udGFjdFN1YnNjcmlwdGlvbi50bztcclxuICAgICAgICAgICAgY2FzZSAnZnJvbSc6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gQ29udGFjdFN1YnNjcmlwdGlvbi5mcm9tO1xyXG4gICAgICAgICAgICBjYXNlICdib3RoJzpcclxuICAgICAgICAgICAgICAgIHJldHVybiBDb250YWN0U3Vic2NyaXB0aW9uLmJvdGg7XHJcbiAgICAgICAgICAgIGNhc2UgJ25vbmUnOlxyXG4gICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIENvbnRhY3RTdWJzY3JpcHRpb24ubm9uZTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgYWRkUm9zdGVyQ29udGFjdChqaWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuc2VuZEFjY2VwdFByZXNlbmNlU3Vic2NyaXB0aW9uUmVxdWVzdChqaWQpO1xyXG4gICAgICAgIHRoaXMuc2VuZEFkZFRvUm9zdGVyKGppZCk7XHJcbiAgICAgICAgdGhpcy5zZW5kU3Vic2NyaWJlVG9QcmVzZW5jZShqaWQpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgc2VuZEFkZFRvUm9zdGVyKGppZDogc3RyaW5nKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY2hhdFNlcnZpY2UuY2hhdENvbm5lY3Rpb25TZXJ2aWNlLnNlbmRJcShcclxuICAgICAgICAgICAgeG1sKCdpcScsIHt0eXBlOiAnc2V0J30sXHJcbiAgICAgICAgICAgICAgICB4bWwoJ3F1ZXJ5Jywge3htbG5zOiAnamFiYmVyOmlxOnJvc3Rlcid9LFxyXG4gICAgICAgICAgICAgICAgICAgIHhtbCgnaXRlbScsIHtqaWR9KSkpKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHNlbmRTdWJzY3JpYmVUb1ByZXNlbmNlKGppZDogc3RyaW5nKSB7XHJcbiAgICAgICAgdGhpcy5jaGF0U2VydmljZS5jaGF0Q29ubmVjdGlvblNlcnZpY2Uuc2VuZChcclxuICAgICAgICAgICAgeG1sKCdwcmVzZW5jZScsIHtpZDogdGhpcy5jaGF0U2VydmljZS5jaGF0Q29ubmVjdGlvblNlcnZpY2UuZ2V0TmV4dElxSWQoKSwgdG86IGppZCwgdHlwZTogJ3N1YnNjcmliZSd9KVxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgcmVtb3ZlUm9zdGVyQ29udGFjdChqaWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgICAgIGNvbnN0IGNvbnRhY3QgPSB0aGlzLmNoYXRTZXJ2aWNlLmdldENvbnRhY3RCeUlkKGppZCk7XHJcbiAgICAgICAgaWYgKGNvbnRhY3QpIHtcclxuICAgICAgICAgICAgY29udGFjdC5zdWJzY3JpcHRpb24kLm5leHQoQ29udGFjdFN1YnNjcmlwdGlvbi5ub25lKTtcclxuICAgICAgICAgICAgY29udGFjdC5wZW5kaW5nT3V0JC5uZXh0KGZhbHNlKTtcclxuICAgICAgICAgICAgY29udGFjdC5wZW5kaW5nSW4kLm5leHQoZmFsc2UpO1xyXG4gICAgICAgICAgICB0aGlzLnNlbmRSZW1vdmVGcm9tUm9zdGVyKGppZCk7XHJcbiAgICAgICAgICAgIHRoaXMuc2VuZFdpdGhkcmF3UHJlc2VuY2VTdWJzY3JpcHRpb24oamlkKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBzZW5kUmVtb3ZlRnJvbVJvc3RlcihqaWQ6IHN0cmluZykge1xyXG4gICAgICAgIHRoaXMuY2hhdFNlcnZpY2UuY2hhdENvbm5lY3Rpb25TZXJ2aWNlLnNlbmRJcShcclxuICAgICAgICAgICAgeG1sKCdpcScsIHt0eXBlOiAnc2V0J30sXHJcbiAgICAgICAgICAgICAgICB4bWwoJ3F1ZXJ5Jywge3htbG5zOiAnamFiYmVyOmlxOnJvc3Rlcid9LFxyXG4gICAgICAgICAgICAgICAgICAgIHhtbCgnaXRlbScsIHtqaWQsIHN1YnNjcmlwdGlvbjogJ3JlbW92ZSd9KSkpKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHNlbmRXaXRoZHJhd1ByZXNlbmNlU3Vic2NyaXB0aW9uKGppZDogc3RyaW5nKSB7XHJcbiAgICAgICAgdGhpcy5jaGF0U2VydmljZS5jaGF0Q29ubmVjdGlvblNlcnZpY2Uuc2VuZChcclxuICAgICAgICAgICAgeG1sKCdwcmVzZW5jZScsIHtpZDogdGhpcy5jaGF0U2VydmljZS5jaGF0Q29ubmVjdGlvblNlcnZpY2UuZ2V0TmV4dElxSWQoKSwgdG86IGppZCwgdHlwZTogJ3Vuc3Vic2NyaWJlZCd9KVxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgcmVmcmVzaFJvc3RlckNvbnRhY3RzKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmdldFJvc3RlckNvbnRhY3RzKCk7XHJcbiAgICB9XHJcbn1cclxuIl19