ngx-stars
Version:
Simple stars rating component for Angular >= 2
201 lines • 38.1 kB
JavaScript
import { Component, EventEmitter, Input, Output } from '@angular/core';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class NgxStarsComponent {
constructor() {
this.maxStars = 5;
this.initialStars = 0;
this.animationSpeed = 100;
this.wholeStars = false;
this.rtl = false;
this.ratingOutput = new EventEmitter();
this.customClassIdentifier = Math.random().toString(36).substring(2);
this.safeSize = () => (Number.isInteger(this.size) && this.size > 0 && this.size < 6) ? this.size : 1;
}
ngOnInit() {
this.setupStarImages();
this.editableStars = Array.from(new Array(this.maxStars)).map((elem, index) => new EditableStar(index));
if (this.rtl) {
this.editableStars = this.editableStars.reverse();
}
this.setRating(this.initialStars);
if (this.animation) {
this.animationInterval = setInterval(this.starAnimation.bind(this), this.animationSpeed);
}
}
ngOnDestroy() {
// remove the three custom classes we created if custom image urls were provided
if (this.customCssClasses) {
this.customCssClasses.forEach(style => {
if (style && style.parentNode) {
style.parentNode.removeChild(style);
}
});
}
}
setupStarImages() {
if (this.customStarIcons) {
this.customCssClasses = [];
Object.keys(this.customStarIcons).map(key => key).forEach(starType => {
const classname = this.getStarClass(starType);
this.createCssClass(classname, starType);
});
}
}
createCssClass(classname, starType) {
const clazz = document.createElement('style');
clazz.type = 'text/css';
clazz.innerHTML = `.${classname} {
-webkit-mask-image: url(${this.customStarIcons[starType]});
mask-image: url(${this.customStarIcons[starType]});
}`;
document.getElementsByTagName('head')[0].appendChild(clazz);
this.customCssClasses.push(clazz);
}
starPadding() {
return { 'margin-right': this.customPadding || `calc(${this.starSize().width} / 10)` };
}
starColorAndSize() {
return Object.assign({}, this.starColor(), this.starSize());
}
starColor() {
return { 'background-color': this.color || 'crimson' };
}
starSize() {
return {
height: this.customSize || `${15 * this.safeSize()}px`,
width: this.customSize || `${16 * this.safeSize()}px`,
};
}
zeroStarLeft() {
if (this.rtl) {
const width = this.starSize()['width'];
return `calc(${width} * ${this.maxStars})`;
}
return '-16px';
}
starAnimation() {
this.animationRunning = true;
if (this.rating < this.maxStars) {
this.setRating(this.rating += 0.5);
}
else {
this.setRating(0);
}
}
cancelStarAnimation() {
if (this.animationRunning) {
clearInterval(this.animationInterval);
this.rating = 0;
this.animationRunning = false;
}
}
setRating(rating) {
this.rating = Math.round(rating * 2) / 2;
this.onStarsUnhover();
}
onStarHover(event, clickedStar) {
this.cancelStarAnimation();
const clickedInFirstHalf = this.clickedInFirstHalf(event);
// fill in either a half or whole star depending on where user clicked
clickedStar.classname = (!this.wholeStars && clickedInFirstHalf) ? this.getStarClass('half') : this.getStarClass('full');
// fill in all stars in previous positions and clear all in later ones
this.editableStars.forEach(star => {
if (star.position > clickedStar.position) {
star.classname = this.getStarClass('empty');
}
else if (star.position < clickedStar.position) {
star.classname = this.getStarClass('full');
}
});
}
onStarClick(event, clickedStar) {
this.cancelStarAnimation();
// lock in current rating
const clickedInFirstHalf = this.clickedInFirstHalf(event);
this.rating = clickedStar.position + ((!this.wholeStars && clickedInFirstHalf) ? 0.5 : 1);
this.ratingOutput.emit(this.rating);
}
// hidden star to left of first star lets user click there to set to 0
onZeroStarClick() {
this.setRating(0);
this.ratingOutput.emit(this.rating);
}
onZeroStarHover() {
// clear all stars
this.editableStars.forEach(star => star.classname = this.getStarClass('empty'));
}
onStarsUnhover() {
// when user stops hovering we want to make stars reflect the last rating applied by clicking
this.editableStars.forEach(star => {
const starNumber = star.position + 1;
if (this.rating >= starNumber) {
star.classname = this.getStarClass('full');
}
else if (this.rating > starNumber - 1 && this.rating < starNumber) {
star.classname = this.getStarClass('half');
}
else {
star.classname = this.getStarClass('empty');
}
});
}
clickedInFirstHalf(event) {
const starIcon = event.target;
if (this.rtl) {
return event.pageX > starIcon.getBoundingClientRect().right - starIcon.offsetWidth / 2;
}
else {
return event.pageX < starIcon.getBoundingClientRect().left + starIcon.offsetWidth / 2;
}
}
noop() { }
getStarClass(starType) {
if (this.customCssClasses) {
return `ngx-stars-star-${starType}-${this.customClassIdentifier}`;
}
return `star-${starType}`;
}
// this and the aria-labels and role in the html inspired by https://stackoverflow.com/q/55966205
getAriaLabel() {
return `Rating: ${this.rating} out of ${this.maxStars} stars ${this.readonly ? '' : '. Can be edited.'}`;
}
}
NgxStarsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0", ngImport: i0, type: NgxStarsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
NgxStarsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.0", type: NgxStarsComponent, selector: "ngx-stars", inputs: { maxStars: "maxStars", initialStars: "initialStars", readonly: "readonly", size: "size", customSize: "customSize", color: "color", animation: "animation", animationSpeed: "animationSpeed", customPadding: "customPadding", wholeStars: "wholeStars", customStarIcons: "customStarIcons", rtl: "rtl" }, outputs: { ratingOutput: "ratingOutput" }, ngImport: i0, template: "<div class=\"stars-line\" (mouseleave)=\"readonly ? noop() : onStarsUnhover()\" role=\"img\" [attr.aria-label]=\"getAriaLabel()\">\n <span class=\"star zero-star\" [ngStyle]=\"starSize()\" [style.left]=\"zeroStarLeft()\" aria-hidden=\"true\" (click)=\"readonly ? noop() : onZeroStarClick()\" (mousemove)=\"readonly ? noop() : onZeroStarHover()\"></span>\n <div *ngFor=\"let star of editableStars;\" [ngStyle]=\"starPadding()\" aria-hidden=\"true\" (click)=\"readonly ? noop() : onStarClick($event, star)\" (mousemove)=\"readonly ? noop() : onStarHover($event, star)\">\n <span class=\"star\" [class.star-rtl]=\"rtl\" [ngClass]=\"star.classname\" [ngStyle]=\"starColorAndSize()\" aria-hidden=\"true\"></span>\n </div>\n</div>\n", styles: [".stars-line{display:flex;align-items:center;position:relative}.stars-line>div{z-index:999}.zero-star{color:transparent;position:absolute}.star{display:inline-block;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.star-rtl{transform:scaleX(-1)}.star-empty{-webkit-mask-image:url(\"data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='far' data-icon='star' class='svg-inline--fa fa-star fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M528.1 171.5L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6zM388.6 312.3l23.7 138.4L288 385.4l-124.3 65.3 23.7-138.4-100.6-98 139-20.2 62.2-126 62.2 126 139 20.2-100.6 98z'%3E%3C/path%3E%3C/svg%3E%0A\");mask-image:url(\"data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='far' data-icon='star' class='svg-inline--fa fa-star fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M528.1 171.5L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6zM388.6 312.3l23.7 138.4L288 385.4l-124.3 65.3 23.7-138.4-100.6-98 139-20.2 62.2-126 62.2 126 139 20.2-100.6 98z'%3E%3C/path%3E%3C/svg%3E%0A\")}.star-half{-webkit-mask-image:url(\"data:image/svg+xml,%3C!-- had to hack this one's viewbox otherwise it didn't line up with the other two --%3E%3C!-- changed viewbox from '0 0 536 512' to '-20 0 576 512' --%3E%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='star-half-alt' class='svg-inline--fa fa-star-half-alt fa-w-17' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='-20 0 576 512'%3E%3Cpath fill='currentColor' d='M508.55 171.51L362.18 150.2 296.77 17.81C290.89 5.98 279.42 0 267.95 0c-11.4 0-22.79 5.9-28.69 17.81l-65.43 132.38-146.38 21.29c-26.25 3.8-36.77 36.09-17.74 54.59l105.89 103-25.06 145.48C86.98 495.33 103.57 512 122.15 512c4.93 0 10-1.17 14.87-3.75l130.95-68.68 130.94 68.7c4.86 2.55 9.92 3.71 14.83 3.71 18.6 0 35.22-16.61 31.66-37.4l-25.03-145.49 105.91-102.98c19.04-18.5 8.52-50.8-17.73-54.6zm-121.74 123.2l-18.12 17.62 4.28 24.88 19.52 113.45-102.13-53.59-22.38-11.74.03-317.19 51.03 103.29 11.18 22.63 25.01 3.64 114.23 16.63-82.65 80.38z'%3E%3C/path%3E%3C/svg%3E\");mask-image:url(\"data:image/svg+xml,%3C!-- had to hack this one's viewbox otherwise it didn't line up with the other two --%3E%3C!-- changed viewbox from '0 0 536 512' to '-20 0 576 512' --%3E%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='star-half-alt' class='svg-inline--fa fa-star-half-alt fa-w-17' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='-20 0 576 512'%3E%3Cpath fill='currentColor' d='M508.55 171.51L362.18 150.2 296.77 17.81C290.89 5.98 279.42 0 267.95 0c-11.4 0-22.79 5.9-28.69 17.81l-65.43 132.38-146.38 21.29c-26.25 3.8-36.77 36.09-17.74 54.59l105.89 103-25.06 145.48C86.98 495.33 103.57 512 122.15 512c4.93 0 10-1.17 14.87-3.75l130.95-68.68 130.94 68.7c4.86 2.55 9.92 3.71 14.83 3.71 18.6 0 35.22-16.61 31.66-37.4l-25.03-145.49 105.91-102.98c19.04-18.5 8.52-50.8-17.73-54.6zm-121.74 123.2l-18.12 17.62 4.28 24.88 19.52 113.45-102.13-53.59-22.38-11.74.03-317.19 51.03 103.29 11.18 22.63 25.01 3.64 114.23 16.63-82.65 80.38z'%3E%3C/path%3E%3C/svg%3E\")}.star-full{-webkit-mask-image:url(\"data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='star' class='svg-inline--fa fa-star fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z'%3E%3C/path%3E%3C/svg%3E\");mask-image:url(\"data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='star' class='svg-inline--fa fa-star fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z'%3E%3C/path%3E%3C/svg%3E\")}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0", ngImport: i0, type: NgxStarsComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-stars', template: "<div class=\"stars-line\" (mouseleave)=\"readonly ? noop() : onStarsUnhover()\" role=\"img\" [attr.aria-label]=\"getAriaLabel()\">\n <span class=\"star zero-star\" [ngStyle]=\"starSize()\" [style.left]=\"zeroStarLeft()\" aria-hidden=\"true\" (click)=\"readonly ? noop() : onZeroStarClick()\" (mousemove)=\"readonly ? noop() : onZeroStarHover()\"></span>\n <div *ngFor=\"let star of editableStars;\" [ngStyle]=\"starPadding()\" aria-hidden=\"true\" (click)=\"readonly ? noop() : onStarClick($event, star)\" (mousemove)=\"readonly ? noop() : onStarHover($event, star)\">\n <span class=\"star\" [class.star-rtl]=\"rtl\" [ngClass]=\"star.classname\" [ngStyle]=\"starColorAndSize()\" aria-hidden=\"true\"></span>\n </div>\n</div>\n", styles: [".stars-line{display:flex;align-items:center;position:relative}.stars-line>div{z-index:999}.zero-star{color:transparent;position:absolute}.star{display:inline-block;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.star-rtl{transform:scaleX(-1)}.star-empty{-webkit-mask-image:url(\"data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='far' data-icon='star' class='svg-inline--fa fa-star fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M528.1 171.5L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6zM388.6 312.3l23.7 138.4L288 385.4l-124.3 65.3 23.7-138.4-100.6-98 139-20.2 62.2-126 62.2 126 139 20.2-100.6 98z'%3E%3C/path%3E%3C/svg%3E%0A\");mask-image:url(\"data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='far' data-icon='star' class='svg-inline--fa fa-star fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M528.1 171.5L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6zM388.6 312.3l23.7 138.4L288 385.4l-124.3 65.3 23.7-138.4-100.6-98 139-20.2 62.2-126 62.2 126 139 20.2-100.6 98z'%3E%3C/path%3E%3C/svg%3E%0A\")}.star-half{-webkit-mask-image:url(\"data:image/svg+xml,%3C!-- had to hack this one's viewbox otherwise it didn't line up with the other two --%3E%3C!-- changed viewbox from '0 0 536 512' to '-20 0 576 512' --%3E%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='star-half-alt' class='svg-inline--fa fa-star-half-alt fa-w-17' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='-20 0 576 512'%3E%3Cpath fill='currentColor' d='M508.55 171.51L362.18 150.2 296.77 17.81C290.89 5.98 279.42 0 267.95 0c-11.4 0-22.79 5.9-28.69 17.81l-65.43 132.38-146.38 21.29c-26.25 3.8-36.77 36.09-17.74 54.59l105.89 103-25.06 145.48C86.98 495.33 103.57 512 122.15 512c4.93 0 10-1.17 14.87-3.75l130.95-68.68 130.94 68.7c4.86 2.55 9.92 3.71 14.83 3.71 18.6 0 35.22-16.61 31.66-37.4l-25.03-145.49 105.91-102.98c19.04-18.5 8.52-50.8-17.73-54.6zm-121.74 123.2l-18.12 17.62 4.28 24.88 19.52 113.45-102.13-53.59-22.38-11.74.03-317.19 51.03 103.29 11.18 22.63 25.01 3.64 114.23 16.63-82.65 80.38z'%3E%3C/path%3E%3C/svg%3E\");mask-image:url(\"data:image/svg+xml,%3C!-- had to hack this one's viewbox otherwise it didn't line up with the other two --%3E%3C!-- changed viewbox from '0 0 536 512' to '-20 0 576 512' --%3E%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='star-half-alt' class='svg-inline--fa fa-star-half-alt fa-w-17' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='-20 0 576 512'%3E%3Cpath fill='currentColor' d='M508.55 171.51L362.18 150.2 296.77 17.81C290.89 5.98 279.42 0 267.95 0c-11.4 0-22.79 5.9-28.69 17.81l-65.43 132.38-146.38 21.29c-26.25 3.8-36.77 36.09-17.74 54.59l105.89 103-25.06 145.48C86.98 495.33 103.57 512 122.15 512c4.93 0 10-1.17 14.87-3.75l130.95-68.68 130.94 68.7c4.86 2.55 9.92 3.71 14.83 3.71 18.6 0 35.22-16.61 31.66-37.4l-25.03-145.49 105.91-102.98c19.04-18.5 8.52-50.8-17.73-54.6zm-121.74 123.2l-18.12 17.62 4.28 24.88 19.52 113.45-102.13-53.59-22.38-11.74.03-317.19 51.03 103.29 11.18 22.63 25.01 3.64 114.23 16.63-82.65 80.38z'%3E%3C/path%3E%3C/svg%3E\")}.star-full{-webkit-mask-image:url(\"data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='star' class='svg-inline--fa fa-star fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z'%3E%3C/path%3E%3C/svg%3E\");mask-image:url(\"data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='star' class='svg-inline--fa fa-star fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z'%3E%3C/path%3E%3C/svg%3E\")}\n"] }]
}], propDecorators: { maxStars: [{
type: Input
}], initialStars: [{
type: Input
}], readonly: [{
type: Input
}], size: [{
type: Input
}], customSize: [{
type: Input
}], color: [{
type: Input
}], animation: [{
type: Input
}], animationSpeed: [{
type: Input
}], customPadding: [{
type: Input
}], wholeStars: [{
type: Input
}], customStarIcons: [{
type: Input
}], rtl: [{
type: Input
}], ratingOutput: [{
type: Output
}] } });
export class EditableStar {
constructor(position) {
this.position = position;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXN0YXJzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1zdGFycy9zcmMvbGliL25neC1zdGFycy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtc3RhcnMvc3JjL2xpYi9uZ3gtc3RhcnMuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFxQixNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7OztBQU8xRixNQUFNLE9BQU8saUJBQWlCO0lBTDlCO1FBUUUsYUFBUSxHQUFXLENBQUMsQ0FBQztRQUdyQixpQkFBWSxHQUFXLENBQUMsQ0FBQztRQWtCekIsbUJBQWMsR0FBVyxHQUFHLENBQUM7UUFNN0IsZUFBVSxHQUFZLEtBQUssQ0FBQztRQU01QixRQUFHLEdBQVksS0FBSyxDQUFDO1FBR3JCLGlCQUFZLEdBQXlCLElBQUksWUFBWSxFQUFFLENBQUM7UUFRaEQsMEJBQXFCLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7UUEwRWhFLGFBQVEsR0FBRyxHQUFHLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztLQXVHMUc7SUEvS0MsUUFBUTtRQUNOLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLENBQUMsSUFB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TTs7QUE4TFQsTUFBTSxPQUFPLFlBQVk7SUFJdkIsWUFBWSxRQUFnQjtRQUMxQixJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztJQUMzQixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE9uRGVzdHJveSwgT25Jbml0LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LXN0YXJzJyxcbiAgdGVtcGxhdGVVcmw6ICcuL25neC1zdGFycy5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWyAnLi9uZ3gtc3RhcnMuY29tcG9uZW50LmNzcycgXSxcbn0pXG5leHBvcnQgY2xhc3MgTmd4U3RhcnNDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG5cbiAgQElucHV0KClcbiAgbWF4U3RhcnM6IG51bWJlciA9IDU7XG5cbiAgQElucHV0KClcbiAgaW5pdGlhbFN0YXJzOiBudW1iZXIgPSAwO1xuXG4gIEBJbnB1dCgpXG4gIHJlYWRvbmx5OiBib29sZWFuO1xuXG4gIEBJbnB1dCgpXG4gIHNpemU6IG51bWJlcjtcblxuICBASW5wdXQoKVxuICBjdXN0b21TaXplOiBzdHJpbmc7XG5cbiAgQElucHV0KClcbiAgY29sb3I6IHN0cmluZztcblxuICBASW5wdXQoKVxuICBhbmltYXRpb246IGJvb2xlYW47XG5cbiAgQElucHV0KClcbiAgYW5pbWF0aW9uU3BlZWQ6IG51bWJlciA9IDEwMDtcblxuICBASW5wdXQoKVxuICBjdXN0b21QYWRkaW5nOiBzdHJpbmc7XG5cbiAgQElucHV0KClcbiAgd2hvbGVTdGFyczogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpXG4gIGN1c3RvbVN0YXJJY29uczogeyBlbXB0eTogc3RyaW5nLCBoYWxmOiBzdHJpbmcsIGZ1bGw6IHN0cmluZyB9O1xuXG4gIEBJbnB1dCgpXG4gIHJ0bDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIEBPdXRwdXQoKVxuICByYXRpbmdPdXRwdXQ6IEV2ZW50RW1pdHRlcjxudW1iZXI+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIHJhdGluZzogbnVtYmVyO1xuICBlZGl0YWJsZVN0YXJzOiBFZGl0YWJsZVN0YXJbXTtcbiAgYW5pbWF0aW9uSW50ZXJ2YWw6IGFueTtcbiAgYW5pbWF0aW9uUnVubmluZzogYm9vbGVhbjtcblxuICBwcml2YXRlIGN1c3RvbUNzc0NsYXNzZXM6IEhUTUxTdHlsZUVsZW1lbnRbXTtcbiAgcHJpdmF0ZSBjdXN0b21DbGFzc0lkZW50aWZpZXIgPSBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHJpbmcoMik7XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5zZXR1cFN0YXJJbWFnZXMoKTtcbiAgICB0aGlzLmVkaXRhYmxlU3RhcnMgPSBBcnJheS5mcm9tKG5ldyBBcnJheSh0aGlzLm1heFN0YXJzKSkubWFwKChlbGVtLCBpbmRleCkgPT4gbmV3IEVkaXRhYmxlU3RhcihpbmRleCkpO1xuICAgIGlmICh0aGlzLnJ0bCkge1xuICAgICAgdGhpcy5lZGl0YWJsZVN0YXJzID0gdGhpcy5lZGl0YWJsZVN0YXJzLnJldmVyc2UoKTtcbiAgICB9XG4gICAgdGhpcy5zZXRSYXRpbmcodGhpcy5pbml0aWFsU3RhcnMpO1xuXG4gICAgaWYgKHRoaXMuYW5pbWF0aW9uKSB7XG4gICAgICB0aGlzLmFuaW1hdGlvbkludGVydmFsID0gc2V0SW50ZXJ2YWwodGhpcy5zdGFyQW5pbWF0aW9uLmJpbmQodGhpcyksIHRoaXMuYW5pbWF0aW9uU3BlZWQpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIC8vIHJlbW92ZSB0aGUgdGhyZWUgY3VzdG9tIGNsYXNzZXMgd2UgY3JlYXRlZCBpZiBjdXN0b20gaW1hZ2UgdXJscyB3ZXJlIHByb3ZpZGVkXG4gICAgaWYgKHRoaXMuY3VzdG9tQ3NzQ2xhc3Nlcykge1xuICAgICAgdGhpcy5jdXN0b21Dc3NDbGFzc2VzLmZvckVhY2goc3R5bGUgPT4ge1xuICAgICAgICBpZiAoc3R5bGUgJiYgc3R5bGUucGFyZW50Tm9kZSkge1xuICAgICAgICAgIHN0eWxlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoc3R5bGUpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldHVwU3RhckltYWdlcygpIHtcbiAgICBpZiAodGhpcy5jdXN0b21TdGFySWNvbnMpIHtcbiAgICAgIHRoaXMuY3VzdG9tQ3NzQ2xhc3NlcyA9IFtdO1xuICAgICAgT2JqZWN0LmtleXModGhpcy5jdXN0b21TdGFySWNvbnMpLm1hcChrZXkgPT4ga2V5IGFzIFN0YXJUeXBlKS5mb3JFYWNoKHN0YXJUeXBlID0+IHtcbiAgICAgICAgY29uc3QgY2xhc3NuYW1lID0gdGhpcy5nZXRTdGFyQ2xhc3Moc3RhclR5cGUpO1xuICAgICAgICB0aGlzLmNyZWF0ZUNzc0NsYXNzKGNsYXNzbmFtZSwgc3RhclR5cGUpO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVDc3NDbGFzcyhjbGFzc25hbWU6IHN0cmluZywgc3RhclR5cGU6IFN0YXJUeXBlKSB7XG4gICAgY29uc3QgY2xhenogPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzdHlsZScpO1xuICAgIGNsYXp6LnR5cGUgPSAndGV4dC9jc3MnO1xuICAgIGNsYXp6LmlubmVySFRNTCA9IGAuJHtjbGFzc25hbWV9IHtcbiAgICAgIC13ZWJraXQtbWFzay1pbWFnZTogdXJsKCR7dGhpcy5jdXN0b21TdGFySWNvbnNbc3RhclR5cGVdfSk7XG4gICAgICBtYXNrLWltYWdlOiB1cmwoJHt0aGlzLmN1c3RvbVN0YXJJY29uc1tzdGFyVHlwZV19KTtcbiAgICB9YDtcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnaGVhZCcpWzBdLmFwcGVuZENoaWxkKGNsYXp6KTtcbiAgICB0aGlzLmN1c3RvbUNzc0NsYXNzZXMucHVzaChjbGF6eik7XG4gIH1cblxuICBzdGFyUGFkZGluZygpOiB7IFtwOiBzdHJpbmddOiBzdHJpbmcgfSB7XG4gICAgcmV0dXJuIHsgJ21hcmdpbi1yaWdodCc6IHRoaXMuY3VzdG9tUGFkZGluZyB8fCBgY2FsYygke3RoaXMuc3RhclNpemUoKS53aWR0aH0gLyAxMClgIH07XG4gIH1cblxuICBzdGFyQ29sb3JBbmRTaXplKCk6IHsgW3A6IHN0cmluZ106IHN0cmluZyB9IHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGFyQ29sb3IoKSwgdGhpcy5zdGFyU2l6ZSgpKTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhckNvbG9yKCk6IHsgW3A6IHN0cmluZ106IHN0cmluZyB9IHtcbiAgICByZXR1cm4geyAnYmFja2dyb3VuZC1jb2xvcic6IHRoaXMuY29sb3IgfHwgJ2NyaW1zb24nIH07XG4gIH1cblxuICBzdGFyU2l6ZSgpOiB7IFtwOiBzdHJpbmddOiBzdHJpbmcgfSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlaWdodDogdGhpcy5jdXN0b21TaXplIHx8IGAkezE1ICogdGhpcy5zYWZlU2l6ZSgpfXB4YCxcbiAgICAgIHdpZHRoOiB0aGlzLmN1c3RvbVNpemUgfHwgYCR7MTYgKiB0aGlzLnNhZmVTaXplKCl9cHhgLFxuICAgIH07XG4gIH1cblxuICB6ZXJvU3RhckxlZnQoKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5ydGwpIHtcbiAgICAgIGNvbnN0IHdpZHRoID0gdGhpcy5zdGFyU2l6ZSgpWyd3aWR0aCddO1xuICAgICAgcmV0dXJuIGBjYWxjKCR7d2lkdGh9ICogJHt0aGlzLm1heFN0YXJzfSlgO1xuICAgIH1cbiAgICByZXR1cm4gJy0xNnB4JztcbiAgfVxuXG4gIHByaXZhdGUgc2FmZVNpemUgPSAoKSA9PiAoTnVtYmVyLmlzSW50ZWdlcih0aGlzLnNpemUpICYmIHRoaXMuc2l6ZSA+IDAgJiYgdGhpcy5zaXplIDwgNikgPyB0aGlzLnNpemUgOiAxO1xuXG4gIHN0YXJBbmltYXRpb24oKTogdm9pZCB7XG4gICAgdGhpcy5hbmltYXRpb25SdW5uaW5nID0gdHJ1ZTtcbiAgICBpZiAodGhpcy5yYXRpbmcgPCB0aGlzLm1heFN0YXJzKSB7XG4gICAgICB0aGlzLnNldFJhdGluZyh0aGlzLnJhdGluZyArPSAwLjUpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHRoaXMuc2V0UmF0aW5nKDApO1xuICAgIH1cbiAgfVxuXG4gIGNhbmNlbFN0YXJBbmltYXRpb24oKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuYW5pbWF0aW9uUnVubmluZykge1xuICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmFuaW1hdGlvbkludGVydmFsKTtcbiAgICAgIHRoaXMucmF0aW5nID0gMDtcbiAgICAgIHRoaXMuYW5pbWF0aW9uUnVubmluZyA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIHNldFJhdGluZyhyYXRpbmc6IG51bWJlcikge1xuICAgIHRoaXMucmF0aW5nID0gTWF0aC5yb3VuZChyYXRpbmcgKiAyKSAvIDI7XG4gICAgdGhpcy5vblN0YXJzVW5ob3ZlcigpO1xuICB9XG5cbiAgb25TdGFySG92ZXIoZXZlbnQ6IE1vdXNlRXZlbnQsIGNsaWNrZWRTdGFyOiBFZGl0YWJsZVN0YXIpOiB2b2lkIHtcbiAgICB0aGlzLmNhbmNlbFN0YXJBbmltYXRpb24oKTtcblxuICAgIGNvbnN0IGNsaWNrZWRJbkZpcnN0SGFsZiA9IHRoaXMuY2xpY2tlZEluRmlyc3RIYWxmKGV2ZW50KTtcblxuICAgIC8vIGZpbGwgaW4gZWl0aGVyIGEgaGFsZiBvciB3aG9sZSBzdGFyIGRlcGVuZGluZyBvbiB3aGVyZSB1c2VyIGNsaWNrZWRcbiAgICBjbGlja2VkU3Rhci5jbGFzc25hbWUgPSAoIXRoaXMud2hvbGVTdGFycyAmJiBjbGlja2VkSW5GaXJzdEhhbGYpID8gdGhpcy5nZXRTdGFyQ2xhc3MoJ2hhbGYnKSA6IHRoaXMuZ2V0U3RhckNsYXNzKCdmdWxsJyk7XG5cbiAgICAvLyBmaWxsIGluIGFsbCBzdGFycyBpbiBwcmV2aW91cyBwb3NpdGlvbnMgYW5kIGNsZWFyIGFsbCBpbiBsYXRlciBvbmVzXG4gICAgdGhpcy5lZGl0YWJsZVN0YXJzLmZvckVhY2goc3RhciA9PiB7XG4gICAgICBpZiAoc3Rhci5wb3NpdGlvbiA+IGNsaWNrZWRTdGFyLnBvc2l0aW9uKSB7XG4gICAgICAgIHN0YXIuY2xhc3NuYW1lID0gdGhpcy5nZXRTdGFyQ2xhc3MoJ2VtcHR5Jyk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChzdGFyLnBvc2l0aW9uIDwgY2xpY2tlZFN0YXIucG9zaXRpb24pIHtcbiAgICAgICAgc3Rhci5jbGFzc25hbWUgPSB0aGlzLmdldFN0YXJDbGFzcygnZnVsbCcpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgb25TdGFyQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQsIGNsaWNrZWRTdGFyOiBFZGl0YWJsZVN0YXIpOiB2b2lkIHtcbiAgICB0aGlzLmNhbmNlbFN0YXJBbmltYXRpb24oKTtcblxuICAgIC8vIGxvY2sgaW4gY3VycmVudCByYXRpbmdcbiAgICBjb25zdCBjbGlja2VkSW5GaXJzdEhhbGYgPSB0aGlzLmNsaWNrZWRJbkZpcnN0SGFsZihldmVudCk7XG4gICAgdGhpcy5yYXRpbmcgPSBjbGlja2VkU3Rhci5wb3NpdGlvbiArICgoIXRoaXMud2hvbGVTdGFycyAmJiBjbGlja2VkSW5GaXJzdEhhbGYpID8gMC41IDogMSk7XG4gICAgdGhpcy5yYXRpbmdPdXRwdXQuZW1pdCh0aGlzLnJhdGluZyk7XG4gIH1cblxuICAvLyBoaWRkZW4gc3RhciB0byBsZWZ0IG9mIGZpcnN0IHN0YXIgbGV0cyB1c2VyIGNsaWNrIHRoZXJlIHRvIHNldCB0byAwXG4gIG9uWmVyb1N0YXJDbGljaygpOiB2b2lkIHtcbiAgICB0aGlzLnNldFJhdGluZygwKTtcbiAgICB0aGlzLnJhdGluZ091dHB1dC5lbWl0KHRoaXMucmF0aW5nKTtcbiAgfVxuXG4gIG9uWmVyb1N0YXJIb3ZlcigpOiB2b2lkIHtcbiAgICAvLyBjbGVhciBhbGwgc3RhcnNcbiAgICB0aGlzLmVkaXRhYmxlU3RhcnMuZm9yRWFjaChzdGFyID0+IHN0YXIuY2xhc3NuYW1lID0gdGhpcy5nZXRTdGFyQ2xhc3MoJ2VtcHR5JykpO1xuICB9XG5cbiAgb25TdGFyc1VuaG92ZXIoKSB7XG4gICAgLy8gd2hlbiB1c2VyIHN0b3BzIGhvdmVyaW5nIHdlIHdhbnQgdG8gbWFrZSBzdGFycyByZWZsZWN0IHRoZSBsYXN0IHJhdGluZyBhcHBsaWVkIGJ5IGNsaWNraW5nXG4gICAgdGhpcy5lZGl0YWJsZVN0YXJzLmZvckVhY2goc3RhciA9PiB7XG4gICAgICBjb25zdCBzdGFyTnVtYmVyID0gc3Rhci5wb3NpdGlvbiArIDE7XG4gICAgICBpZiAodGhpcy5yYXRpbmcgPj0gc3Rhck51bWJlcikge1xuICAgICAgICBzdGFyLmNsYXNzbmFtZSA9IHRoaXMuZ2V0U3RhckNsYXNzKCdmdWxsJyk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmICh0aGlzLnJhdGluZyA+IHN0YXJOdW1iZXIgLSAxICYmIHRoaXMucmF0aW5nIDwgc3Rhck51bWJlcikge1xuICAgICAgICBzdGFyLmNsYXNzbmFtZSA9IHRoaXMuZ2V0U3RhckNsYXNzKCdoYWxmJyk7XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgc3Rhci5jbGFzc25hbWUgPSB0aGlzLmdldFN0YXJDbGFzcygnZW1wdHknKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgY2xpY2tlZEluRmlyc3RIYWxmKGV2ZW50OiBNb3VzZUV2ZW50KTogYm9vbGVhbiB7XG4gICAgY29uc3Qgc3Rhckljb24gPSBldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XG4gICAgaWYgKHRoaXMucnRsKSB7XG4gICAgICByZXR1cm4gZXZlbnQucGFnZVggPiBzdGFySWNvbi5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5yaWdodCAtIHN0YXJJY29uLm9mZnNldFdpZHRoIC8gMjtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICByZXR1cm4gZXZlbnQucGFnZVggPCBzdGFySWNvbi5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5sZWZ0ICsgc3Rhckljb24ub2Zmc2V0V2lkdGggLyAyO1xuICAgIH1cbiAgfVxuXG4gIG5vb3AoKTogdm9pZCB7fVxuXG4gIHByaXZhdGUgZ2V0U3RhckNsYXNzKHN0YXJUeXBlOiBTdGFyVHlwZSkge1xuICAgIGlmICh0aGlzLmN1c3RvbUNzc0NsYXNzZXMpIHtcbiAgICAgIHJldHVybiBgbmd4LXN0YXJzLXN0YXItJHtzdGFyVHlwZX0tJHt0aGlzLmN1c3RvbUNsYXNzSWRlbnRpZmllcn1gO1xuICAgIH1cbiAgICByZXR1cm4gYHN0YXItJHtzdGFyVHlwZX1gO1xuICB9XG5cbiAgLy8gdGhpcyBhbmQgdGhlIGFyaWEtbGFiZWxzIGFuZCByb2xlIGluIHRoZSBodG1sIGluc3BpcmVkIGJ5IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcS81NTk2NjIwNVxuICBnZXRBcmlhTGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYFJhdGluZzogJHt0aGlzLnJhdGluZ30gb3V0IG9mICR7dGhpcy5tYXhTdGFyc30gc3RhcnMgJHt0aGlzLnJlYWRvbmx5ID8gJycgOiAnLiBDYW4gYmUgZWRpdGVkLid9YDtcbiAgfVxufVxuXG5leHBvcnQgdHlwZSBTdGFyVHlwZSA9ICdlbXB0eScgfCAnaGFsZicgfCAnZnVsbCc7XG5cbmV4cG9ydCBjbGFzcyBFZGl0YWJsZVN0YXIge1xuICBwb3NpdGlvbjogbnVtYmVyO1xuICBjbGFzc25hbWU6IHN0cmluZztcblxuICBjb25zdHJ1Y3Rvcihwb3NpdGlvbjogbnVtYmVyKSB7XG4gICAgdGhpcy5wb3NpdGlvbiA9IHBvc2l0aW9uO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwic3RhcnMtbGluZVwiIChtb3VzZWxlYXZlKT1cInJlYWRvbmx5ID8gbm9vcCgpIDogb25TdGFyc1VuaG92ZXIoKVwiIHJvbGU9XCJpbWdcIiBbYXR0ci5hcmlhLWxhYmVsXT1cImdldEFyaWFMYWJlbCgpXCI+XG4gIDxzcGFuIGNsYXNzPVwic3RhciB6ZXJvLXN0YXJcIiBbbmdTdHlsZV09XCJzdGFyU2l6ZSgpXCIgW3N0eWxlLmxlZnRdPVwiemVyb1N0YXJMZWZ0KClcIiBhcmlhLWhpZGRlbj1cInRydWVcIiAoY2xpY2spPVwicmVhZG9ubHkgPyBub29wKCkgOiBvblplcm9TdGFyQ2xpY2soKVwiIChtb3VzZW1vdmUpPVwicmVhZG9ubHkgPyBub29wKCkgOiBvblplcm9TdGFySG92ZXIoKVwiPjwvc3Bhbj5cbiAgPGRpdiAqbmdGb3I9XCJsZXQgc3RhciBvZiBlZGl0YWJsZVN0YXJzO1wiIFtuZ1N0eWxlXT1cInN0YXJQYWRkaW5nKClcIiBhcmlhLWhpZGRlbj1cInRydWVcIiAoY2xpY2spPVwicmVhZG9ubHkgPyBub29wKCkgOiBvblN0YXJDbGljaygkZXZlbnQsIHN0YXIpXCIgKG1vdXNlbW92ZSk9XCJyZWFkb25seSA/IG5vb3AoKSA6IG9uU3RhckhvdmVyKCRldmVudCwgc3RhcilcIj5cbiAgICA8c3BhbiBjbGFzcz1cInN0YXJcIiBbY2xhc3Muc3Rhci1ydGxdPVwicnRsXCIgW25nQ2xhc3NdPVwic3Rhci5jbGFzc25hbWVcIiBbbmdTdHlsZV09XCJzdGFyQ29sb3JBbmRTaXplKClcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L3NwYW4+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=