UNPKG

ngx-captcha-ssr

Version:

Dynamic captcha (Google reCaptcha) implementation for Angular

313 lines 35.6 kB
import { isPlatformBrowser } from "@angular/common"; import { Directive, EventEmitter, Inject, InjectFlags, Injector, Input, NgZone, Output, PLATFORM_ID, Renderer2, } from "@angular/core"; import { NgControl, } from "@angular/forms"; import { ScriptService } from "../services/script.service"; import * as i0 from "@angular/core"; import * as i1 from "../services/script.service"; export class BaseReCaptchaComponentDirective { constructor(renderer, zone, injector, scriptService, platformId) { this.renderer = renderer; this.zone = zone; this.injector = injector; this.scriptService = scriptService; this.platformId = platformId; /** * Prefix of the captcha element */ this.captchaElemPrefix = "ngx_captcha_id_"; this.setupCaptcha = true; /** * Indicates if global domain 'recaptcha.net' should be used instead of default domain ('google.com') */ this.useGlobalDomain = false; this.useEnterprise = false; /** * Type */ this.type = "image"; /** * Tab index */ this.tabIndex = 0; /** * Called when captcha receives successful response. * Captcha response token is passed to event. */ this.success = new EventEmitter(); /** * Called when captcha is loaded. Event receives id of the captcha */ this.load = new EventEmitter(); /** * Called when captcha is reset. */ this.reset = new EventEmitter(); /** * Called when captcha is loaded & ready. I.e. when you need to execute captcha on component load. */ this.ready = new EventEmitter(); /** * Error callback */ this.error = new EventEmitter(); /** * Expired callback */ this.expire = new EventEmitter(); /** * Indicates if captcha should be set on load */ this.setupAfterLoad = false; /** * If enabled, captcha will reset after receiving success response. This is useful * when invisible captcha need to be resolved multiple times on same page */ this.resetCaptchaAfterSuccess = false; /** * Required by ControlValueAccessor */ this.onChange = (val) => { }; this.onTouched = (val) => { }; /** * Indicates if captcha is loaded */ this.isLoaded = false; } ngAfterViewInit() { this.control = this.injector.get(NgControl, undefined, InjectFlags.Optional)?.control; } ngAfterViewChecked() { if (this.setupCaptcha) { this.setupCaptcha = false; this.setupComponent(); } } ngOnChanges(changes) { // cleanup scripts if language changed because they need to be reloaded if (changes && changes.hl) { // cleanup scripts when language changes if (!changes.hl.firstChange && changes.hl.currentValue !== changes.hl.previousValue) { this.scriptService.cleanup(); } } if (changes && changes.useGlobalDomain) { // cleanup scripts when domain changes if (!changes.useGlobalDomain.firstChange && changes.useGlobalDomain.currentValue !== changes.useGlobalDomain.previousValue) { this.scriptService.cleanup(); } } this.setupCaptcha = true; } /** * Gets captcha response as per reCaptcha docs */ getResponse() { return this.reCaptchaApi.getResponse(this.captchaId); } /** * Gets Id of captcha widget */ getCaptchaId() { return this.captchaId; } /** * Resets captcha */ resetCaptcha() { this.zone.run(() => { // reset captcha using Google js api this.reCaptchaApi.reset(); // required due to forms this.onChange(undefined); this.onTouched(undefined); // trigger reset event this.reset.next(); }); } /** * Gets last submitted captcha response */ getCurrentResponse() { return this.currentResponse; } /** * Reload captcha. Useful when properties (i.e. theme) changed and captcha need to reflect them */ reloadCaptcha() { this.setupComponent(); } ensureCaptchaElem(captchaElemId) { if (isPlatformBrowser(this.platformId)) { const captchaElem = document.getElementById(captchaElemId); if (!captchaElem) { throw Error(`Captcha element with id '${captchaElemId}' was not found`); } // assign captcha alem this.captchaElem = captchaElem; } } /** * Responsible for instantiating captcha element */ renderReCaptcha() { // run outside angular zone due to timeout issues when testing // details: https://github.com/Enngage/ngx-captcha/issues/26 this.zone.runOutsideAngular(() => { // to fix reCAPTCHA placeholder element must be an element or id // https://github.com/Enngage/ngx-captcha/issues/96 setTimeout(() => { this.captchaId = this.reCaptchaApi.render(this.captchaElemId, this.getCaptchaProperties()); this.ready.next(); }, 0); }); } /** * Called when captcha receives response * @param callback Callback */ handleCallback(callback) { this.currentResponse = callback; this.success.next(callback); this.zone.run(() => { this.onChange(callback); this.onTouched(callback); }); if (this.resetCaptchaAfterSuccess) { this.resetCaptcha(); } } getPseudoUniqueNumber() { return new Date().getUTCMilliseconds() + Math.floor(Math.random() * 9999); } setupComponent() { // captcha specific setup this.captchaSpecificSetup(); // create captcha wrapper this.createAndSetCaptchaElem(); this.scriptService.registerCaptchaScript({ useGlobalDomain: this.useGlobalDomain, useEnterprise: this.useEnterprise, }, "explicit", (grecaptcha) => { this.onloadCallback(grecaptcha); }, this.hl); } /** * Called when google's recaptcha script is ready */ onloadCallback(grecapcha) { // assign reference to reCaptcha Api once its loaded this.reCaptchaApi = grecapcha; if (!this.reCaptchaApi) { throw Error(`ReCaptcha Api was not initialized correctly`); } // loaded flag this.isLoaded = true; // fire load event this.load.next(); // render captcha this.renderReCaptcha(); // setup component if it was flagged as such if (this.setupAfterLoad) { this.setupAfterLoad = false; this.setupComponent(); } } generateNewElemId() { return this.captchaElemPrefix + this.getPseudoUniqueNumber(); } createAndSetCaptchaElem() { // generate new captcha id this.captchaElemId = this.generateNewElemId(); if (!this.captchaElemId) { throw Error(`Captcha elem Id is not set`); } if (!this.captchaWrapperElem) { throw Error(`Captcha DOM element is not initialized`); } // remove old html this.captchaWrapperElem.nativeElement.innerHTML = ""; // create new wrapper for captcha const newElem = this.renderer.createElement("div"); newElem.id = this.captchaElemId; this.renderer.appendChild(this.captchaWrapperElem.nativeElement, newElem); // when use captcha in cdk stepper then throwing error Captcha element with id 'ngx_captcha_id_XXXX' not found // to fix it checking ensureCaptchaElem in timeout so that its check in next call and its able to find element setTimeout(() => { // update captcha elem if (this.captchaElemId) { this.ensureCaptchaElem(this.captchaElemId); } }, 0); } /** * To be aligned with the ControlValueAccessor interface we need to implement this method * However as we don't want to update the recaptcha, this doesn't need to be implemented */ writeValue(obj) { } /** * This method helps us tie together recaptcha and our formControl values */ registerOnChange(fn) { this.onChange = fn; } /** * At some point we might be interested whether the user has touched our component */ registerOnTouched(fn) { this.onTouched = fn; } /** * Handles error callback */ handleErrorCallback() { this.zone.run(() => { this.onChange(undefined); this.onTouched(undefined); }); this.error.next(); } /** * Handles expired callback */ handleExpireCallback() { this.expire.next(); // reset captcha on expire callback this.resetCaptcha(); } } /** @nocollapse */ BaseReCaptchaComponentDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BaseReCaptchaComponentDirective, deps: [{ token: i0.Renderer2 }, { token: i0.NgZone }, { token: i0.Injector }, { token: i1.ScriptService }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ BaseReCaptchaComponentDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.4", type: BaseReCaptchaComponentDirective, inputs: { siteKey: "siteKey", useGlobalDomain: "useGlobalDomain", useEnterprise: "useEnterprise", type: "type", hl: "hl", tabIndex: "tabIndex" }, outputs: { success: "success", load: "load", reset: "reset", ready: "ready", error: "error", expire: "expire" }, usesOnChanges: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BaseReCaptchaComponentDirective, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: i1.ScriptService }, { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; }, propDecorators: { siteKey: [{ type: Input }], useGlobalDomain: [{ type: Input }], useEnterprise: [{ type: Input }], type: [{ type: Input }], hl: [{ type: Input }], tabIndex: [{ type: Input }], success: [{ type: Output }], load: [{ type: Output }], reset: [{ type: Output }], ready: [{ type: Output }], error: [{ type: Output }], expire: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1yZS1jYXB0Y2hhLWNvbXBvbmVudC5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvYmFzZS1yZS1jYXB0Y2hhLWNvbXBvbmVudC5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDcEQsT0FBTyxFQUdMLFNBQVMsRUFFVCxZQUFZLEVBQ1osTUFBTSxFQUNOLFdBQVcsRUFDWCxRQUFRLEVBQ1IsS0FBSyxFQUNMLE1BQU0sRUFFTixNQUFNLEVBQ04sV0FBVyxFQUNYLFNBQVMsR0FFVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBR0wsU0FBUyxHQUNWLE1BQU0sZ0JBQWdCLENBQUM7QUFHeEIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFDOzs7QUFHM0QsTUFBTSxPQUFnQiwrQkFBK0I7SUFnSW5ELFlBQ1ksUUFBbUIsRUFDbkIsSUFBWSxFQUNaLFFBQWtCLEVBQ2xCLGFBQTRCLEVBQ1AsVUFBa0I7UUFKdkMsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQUNuQixTQUFJLEdBQUosSUFBSSxDQUFRO1FBQ1osYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUNsQixrQkFBYSxHQUFiLGFBQWEsQ0FBZTtRQUNQLGVBQVUsR0FBVixVQUFVLENBQVE7UUFsSW5EOztXQUVHO1FBQ2dCLHNCQUFpQixHQUFHLGlCQUFpQixDQUFDO1FBRWpELGlCQUFZLEdBQVksSUFBSSxDQUFDO1FBUXJDOztXQUVHO1FBQ00sb0JBQWUsR0FBWSxLQUFLLENBQUM7UUFFakMsa0JBQWEsR0FBWSxLQUFLLENBQUM7UUFFeEM7O1dBRUc7UUFDTSxTQUFJLEdBQXNCLE9BQU8sQ0FBQztRQU8zQzs7V0FFRztRQUNNLGFBQVEsR0FBRyxDQUFDLENBQUM7UUFFdEI7OztXQUdHO1FBQ08sWUFBTyxHQUFH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QkFBZCxNQUFNO2dCQUtHLE1BQU07c0JBQWYsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGlzUGxhdGZvcm1Ccm93c2VyIH0gZnJvbSBcIkBhbmd1bGFyL2NvbW1vblwiO1xyXG5pbXBvcnQge1xyXG4gIEFmdGVyVmlld0NoZWNrZWQsXHJcbiAgQWZ0ZXJWaWV3SW5pdCxcclxuICBEaXJlY3RpdmUsXHJcbiAgRWxlbWVudFJlZixcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgSW5qZWN0LFxyXG4gIEluamVjdEZsYWdzLFxyXG4gIEluamVjdG9yLFxyXG4gIElucHV0LFxyXG4gIE5nWm9uZSxcclxuICBPbkNoYW5nZXMsXHJcbiAgT3V0cHV0LFxyXG4gIFBMQVRGT1JNX0lELFxyXG4gIFJlbmRlcmVyMixcclxuICBTaW1wbGVDaGFuZ2VzLFxyXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XHJcbmltcG9ydCB7XHJcbiAgQWJzdHJhY3RDb250cm9sLFxyXG4gIENvbnRyb2xWYWx1ZUFjY2Vzc29yLFxyXG4gIE5nQ29udHJvbCxcclxufSBmcm9tIFwiQGFuZ3VsYXIvZm9ybXNcIjtcclxuXHJcbmltcG9ydCB7IFJlQ2FwdGNoYVR5cGUgfSBmcm9tIFwiLi4vbW9kZWxzL3JlY2FwdGNoYS10eXBlLmVudW1cIjtcclxuaW1wb3J0IHsgU2NyaXB0U2VydmljZSB9IGZyb20gXCIuLi9zZXJ2aWNlcy9zY3JpcHQuc2VydmljZVwiO1xyXG5cclxuQERpcmVjdGl2ZSgpXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlUmVDYXB0Y2hhQ29tcG9uZW50RGlyZWN0aXZlXHJcbiAgaW1wbGVtZW50cyBPbkNoYW5nZXMsIENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBBZnRlclZpZXdJbml0LCBBZnRlclZpZXdDaGVja2VkXHJcbntcclxuICAvKipcclxuICAgKiBQcmVmaXggb2YgdGhlIGNhcHRjaGEgZWxlbWVudFxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCByZWFkb25seSBjYXB0Y2hhRWxlbVByZWZpeCA9IFwibmd4X2NhcHRjaGFfaWRfXCI7XHJcblxyXG4gIHByaXZhdGUgc2V0dXBDYXB0Y2hhOiBib29sZWFuID0gdHJ1ZTtcclxuXHJcbiAgLyoqXHJcbiAgICogR29vZ2xlJ3Mgc2l0ZSBrZXkuXHJcbiAgICogWW91IGNhbiBmaW5kIHRoaXMgdW5kZXIgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9yZWNhcHRjaGFcclxuICAgKi9cclxuICBASW5wdXQoKSBzaXRlS2V5Pzogc3RyaW5nO1xyXG5cclxuICAvKipcclxuICAgKiBJbmRpY2F0ZXMgaWYgZ2xvYmFsIGRvbWFpbiAncmVjYXB0Y2hhLm5ldCcgc2hvdWxkIGJlIHVzZWQgaW5zdGVhZCBvZiBkZWZhdWx0IGRvbWFpbiAoJ2dvb2dsZS5jb20nKVxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIHVzZUdsb2JhbERvbWFpbjogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICBASW5wdXQoKSB1c2VFbnRlcnByaXNlOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIC8qKlxyXG4gICAqIFR5cGVcclxuICAgKi9cclxuICBASW5wdXQoKSB0eXBlOiBcImF1ZGlvXCIgfCBcImltYWdlXCIgPSBcImltYWdlXCI7XHJcblxyXG4gIC8qKlxyXG4gICAqIExhbmd1YWdlIGNvZGUuIEF1dG8tZGV0ZWN0cyB0aGUgdXNlcidzIGxhbmd1YWdlIGlmIHVuc3BlY2lmaWVkLlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIGhsPzogc3RyaW5nO1xyXG5cclxuICAvKipcclxuICAgKiBUYWIgaW5kZXhcclxuICAgKi9cclxuICBASW5wdXQoKSB0YWJJbmRleCA9IDA7XHJcblxyXG4gIC8qKlxyXG4gICAqIENhbGxlZCB3aGVuIGNhcHRjaGEgcmVjZWl2ZXMgc3VjY2Vzc2Z1bCByZXNwb25zZS5cclxuICAgKiBDYXB0Y2hhIHJlc3BvbnNlIHRva2VuIGlzIHBhc3NlZCB0byBldmVudC5cclxuICAgKi9cclxuICBAT3V0cHV0KCkgc3VjY2VzcyA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xyXG5cclxuICAvKipcclxuICAgKiBDYWxsZWQgd2hlbiBjYXB0Y2hhIGlzIGxvYWRlZC4gRXZlbnQgcmVjZWl2ZXMgaWQgb2YgdGhlIGNhcHRjaGFcclxuICAgKi9cclxuICBAT3V0cHV0KCkgbG9hZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQ2FsbGVkIHdoZW4gY2FwdGNoYSBpcyByZXNldC5cclxuICAgKi9cclxuICBAT3V0cHV0KCkgcmVzZXQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIENhbGxlZCB3aGVuIGNhcHRjaGEgaXMgbG9hZGVkICYgcmVhZHkuIEkuZS4gd2hlbiB5b3UgbmVlZCB0byBleGVjdXRlIGNhcHRjaGEgb24gY29tcG9uZW50IGxvYWQuXHJcbiAgICovXHJcbiAgQE91dHB1dCgpIHJlYWR5ID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICAvKipcclxuICAgKiBFcnJvciBjYWxsYmFja1xyXG4gICAqL1xyXG4gIEBPdXRwdXQoKSBlcnJvciA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgLyoqXHJcbiAgICogRXhwaXJlZCBjYWxsYmFja1xyXG4gICAqL1xyXG4gIEBPdXRwdXQoKSBleHBpcmUgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcblxyXG4gIGFic3RyYWN0IGNhcHRjaGFXcmFwcGVyRWxlbT86IEVsZW1lbnRSZWY7XHJcblxyXG4gIC8qKlxyXG4gICAqIEluZGljYXRlcyBpZiBjYXB0Y2hhIHNob3VsZCBiZSBzZXQgb24gbG9hZFxyXG4gICAqL1xyXG4gIHByaXZhdGUgc2V0dXBBZnRlckxvYWQgPSBmYWxzZTtcclxuXHJcbiAgLyoqXHJcbiAgICogQ2FwdGNoYSBlbGVtZW50XHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIGNhcHRjaGFFbGVtPzogSFRNTEVsZW1lbnQ7XHJcblxyXG4gIC8qKlxyXG4gICAqIElkIG9mIHRoZSBjYXB0Y2hhIGVsZW1cclxuICAgKi9cclxuICBwcm90ZWN0ZWQgY2FwdGNoYUlkPzogbnVtYmVyO1xyXG5cclxuICAvKipcclxuICAgKiBIb2xkcyBsYXN0IHJlc3BvbnNlIHZhbHVlXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIGN1cnJlbnRSZXNwb25zZT86IHN0cmluZztcclxuXHJcbiAgLyoqXHJcbiAgICogSWYgZW5hYmxlZCwgY2FwdGNoYSB3aWxsIHJlc2V0IGFmdGVyIHJlY2VpdmluZyBzdWNjZXNzIHJlc3BvbnNlLiBUaGlzIGlzIHVzZWZ1bFxyXG4gICAqIHdoZW4gaW52aXNpYmxlIGNhcHRjaGEgbmVlZCB0byBiZSByZXNvbHZlZCBtdWx0aXBsZSB0aW1lcyBvbiBzYW1lIHBhZ2VcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgcmVzZXRDYXB0Y2hhQWZ0ZXJTdWNjZXNzID0gZmFsc2U7XHJcblxyXG4gIC8qKlxyXG4gICAqIENhcHRjaGEgdHlwZVxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBhYnN0cmFjdCByZWNhcHRjaGFUeXBlOiBSZUNhcHRjaGFUeXBlO1xyXG5cclxuICAvKipcclxuICAgKiBSZXF1aXJlZCBieSBDb250cm9sVmFsdWVBY2Nlc3NvclxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBvbkNoYW5nZTogKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpID0+IHZvaWQgPSAodmFsKSA9PiB7fTtcclxuICBwcm90ZWN0ZWQgb25Ub3VjaGVkOiAodmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCkgPT4gdm9pZCA9ICh2YWwpID0+IHt9O1xyXG5cclxuICAvKipcclxuICAgKiBJbmRpY2F0ZXMgaWYgY2FwdGNoYSBpcyBsb2FkZWRcclxuICAgKi9cclxuICBwdWJsaWMgaXNMb2FkZWQgPSBmYWxzZTtcclxuXHJcbiAgLyoqXHJcbiAgICogUmVmZXJlbmNlIHRvIGdsb2JhbCByZUNhcHRjaGEgQVBJXHJcbiAgICovXHJcbiAgcHVibGljIHJlQ2FwdGNoYUFwaT86IGFueTtcclxuXHJcbiAgLyoqXHJcbiAgICogSWQgb2YgdGhlIERPTSBlbGVtZW50IHdyYXBwaW5nIGNhcHRjaGFcclxuICAgKi9cclxuICBwdWJsaWMgY2FwdGNoYUVsZW1JZD86IHN0cmluZztcclxuXHJcbiAgLyoqXHJcbiAgICogRm9ybSBDb250cm9sIHRvIGJlIGVuYWJsZSB1c2FnZSBpbiByZWFjdGl2ZSBmb3Jtc1xyXG4gICAqL1xyXG4gIHB1YmxpYyBjb250cm9sPzogQWJzdHJhY3RDb250cm9sIHwgbnVsbDtcclxuXHJcbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKFxyXG4gICAgcHJvdGVjdGVkIHJlbmRlcmVyOiBSZW5kZXJlcjIsXHJcbiAgICBwcm90ZWN0ZWQgem9uZTogTmdab25lLFxyXG4gICAgcHJvdGVjdGVkIGluamVjdG9yOiBJbmplY3RvcixcclxuICAgIHByb3RlY3RlZCBzY3JpcHRTZXJ2aWNlOiBTY3JpcHRTZXJ2aWNlLFxyXG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJvdGVjdGVkIHBsYXRmb3JtSWQ6IE9iamVjdFxyXG4gICkge31cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCkge1xyXG4gICAgdGhpcy5jb250cm9sID0gdGhpcy5pbmplY3Rvci5nZXQ8TmdDb250cm9sIHwgdW5kZWZpbmVkPihcclxuICAgICAgTmdDb250cm9sLFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIEluamVjdEZsYWdzLk9wdGlvbmFsXHJcbiAgICApPy5jb250cm9sO1xyXG4gIH1cclxuXHJcbiAgbmdBZnRlclZpZXdDaGVja2VkKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuc2V0dXBDYXB0Y2hhKSB7XHJcbiAgICAgIHRoaXMuc2V0dXBDYXB0Y2hhID0gZmFsc2U7XHJcbiAgICAgIHRoaXMuc2V0dXBDb21wb25lbnQoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgcmVDYXB0Y2hhIHByb3BlcnRpZXNcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgYWJzdHJhY3QgZ2V0Q2FwdGNoYVByb3BlcnRpZXMoKTogYW55O1xyXG5cclxuICAvKipcclxuICAgKiBVc2VkIGZvciBjYXB0Y2hhIHNwZWNpZmljIHNldHVwXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIGFic3RyYWN0IGNhcHRjaGFTcGVjaWZpY1NldHVwKCk6IHZvaWQ7XHJcblxyXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgIC8vIGNsZWFudXAgc2NyaXB0cyBpZiBsYW5ndWFnZSBjaGFuZ2VkIGJlY2F1c2UgdGhleSBuZWVkIHRvIGJlIHJlbG9hZGVkXHJcbiAgICBpZiAoY2hhbmdlcyAmJiBjaGFuZ2VzLmhsKSB7XHJcbiAgICAgIC8vIGNsZWFudXAgc2NyaXB0cyB3aGVuIGxhbmd1YWdlIGNoYW5nZXNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICFjaGFuZ2VzLmhsLmZpcnN0Q2hhbmdlICYmXHJcbiAgICAgICAgY2hhbmdlcy5obC5jdXJyZW50VmFsdWUgIT09IGNoYW5nZXMuaGwucHJldmlvdXNWYWx1ZVxyXG4gICAgICApIHtcclxuICAgICAgICB0aGlzLnNjcmlwdFNlcnZpY2UuY2xlYW51cCgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGNoYW5nZXMgJiYgY2hhbmdlcy51c2VHbG9iYWxEb21haW4pIHtcclxuICAgICAgLy8gY2xlYW51cCBzY3JpcHRzIHdoZW4gZG9tYWluIGNoYW5nZXNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICFjaGFuZ2VzLnVzZUdsb2JhbERvbWFpbi5maXJzdENoYW5nZSAmJlxyXG4gICAgICAgIGNoYW5nZXMudXNlR2xvYmFsRG9tYWluLmN1cnJlbnRWYWx1ZSAhPT1cclxuICAgICAgICAgIGNoYW5nZXMudXNlR2xvYmFsRG9tYWluLnByZXZpb3VzVmFsdWVcclxuICAgICAgKSB7XHJcbiAgICAgICAgdGhpcy5zY3JpcHRTZXJ2aWNlLmNsZWFudXAoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuc2V0dXBDYXB0Y2hhID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgY2FwdGNoYSByZXNwb25zZSBhcyBwZXIgcmVDYXB0Y2hhIGRvY3NcclxuICAgKi9cclxuICBnZXRSZXNwb25zZSgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMucmVDYXB0Y2hhQXBpLmdldFJlc3BvbnNlKHRoaXMuY2FwdGNoYUlkKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgSWQgb2YgY2FwdGNoYSB3aWRnZXRcclxuICAgKi9cclxuICBnZXRDYXB0Y2hhSWQoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcclxuICAgIHJldHVybiB0aGlzLmNhcHRjaGFJZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlc2V0cyBjYXB0Y2hhXHJcbiAgICovXHJcbiAgcmVzZXRDYXB0Y2hhKCk6IHZvaWQge1xyXG4gICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XHJcbiAgICAgIC8vIHJlc2V0IGNhcHRjaGEgdXNpbmcgR29vZ2xlIGpzIGFwaVxyXG4gICAgICB0aGlzLnJlQ2FwdGNoYUFwaS5yZXNldCgpO1xyXG5cclxuICAgICAgLy8gcmVxdWlyZWQgZHVlIHRvIGZvcm1zXHJcbiAgICAgIHRoaXMub25DaGFuZ2UodW5kZWZpbmVkKTtcclxuICAgICAgdGhpcy5vblRvdWNoZWQodW5kZWZpbmVkKTtcclxuXHJcbiAgICAgIC8vIHRyaWdnZXIgcmVzZXQgZXZlbnRcclxuICAgICAgdGhpcy5yZXNldC5uZXh0KCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgbGFzdCBzdWJtaXR0ZWQgY2FwdGNoYSByZXNwb25zZVxyXG4gICAqL1xyXG4gIGdldEN1cnJlbnRSZXNwb25zZSgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIHRoaXMuY3VycmVudFJlc3BvbnNlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVsb2FkIGNhcHRjaGEuIFVzZWZ1bCB3aGVuIHByb3BlcnRpZXMgKGkuZS4gdGhlbWUpIGNoYW5nZWQgYW5kIGNhcHRjaGEgbmVlZCB0byByZWZsZWN0IHRoZW1cclxuICAgKi9cclxuICByZWxvYWRDYXB0Y2hhKCk6IHZvaWQge1xyXG4gICAgdGhpcy5zZXR1cENvbXBvbmVudCgpO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIGVuc3VyZUNhcHRjaGFFbGVtKGNhcHRjaGFFbGVtSWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYoaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybUlkKSkge1xyXG4gICAgICBjb25zdCBjYXB0Y2hhRWxlbSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGNhcHRjaGFFbGVtSWQpO1xyXG5cclxuICAgICAgaWYgKCFjYXB0Y2hhRWxlbSkge1xyXG4gICAgICAgIHRocm93IEVycm9yKGBDYXB0Y2hhIGVsZW1lbnQgd2l0aCBpZCAnJHtjYXB0Y2hhRWxlbUlkfScgd2FzIG5vdCBmb3VuZGApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBhc3NpZ24gY2FwdGNoYSBhbGVtXHJcbiAgICAgIHRoaXMuY2FwdGNoYUVsZW0gPSBjYXB0Y2hhRWxlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlc3BvbnNpYmxlIGZvciBpbnN0YW50aWF0aW5nIGNhcHRjaGEgZWxlbWVudFxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCByZW5kZXJSZUNhcHRjaGEoKTogdm9pZCB7XHJcbiAgICAvLyBydW4gb3V0c2lkZSBhbmd1bGFyIHpvbmUgZHVlIHRvIHRpbWVvdXQgaXNzdWVzIHdoZW4gdGVzdGluZ1xyXG4gICAgLy8gZGV0YWlsczogaHR0cHM6Ly9naXRodWIuY29tL0VubmdhZ2Uvbmd4LWNhcHRjaGEvaXNzdWVzLzI2XHJcbiAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICAvLyB0byBmaXggcmVDQVBUQ0hBIHBsYWNlaG9sZGVyIGVsZW1lbnQgbXVzdCBiZSBhbiBlbGVtZW50IG9yIGlkXHJcbiAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9Fbm5nYWdlL25neC1jYXB0Y2hhL2lzc3Vlcy85NlxyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICB0aGlzLmNhcHRjaGFJZCA9IHRoaXMucmVDYXB0Y2hhQXBpLnJlbmRlcihcclxuICAgICAgICAgIHRoaXMuY2FwdGNoYUVsZW1JZCxcclxuICAgICAgICAgIHRoaXMuZ2V0Q2FwdGNoYVByb3BlcnRpZXMoKVxyXG4gICAgICAgICk7XHJcbiAgICAgICAgdGhpcy5yZWFkeS5uZXh0KCk7XHJcbiAgICAgIH0sIDApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDYWxsZWQgd2hlbiBjYXB0Y2hhIHJlY2VpdmVzIHJlc3BvbnNlXHJcbiAgICogQHBhcmFtIGNhbGxiYWNrIENhbGxiYWNrXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIGhhbmRsZUNhbGxiYWNrKGNhbGxiYWNrOiBhbnkpOiB2b2lkIHtcclxuICAgIHRoaXMuY3VycmVudFJlc3BvbnNlID0gY2FsbGJhY2s7XHJcbiAgICB0aGlzLnN1Y2Nlc3MubmV4dChjYWxsYmFjayk7XHJcblxyXG4gICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XHJcbiAgICAgIHRoaXMub25DaGFuZ2UoY2FsbGJhY2spO1xyXG4gICAgICB0aGlzLm9uVG91Y2hlZChjYWxsYmFjayk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAodGhpcy5yZXNldENhcHRjaGFBZnRlclN1Y2Nlc3MpIHtcclxuICAgICAgdGhpcy5yZXNldENhcHRjaGEoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0UHNldWRvVW5pcXVlTnVtYmVyKCk6IG51bWJlciB7XHJcbiAgICByZXR1cm4gbmV3IERhdGUoKS5nZXRVVENNaWxsaXNlY29uZHMoKSArIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDk5OTkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXR1cENvbXBvbmVudCgpOiB2b2lkIHtcclxuICAgIC8vIGNhcHRjaGEgc3BlY2lmaWMgc2V0dXBcclxuICAgIHRoaXMuY2FwdGNoYVNwZWNpZmljU2V0dXAoKTtcclxuXHJcbiAgICAvLyBjcmVhdGUgY2FwdGNoYSB3cmFwcGVyXHJcbiAgICB0aGlzLmNyZWF0ZUFuZFNldENhcHRjaGFFbGVtKCk7XHJcblxyXG4gICAgdGhpcy5zY3JpcHRTZXJ2aWNlLnJlZ2lzdGVyQ2FwdGNoYVNjcmlwdChcclxuICAgICAge1xyXG4gICAgICAgIHVzZUdsb2JhbERvbWFpbjogdGhpcy51c2VHbG9iYWxEb21haW4sXHJcbiAgICAgICAgdXNlRW50ZXJwcmlzZTogdGhpcy51c2VFbnRlcnByaXNlLFxyXG4gICAgICB9LFxyXG4gICAgICBcImV4cGxpY2l0XCIsXHJcbiAgICAgIChncmVjYXB0Y2hhKSA9PiB7XHJcbiAgICAgICAgdGhpcy5vbmxvYWRDYWxsYmFjayhncmVjYXB0Y2hhKTtcclxuICAgICAgfSxcclxuICAgICAgdGhpcy5obFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENhbGxlZCB3aGVuIGdvb2dsZSdzIHJlY2FwdGNoYSBzY3JpcHQgaXMgcmVhZHlcclxuICAgKi9cclxuICBwcml2YXRlIG9ubG9hZENhbGxiYWNrKGdyZWNhcGNoYTogYW55KTogdm9pZCB7XHJcbiAgICAvLyBhc3NpZ24gcmVmZXJlbmNlIHRvIHJlQ2FwdGNoYSBBcGkgb25jZSBpdHMgbG9hZGVkXHJcbiAgICB0aGlzLnJlQ2FwdGNoYUFwaSA9IGdyZWNhcGNoYTtcclxuXHJcbiAgICBpZiAoIXRoaXMucmVDYXB0Y2hhQXBpKSB7XHJcbiAgICAgIHRocm93IEVycm9yKGBSZUNhcHRjaGEgQXBpIHdhcyBub3QgaW5pdGlhbGl6ZWQgY29ycmVjdGx5YCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gbG9hZGVkIGZsYWdcclxuICAgIHRoaXMuaXNMb2FkZWQgPSB0cnVlO1xyXG5cclxuICAgIC8vIGZpcmUgbG9hZCBldmVudFxyXG4gICAgdGhpcy5sb2FkLm5leHQoKTtcclxuXHJcbiAgICAvLyByZW5kZXIgY2FwdGNoYVxyXG4gICAgdGhpcy5yZW5kZXJSZUNhcHRjaGEoKTtcclxuXHJcbiAgICAvLyBzZXR1cCBjb21wb25lbnQgaWYgaXQgd2FzIGZsYWdnZWQgYXMgc3VjaFxyXG4gICAgaWYgKHRoaXMuc2V0dXBBZnRlckxvYWQpIHtcclxuICAgICAgdGhpcy5zZXR1cEFmdGVyTG9hZCA9IGZhbHNlO1xyXG4gICAgICB0aGlzLnNldHVwQ29tcG9uZW50KCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdlbmVyYXRlTmV3RWxlbUlkKCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gdGhpcy5jYXB0Y2hhRWxlbVByZWZpeCArIHRoaXMuZ2V0UHNldWRvVW5pcXVlTnVtYmVyKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNyZWF0ZUFuZFNldENhcHRjaGFFbGVtKCk6IHZvaWQge1xyXG4gICAgLy8gZ2VuZXJhdGUgbmV3IGNhcHRjaGEgaWRcclxuICAgIHRoaXMuY2FwdGNoYUVsZW1JZCA9IHRoaXMuZ2VuZXJhdGVOZXdFbGVtSWQoKTtcclxuXHJcbiAgICBpZiAoIXRoaXMuY2FwdGNoYUVsZW1JZCkge1xyXG4gICAgICB0aHJvdyBFcnJvcihgQ2FwdGNoYSBlbGVtIElkIGlzIG5vdCBzZXRgKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXRoaXMuY2FwdGNoYVdyYXBwZXJFbGVtKSB7XHJcbiAgICAgIHRocm93IEVycm9yKGBDYXB0Y2hhIERPTSBlbGVtZW50IGlzIG5vdCBpbml0aWFsaXplZGApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHJlbW92ZSBvbGQgaHRtbFxyXG4gICAgdGhpcy5jYXB0Y2hhV3JhcHBlckVsZW0ubmF0aXZlRWxlbWVudC5pbm5lckhUTUwgPSBcIlwiO1xyXG5cclxuICAgIC8vIGNyZWF0ZSBuZXcgd3JhcHBlciBmb3IgY2FwdGNoYVxyXG4gICAgY29uc3QgbmV3RWxlbSA9IHRoaXMucmVuZGVyZXIuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcclxuICAgIG5ld0VsZW0uaWQgPSB0aGlzLmNhcHRjaGFFbGVtSWQ7XHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5hcHBlbmRDaGlsZCh0aGlzLmNhcHRjaGFXcmFwcGVyRWxlbS5uYXRpdmVFbGVtZW50LCBuZXdFbGVtKTtcclxuXHJcbiAgICAvLyB3aGVuIHVzZSBjYXB0Y2hhIGluIGNkayBzdGVwcGVyIHRoZW4gdGhyb3dpbmcgZXJyb3IgQ2FwdGNoYSBlbGVtZW50IHdpdGggaWQgJ25neF9jYXB0Y2hhX2lkX1hYWFgnIG5vdCBmb3VuZFxyXG4gICAgLy8gdG8gZml4IGl0IGNoZWNraW5nIGVuc3VyZUNhcHRjaGFFbGVtIGluIHRpbWVvdXQgc28gdGhhdCBpdHMgY2hlY2sgaW4gbmV4dCBjYWxsIGFuZCBpdHMgYWJsZSB0byBmaW5kIGVsZW1lbnRcclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAvLyB1cGRhdGUgY2FwdGNoYSBlbGVtXHJcbiAgICAgIGlmICh0aGlzLmNhcHRjaGFFbGVtSWQpIHtcclxuICAgICAgICB0aGlzLmVuc3VyZUNhcHRjaGFFbGVtKHRoaXMuY2FwdGNoYUVsZW1JZCk7XHJcbiAgICAgIH1cclxuICAgIH0sIDApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVG8gYmUgYWxpZ25lZCB3aXRoIHRoZSBDb250cm9sVmFsdWVBY2Nlc3NvciBpbnRlcmZhY2Ugd2UgbmVlZCB0byBpbXBsZW1lbnQgdGhpcyBtZXRob2RcclxuICAgKiBIb3dldmVyIGFzIHdlIGRvbid0IHdhbnQgdG8gdXBkYXRlIHRoZSByZWNhcHRjaGEsIHRoaXMgZG9lc24ndCBuZWVkIHRvIGJlIGltcGxlbWVudGVkXHJcbiAgICovXHJcbiAgcHVibGljIHdyaXRlVmFsdWUob2JqOiBhbnkpOiB2b2lkIHt9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoaXMgbWV0aG9kIGhlbHBzIHVzIHRpZSB0b2dldGhlciByZWNhcHRjaGEgYW5kIG91ciBmb3JtQ29udHJvbCB2YWx1ZXNcclxuICAgKi9cclxuICBwdWJsaWMgcmVnaXN0ZXJPbkNoYW5nZShmbjogYW55KTogdm9pZCB7XHJcbiAgICB0aGlzLm9uQ2hhbmdlID0gZm47XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBBdCBzb21lIHBvaW50IHdlIG1pZ2h0IGJlIGludGVyZXN0ZWQgd2hldGhlciB0aGUgdXNlciBoYXMgdG91Y2hlZCBvdXIgY29tcG9uZW50XHJcbiAgICovXHJcbiAgcHVibGljIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiBhbnkpOiB2b2lkIHtcclxuICAgIHRoaXMub25Ub3VjaGVkID0gZm47XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBIYW5kbGVzIGVycm9yIGNhbGxiYWNrXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIGhhbmRsZUVycm9yQ2FsbGJhY2soKTogdm9pZCB7XHJcbiAgICB0aGlzLnpvbmUucnVuKCgpID0+IHtcclxuICAgICAgdGhpcy5vbkNoYW5nZSh1bmRlZmluZWQpO1xyXG4gICAgICB0aGlzLm9uVG91Y2hlZCh1bmRlZmluZWQpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5lcnJvci5uZXh0KCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBIYW5kbGVzIGV4cGlyZWQgY2FsbGJhY2tcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgaGFuZGxlRXhwaXJlQ2FsbGJhY2soKTogdm9pZCB7XHJcbiAgICB0aGlzLmV4cGlyZS5uZXh0KCk7XHJcblxyXG4gICAgLy8gcmVzZXQgY2FwdGNoYSBvbiBleHBpcmUgY2FsbGJhY2tcclxuICAgIHRoaXMucmVzZXRDYXB0Y2hhKCk7XHJcbiAgfVxyXG59XHJcbiJdfQ==