ngx-captcha
Version:
Dynamic captcha (Google reCaptcha) implementation for Angular
295 lines • 33.8 kB
JavaScript
import { EventEmitter, Injector, InjectFlags, Input, NgZone, Output, Renderer2, Directive, } 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 BaseReCaptchaComponent {
constructor(renderer, zone, injector, scriptService) {
this.renderer = renderer;
this.zone = zone;
this.injector = injector;
this.scriptService = scriptService;
/**
* 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;
/**
* 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;
/**
* 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) {
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(this.useGlobalDomain, "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 */ /** @nocollapse */ BaseReCaptchaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: BaseReCaptchaComponent, deps: [{ token: i0.Renderer2 }, { token: i0.NgZone }, { token: i0.Injector }, { token: i1.ScriptService }], target: i0.ɵɵFactoryTarget.Directive });
/** @nocollapse */ /** @nocollapse */ BaseReCaptchaComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.0.3", type: BaseReCaptchaComponent, inputs: { siteKey: "siteKey", useGlobalDomain: "useGlobalDomain", 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: "13.0.3", ngImport: i0, type: BaseReCaptchaComponent, decorators: [{
type: Directive
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: i1.ScriptService }]; }, propDecorators: { siteKey: [{
type: Input
}], useGlobalDomain: [{
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1yZWNhcHRjaGEuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL2Jhc2UtcmVjYXB0Y2hhLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBSUwsWUFBWSxFQUNaLFFBQVEsRUFDUixXQUFXLEVBQ1gsS0FBSyxFQUNMLE1BQU0sRUFFTixNQUFNLEVBQ04sU0FBUyxFQUVULFNBQVMsR0FDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBR0wsU0FBUyxHQUVWLE1BQU0sZ0JBQWdCLENBQUM7QUFJeEIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFDOzs7QUFHM0QsTUFBTSxPQUFnQixzQkFBc0I7SUE4SDFDLFlBQ1ksUUFBbUIsRUFDbkIsSUFBWSxFQUNaLFFBQWtCLEVBQ2xCLGFBQTRCO1FBSDVCLGFBQVEsR0FBUixRQUFRLENBQVc7UUFDbkIsU0FBSSxHQUFKLElBQUksQ0FBUTtRQUNaLGFBQVEsR0FBUixRQUFRLENBQVU7UUFDbEIsa0JBQWEsR0FBYixhQUFhLENBQWU7UUEvSHhDOztXQUVHO1FBQ2dCLHNCQUFpQixHQUFHLGlCQUFpQixDQUFDO1FBRWpELGlCQUFZLEdBQVksSUFBSSxDQUFDO1FBUXJDOztXQUVHO1FBQ00sb0JBQWUsR0FBWSxLQUFLLENBQUM7UUFFMUM7O1dBRUc7UUFDTSxTQUFJLEdBQXNCLE9BQU8sQ0FBQztRQU8zQzs7V0FFRztRQUNNLGFBQVEsR0FBRyxDQUFDLENBQUM7UUFFdEI7OztXQUdHO1FBQ08sWUFBTyxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFFL0M7O1dBRUc7UUFDTyxTQUFJLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUUxQzs7V0FFRztRQUNPLFVBQUssR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBRTNDOztXQUVHO1FBQ08sVUFBSyxHQUFHLElBQUksWUFB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QUFDLENBQUM7UUFDNUIsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3BCLENBQUM7SUFFRDs7T0FFRztJQUNPLG9CQUFvQjtRQUM1QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBRW5CLG1DQUFtQztRQUNuQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDdEIsQ0FBQzs7eUpBaFptQixzQkFBc0I7NklBQXRCLHNCQUFzQjsyRkFBdEIsc0JBQXNCO2tCQUQzQyxTQUFTO3dLQWVDLE9BQU87c0JBQWYsS0FBSztnQkFLRyxlQUFlO3NCQUF2QixLQUFLO2dCQUtHLElBQUk7c0JBQVosS0FBSztnQkFLRyxFQUFFO3NCQUFWLEtBQUs7Z0JBS0csUUFBUTtzQkFBaEIsS0FBSztnQkFNSSxPQUFPO3NCQUFoQixNQUFNO2dCQUtHLElBQUk7c0JBQWIsTUFBTTtnQkFLRyxLQUFLO3NCQUFkLE1BQU07Z0JBS0csS0FBSztzQkFBZCxNQUFNO2dCQUtHLEtBQUs7c0JBQWQsTUFBTTtnQkFLRyxNQUFNO3NCQUFmLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIEFmdGVyVmlld0NoZWNrZWQsXHJcbiAgQWZ0ZXJWaWV3SW5pdCxcclxuICBFbGVtZW50UmVmLFxyXG4gIEV2ZW50RW1pdHRlcixcclxuICBJbmplY3RvcixcclxuICBJbmplY3RGbGFncyxcclxuICBJbnB1dCxcclxuICBOZ1pvbmUsXHJcbiAgT25DaGFuZ2VzLFxyXG4gIE91dHB1dCxcclxuICBSZW5kZXJlcjIsXHJcbiAgU2ltcGxlQ2hhbmdlcyxcclxuICBEaXJlY3RpdmUsXHJcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuaW1wb3J0IHtcclxuICBDb250cm9sVmFsdWVBY2Nlc3NvcixcclxuICBGb3JtQ29udHJvbCxcclxuICBOZ0NvbnRyb2wsXHJcbiAgQWJzdHJhY3RDb250cm9sLFxyXG59IGZyb20gXCJAYW5ndWxhci9mb3Jtc1wiO1xyXG5pbXBvcnQgeyBUeXBlIH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuXHJcbmltcG9ydCB7IFJlQ2FwdGNoYVR5cGUgfSBmcm9tIFwiLi4vbW9kZWxzL3JlY2FwdGNoYS10eXBlLmVudW1cIjtcclxuaW1wb3J0IHsgU2NyaXB0U2VydmljZSB9IGZyb20gXCIuLi9zZXJ2aWNlcy9zY3JpcHQuc2VydmljZVwiO1xyXG5cclxuQERpcmVjdGl2ZSgpXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlUmVDYXB0Y2hhQ29tcG9uZW50XHJcbiAgaW1wbGVtZW50cyBPbkNoYW5nZXMsIENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBBZnRlclZpZXdJbml0LCBBZnRlclZpZXdDaGVja2VkXHJcbntcclxuICAvKipcclxuICAgKiBQcmVmaXggb2YgdGhlIGNhcHRjaGEgZWxlbWVudFxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCByZWFkb25seSBjYXB0Y2hhRWxlbVByZWZpeCA9IFwibmd4X2NhcHRjaGFfaWRfXCI7XHJcblxyXG4gIHByaXZhdGUgc2V0dXBDYXB0Y2hhOiBib29sZWFuID0gdHJ1ZTtcclxuXHJcbiAgLyoqXHJcbiAgICogR29vZ2xlJ3Mgc2l0ZSBrZXkuXHJcbiAgICogWW91IGNhbiBmaW5kIHRoaXMgdW5kZXIgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9yZWNhcHRjaGFcclxuICAgKi9cclxuICBASW5wdXQoKSBzaXRlS2V5OiBzdHJpbmc7XHJcblxyXG4gIC8qKlxyXG4gICAqIEluZGljYXRlcyBpZiBnbG9iYWwgZG9tYWluICdyZWNhcHRjaGEubmV0JyBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGRlZmF1bHQgZG9tYWluICgnZ29vZ2xlLmNvbScpXHJcbiAgICovXHJcbiAgQElucHV0KCkgdXNlR2xvYmFsRG9tYWluOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIC8qKlxyXG4gICAqIFR5cGVcclxuICAgKi9cclxuICBASW5wdXQoKSB0eXBlOiBcImF1ZGlvXCIgfCBcImltYWdlXCIgPSBcImltYWdlXCI7XHJcblxyXG4gIC8qKlxyXG4gICAqIExhbmd1YWdlIGNvZGUuIEF1dG8tZGV0ZWN0cyB0aGUgdXNlcidzIGxhbmd1YWdlIGlmIHVuc3BlY2lmaWVkLlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIGhsOiBzdHJpbmc7XHJcblxyXG4gIC8qKlxyXG4gICAqIFRhYiBpbmRleFxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIHRhYkluZGV4ID0gMDtcclxuXHJcbiAgLyoqXHJcbiAgICogQ2FsbGVkIHdoZW4gY2FwdGNoYSByZWNlaXZlcyBzdWNjZXNzZnVsIHJlc3BvbnNlLlxyXG4gICAqIENhcHRjaGEgcmVzcG9uc2UgdG9rZW4gaXMgcGFzc2VkIHRvIGV2ZW50LlxyXG4gICAqL1xyXG4gIEBPdXRwdXQoKSBzdWNjZXNzID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIENhbGxlZCB3aGVuIGNhcHRjaGEgaXMgbG9hZGVkLiBFdmVudCByZWNlaXZlcyBpZCBvZiB0aGUgY2FwdGNoYVxyXG4gICAqL1xyXG4gIEBPdXRwdXQoKSBsb2FkID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICAvKipcclxuICAgKiBDYWxsZWQgd2hlbiBjYXB0Y2hhIGlzIHJlc2V0LlxyXG4gICAqL1xyXG4gIEBPdXRwdXQoKSByZXNldCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQ2FsbGVkIHdoZW4gY2FwdGNoYSBpcyBsb2FkZWQgJiByZWFkeS4gSS5lLiB3aGVuIHlvdSBuZWVkIHRvIGV4ZWN1dGUgY2FwdGNoYSBvbiBjb21wb25lbnQgbG9hZC5cclxuICAgKi9cclxuICBAT3V0cHV0KCkgcmVhZHkgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEVycm9yIGNhbGxiYWNrXHJcbiAgICovXHJcbiAgQE91dHB1dCgpIGVycm9yID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICAvKipcclxuICAgKiBFeHBpcmVkIGNhbGxiYWNrXHJcbiAgICovXHJcbiAgQE91dHB1dCgpIGV4cGlyZSA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgYWJzdHJhY3QgY2FwdGNoYVdyYXBwZXJFbGVtPzogRWxlbWVudFJlZjtcclxuXHJcbiAgLyoqXHJcbiAgICogSW5kaWNhdGVzIGlmIGNhcHRjaGEgc2hvdWxkIGJlIHNldCBvbiBsb2FkXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzZXR1cEFmdGVyTG9hZCA9IGZhbHNlO1xyXG5cclxuICAvKipcclxuICAgKiBDYXB0Y2hhIGVsZW1lbnRcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgY2FwdGNoYUVsZW0/OiBIVE1MRWxlbWVudDtcclxuXHJcbiAgLyoqXHJcbiAgICogSWQgb2YgdGhlIGNhcHRjaGEgZWxlbVxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBjYXB0Y2hhSWQ/OiBudW1iZXI7XHJcblxyXG4gIC8qKlxyXG4gICAqIEhvbGRzIGxhc3QgcmVzcG9uc2UgdmFsdWVcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgY3VycmVudFJlc3BvbnNlPzogc3RyaW5nO1xyXG5cclxuICAvKipcclxuICAgKiBJZiBlbmFibGVkLCBjYXB0Y2hhIHdpbGwgcmVzZXQgYWZ0ZXIgcmVjZWl2aW5nIHN1Y2Nlc3MgcmVzcG9uc2UuIFRoaXMgaXMgdXNlZnVsXHJcbiAgICogd2hlbiBpbnZpc2libGUgY2FwdGNoYSBuZWVkIHRvIGJlIHJlc29sdmVkIG11bHRpcGxlIHRpbWVzIG9uIHNhbWUgcGFnZVxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCByZXNldENhcHRjaGFBZnRlclN1Y2Nlc3MgPSBmYWxzZTtcclxuXHJcbiAgLyoqXHJcbiAgICogQ2FwdGNoYSB0eXBlXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIGFic3RyYWN0IHJlY2FwdGNoYVR5cGU6IFJlQ2FwdGNoYVR5cGU7XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlcXVpcmVkIGJ5IENvbnRyb2xWYWx1ZUFjY2Vzc29yXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIG9uQ2hhbmdlOiAodmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCkgPT4gdm9pZDtcclxuICBwcm90ZWN0ZWQgb25Ub3VjaGVkOiAodmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCkgPT4gdm9pZDtcclxuXHJcbiAgLyoqXHJcbiAgICogSW5kaWNhdGVzIGlmIGNhcHRjaGEgaXMgbG9hZGVkXHJcbiAgICovXHJcbiAgcHVibGljIGlzTG9hZGVkID0gZmFsc2U7XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlZmVyZW5jZSB0byBnbG9iYWwgcmVDYXB0Y2hhIEFQSVxyXG4gICAqL1xyXG4gIHB1YmxpYyByZUNhcHRjaGFBcGk/OiBhbnk7XHJcblxyXG4gIC8qKlxyXG4gICAqIElkIG9mIHRoZSBET00gZWxlbWVudCB3cmFwcGluZyBjYXB0Y2hhXHJcbiAgICovXHJcbiAgcHVibGljIGNhcHRjaGFFbGVtSWQ/OiBzdHJpbmc7XHJcblxyXG4gIC8qKlxyXG4gICAqIEZvcm0gQ29udHJvbCB0byBiZSBlbmFibGUgdXNhZ2UgaW4gcmVhY3RpdmUgZm9ybXNcclxuICAgKi9cclxuICBwdWJsaWMgY29udHJvbD86IEFic3RyYWN0Q29udHJvbCB8IG51bGw7XHJcblxyXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihcclxuICAgIHByb3RlY3RlZCByZW5kZXJlcjogUmVuZGVyZXIyLFxyXG4gICAgcHJvdGVjdGVkIHpvbmU6IE5nWm9uZSxcclxuICAgIHByb3RlY3RlZCBpbmplY3RvcjogSW5qZWN0b3IsXHJcbiAgICBwcm90ZWN0ZWQgc2NyaXB0U2VydmljZTogU2NyaXB0U2VydmljZVxyXG4gICkge31cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCkge1xyXG4gICAgdGhpcy5jb250cm9sID0gdGhpcy5pbmplY3Rvci5nZXQ8TmdDb250cm9sIHwgdW5kZWZpbmVkPihcclxuICAgICAgTmdDb250cm9sLFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIEluamVjdEZsYWdzLk9wdGlvbmFsXHJcbiAgICApPy5jb250cm9sO1xyXG4gIH1cclxuXHJcbiAgbmdBZnRlclZpZXdDaGVja2VkKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuc2V0dXBDYXB0Y2hhKSB7XHJcbiAgICAgIHRoaXMuc2V0dXBDYXB0Y2hhID0gZmFsc2U7XHJcbiAgICAgIHRoaXMuc2V0dXBDb21wb25lbnQoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgcmVDYXB0Y2hhIHByb3BlcnRpZXNcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgYWJzdHJhY3QgZ2V0Q2FwdGNoYVByb3BlcnRpZXMoKTogYW55O1xyXG5cclxuICAvKipcclxuICAgKiBVc2VkIGZvciBjYXB0Y2hhIHNwZWNpZmljIHNldHVwXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIGFic3RyYWN0IGNhcHRjaGFTcGVjaWZpY1NldHVwKCk6IHZvaWQ7XHJcblxyXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgIC8vIGNsZWFudXAgc2NyaXB0cyBpZiBsYW5ndWFnZSBjaGFuZ2VkIGJlY2F1c2UgdGhleSBuZWVkIHRvIGJlIHJlbG9hZGVkXHJcbiAgICBpZiAoY2hhbmdlcyAmJiBjaGFuZ2VzLmhsKSB7XHJcbiAgICAgIC8vIGNsZWFudXAgc2NyaXB0cyB3aGVuIGxhbmd1YWdlIGNoYW5nZXNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICFjaGFuZ2VzLmhsLmZpcnN0Q2hhbmdlICYmXHJcbiAgICAgICAgY2hhbmdlcy5obC5jdXJyZW50VmFsdWUgIT09IGNoYW5nZXMuaGwucHJldmlvdXNWYWx1ZVxyXG4gICAgICApIHtcclxuICAgICAgICB0aGlzLnNjcmlwdFNlcnZpY2UuY2xlYW51cCgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGNoYW5nZXMgJiYgY2hhbmdlcy51c2VHbG9iYWxEb21haW4pIHtcclxuICAgICAgLy8gY2xlYW51cCBzY3JpcHRzIHdoZW4gZG9tYWluIGNoYW5nZXNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICFjaGFuZ2VzLnVzZUdsb2JhbERvbWFpbi5maXJzdENoYW5nZSAmJlxyXG4gICAgICAgIGNoYW5nZXMudXNlR2xvYmFsRG9tYWluLmN1cnJlbnRWYWx1ZSAhPT1cclxuICAgICAgICAgIGNoYW5nZXMudXNlR2xvYmFsRG9tYWluLnByZXZpb3VzVmFsdWVcclxuICAgICAgKSB7XHJcbiAgICAgICAgdGhpcy5zY3JpcHRTZXJ2aWNlLmNsZWFudXAoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuc2V0dXBDYXB0Y2hhID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgY2FwdGNoYSByZXNwb25zZSBhcyBwZXIgcmVDYXB0Y2hhIGRvY3NcclxuICAgKi9cclxuICBnZXRSZXNwb25zZSgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMucmVDYXB0Y2hhQXBpLmdldFJlc3BvbnNlKHRoaXMuY2FwdGNoYUlkKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgSWQgb2YgY2FwdGNoYSB3aWRnZXRcclxuICAgKi9cclxuICBnZXRDYXB0Y2hhSWQoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcclxuICAgIHJldHVybiB0aGlzLmNhcHRjaGFJZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlc2V0cyBjYXB0Y2hhXHJcbiAgICovXHJcbiAgcmVzZXRDYXB0Y2hhKCk6IHZvaWQge1xyXG4gICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XHJcbiAgICAgIC8vIHJlc2V0IGNhcHRjaGEgdXNpbmcgR29vZ2xlIGpzIGFwaVxyXG4gICAgICB0aGlzLnJlQ2FwdGNoYUFwaS5yZXNldCgpO1xyXG5cclxuICAgICAgLy8gcmVxdWlyZWQgZHVlIHRvIGZvcm1zXHJcbiAgICAgIHRoaXMub25DaGFuZ2UodW5kZWZpbmVkKTtcclxuICAgICAgdGhpcy5vblRvdWNoZWQodW5kZWZpbmVkKTtcclxuXHJcbiAgICAgIC8vIHRyaWdnZXIgcmVzZXQgZXZlbnRcclxuICAgICAgdGhpcy5yZXNldC5uZXh0KCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgbGFzdCBzdWJtaXR0ZWQgY2FwdGNoYSByZXNwb25zZVxyXG4gICAqL1xyXG4gIGdldEN1cnJlbnRSZXNwb25zZSgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIHRoaXMuY3VycmVudFJlc3BvbnNlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVsb2FkIGNhcHRjaGEuIFVzZWZ1bCB3aGVuIHByb3BlcnRpZXMgKGkuZS4gdGhlbWUpIGNoYW5nZWQgYW5kIGNhcHRjaGEgbmVlZCB0byByZWZsZWN0IHRoZW1cclxuICAgKi9cclxuICByZWxvYWRDYXB0Y2hhKCk6IHZvaWQge1xyXG4gICAgdGhpcy5zZXR1cENvbXBvbmVudCgpO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIGVuc3VyZUNhcHRjaGFFbGVtKGNhcHRjaGFFbGVtSWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3QgY2FwdGNoYUVsZW0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChjYXB0Y2hhRWxlbUlkKTtcclxuXHJcbiAgICBpZiAoIWNhcHRjaGFFbGVtKSB7XHJcbiAgICAgIHRocm93IEVycm9yKGBDYXB0Y2hhIGVsZW1lbnQgd2l0aCBpZCAnJHtjYXB0Y2hhRWxlbUlkfScgd2FzIG5vdCBmb3VuZGApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGFzc2lnbiBjYXB0Y2hhIGFsZW1cclxuICAgIHRoaXMuY2FwdGNoYUVsZW0gPSBjYXB0Y2hhRWxlbTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlc3BvbnNpYmxlIGZvciBpbnN0YW50aWF0aW5nIGNhcHRjaGEgZWxlbWVudFxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCByZW5kZXJSZUNhcHRjaGEoKTogdm9pZCB7XHJcbiAgICAvLyBydW4gb3V0c2lkZSBhbmd1bGFyIHpvbmUgZHVlIHRvIHRpbWVvdXQgaXNzdWVzIHdoZW4gdGVzdGluZ1xyXG4gICAgLy8gZGV0YWlsczogaHR0cHM6Ly9naXRodWIuY29tL0VubmdhZ2Uvbmd4LWNhcHRjaGEvaXNzdWVzLzI2XHJcbiAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICAvLyB0byBmaXggcmVDQVBUQ0hBIHBsYWNlaG9sZGVyIGVsZW1lbnQgbXVzdCBiZSBhbiBlbGVtZW50IG9yIGlkXHJcbiAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9Fbm5nYWdlL25neC1jYXB0Y2hhL2lzc3Vlcy85NlxyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICB0aGlzLmNhcHRjaGFJZCA9IHRoaXMucmVDYXB0Y2hhQXBpLnJlbmRlcihcclxuICAgICAgICAgIHRoaXMuY2FwdGNoYUVsZW1JZCxcclxuICAgICAgICAgIHRoaXMuZ2V0Q2FwdGNoYVByb3BlcnRpZXMoKVxyXG4gICAgICAgICk7XHJcbiAgICAgICAgdGhpcy5yZWFkeS5uZXh0KCk7XHJcbiAgICAgIH0sIDApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDYWxsZWQgd2hlbiBjYXB0Y2hhIHJlY2VpdmVzIHJlc3BvbnNlXHJcbiAgICogQHBhcmFtIGNhbGxiYWNrIENhbGxiYWNrXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIGhhbmRsZUNhbGxiYWNrKGNhbGxiYWNrOiBhbnkpOiB2b2lkIHtcclxuICAgIHRoaXMuY3VycmVudFJlc3BvbnNlID0gY2FsbGJhY2s7XHJcbiAgICB0aGlzLnN1Y2Nlc3MubmV4dChjYWxsYmFjayk7XHJcblxyXG4gICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XHJcbiAgICAgIHRoaXMub25DaGFuZ2UoY2FsbGJhY2spO1xyXG4gICAgICB0aGlzLm9uVG91Y2hlZChjYWxsYmFjayk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAodGhpcy5yZXNldENhcHRjaGFBZnRlclN1Y2Nlc3MpIHtcclxuICAgICAgdGhpcy5yZXNldENhcHRjaGEoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0UHNldWRvVW5pcXVlTnVtYmVyKCk6IG51bWJlciB7XHJcbiAgICByZXR1cm4gbmV3IERhdGUoKS5nZXRVVENNaWxsaXNlY29uZHMoKSArIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDk5OTkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXR1cENvbXBvbmVudCgpOiB2b2lkIHtcclxuICAgIC8vIGNhcHRjaGEgc3BlY2lmaWMgc2V0dXBcclxuICAgIHRoaXMuY2FwdGNoYVNwZWNpZmljU2V0dXAoKTtcclxuXHJcbiAgICAvLyBjcmVhdGUgY2FwdGNoYSB3cmFwcGVyXHJcbiAgICB0aGlzLmNyZWF0ZUFuZFNldENhcHRjaGFFbGVtKCk7XHJcblxyXG4gICAgdGhpcy5zY3JpcHRTZXJ2aWNlLnJlZ2lzdGVyQ2FwdGNoYVNjcmlwdChcclxuICAgICAgdGhpcy51c2VHbG9iYWxEb21haW4sXHJcbiAgICAgIFwiZXhwbGljaXRcIixcclxuICAgICAgKGdyZWNhcHRjaGEpID0+IHtcclxuICAgICAgICB0aGlzLm9ubG9hZENhbGxiYWNrKGdyZWNhcHRjaGEpO1xyXG4gICAgICB9LFxyXG4gICAgICB0aGlzLmhsXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2FsbGVkIHdoZW4gZ29vZ2xlJ3MgcmVjYXB0Y2hhIHNjcmlwdCBpcyByZWFkeVxyXG4gICAqL1xyXG4gIHByaXZhdGUgb25sb2FkQ2FsbGJhY2soZ3JlY2FwY2hhOiBhbnkpOiB2b2lkIHtcclxuICAgIC8vIGFzc2lnbiByZWZlcmVuY2UgdG8gcmVDYXB0Y2hhIEFwaSBvbmNlIGl0cyBsb2FkZWRcclxuICAgIHRoaXMucmVDYXB0Y2hhQXBpID0gZ3JlY2FwY2hhO1xyXG5cclxuICAgIGlmICghdGhpcy5yZUNhcHRjaGFBcGkpIHtcclxuICAgICAgdGhyb3cgRXJyb3IoYFJlQ2FwdGNoYSBBcGkgd2FzIG5vdCBpbml0aWFsaXplZCBjb3JyZWN0bHlgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBsb2FkZWQgZmxhZ1xyXG4gICAgdGhpcy5pc0xvYWRlZCA9IHRydWU7XHJcblxyXG4gICAgLy8gZmlyZSBsb2FkIGV2ZW50XHJcbiAgICB0aGlzLmxvYWQubmV4dCgpO1xyXG5cclxuICAgIC8vIHJlbmRlciBjYXB0Y2hhXHJcbiAgICB0aGlzLnJlbmRlclJlQ2FwdGNoYSgpO1xyXG5cclxuICAgIC8vIHNldHVwIGNvbXBvbmVudCBpZiBpdCB3YXMgZmxhZ2dlZCBhcyBzdWNoXHJcbiAgICBpZiAodGhpcy5zZXR1cEFmdGVyTG9hZCkge1xyXG4gICAgICB0aGlzLnNldHVwQWZ0ZXJMb2FkID0gZmFsc2U7XHJcbiAgICAgIHRoaXMuc2V0dXBDb21wb25lbnQoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2VuZXJhdGVOZXdFbGVtSWQoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLmNhcHRjaGFFbGVtUHJlZml4ICsgdGhpcy5nZXRQc2V1ZG9VbmlxdWVOdW1iZXIoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgY3JlYXRlQW5kU2V0Q2FwdGNoYUVsZW0oKTogdm9pZCB7XHJcbiAgICAvLyBnZW5lcmF0ZSBuZXcgY2FwdGNoYSBpZFxyXG4gICAgdGhpcy5jYXB0Y2hhRWxlbUlkID0gdGhpcy5nZW5lcmF0ZU5ld0VsZW1JZCgpO1xyXG5cclxuICAgIGlmICghdGhpcy5jYXB0Y2hhRWxlbUlkKSB7XHJcbiAgICAgIHRocm93IEVycm9yKGBDYXB0Y2hhIGVsZW0gSWQgaXMgbm90IHNldGApO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghdGhpcy5jYXB0Y2hhV3JhcHBlckVsZW0pIHtcclxuICAgICAgdGhyb3cgRXJyb3IoYENhcHRjaGEgRE9NIGVsZW1lbnQgaXMgbm90IGluaXRpYWxpemVkYCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gcmVtb3ZlIG9sZCBodG1sXHJcbiAgICB0aGlzLmNhcHRjaGFXcmFwcGVyRWxlbS5uYXRpdmVFbGVtZW50LmlubmVySFRNTCA9IFwiXCI7XHJcblxyXG4gICAgLy8gY3JlYXRlIG5ldyB3cmFwcGVyIGZvciBjYXB0Y2hhXHJcbiAgICBjb25zdCBuZXdFbGVtID0gdGhpcy5yZW5kZXJlci5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xyXG4gICAgbmV3RWxlbS5pZCA9IHRoaXMuY2FwdGNoYUVsZW1JZDtcclxuXHJcbiAgICB0aGlzLnJlbmRlcmVyLmFwcGVuZENoaWxkKHRoaXMuY2FwdGNoYVdyYXBwZXJFbGVtLm5hdGl2ZUVsZW1lbnQsIG5ld0VsZW0pO1xyXG5cclxuICAgIC8vIHdoZW4gdXNlIGNhcHRjaGEgaW4gY2RrIHN0ZXBwZXIgdGhlbiB0aHJvd2luZyBlcnJvciBDYXB0Y2hhIGVsZW1lbnQgd2l0aCBpZCAnbmd4X2NhcHRjaGFfaWRfWFhYWCcgbm90IGZvdW5kXHJcbiAgICAvLyB0byBmaXggaXQgY2hlY2tpbmcgZW5zdXJlQ2FwdGNoYUVsZW0gaW4gdGltZW91dCBzbyB0aGF0IGl0cyBjaGVjayBpbiBuZXh0IGNhbGwgYW5kIGl0cyBhYmxlIHRvIGZpbmQgZWxlbWVudFxyXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIC8vIHVwZGF0ZSBjYXB0Y2hhIGVsZW1cclxuICAgICAgaWYgKHRoaXMuY2FwdGNoYUVsZW1JZCkge1xyXG4gICAgICAgIHRoaXMuZW5zdXJlQ2FwdGNoYUVsZW0odGhpcy5jYXB0Y2hhRWxlbUlkKTtcclxuICAgICAgfVxyXG4gICAgfSwgMCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUbyBiZSBhbGlnbmVkIHdpdGggdGhlIENvbnRyb2xWYWx1ZUFjY2Vzc29yIGludGVyZmFjZSB3ZSBuZWVkIHRvIGltcGxlbWVudCB0aGlzIG1ldGhvZFxyXG4gICAqIEhvd2V2ZXIgYXMgd2UgZG9uJ3Qgd2FudCB0byB1cGRhdGUgdGhlIHJlY2FwdGNoYSwgdGhpcyBkb2Vzbid0IG5lZWQgdG8gYmUgaW1wbGVtZW50ZWRcclxuICAgKi9cclxuICBwdWJsaWMgd3JpdGVWYWx1ZShvYmo6IGFueSk6IHZvaWQge31cclxuXHJcbiAgLyoqXHJcbiAgICogVGhpcyBtZXRob2QgaGVscHMgdXMgdGllIHRvZ2V0aGVyIHJlY2FwdGNoYSBhbmQgb3VyIGZvcm1Db250cm9sIHZhbHVlc1xyXG4gICAqL1xyXG4gIHB1YmxpYyByZWdpc3Rlck9uQ2hhbmdlKGZuOiBhbnkpOiB2b2lkIHtcclxuICAgIHRoaXMub25DaGFuZ2UgPSBmbjtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEF0IHNvbWUgcG9pbnQgd2UgbWlnaHQgYmUgaW50ZXJlc3RlZCB3aGV0aGVyIHRoZSB1c2VyIGhhcyB0b3VjaGVkIG91ciBjb21wb25lbnRcclxuICAgKi9cclxuICBwdWJsaWMgcmVnaXN0ZXJPblRvdWNoZWQoZm46IGFueSk6IHZvaWQge1xyXG4gICAgdGhpcy5vblRvdWNoZWQgPSBmbjtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZXMgZXJyb3IgY2FsbGJhY2tcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgaGFuZGxlRXJyb3JDYWxsYmFjaygpOiB2b2lkIHtcclxuICAgIHRoaXMuem9uZS5ydW4oKCkgPT4ge1xyXG4gICAgICB0aGlzLm9uQ2hhbmdlKHVuZGVmaW5lZCk7XHJcbiAgICAgIHRoaXMub25Ub3VjaGVkKHVuZGVmaW5lZCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICB0aGlzLmVycm9yLm5leHQoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZXMgZXhwaXJlZCBjYWxsYmFja1xyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBoYW5kbGVFeHBpcmVDYWxsYmFjaygpOiB2b2lkIHtcclxuICAgIHRoaXMuZXhwaXJlLm5leHQoKTtcclxuXHJcbiAgICAvLyByZXNldCBjYXB0Y2hhIG9uIGV4cGlyZSBjYWxsYmFja1xyXG4gICAgdGhpcy5yZXNldENhcHRjaGEoKTtcclxuICB9XHJcbn1cclxuIl19