moh-common-lib
Version:
A library of Angular components, services, and styles for B.C. Government Ministry of Health (MoH).
236 lines • 22.2 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, Input, Output, EventEmitter, HostListener, forwardRef } from '@angular/core';
import { Base } from '../../models/base';
import { ControlContainer, NgForm } from '@angular/forms';
import * as zxcvbn_ from 'zxcvbn';
// Awkward necessary workaround due to bug in build tools
// https://github.com/jvandemo/generator-angular2-library/issues/221#issuecomment-355945207
/** @type {?} */
const zxcvbn = zxcvbn_;
/**
* Interface for passing in error messages
* Example:
* errorMessages = {
* required: this.componentLabel + ' is required.',
* minLength: this.componentLabel + ' must be ' + this.minLen + ' characters.',
* criteria: this.componentLabel + ' does not meet password criteria.'
* }
* @record
*/
export function PasswordErrorMsg() { }
if (false) {
/** @type {?|undefined} */
PasswordErrorMsg.prototype.required;
/** @type {?|undefined} */
PasswordErrorMsg.prototype.minLength;
/** @type {?|undefined} */
PasswordErrorMsg.prototype.criteria;
}
/**
* PasswordComponent is a text input for a user's password. It includes:
*
* - A password strength bar
* - Minimum length validations
*
* Note - if your application has requirements to check things like username is not
* present in password, we recommend doing this in the (passwordChange) callback.
*
* \@example
* <common-password componentLabel="{{newPwdLabel}}"
* [showPasswordStrength]="true"
* [minLen]="pwdMinLen"
* [pwdCriteria]="pwdValidChars"
* [password]="data.password"
* (passwordChange)="setNewPassword($event)"></common-password>
*
* @export
*/
export class PasswordComponent extends Base {
constructor() {
super();
// Inputs for the component
this.label = 'Password';
this.isRequired = true;
this.isDisabled = false;
this.minLen = '8';
this.maxLen = '32';
this.showPasswordStrength = false;
this.objectID = 'password_' + this.objectId;
// Output from the component
this.passwordChange = new EventEmitter();
this.blurEvent = new EventEmitter();
// Flag for the fa-eye to show or hide password
this.hideValue = true;
this.strengthPercentage = 0;
// default messages
this.requiredMsgSeg = ' is required.';
this.minLenMsgSeg1 = ' must be at least ';
this.minLenMsgSeg2 = ' characters in length.';
this.criteriaMsg = ' contains invalid characters.';
}
/**
* @return {?}
*/
ngOnInit() {
// Set default messages
this.errMsg = {
required: this.label + this.requiredMsgSeg,
minLength: this.label + this.minLenMsgSeg1 + this.minLen + this.minLenMsgSeg2,
criteria: this.label + this.criteriaMsg
};
// Replace default message if provided
if (this.errorMessages) {
if (this.errorMessages.required) {
this.errMsg.required = this.errorMessages.required;
}
if (this.errorMessages.minLength) {
this.errMsg.minLength = this.errorMessages.minLength;
}
if (this.errorMessages.criteria) {
this.errMsg.criteria = this.errorMessages.criteria;
}
}
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (changes.password && this.password) {
// Check strength of password
this.pswdStrength = this.getPasswordStrength(this.password);
this.strengthPercentage = ((this.pswdStrength + 1) / 5) * 100;
}
}
/**
* Passes the value entered back to the calling component
* @param {?} password value the was entered by
* @return {?}
*/
setPassword(password) {
this.passwordChange.emit(password);
}
/**
* @param {?} $event
* @return {?}
*/
onInputBlur($event) {
this.blurEvent.emit(event);
}
// Prevent user from pasting data into the text box
/**
* @param {?} event
* @return {?}
*/
onPaste(event) {
return false;
}
/**
* Get the strength of the password
* 0 = too guessable: risky password. (guesses < 10^3)
* 1 = very guessable: protection from throttled online attacks. (guesses < 10^6)
* 2 = somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)
* 3 = safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)
* 4 = very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)
*
* https://github.com/dropbox/zxcvbn
* @private
* @param {?} password
* @return {?}
*/
getPasswordStrength(password) {
// Password strength feedback
/** @type {?} */
const pswdFeedback = zxcvbn(password);
return pswdFeedback.score;
}
}
PasswordComponent.decorators = [
{ type: Component, args: [{
selector: 'common-password',
template: "<label class=\"control-label\" for=\"{{objectID}}\">{{label}}</label>\r\n<input #pswdRef=\"ngModel\"\r\n type=\"{{hideValue? 'password': 'text'}}\"\r\n class=\"form-control password-field\"\r\n name=\"{{objectID}}\"\r\n id=\"{{objectID}}\"\r\n [ngModel]=\"password\"\r\n (ngModelChange)=\"setPassword($event)\"\r\n (blur)=\"onInputBlur($event)\"\r\n [pattern]=\"pwdCriteria\"\r\n [required]=\"isRequired\"\r\n [minlength]=\"minLen\"\r\n [maxlength]=\"maxLen\"\r\n [disabled]=\"isDisabled\"\r\n autocomplete=\"off\"/>\r\n<span class=\"fa fa-fw {{hideValue? 'fa-eye' : 'fa-eye-slash'}} password-field-icon\"\r\n (click)='hideValue = !hideValue'></span>\r\n<div *ngIf='password && showPasswordStrength'>\r\n<!-- The progress bar -->\r\n <div class=\"progress password-strength-bar\" >\r\n <div class=\"progress-bar {{pswdStrength >= 4? 'bg-success' : (pswdStrength >= 3? 'bg-warning' : 'bg-danger')}}\"\r\n role=\"progressbar\"\r\n [style.width]='strengthPercentage + \"%\"'\r\n [attr.aria-valuenow]=\"strengthPercentage\"\r\n aria-valuemin=\"0\"\r\n aria-valuemax=\"100\">\r\n </div>\r\n </div>\r\n <span class=\"password-progress-label {{pswdStrength >= 4? 'text-success' : (pswdStrength >= 3? 'text-warning' : 'text-danger')}}\"></span>\r\n</div>\r\n<!-- Error messages for component -->\r\n<div *ngIf=\"!pswdRef.disabled && (pswdRef.touched || pswdRef.dirty)\"\r\n role=\"alert\"\r\n class='error-container'\r\n aria-live=\"assertive\">\r\n <div class=\"text-danger\" *ngIf=\"pswdRef?.errors?.required\">\r\n {{errMsg.required}}\r\n </div>\r\n <div class=\"text-danger\" *ngIf=\"pswdRef?.errors?.minlength\">\r\n {{errMsg.minLength}}\r\n </div>\r\n <div class=\"text-danger\" *ngIf=\"pswdRef?.errors?.pattern && !pswdRef?.errors?.minlength\">\r\n {{errMsg.criteria}}\r\n </div>\r\n</div>\r\n\r\n",
/* Re-use the same ngForm that it's parent is using. The component will show
* up in its parents `this.form`, and will auto-update `this.form.valid`
*/
viewProviders: [{ provide: ControlContainer, useExisting: forwardRef((/**
* @return {?}
*/
() => NgForm)) }],
styles: [".password-field-icon{float:right;margin-left:-25px;margin-top:-25px;margin-right:.5rem;position:relative;z-index:2}.password-field{padding-right:2rem}.password-strength-bar{min-width:0;max-width:75%;height:.5rem;margin-top:1em}.password-progress-label{float:right;margin-left:-15px;margin-top:-15px;position:relative;z-index:2}.password-strength-bar+.text-success::after{content:'Good'}.password-strength-bar+.text-warning::after{content:'OK'}.password-strength-bar+.text-danger::after{content:'Bad'}input{width:100%}input[type=password]::-ms-clear,input[type=password]::-ms-reveal{display:none}"]
}] }
];
/** @nocollapse */
PasswordComponent.ctorParameters = () => [];
PasswordComponent.propDecorators = {
label: [{ type: Input }],
isRequired: [{ type: Input }],
isDisabled: [{ type: Input }],
password: [{ type: Input }],
pwdCriteria: [{ type: Input }],
minLen: [{ type: Input }],
maxLen: [{ type: Input }],
errorMessages: [{ type: Input }],
showPasswordStrength: [{ type: Input }],
objectID: [{ type: Input }],
passwordChange: [{ type: Output }],
blurEvent: [{ type: Output }],
onPaste: [{ type: HostListener, args: ['document:paste', ['$event'],] }]
};
if (false) {
/** @type {?} */
PasswordComponent.prototype.label;
/** @type {?} */
PasswordComponent.prototype.isRequired;
/** @type {?} */
PasswordComponent.prototype.isDisabled;
/** @type {?} */
PasswordComponent.prototype.password;
/** @type {?} */
PasswordComponent.prototype.pwdCriteria;
/** @type {?} */
PasswordComponent.prototype.minLen;
/** @type {?} */
PasswordComponent.prototype.maxLen;
/** @type {?} */
PasswordComponent.prototype.errorMessages;
/** @type {?} */
PasswordComponent.prototype.showPasswordStrength;
/** @type {?} */
PasswordComponent.prototype.objectID;
/** @type {?} */
PasswordComponent.prototype.passwordChange;
/** @type {?} */
PasswordComponent.prototype.blurEvent;
/** @type {?} */
PasswordComponent.prototype.hideValue;
/** @type {?} */
PasswordComponent.prototype.pswdStrength;
/** @type {?} */
PasswordComponent.prototype.strengthPercentage;
/** @type {?} */
PasswordComponent.prototype.errMsg;
/**
* @type {?}
* @private
*/
PasswordComponent.prototype.requiredMsgSeg;
/**
* @type {?}
* @private
*/
PasswordComponent.prototype.minLenMsgSeg1;
/**
* @type {?}
* @private
*/
PasswordComponent.prototype.minLenMsgSeg2;
/**
* @type {?}
* @private
*/
PasswordComponent.prototype.criteriaMsg;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFzc3dvcmQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vbW9oLWNvbW1vbi1saWIvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50cy9wYXNzd29yZC9wYXNzd29yZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFhLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwSCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDekMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzFELE9BQU8sS0FBSyxPQUFPLE1BQU0sUUFBUSxDQUFDOzs7O01BRzVCLE1BQU0sR0FBRyxPQUFPOzs7Ozs7Ozs7OztBQWV0QixzQ0FJQzs7O0lBSEMsb0NBQWtCOztJQUNsQixxQ0FBbUI7O0lBQ25CLG9DQUFrQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBOEJwQixNQUFNLE9BQU8saUJBQWtCLFNBQVEsSUFBSTtJQWlDekM7UUFDRSxLQUFLLEVBQUUsQ0FBQzs7UUEvQkQsVUFBSyxHQUFXLFVBQVUsQ0FBQztRQUMzQixlQUFVLEdBQVksSUFBSSxDQUFDO1FBQzNCLGVBQVUsR0FBWSxLQUFLLENBQUM7UUFHNUIsV0FBTSxHQUFZLEdBQUcsQ0FBQztRQUN0QixXQUFNLEdBQVksSUFBSSxDQUFDO1FBRXZCLHlCQUFvQixHQUFZLEtBQUssQ0FBQztRQUN0QyxhQUFRLEdBQVcsV0FBVyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7O1FBSTlDLG1CQUFjLEdBQXlCLElBQUksWUFBWSxFQUFVLENBQUM7UUFDbEUsY0FBUyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7O1FBR2xDLGNBQVMsR0FBRyxJQUFJLENBQUM7UUFFakIsdUJBQWtCLEdBQUcsQ0FBQyxDQUFDOztRQUt0QixtQkFBYyxHQUFXLGVBQWUsQ0FBQztRQUN6QyxrQkFBYSxHQUFXLG9CQUFvQixDQUFDO1FBQzdDLGtCQUFhLEdBQVcsd0JBQXdCLENBQUM7UUFDakQsZ0JBQVcsR0FBVywrQkFBK0IsQ0FBQztJQUs5RCxDQUFDOzs7O0lBRUQsUUFBUTtRQUVOLHVCQUF1QjtRQUN2QixJQUFJLENBQUMsTUFBTSxHQUFNO1lBQ2YsUUFBUSxFQUFFLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLGNBQWM7WUFDMUMsU0FBUyxFQUFFLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxhQUFhO1lBQzdFLFFBQVEsRUFBRSxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxXQUFXO1NBQ3hDLENBQUM7UUFFRixzQ0FBc0M7UUFDdEMsSUFBSyxJQUFJLENBQUMsYUFBYSxFQUFHO1lBRXhCLElBQUssSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLEVBQUc7Z0JBQ2pDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDO2FBQ3BEO1lBRUQsSUFBSyxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRztnQkFDbEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUM7YUFDdEQ7WUFFRCxJQUFLLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxFQUFHO2dCQUNqQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQzthQUNwRDtTQUNGO0lBQ0gsQ0FBQzs7Ozs7SUFFRCxXQUFXLENBQUMsT0FBTztRQUNqQixJQUFJLE9BQU8sQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUVyQyw2QkFBNkI7WUFDN0IsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBRSxDQUFDO1lBQzlELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUUsR0FBRyxHQUFHLENBQUM7U0FDaEU7SUFDSCxDQUFDOzs7Ozs7SUFNRCxXQUFXLENBQUUsUUFBZ0I7UUFDM0IsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUUsUUFBUSxDQUFFLENBQUM7SUFDdkMsQ0FBQzs7Ozs7SUFFRCxXQUFXLENBQUMsTUFBTTtRQUNoQixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQztJQUMvQixDQUFDOzs7Ozs7SUFJRCxPQUFPLENBQUUsS0FBSztRQUNWLE9BQU8sS0FBSyxDQUFDO0lBQ2pCLENBQUM7Ozs7Ozs7Ozs7Ozs7O0lBYU8sbUJBQW1CLENBQUUsUUFBZ0I7OztjQUVyQyxZQUFZLEdBQUcsTUFBTSxDQUFFLFFBQVEsQ0FBRTtRQUN2QyxPQUFPLFlBQVksQ0FBQyxLQUFLLENBQUM7SUFDNUIsQ0FBQzs7O1lBbEhGLFNBQVMsU0FBQztnQkFDVCxRQUFRLEVBQUUsaUJBQWlCO2dCQUMzQiwyNkRBQXdDOzs7O2dCQUt4QyxhQUFhLEVBQUUsQ0FBRSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsVUFBVTs7O3dCQUFDLEdBQUcsRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUU7O2FBQ3pGOzs7OztvQkFJRSxLQUFLO3lCQUNMLEtBQUs7eUJBQ0wsS0FBSzt1QkFDTCxLQUFLOzBCQUNMLEtBQUs7cUJBQ0wsS0FBSztxQkFDTCxLQUFLOzRCQUNMLEtBQUs7bUNBQ0wsS0FBSzt1QkFDTCxLQUFLOzZCQUlMLE1BQU07d0JBQ04sTUFBTTtzQkFvRU4sWUFBWSxTQUFFLGdCQUFnQixFQUFFLENBQUMsUUFBUSxDQUFDOzs7O0lBbEYzQyxrQ0FBb0M7O0lBQ3BDLHVDQUFvQzs7SUFDcEMsdUNBQXFDOztJQUNyQyxxQ0FBMEI7O0lBQzFCLHdDQUFzQzs7SUFDdEMsbUNBQStCOztJQUMvQixtQ0FBZ0M7O0lBQ2hDLDBDQUF5Qzs7SUFDekMsaURBQStDOztJQUMvQyxxQ0FBd0Q7O0lBSXhELDJDQUE0RTs7SUFDNUUsc0NBQXlDOztJQUd6QyxzQ0FBd0I7O0lBQ3hCLHlDQUE0Qjs7SUFDNUIsK0NBQThCOztJQUU5QixtQ0FBZ0M7Ozs7O0lBR2hDLDJDQUFpRDs7Ozs7SUFDakQsMENBQXFEOzs7OztJQUNyRCwwQ0FBeUQ7Ozs7O0lBQ3pELHdDQUE4RCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgT25DaGFuZ2VzLCBmb3J3YXJkUmVmIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEJhc2UgfSBmcm9tICcuLi8uLi9tb2RlbHMvYmFzZSc7XHJcbmltcG9ydCB7IENvbnRyb2xDb250YWluZXIsIE5nRm9ybSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0ICogYXMgenhjdmJuXyBmcm9tICd6eGN2Ym4nO1xyXG4vLyBBd2t3YXJkIG5lY2Vzc2FyeSB3b3JrYXJvdW5kIGR1ZSB0byBidWcgaW4gYnVpbGQgdG9vbHNcclxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2p2YW5kZW1vL2dlbmVyYXRvci1hbmd1bGFyMi1saWJyYXJ5L2lzc3Vlcy8yMjEjaXNzdWVjb21tZW50LTM1NTk0NTIwN1xyXG5jb25zdCB6eGN2Ym4gPSB6eGN2Ym5fO1xyXG5cclxuXHJcbi8qKlxyXG4gKiBUT0RPOiAgQ29udmVydCB0byBjdXN0b20gZm9ybSBjb250cm9sIC0gcmVtb3ZlIG5nRm9ybVxyXG4gKi9cclxuLyoqXHJcbiAqIEludGVyZmFjZSBmb3IgcGFzc2luZyBpbiBlcnJvciBtZXNzYWdlc1xyXG4gKiBFeGFtcGxlOlxyXG4gKiAgZXJyb3JNZXNzYWdlcyA9IHtcclxuICogICAgICAgcmVxdWlyZWQ6IHRoaXMuY29tcG9uZW50TGFiZWwgKyAnIGlzIHJlcXVpcmVkLicsXHJcbiAqICAgICAgIG1pbkxlbmd0aDogdGhpcy5jb21wb25lbnRMYWJlbCArICcgbXVzdCBiZSAnICsgdGhpcy5taW5MZW4gKyAnIGNoYXJhY3RlcnMuJyxcclxuICogICAgICAgY3JpdGVyaWE6IHRoaXMuY29tcG9uZW50TGFiZWwgKyAnIGRvZXMgbm90IG1lZXQgcGFzc3dvcmQgY3JpdGVyaWEuJ1xyXG4gKiAgICAgfVxyXG4gKi9cclxuZXhwb3J0IGludGVyZmFjZSBQYXNzd29yZEVycm9yTXNnIHtcclxuICByZXF1aXJlZD86IHN0cmluZztcclxuICBtaW5MZW5ndGg/OiBzdHJpbmc7XHJcbiAgY3JpdGVyaWE/OiBzdHJpbmc7XHJcbn1cclxuLyoqXHJcbiAqIFBhc3N3b3JkQ29tcG9uZW50IGlzIGEgdGV4dCBpbnB1dCBmb3IgYSB1c2VyJ3MgcGFzc3dvcmQuIEl0IGluY2x1ZGVzOlxyXG4gKlxyXG4gKiAtIEEgcGFzc3dvcmQgc3RyZW5ndGggYmFyXHJcbiAqIC0gTWluaW11bSBsZW5ndGggdmFsaWRhdGlvbnNcclxuICpcclxuICogTm90ZSAtIGlmIHlvdXIgYXBwbGljYXRpb24gaGFzIHJlcXVpcmVtZW50cyB0byBjaGVjayB0aGluZ3MgbGlrZSB1c2VybmFtZSBpcyBub3RcclxuICogcHJlc2VudCBpbiBwYXNzd29yZCwgd2UgcmVjb21tZW5kIGRvaW5nIHRoaXMgaW4gdGhlIChwYXNzd29yZENoYW5nZSkgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqICAgICAgIDxjb21tb24tcGFzc3dvcmQgY29tcG9uZW50TGFiZWw9XCJ7e25ld1B3ZExhYmVsfX1cIlxyXG4gKiAgICAgICAgICAgICAgICAgICAgICBbc2hvd1Bhc3N3b3JkU3RyZW5ndGhdPVwidHJ1ZVwiXHJcbiAqICAgICAgICAgICAgICAgICAgICAgIFttaW5MZW5dPVwicHdkTWluTGVuXCJcclxuICogICAgICAgICAgICAgICAgICAgICAgW3B3ZENyaXRlcmlhXT1cInB3ZFZhbGlkQ2hhcnNcIlxyXG4gKiAgICAgICAgICAgICAgICAgICAgICBbcGFzc3dvcmRdPVwiZGF0YS5wYXNzd29yZFwiXHJcbiAqICAgICAgICAgICAgICAgICAgICAgIChwYXNzd29yZENoYW5nZSk9XCJzZXROZXdQYXNzd29yZCgkZXZlbnQpXCI+PC9jb21tb24tcGFzc3dvcmQ+XHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnY29tbW9uLXBhc3N3b3JkJyxcclxuICB0ZW1wbGF0ZVVybDogJy4vcGFzc3dvcmQuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL3Bhc3N3b3JkLmNvbXBvbmVudC5zY3NzJ10sXHJcbiAgLyogUmUtdXNlIHRoZSBzYW1lIG5nRm9ybSB0aGF0IGl0J3MgcGFyZW50IGlzIHVzaW5nLiBUaGUgY29tcG9uZW50IHdpbGwgc2hvd1xyXG4gICAqIHVwIGluIGl0cyBwYXJlbnRzIGB0aGlzLmZvcm1gLCBhbmQgd2lsbCBhdXRvLXVwZGF0ZSBgdGhpcy5mb3JtLnZhbGlkYFxyXG4gICAqL1xyXG4gIHZpZXdQcm92aWRlcnM6IFsgeyBwcm92aWRlOiBDb250cm9sQ29udGFpbmVyLCB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBOZ0Zvcm0gKSB9IF1cclxufSlcclxuZXhwb3J0IGNsYXNzIFBhc3N3b3JkQ29tcG9uZW50IGV4dGVuZHMgQmFzZSBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzIHtcclxuXHJcbiAgLy8gSW5wdXRzIGZvciB0aGUgY29tcG9uZW50XHJcbiAgQElucHV0KCkgbGFiZWw6IHN0cmluZyA9ICdQYXNzd29yZCc7XHJcbiAgQElucHV0KCkgaXNSZXF1aXJlZDogYm9vbGVhbiA9IHRydWU7XHJcbiAgQElucHV0KCkgaXNEaXNhYmxlZDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIHBhc3N3b3JkOiBzdHJpbmc7XHJcbiAgQElucHV0KCkgcHdkQ3JpdGVyaWE6IHN0cmluZyB8IFJlZ0V4cDtcclxuICBASW5wdXQoKSBtaW5MZW46IHN0cmluZyAgPSAnOCc7XHJcbiAgQElucHV0KCkgbWF4TGVuOiBzdHJpbmcgID0gJzMyJztcclxuICBASW5wdXQoKSBlcnJvck1lc3NhZ2VzOiBQYXNzd29yZEVycm9yTXNnO1xyXG4gIEBJbnB1dCgpIHNob3dQYXNzd29yZFN0cmVuZ3RoOiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgb2JqZWN0SUQ6IHN0cmluZyA9ICdwYXNzd29yZF8nICsgdGhpcy5vYmplY3RJZDtcclxuXHJcblxyXG4gIC8vIE91dHB1dCBmcm9tIHRoZSBjb21wb25lbnRcclxuICBAT3V0cHV0KCkgcGFzc3dvcmRDaGFuZ2U6IEV2ZW50RW1pdHRlcjxzdHJpbmc+ID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XHJcbiAgQE91dHB1dCgpIGJsdXJFdmVudCA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuXHJcbiAgLy8gRmxhZyBmb3IgdGhlIGZhLWV5ZSB0byBzaG93IG9yIGhpZGUgcGFzc3dvcmRcclxuICBwdWJsaWMgaGlkZVZhbHVlID0gdHJ1ZTtcclxuICBwdWJsaWMgcHN3ZFN0cmVuZ3RoOiBudW1iZXI7XHJcbiAgcHVibGljIHN0cmVuZ3RoUGVyY2VudGFnZSA9IDA7XHJcblxyXG4gIHB1YmxpYyBlcnJNc2c6IFBhc3N3b3JkRXJyb3JNc2c7XHJcblxyXG4gIC8vIGRlZmF1bHQgbWVzc2FnZXNcclxuICBwcml2YXRlIHJlcXVpcmVkTXNnU2VnOiBzdHJpbmcgPSAnIGlzIHJlcXVpcmVkLic7XHJcbiAgcHJpdmF0ZSBtaW5MZW5Nc2dTZWcxOiBzdHJpbmcgPSAnIG11c3QgYmUgYXQgbGVhc3QgJztcclxuICBwcml2YXRlIG1pbkxlbk1zZ1NlZzI6IHN0cmluZyA9ICcgY2hhcmFjdGVycyBpbiBsZW5ndGguJztcclxuICBwcml2YXRlIGNyaXRlcmlhTXNnOiBzdHJpbmcgPSAnIGNvbnRhaW5zIGludmFsaWQgY2hhcmFjdGVycy4nO1xyXG5cclxuXHJcbiAgY29uc3RydWN0b3IoKSB7XHJcbiAgICBzdXBlcigpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkluaXQoKSB7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgbWVzc2FnZXNcclxuICAgIHRoaXMuZXJyTXNnID0gICAge1xyXG4gICAgICByZXF1aXJlZDogdGhpcy5sYWJlbCArIHRoaXMucmVxdWlyZWRNc2dTZWcsXHJcbiAgICAgIG1pbkxlbmd0aDogdGhpcy5sYWJlbCArIHRoaXMubWluTGVuTXNnU2VnMSArIHRoaXMubWluTGVuICsgdGhpcy5taW5MZW5Nc2dTZWcyLFxyXG4gICAgICBjcml0ZXJpYTogdGhpcy5sYWJlbCArIHRoaXMuY3JpdGVyaWFNc2dcclxuICAgIH07XHJcblxyXG4gICAgLy8gUmVwbGFjZSBkZWZhdWx0IG1lc3NhZ2UgaWYgcHJvdmlkZWRcclxuICAgIGlmICggdGhpcy5lcnJvck1lc3NhZ2VzICkge1xyXG5cclxuICAgICAgaWYgKCB0aGlzLmVycm9yTWVzc2FnZXMucmVxdWlyZWQgKSB7XHJcbiAgICAgICAgdGhpcy5lcnJNc2cucmVxdWlyZWQgPSB0aGlzLmVycm9yTWVzc2FnZXMucmVxdWlyZWQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICggdGhpcy5lcnJvck1lc3NhZ2VzLm1pbkxlbmd0aCApIHtcclxuICAgICAgICB0aGlzLmVyck1zZy5taW5MZW5ndGggPSB0aGlzLmVycm9yTWVzc2FnZXMubWluTGVuZ3RoO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoIHRoaXMuZXJyb3JNZXNzYWdlcy5jcml0ZXJpYSApIHtcclxuICAgICAgICB0aGlzLmVyck1zZy5jcml0ZXJpYSA9IHRoaXMuZXJyb3JNZXNzYWdlcy5jcml0ZXJpYTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgbmdPbkNoYW5nZXMoY2hhbmdlcykge1xyXG4gICAgaWYgKGNoYW5nZXMucGFzc3dvcmQgJiYgdGhpcy5wYXNzd29yZCkge1xyXG5cclxuICAgICAgLy8gQ2hlY2sgc3RyZW5ndGggb2YgcGFzc3dvcmRcclxuICAgICAgdGhpcy5wc3dkU3RyZW5ndGggPSB0aGlzLmdldFBhc3N3b3JkU3RyZW5ndGgoIHRoaXMucGFzc3dvcmQgKTtcclxuICAgICAgdGhpcy5zdHJlbmd0aFBlcmNlbnRhZ2UgPSAoKHRoaXMucHN3ZFN0cmVuZ3RoICsgMSkgLyA1ICkgKiAxMDA7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBQYXNzZXMgdGhlIHZhbHVlIGVudGVyZWQgYmFjayB0byB0aGUgY2FsbGluZyBjb21wb25lbnRcclxuICAgKiBAcGFyYW0gcGFzc3dvcmQgdmFsdWUgdGhlIHdhcyBlbnRlcmVkIGJ5XHJcbiAgICovXHJcbiAgc2V0UGFzc3dvcmQoIHBhc3N3b3JkOiBzdHJpbmcgKSB7XHJcbiAgICB0aGlzLnBhc3N3b3JkQ2hhbmdlLmVtaXQoIHBhc3N3b3JkICk7XHJcbiAgfVxyXG5cclxuICBvbklucHV0Qmx1cigkZXZlbnQpIHtcclxuICAgIHRoaXMuYmx1ckV2ZW50LmVtaXQoIGV2ZW50ICk7XHJcbiAgfVxyXG5cclxuICAvLyBQcmV2ZW50IHVzZXIgZnJvbSBwYXN0aW5nIGRhdGEgaW50byB0aGUgdGV4dCBib3hcclxuICBASG9zdExpc3RlbmVyKCAnZG9jdW1lbnQ6cGFzdGUnLCBbJyRldmVudCddIClcclxuICBvblBhc3RlKCBldmVudCApIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2V0IHRoZSBzdHJlbmd0aCBvZiB0aGUgcGFzc3dvcmRcclxuXHJcbiAgICogICAgMCA9IHRvbyBndWVzc2FibGU6IHJpc2t5IHBhc3N3b3JkLiAoZ3Vlc3NlcyA8IDEwXjMpXHJcbiAgICogICAgMSA9IHZlcnkgZ3Vlc3NhYmxlOiBwcm90ZWN0aW9uIGZyb20gdGhyb3R0bGVkIG9ubGluZSBhdHRhY2tzLiAoZ3Vlc3NlcyA8IDEwXjYpXHJcbiAgICogICAgMiA9IHNvbWV3aGF0IGd1ZXNzYWJsZTogcHJvdGVjdGlvbiBmcm9tIHVudGhyb3R0bGVkIG9ubGluZSBhdHRhY2tzLiAoZ3Vlc3NlcyA8IDEwXjgpXHJcbiAgICogICAgMyA9IHNhZmVseSB1bmd1ZXNzYWJsZTogbW9kZXJhdGUgcHJvdGVjdGlvbiBmcm9tIG9mZmxpbmUgc2xvdy1oYXNoIHNjZW5hcmlvLiAoZ3Vlc3NlcyA8IDEwXjEwKVxyXG4gICAqICAgIDQgPSB2ZXJ5IHVuZ3Vlc3NhYmxlOiBzdHJvbmcgcHJvdGVjdGlvbiBmcm9tIG9mZmxpbmUgc2xvdy1oYXNoIHNjZW5hcmlvLiAoZ3Vlc3NlcyA+PSAxMF4xMClcclxuICAgKlxyXG4gICAqICBodHRwczovL2dpdGh1Yi5jb20vZHJvcGJveC96eGN2Ym5cclxuICAgKi9cclxuICBwcml2YXRlIGdldFBhc3N3b3JkU3RyZW5ndGgoIHBhc3N3b3JkOiBzdHJpbmcgKTogbnVtYmVyIHtcclxuICAgIC8vIFBhc3N3b3JkIHN0cmVuZ3RoIGZlZWRiYWNrXHJcbiAgICBjb25zdCBwc3dkRmVlZGJhY2sgPSB6eGN2Ym4oIHBhc3N3b3JkICk7XHJcbiAgICByZXR1cm4gcHN3ZEZlZWRiYWNrLnNjb3JlO1xyXG4gIH1cclxufVxyXG4iXX0=