ng-zorro-antd
Version:
An enterprise-class UI components based on Ant Design and Angular
500 lines (492 loc) • 55.9 kB
JavaScript
import { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, Component, EventEmitter, ViewChild, ViewEncapsulation } from '@angular/core';
import { fromEvent } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fadeMotion } from 'ng-zorro-antd/core/animation';
import { NzDestroyService } from 'ng-zorro-antd/core/services';
import { isNotNil } from 'ng-zorro-antd/core/util';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { NZ_CONFIG_MODULE_NAME } from './image-config';
import { getClientSize, getFitContentPosition, getOffset } from './utils';
import * as i0 from "@angular/core";
import * as i1 from "ng-zorro-antd/core/config";
import * as i2 from "./image-preview-options";
import * as i3 from "ng-zorro-antd/core/services";
import * as i4 from "@angular/platform-browser";
import * as i5 from "ng-zorro-antd/icon";
const initialPosition = {
x: 0,
y: 0
};
export const NZ_DEFAULT_SCALE_STEP = 0.5;
const NZ_DEFAULT_ZOOM = 1;
const NZ_DEFAULT_ROTATE = 0;
export class NzImagePreviewComponent {
get animationDisabled() {
return this.config.nzNoAnimation ?? false;
}
get maskClosable() {
const defaultConfig = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME) || {};
return this.config.nzMaskClosable ?? defaultConfig.nzMaskClosable ?? true;
}
constructor(ngZone, cdr, nzConfigService, config, destroy$, sanitizer) {
this.ngZone = ngZone;
this.cdr = cdr;
this.nzConfigService = nzConfigService;
this.config = config;
this.destroy$ = destroy$;
this.sanitizer = sanitizer;
this._defaultNzZoom = NZ_DEFAULT_ZOOM;
this._defaultNzScaleStep = NZ_DEFAULT_SCALE_STEP;
this._defaultNzRotate = NZ_DEFAULT_ROTATE;
this.images = [];
this.index = 0;
this.isDragging = false;
this.visible = true;
this.animationStateChanged = new EventEmitter();
this.scaleStepMap = new Map();
this.previewImageTransform = '';
this.previewImageWrapperTransform = '';
this.operations = [
{
icon: 'close',
onClick: () => {
this.onClose();
},
type: 'close'
},
{
icon: 'zoom-in',
onClick: () => {
this.onZoomIn();
},
type: 'zoomIn'
},
{
icon: 'zoom-out',
onClick: () => {
this.onZoomOut();
},
type: 'zoomOut'
},
{
icon: 'rotate-right',
onClick: () => {
this.onRotateRight();
},
type: 'rotateRight'
},
{
icon: 'rotate-left',
onClick: () => {
this.onRotateLeft();
},
type: 'rotateLeft'
},
{
icon: 'swap',
onClick: () => {
this.onHorizontalFlip();
},
type: 'flipHorizontally'
},
{
icon: 'swap',
onClick: () => {
this.onVerticalFlip();
},
type: 'flipVertically',
rotate: 90
}
];
this.zoomOutDisabled = false;
this.position = { ...initialPosition };
this.closeClick = new EventEmitter();
this.zoom = this.config.nzZoom ?? this._defaultNzZoom;
this.scaleStep = this.config.nzScaleStep ?? this._defaultNzScaleStep;
this.rotate = this.config.nzRotate ?? this._defaultNzRotate;
this.flipHorizontally = this.config.nzFlipHorizontally ?? false;
this.flipVertically = this.config.nzFlipVertically ?? false;
this.updateZoomOutDisabled();
this.updatePreviewImageTransform();
this.updatePreviewImageWrapperTransform();
}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
fromEvent(this.imagePreviewWrapper.nativeElement, 'mousedown')
.pipe(takeUntil(this.destroy$))
.subscribe(() => {
this.isDragging = true;
});
fromEvent(this.imagePreviewWrapper.nativeElement, 'wheel')
.pipe(takeUntil(this.destroy$))
.subscribe(event => {
this.ngZone.run(() => this.wheelZoomEventHandler(event));
});
});
}
setImages(images, scaleStepMap) {
if (scaleStepMap)
this.scaleStepMap = scaleStepMap;
this.images = images;
this.markForCheck();
}
switchTo(index) {
this.index = index;
this.markForCheck();
}
next() {
if (this.index < this.images.length - 1) {
this.reset();
this.index++;
this.updatePreviewImageTransform();
this.updatePreviewImageWrapperTransform();
this.updateZoomOutDisabled();
this.markForCheck();
}
}
prev() {
if (this.index > 0) {
this.reset();
this.index--;
this.updatePreviewImageTransform();
this.updatePreviewImageWrapperTransform();
this.updateZoomOutDisabled();
this.markForCheck();
}
}
markForCheck() {
this.cdr.markForCheck();
}
onClose() {
this.visible = false;
this.closeClick.emit();
}
onZoomIn() {
const zoomStep = this.scaleStepMap.get(this.images[this.index].src ?? this.images[this.index].srcset) ?? this.scaleStep;
this.zoom += zoomStep;
this.updatePreviewImageTransform();
this.updateZoomOutDisabled();
}
onZoomOut() {
if (this.zoom > 1) {
const zoomStep = this.scaleStepMap.get(this.images[this.index].src ?? this.images[this.index].srcset) ?? this.scaleStep;
this.zoom -= zoomStep;
this.updatePreviewImageTransform();
this.updateZoomOutDisabled();
if (this.zoom <= 1) {
this.reCenterImage();
}
}
}
onRotateRight() {
this.rotate += 90;
this.updatePreviewImageTransform();
}
onRotateLeft() {
this.rotate -= 90;
this.updatePreviewImageTransform();
}
onSwitchLeft(event) {
event.preventDefault();
event.stopPropagation();
this.prev();
}
onSwitchRight(event) {
event.preventDefault();
event.stopPropagation();
this.next();
}
onHorizontalFlip() {
this.flipHorizontally = !this.flipHorizontally;
this.updatePreviewImageTransform();
}
onVerticalFlip() {
this.flipVertically = !this.flipVertically;
this.updatePreviewImageTransform();
}
wheelZoomEventHandler(event) {
event.preventDefault();
event.stopPropagation();
this.handlerImageTransformationWhileZoomingWithMouse(event, event.deltaY);
this.handleImageScaleWhileZoomingWithMouse(event.deltaY);
this.updatePreviewImageWrapperTransform();
this.updatePreviewImageTransform();
this.markForCheck();
}
onAnimationStart(event) {
this.animationStateChanged.emit(event);
}
onAnimationDone(event) {
this.animationStateChanged.emit(event);
}
onDragEnd(event) {
this.isDragging = false;
const width = this.imageRef.nativeElement.offsetWidth * this.zoom;
const height = this.imageRef.nativeElement.offsetHeight * this.zoom;
const { left, top } = getOffset(this.imageRef.nativeElement);
const { width: clientWidth, height: clientHeight } = getClientSize();
const isRotate = this.rotate % 180 !== 0;
const fitContentParams = {
width: isRotate ? height : width,
height: isRotate ? width : height,
left,
top,
clientWidth,
clientHeight
};
const fitContentPos = getFitContentPosition(fitContentParams);
if (isNotNil(fitContentPos.x) || isNotNil(fitContentPos.y)) {
this.position = { ...this.position, ...fitContentPos };
}
else if (!isNotNil(fitContentPos.x) && !isNotNil(fitContentPos.y)) {
this.position = {
x: event.source.getFreeDragPosition().x,
y: event.source.getFreeDragPosition().y
};
}
}
sanitizerResourceUrl(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
updatePreviewImageTransform() {
this.previewImageTransform = `scale3d(${this.zoom * (this.flipHorizontally ? -1 : 1)}, ${this.zoom * (this.flipVertically ? -1 : 1)}, 1) rotate(${this.rotate}deg)`;
}
updatePreviewImageWrapperTransform() {
this.previewImageWrapperTransform = `translate3d(${this.position.x}px, ${this.position.y}px, 0)`;
}
updateZoomOutDisabled() {
this.zoomOutDisabled = this.zoom <= 1;
}
handlerImageTransformationWhileZoomingWithMouse(event, deltaY) {
let scaleValue;
const imageElement = this.imageRef.nativeElement;
const elementTransform = getComputedStyle(imageElement).transform;
const matrixValue = elementTransform.match(/matrix.*\((.+)\)/);
if (matrixValue) {
scaleValue = +matrixValue[1].split(', ')[0];
}
else {
scaleValue = this.zoom;
}
const x = (event.clientX - imageElement.getBoundingClientRect().x) / scaleValue;
const y = (event.clientY - imageElement.getBoundingClientRect().y) / scaleValue;
const halfOfScaleStepValue = deltaY < 0 ? this.scaleStep / 2 : -this.scaleStep / 2;
this.position.x += -x * halfOfScaleStepValue * 2 + imageElement.offsetWidth * halfOfScaleStepValue;
this.position.y += -y * halfOfScaleStepValue * 2 + imageElement.offsetHeight * halfOfScaleStepValue;
}
handleImageScaleWhileZoomingWithMouse(deltaY) {
if (this.isZoomedInWithMouseWheel(deltaY)) {
this.onZoomIn();
}
else {
this.onZoomOut();
}
if (this.zoom <= 1) {
this.reCenterImage();
}
}
isZoomedInWithMouseWheel(delta) {
return delta < 0;
}
reset() {
this.zoom = this.config.nzZoom ?? this._defaultNzZoom;
this.scaleStep = this.config.nzScaleStep ?? this._defaultNzScaleStep;
this.rotate = this.config.nzRotate ?? this._defaultNzRotate;
this.flipHorizontally = false;
this.flipVertically = false;
this.reCenterImage();
}
reCenterImage() {
this.position = { ...initialPosition };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: NzImagePreviewComponent, deps: [{ token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: i1.NzConfigService }, { token: i2.NzImagePreviewOptions }, { token: i3.NzDestroyService }, { token: i4.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.2", type: NzImagePreviewComponent, isStandalone: true, selector: "nz-image-preview", host: { listeners: { "@fadeMotion.start": "onAnimationStart($event)", "@fadeMotion.done": "onAnimationDone($event)" }, properties: { "class.ant-image-preview-moving": "isDragging", "style.zIndex": "config.nzZIndex", "@.disabled": "config.nzNoAnimation", "@fadeMotion": "visible ? 'enter' : 'leave'" }, classAttribute: "ant-image-preview-root" }, providers: [NzDestroyService], viewQueries: [{ propertyName: "imageRef", first: true, predicate: ["imgRef"], descendants: true }, { propertyName: "imagePreviewWrapper", first: true, predicate: ["imagePreviewWrapper"], descendants: true, static: true }], exportAs: ["nzImagePreview"], ngImport: i0, template: `
<div class="ant-image-preview-mask"></div>
<div class="ant-image-preview-operations-wrapper">
@if (images.length > 1) {
<div
class="ant-image-preview-switch-left"
[class.ant-image-preview-switch-left-disabled]="index <= 0"
(click)="onSwitchLeft($event)"
>
<span nz-icon nzType="left" nzTheme="outline"></span>
</div>
<div
class="ant-image-preview-switch-right"
[class.ant-image-preview-switch-right-disabled]="index >= images.length - 1"
(click)="onSwitchRight($event)"
>
<span nz-icon nzType="right" nzTheme="outline"></span>
</div>
}
<ul class="ant-image-preview-operations">
@if (images.length > 1) {
<li class="ant-image-preview-operations-progress">{{ index + 1 }} / {{ images.length }}</li>
}
@for (option of operations; track option) {
<li
class="ant-image-preview-operations-operation"
[class.ant-image-preview-operations-operation-disabled]="zoomOutDisabled && option.type === 'zoomOut'"
(click)="option.onClick()"
>
<span
class="ant-image-preview-operations-icon"
nz-icon
[nzType]="option.icon"
[nzRotate]="option.rotate ?? 0"
nzTheme="outline"
></span>
</li>
}
</ul>
</div>
<div
class="ant-image-preview-wrap"
tabindex="-1"
(click)="maskClosable && $event.target === $event.currentTarget && onClose()"
>
<div class="ant-image-preview" role="dialog" aria-modal="true">
<div tabindex="0" aria-hidden="true" style="width: 0; height: 0; overflow: hidden; outline: none;"></div>
<div class="ant-image-preview-content">
<div class="ant-image-preview-body">
<div
class="ant-image-preview-img-wrapper"
#imagePreviewWrapper
cdkDrag
[style.transform]="previewImageWrapperTransform"
[cdkDragFreeDragPosition]="position"
(cdkDragEnded)="onDragEnd($event)"
>
@for (image of images; track image; let imageIndex = $index) {
@if (imageIndex === index) {
<img
cdkDragHandle
class="ant-image-preview-img"
#imgRef
[attr.src]="sanitizerResourceUrl(image.src)"
[attr.srcset]="image.srcset"
[attr.alt]="image.alt"
[style.width]="image.width"
[style.height]="image.height"
[style.transform]="previewImageTransform"
/>
}
}
</div>
</div>
</div>
<div tabindex="0" aria-hidden="true" style="width: 0; height: 0; overflow: hidden; outline: none;"></div>
</div>
</div>
`, isInline: true, dependencies: [{ kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i5.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }], animations: [fadeMotion], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: NzImagePreviewComponent, decorators: [{
type: Component,
args: [{
selector: 'nz-image-preview',
exportAs: 'nzImagePreview',
animations: [fadeMotion],
standalone: true,
template: `
<div class="ant-image-preview-mask"></div>
<div class="ant-image-preview-operations-wrapper">
@if (images.length > 1) {
<div
class="ant-image-preview-switch-left"
[class.ant-image-preview-switch-left-disabled]="index <= 0"
(click)="onSwitchLeft($event)"
>
<span nz-icon nzType="left" nzTheme="outline"></span>
</div>
<div
class="ant-image-preview-switch-right"
[class.ant-image-preview-switch-right-disabled]="index >= images.length - 1"
(click)="onSwitchRight($event)"
>
<span nz-icon nzType="right" nzTheme="outline"></span>
</div>
}
<ul class="ant-image-preview-operations">
@if (images.length > 1) {
<li class="ant-image-preview-operations-progress">{{ index + 1 }} / {{ images.length }}</li>
}
@for (option of operations; track option) {
<li
class="ant-image-preview-operations-operation"
[class.ant-image-preview-operations-operation-disabled]="zoomOutDisabled && option.type === 'zoomOut'"
(click)="option.onClick()"
>
<span
class="ant-image-preview-operations-icon"
nz-icon
[nzType]="option.icon"
[nzRotate]="option.rotate ?? 0"
nzTheme="outline"
></span>
</li>
}
</ul>
</div>
<div
class="ant-image-preview-wrap"
tabindex="-1"
(click)="maskClosable && $event.target === $event.currentTarget && onClose()"
>
<div class="ant-image-preview" role="dialog" aria-modal="true">
<div tabindex="0" aria-hidden="true" style="width: 0; height: 0; overflow: hidden; outline: none;"></div>
<div class="ant-image-preview-content">
<div class="ant-image-preview-body">
<div
class="ant-image-preview-img-wrapper"
#imagePreviewWrapper
cdkDrag
[style.transform]="previewImageWrapperTransform"
[cdkDragFreeDragPosition]="position"
(cdkDragEnded)="onDragEnd($event)"
>
@for (image of images; track image; let imageIndex = $index) {
@if (imageIndex === index) {
<img
cdkDragHandle
class="ant-image-preview-img"
#imgRef
[attr.src]="sanitizerResourceUrl(image.src)"
[attr.srcset]="image.srcset"
[attr.alt]="image.alt"
[style.width]="image.width"
[style.height]="image.height"
[style.transform]="previewImageTransform"
/>
}
}
</div>
</div>
</div>
<div tabindex="0" aria-hidden="true" style="width: 0; height: 0; overflow: hidden; outline: none;"></div>
</div>
</div>
`,
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
host: {
class: 'ant-image-preview-root',
'[class.ant-image-preview-moving]': 'isDragging',
'[style.zIndex]': 'config.nzZIndex',
'[@.disabled]': 'config.nzNoAnimation',
'[@fadeMotion]': `visible ? 'enter' : 'leave'`,
'(@fadeMotion.start)': 'onAnimationStart($event)',
'(@fadeMotion.done)': 'onAnimationDone($event)'
},
imports: [NzIconModule, CdkDragHandle, CdkDrag],
providers: [NzDestroyService]
}]
}], ctorParameters: () => [{ type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: i1.NzConfigService }, { type: i2.NzImagePreviewOptions }, { type: i3.NzDestroyService }, { type: i4.DomSanitizer }], propDecorators: { imageRef: [{
type: ViewChild,
args: ['imgRef']
}], imagePreviewWrapper: [{
type: ViewChild,
args: ['imagePreviewWrapper', { static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtcHJldmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9jb21wb25lbnRzL2ltYWdlL2ltYWdlLXByZXZpZXcuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU1BLE9BQU8sRUFBRSxPQUFPLEVBQWMsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDNUUsT0FBTyxFQUNMLHVCQUF1QixFQUV2QixTQUFTLEVBRVQsWUFBWSxFQUdaLFNBQVMsRUFDVCxpQkFBaUIsRUFDbEIsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNqQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRTFELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRS9ELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFbEQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFJdkQsT0FBTyxFQUFFLGFBQWEsRUFBRSxxQkFBcUIsRUFBRSxTQUFTLEVBQUUsTUFBTSxTQUFTLENBQUM7Ozs7Ozs7QUFTMUUsTUFBTSxlQUFlLEdBQUc7SUFDdEIsQ0FBQyxFQUFFLENBQUM7SUFDSixDQUFDLEVBQUUsQ0FBQztDQUNMLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyxHQUFHLENBQUM7QUFDekMsTUFBTSxlQUFlLEdBQUcsQ0FBQyxDQUFDO0FBQzFCLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxDQUFDO0FBeUc1QixNQUFNLE9BQU8sdUJBQXVCO0lBaUZsQyxJQUFJLGlCQUFpQjtRQUNuQixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxJQUFJLEtBQUssQ0FBQztJQUM1QyxDQUFDO0lBRUQsSUFBSSxZQUFZO1FBQ2QsTUFBTSxhQUFhLEdBQWMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxxQkFBcUIsQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN6RyxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxJQUFJLGFBQWEsQ0FBQyxjQUFjLElBQUksSUFBSSxDQUFDO0lBQzVFLENBQUM7SUFFRCxZQUNVLE1BQWMsRUFDZCxHQUFzQixFQUN2QixlQUFnQyxFQUNoQyxNQUE2QixFQUM1QixRQUEwQixFQUMxQixTQUF1QjtRQUx2QixXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQ2QsUUFBRyxHQUFILEdBQUcsQ0FBbUI7UUFDdkIsb0JBQWUsR0FBZixlQUFlLENBQWlCO1FBQ2hDLFdBQU0sR0FBTixNQUFNLENBQXVCO1FBQzVCLGFBQVEsR0FBUixRQUFRLENBQWtCO1FBQzFCLGNBQVMsR0FBVCxTQUFTLENBQWM7UUEvRnhCLG1CQUFjLEdBQUcsZUFBZSxDQUFDO1FBQ2pDLHdCQUFtQixHQUFHLHFCQUFxQixDQUFDO1FBQzVDLHFCQUFnQixHQUFHLGlCQUFpQixDQUFDO1FBRTlDLFdBQU0sR0FBYyxFQUFFLENBQUM7UUFDdkIsVUFBSyxHQUFHLENBQUMsQ0FBQztRQUNWLGVBQVUsR0FBRyxLQUFLLENBQUM7UUFDbkIsWUFBTyxHQUFHLElBQUksQ0FBQztRQUNmLDBCQUFxQixHQUFHLElBQUksWUFBWSxFQUFrQixDQUFDO1FBQzNELGlCQUFZLEdBQXNDLElBQUksR0FBRyxFQUFnQyxDQUFDO1FBRTFGLDBCQUFxQixHQUFHLEVBQUUsQ0FBQztRQUMzQixpQ0FBNEIsR0FBRyxFQUFFLENBQUM7UUFDbEMsZUFBVSxHQUFnQztZQUN4QztnQkFDRSxJQUFJLEVBQUUsT0FBTztnQkFDYixPQUFPLEVBQUUsR0FBRyxFQUFFO29CQUNaLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDakIsQ0FBQztnQkFDRCxJQUFJLEVBQUUsT0FBTzthQUNkO1lBQ0Q7Z0JBQ0UsSUFBSSxFQUFFLFNBQVM7Z0JBQ2YsT0FBTyxFQUFFLEdBQUcsRUFBRTtvQkFDWixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ2xCLENBQUM7Z0JBQ0QsSUFBSSxFQUFFLFFBQVE7YUFDZjtZQUNEO2dCQUNFLElBQUksRUFBRSxVQUFVO2dCQUNoQixPQUFPLEVBQUUsR0FBRyxFQUFFO29CQUNaLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDbkIsQ0FBQztnQkFDRCxJQUFJLEVBQUUsU0FBUzthQUNoQjtZQUNEO2dCQUNFLElBQUksRUFBRSxjQUFjO2dCQUNwQixPQUFPLEVBQUUsR0FBRyxFQUFFO29CQUNaLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQkFDdkIsQ0FBQztnQkFDRCxJQUFJLEVBQUUsYUFBYTthQUNwQjtZQUNEO2dCQUNFLElBQUksRUFBRSxhQUFhO2dCQUNuQixPQUFPLEVBQUUsR0FBRyxFQUFFO29CQUNaLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFDdEIsQ0FBQztnQkFDRCxJQUFJLEVBQUUsWUFBWTthQUNuQjtZQUNEO2dCQUNFLElBQUksRUFBRSxNQUFNO2dCQUNaLE9BQU8sRUFBRSxHQUFHLEVBQUU7b0JBQ1osSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7Z0JBQzFCLENBQUM7Z0JBQ0QsSUFBSSxFQUFFLGtCQUFrQjthQUN6QjtZQUNEO2dCQUNFLElBQUksRUFBRSxNQUFNO2dCQUNaLE9BQU8sRUFBRSxHQUFHLEVBQUU7b0JBQ1osSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUN4QixDQUFDO2dCQUNELElBQUksRUFBRSxnQkFBZ0I7Z0JBQ3RCLE1BQU0sRUFBRSxFQUFFO2FBQ1g7U0FDRixDQUFDO1FBRUYsb0JBQWUsR0FBRyxLQUFLLENBQUM7UUFDeEIsYUFBUSxHQUFHLEVBQUUsR0FBRyxlQUFlLEVBQUUsQ0FBQztRQUVsQyxlQUFVLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQTRCcEMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsY0FBYyxDQUFDO1FBQ3RELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLG1CQUFtQixDQUFDO1FBQ3JFLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLGdCQUFnQixDQUFDO1FBQzVELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixJQUFJLEtBQUssQ0FBQztRQUNoRSxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLElBQUksS0FBSyxDQUFDO1FBQzVELElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQzdCLElBQUksQ0FBQywyQkFBMkIsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxrQ0FBa0MsRUFBRSxDQUFDO0lBQzVDLENBQUM7SUFFRCxRQUFRO1FBQ04sSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLEVBQUU7WUFDakMsU0FBUyxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxhQUFhLEVBQUUsV0FBVyxDQUFDO2lCQUMzRCxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztpQkFDOUIsU0FBUyxDQUFDLEdBQUcsRUFBRTtnQkFDZCxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztZQUN6QixDQUFDLENBQUMsQ0FBQztZQUVMLFNBQVMsQ0FBYSxJQUFJLENBQUMsbUJBQW1CLENBQUMsYUFBYSxFQUFFLE9BQU8sQ0FBQztpQkFDbkUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7aUJBQzlCLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRTtnQkFDakIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDM0QsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxTQUFTLENBQUMsTUFBaUIsRUFBRSxZQUFrQztRQUM3RCxJQUFJLFlBQVk7WUFBRSxJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztRQUNuRCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDdEIsQ0FBQztJQUVELFFBQVEsQ0FBQyxLQUFhO1FBQ3BCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBRUQsSUFBSTtRQUNGLElBQUksSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4QyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDYixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDYixJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztZQUNuQyxJQUFJLENBQUMsa0NBQWtDLEVBQUUsQ0FBQztZQUMxQyxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztZQUM3QixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDdEIsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJO1FBQ0YsSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNiLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNiLElBQUksQ0FBQywyQkFBMkIsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxrQ0FBa0MsRUFBRSxDQUFDO1lBQzFDLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1lBQzdCLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUN0QixDQUFDO0lBQ0gsQ0FBQztJQUVELFlBQVk7UUFDVixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRCxPQUFPO1FBQ0wsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7UUFDckIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRUQsUUFBUTtRQUNOLE1BQU0sUUFBUSxHQUNaLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDO1FBQ3pHLElBQUksQ0FBQyxJQUFJLElBQUksUUFBUSxDQUFDO1FBQ3RCLElBQUksQ0FBQywyQkFBMkIsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO0lBQy9CLENBQUM7SUFFRCxTQUFTO1FBQ1AsSUFBSSxJQUFJLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sUUFBUSxHQUNaLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDO1lBQ3pHLElBQUksQ0FBQyxJQUFJLElBQUksUUFBUSxDQUFDO1lBQ3RCLElBQUksQ0FBQywyQkFBMkIsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1lBRTdCLElBQUksSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDbkIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3ZCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELGFBQWE7UUFDWCxJQUFJLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUNsQixJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztJQUNyQyxDQUFDO0lBRUQsWUFBWTtRQUNWLElBQUksQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO1FBQ2xCLElBQUksQ0FBQywyQkFBMkIsRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFRCxZQUFZLENBQUMsS0FBaUI7UUFDNUIsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDZCxDQUFDO0lBRUQsYUFBYSxDQUFDLEtBQWlCO1FBQzdCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN2QixLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVELGdCQUFnQjtRQUNkLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztRQUMvQyxJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztJQUNyQyxDQUFDO0lBRUQsY0FBYztRQUNaLElBQUksQ0FBQyxjQUFjLEdBQUcsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDO1FBQzNDLElBQUksQ0FBQywyQkFBMkIsRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFRCxxQkFBcUIsQ0FBQyxLQUFpQjtRQUNyQyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdkIsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBRXhCLElBQUksQ0FBQywrQ0FBK0MsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzFFLElBQUksQ0FBQyxxQ0FBcUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFekQsSUFBSSxDQUFDLGtDQUFrQyxFQUFFLENBQUM7UUFDMUMsSUFBSSxDQUFDLDJCQUEyQixFQUFFLENBQUM7UUFFbkMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxLQUFxQjtRQUNwQyxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRCxlQUFlLENBQUMsS0FBcUI7UUFDbkMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQsU0FBUyxDQUFDLEtBQWlCO1FBQ3pCLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQ2xFLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQ3BFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDN0QsTUFBTSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLGFBQWEsRUFBRSxDQUFDO1FBQ3JFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsQ0FBQztRQUN6QyxNQUFNLGdCQUFnQixHQUFHO1lBQ3ZCLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSztZQUNoQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU07WUFDakMsSUFBSTtZQUNKLEdBQUc7WUFDSCxXQUFXO1lBQ1gsWUFBWTtTQUNiLENBQUM7UUFDRixNQUFNLGFBQWEsR0FBRyxxQkFBcUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQzlELElBQUksUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxRQUFRLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDM0QsSUFBSSxDQUFDLFFBQVEsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLGFBQWEsRUFBRSxDQUFDO1FBQ3pELENBQUM7YUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNwRSxJQUFJLENBQUMsUUFBUSxHQUFHO2dCQUNkLENBQUMsRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLG1CQUFtQixFQUFFLENBQUMsQ0FBQztnQkFDdkMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxDQUFDO2FBQ3hDLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVELG9CQUFvQixDQUFDLEdBQVc7UUFDOUIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLDhCQUE4QixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzVELENBQUM7SUFFTywyQkFBMkI7UUFDakMsSUFBSSxDQUFDLHFCQUFxQixHQUFHLFdBQVcsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUNsRixJQUFJLENBQUMsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FDM0MsZUFBZSxJQUFJLENBQUMsTUFBTSxNQUFNLENBQUM7SUFDbkMsQ0FBQztJQUVPLGtDQUFrQztRQUN4QyxJQUFJLENBQUMsNEJBQTRCLEdBQUcsZUFBZSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDO0lBQ25HLENBQUM7SUFFTyxxQkFBcUI7UUFDM0IsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRU8sK0NBQStDLENBQUMsS0FBaUIsRUFBRSxNQUFjO1FBQ3ZGLElBQUksVUFBa0IsQ0FBQztRQUN2QixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQztRQUVqRCxNQUFNLGdCQUFnQixHQUFHLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUNsRSxNQUFNLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUUvRCxJQUFJLFdBQVcsRUFBRSxDQUFDO1lBQ2hCLFVBQVUsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDOUMsQ0FBQzthQUFNLENBQUM7WUFDTixVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN6QixDQUFDO1FBRUQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLFlBQVksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLFVBQVUsQ0FBQztRQUNoRixNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQUcsWUFBWSxDQUFDLHFCQUFxQixFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFDO1FBQ2hGLE1BQU0sb0JBQW9CLEdBQUcsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUM7UUFFbkYsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLFlBQVksQ0FBQyxXQUFXLEdBQUcsb0JBQW9CLENBQUM7UUFDbkcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLFlBQVksQ0FBQyxZQUFZLEdBQUcsb0JBQW9CLENBQUM7SUFDdEcsQ0FBQztJQUVPLHFDQUFxQyxDQUFDLE1BQWM7UUFDMUQsSUFBSSxJQUFJLENBQUMsd0JBQXdCLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUMxQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbEIsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDbkIsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDdkIsQ0FBQztJQUNILENBQUM7SUFFTyx3QkFBd0IsQ0FBQyxLQUFhO1FBQzVDLE9BQU8sS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBRU8sS0FBSztRQUNYLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUN0RCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxJQUFJLElBQUksQ0FBQyxtQkFBbUIsQ0FBQztRQUNyRSxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztRQUM1RCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO1FBQzlCLElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO1FBQzVCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRU8sYUFBYTtRQUNuQixJQUFJLENBQUMsUUFBUSxHQUFHLEVBQUUsR0FBRyxlQUFlLEVBQUUsQ0FBQztJQUN6QyxDQUFDOzhHQTdVVSx1QkFBdUI7a0dBQXZCLHVCQUF1Qix5WkFGdkIsQ0FBQyxnQkFBZ0IsQ0FBQyx1UkFoR25COzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0ZULDJEQWFTLFlBQVksa05BQUUsYUFBYSwrRkFBRSxPQUFPLDBhQWpHbEMsQ0FBQyxVQUFVLENBQUM7OzJGQW9HYix1QkFBdUI7a0JBdkduQyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxrQkFBa0I7b0JBQzVCLFFBQVEsRUFBRSxnQkFBZ0I7b0JBQzFCLFVBQVUsRUFBRSxDQUFDLFVBQVUsQ0FBQztvQkFDeEIsVUFBVSxFQUFFLElBQUk7b0JBQ2hCLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtGVDtvQkFDRCxtQkFBbUIsRUFBRSxLQUFLO29CQUMxQixlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTtvQkFDL0MsYUFBYSxFQUFFLGlCQUFpQixDQUFDLElBQUk7b0JBQ3JDLElBQUksRUFBRTt3QkFDSixLQUFLLEVBQUUsd0JBQXdCO3dCQUMvQixrQ0FBa0MsRUFBRSxZQUFZO3dCQUNoRCxnQkFBZ0IsRUFBRSxpQkFBaUI7d0JBQ25DLGNBQWMsRUFBRSxzQkFBc0I7d0JBQ3RDLGVBQWUsRUFBRSw2QkFBNkI7d0JBQzlDLHFCQUFxQixFQUFFLDBCQUEwQjt3QkFDakQsb0JBQW9CLEVBQUUseUJBQXlCO3FCQUNoRDtvQkFDRCxPQUFPLEVBQUUsQ0FBQyxZQUFZLEVBQUUsYUFBYSxFQUFFLE9BQU8sQ0FBQztvQkFDL0MsU0FBUyxFQUFFLENBQUMsZ0JBQWdCLENBQUM7aUJBQzlCO3VPQXlFc0IsUUFBUTtzQkFBNUIsU0FBUzt1QkFBQyxRQUFRO2dCQUNpQyxtQkFBbUI7c0JBQXRFLFNBQVM7dUJBQUMscUJBQXFCLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2dpdGh1Yi5jb20vTkctWk9SUk8vbmctem9ycm8tYW50ZC9ibG9iL21hc3Rlci9MSUNFTlNFXG4gKi9cblxuaW1wb3J0IHsgQW5pbWF0aW9uRXZlbnQgfSBmcm9tICdAYW5ndWxhci9hbmltYXRpb25zJztcbmltcG9ydCB7IENka0RyYWcsIENka0RyYWdFbmQsIENka0RyYWdIYW5kbGUgfSBmcm9tICdAYW5ndWxhci9jZGsvZHJhZy1kcm9wJztcbmltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIE5nWm9uZSxcbiAgT25Jbml0LFxuICBWaWV3Q2hpbGQsXG4gIFZpZXdFbmNhcHN1bGF0aW9uXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRG9tU2FuaXRpemVyLCBTYWZlUmVzb3VyY2VVcmwgfSBmcm9tICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcbmltcG9ydCB7IGZyb21FdmVudCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBmYWRlTW90aW9uIH0gZnJvbSAnbmctem9ycm8tYW50ZC9jb3JlL2FuaW1hdGlvbic7XG5pbXBvcnQgeyBOekNvbmZpZ1NlcnZpY2UgfSBmcm9tICduZy16b3Jyby1hbnRkL2NvcmUvY29uZmlnJztcbmltcG9ydCB7IE56RGVzdHJveVNlcnZpY2UgfSBmcm9tICduZy16b3Jyby1hbnRkL2NvcmUvc2VydmljZXMnO1xuaW1wb3J0IHsgTnpTYWZlQW55IH0gZnJvbSAnbmctem9ycm8tYW50ZC9jb3JlL3R5cGVzJztcbmltcG9ydCB7IGlzTm90TmlsIH0gZnJvbSAnbmctem9ycm8tYW50ZC9jb3JlL3V0aWwnO1xuaW1wb3J0IHsgTnpJY29uTW9kdWxlIH0gZnJvbSAnbmctem9ycm8tYW50ZC9pY29uJztcblxuaW1wb3J0IHsgTlpfQ09ORklHX01PRFVMRV9OQU1FIH0gZnJvbSAnLi9pbWFnZS1jb25maWcnO1xuaW1wb3J0IHsgTnpJbWFnZSwgTnpJbWFnZVByZXZpZXdPcHRpb25zIH0gZnJvbSAnLi9pbWFnZS1wcmV2aWV3LW9wdGlvbnMnO1xuaW1wb3J0IHsgTnpJbWFnZVByZXZpZXdSZWYgfSBmcm9tICcuL2ltYWdlLXByZXZpZXctcmVmJztcbmltcG9ydCB7IE56SW1hZ2VTY2FsZVN0ZXAsIE56SW1hZ2VVcmwgfSBmcm9tICcuL2ltYWdlLmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBnZXRDbGllbnRTaXplLCBnZXRGaXRDb250ZW50UG9zaXRpb24sIGdldE9mZnNldCB9IGZyb20gJy4vdXRpbHMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE56SW1hZ2VDb250YWluZXJPcGVyYXRpb24ge1xuICBpY29uOiBzdHJpbmc7XG4gIHR5cGU6IHN0cmluZztcbiAgcm90YXRlPzogbnVtYmVyO1xuICBvbkNsaWNrKCk6IHZvaWQ7XG59XG5cbmNvbnN0IGluaXRpYWxQb3NpdGlvbiA9IHtcbiAgeDogMCxcbiAgeTogMFxufTtcblxuZXhwb3J0IGNvbnN0IE5aX0RFRkFVTFRfU0NBTEVfU1RFUCA9IDAuNTtcbmNvbnN0IE5aX0RFRkFVTFRfWk9PTSA9IDE7XG5jb25zdCBOWl9ERUZBVUxUX1JPVEFURSA9IDA7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ256LWltYWdlLXByZXZpZXcnLFxuICBleHBvcnRBczogJ256SW1hZ2VQcmV2aWV3JyxcbiAgYW5pbWF0aW9uczogW2ZhZGVNb3Rpb25dLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJhbnQtaW1hZ2UtcHJldmlldy1tYXNrXCI+PC9kaXY+XG5cbiAgICA8ZGl2IGNsYXNzPVwiYW50LWltYWdlLXByZXZpZXctb3BlcmF0aW9ucy13cmFwcGVyXCI+XG4gICAgICBAaWYgKGltYWdlcy5sZW5ndGggPiAxKSB7XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cImFudC1pbWFnZS1wcmV2aWV3LXN3aXRjaC1sZWZ0XCJcbiAgICAgICAgICBbY2xhc3MuYW50LWltYWdlLXByZXZpZXctc3dpdGNoLWxlZnQtZGlzYWJsZWRdPVwiaW5kZXggPD0gMFwiXG4gICAgICAgICAgKGNsaWNrKT1cIm9uU3dpdGNoTGVmdCgkZXZlbnQpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxzcGFuIG56LWljb24gbnpUeXBlPVwibGVmdFwiIG56VGhlbWU9XCJvdXRsaW5lXCI+PC9zcGFuPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwiYW50LWltYWdlLXByZXZpZXctc3dpdGNoLXJpZ2h0XCJcbiAgICAgICAgICBbY2xhc3MuYW50LWltYWdlLXByZXZpZXctc3dpdGNoLXJpZ2h0LWRpc2FibGVkXT1cImluZGV4ID49IGltYWdlcy5sZW5ndGggLSAxXCJcbiAgICAgICAgICAoY2xpY2spPVwib25Td2l0Y2hSaWdodCgkZXZlbnQpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxzcGFuIG56LWljb24gbnpUeXBlPVwicmlnaHRcIiBuelRoZW1lPVwib3V0bGluZVwiPjwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICB9XG5cbiAgICAgIDx1bCBjbGFzcz1cImFudC1pbWFnZS1wcmV2aWV3LW9wZXJhdGlvbnNcIj5cbiAgICAgICAgQGlmIChpbWFnZXMubGVuZ3RoID4gMSkge1xuICAgICAgICAgIDxsaSBjbGFzcz1cImFudC1pbWFnZS1wcmV2aWV3LW9wZXJhdGlvbnMtcHJvZ3Jlc3NcIj57eyBpbmRleCArIDEgfX0gLyB7eyBpbWFnZXMubGVuZ3RoIH19PC9saT5cbiAgICAgICAgfVxuXG4gICAgICAgIEBmb3IgKG9wdGlvbiBvZiBvcGVyYXRpb25zOyB0cmFjayBvcHRpb24pIHtcbiAgICAgICAgICA8bGlcbiAgICAgICAgICAgIGNsYXNzPVwiYW50LWltYWdlLXByZXZpZXctb3BlcmF0aW9ucy1vcGVyYXRpb25cIlxuICAgICAgICAgICAgW2NsYXNzLmFudC1pbWFnZS1wcmV2aWV3LW9wZXJhdGlvbnMtb3BlcmF0aW9uLWRpc2FibGVkXT1cInpvb21PdXREaXNhYmxlZCAmJiBvcHRpb24udHlwZSA9PT0gJ3pvb21PdXQnXCJcbiAgICAgICAgICAgIChjbGljayk9XCJvcHRpb24ub25DbGljaygpXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgICBjbGFzcz1cImFudC1pbWFnZS1wcmV2aWV3LW9wZXJhdGlvbnMtaWNvblwiXG4gICAgICAgICAgICAgIG56LWljb25cbiAgICAgICAgICAgICAgW256VHlwZV09XCJvcHRpb24uaWNvblwiXG4gICAgICAgICAgICAgIFtuelJvdGF0ZV09XCJvcHRpb24ucm90YXRlID8/IDBcIlxuICAgICAgICAgICAgICBuelRoZW1lPVwib3V0bGluZVwiXG4gICAgICAgICAgICA+PC9zcGFuPlxuICAgICAgICAgIDwvbGk+XG4gICAgICAgIH1cbiAgICAgIDwvdWw+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2XG4gICAgICBjbGFzcz1cImFudC1pbWFnZS1wcmV2aWV3LXdyYXBcIlxuICAgICAgdGFiaW5kZXg9XCItMVwiXG4gICAgICAoY2xpY2spPVwibWFza0Nsb3NhYmxlICYmICRldmVudC50YXJnZXQgPT09ICRldmVudC5jdXJyZW50VGFyZ2V0ICYmIG9uQ2xvc2UoKVwiXG4gICAgPlxuICAgICAgPGRpdiBjbGFzcz1cImFudC1pbWFnZS1wcmV2aWV3XCIgcm9sZT1cImRpYWxvZ1wiIGFyaWEtbW9kYWw9XCJ0cnVlXCI+XG4gICAgICAgIDxkaXYgdGFiaW5kZXg9XCIwXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgc3R5bGU9XCJ3aWR0aDogMDsgaGVpZ2h0OiAwOyBvdmVyZmxvdzogaGlkZGVuOyBvdXRsaW5lOiBub25lO1wiPjwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiYW50LWltYWdlLXByZXZpZXctY29udGVudFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJhbnQtaW1hZ2UtcHJldmlldy1ib2R5XCI+XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgIGNsYXNzPVwiYW50LWltYWdlLXByZXZpZXctaW1nLXdyYXBwZXJcIlxuICAgICAgICAgICAgICAjaW1hZ2VQcmV2aWV3V3JhcHBlclxuICAgICAgICAgICAgICBjZGtEcmFnXG4gICAgICAgICAgICAgIFtzdHlsZS50cmFuc2Zvcm1dPVwicHJldmlld0ltYWdlV3JhcHBlclRyYW5zZm9ybVwiXG4gICAgICAgICAgICAgIFtjZGtEcmFnRnJlZURyYWdQb3NpdGlvbl09XCJwb3NpdGlvblwiXG4gICAgICAgICAgICAgIChjZGtEcmFnRW5kZWQpPVwib25EcmFnRW5kKCRldmVudClcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICBAZm9yIChpbWFnZSBvZiBpbWFnZXM7IHRyYWNrIGltYWdlOyBsZXQgaW1hZ2VJbmRleCA9ICRpbmRleCkge1xuICAgICAgICAgICAgICAgIEBpZiAoaW1hZ2VJbmRleCA9PT0gaW5kZXgpIHtcbiAgICAgICAgICAgICAgICAgIDxpbWdcbiAgICAgICAgICAgICAgICAgICAgY2RrRHJhZ0hhbmRsZVxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImFudC1pbWFnZS1wcmV2aWV3LWltZ1wiXG4gICAgICAgICAgICAgICAgICAgICNpbWdSZWZcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIuc3JjXT1cInNhbml0aXplclJlc291cmNlVXJsKGltYWdlLnNyYylcIlxuICAgICAgICAgICAgICAgICAgICBbYXR0ci5zcmNzZXRdPVwiaW1hZ2Uuc3Jjc2V0XCJcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIuYWx0XT1cImltYWdlLmFsdFwiXG4gICAgICAgICAgICAgICAgICAgIFtzdHlsZS53aWR0aF09XCJpbWFnZS53aWR0aFwiXG4gICAgICAgICAgICAgICAgICAgIFtzdHlsZS5oZWlnaHRdPVwiaW1hZ2UuaGVpZ2h0XCJcbiAgICAgICAgICAgICAgICAgICAgW3N0eWxlLnRyYW5zZm9ybV09XCJwcmV2aWV3SW1hZ2VUcmFuc2Zvcm1cIlxuICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiB0YWJpbmRleD1cIjBcIiBhcmlhLWhpZGRlbj1cInRydWVcIiBzdHlsZT1cIndpZHRoOiAwOyBoZWlnaHQ6IDA7IG92ZXJmbG93OiBoaWRkZW47IG91dGxpbmU6IG5vbmU7XCI+PC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgYCxcbiAgcHJlc2VydmVXaGl0ZXNwYWNlczogZmFsc2UsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBob3N0OiB7XG4gICAgY2xhc3M6ICdhbnQtaW1hZ2UtcHJldmlldy1yb290JyxcbiAgICAnW2NsYXNzLmFudC1pbWFnZS1wcmV2aWV3LW1vdmluZ10nOiAnaXNEcmFnZ2luZycsXG4gICAgJ1tzdHlsZS56SW5kZXhdJzogJ2NvbmZpZy5uelpJbmRleCcsXG4gICAgJ1tALmRpc2FibGVkXSc6ICdjb25maWcubnpOb0FuaW1hdGlvbicsXG4gICAgJ1tAZmFkZU1vdGlvbl0nOiBgdmlzaWJsZSA/ICdlbnRlcicgOiAnbGVhdmUnYCxcbiAgICAnKEBmYWRlTW90aW9uLnN0YXJ0KSc6ICdvbkFuaW1hdGlvblN0YXJ0KCRldmVudCknLFxuICAgICcoQGZhZGVNb3Rpb24uZG9uZSknOiAnb25BbmltYXRpb25Eb25lKCRldmVudCknXG4gIH0sXG4gIGltcG9ydHM6IFtOekljb25Nb2R1bGUsIENka0RyYWdIYW5kbGUsIENka0RyYWddLFxuICBwcm92aWRlcnM6IFtOekRlc3Ryb3lTZXJ2aWNlXVxufSlcbmV4cG9ydCBjbGFzcyBOekltYWdlUHJldmlld0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIHJlYWRvbmx5IF9kZWZhdWx0Tnpab29tID0gTlpfREVGQVVMVF9aT09NO1xuICByZWFkb25seSBfZGVmYXVsdE56U2NhbGVTdGVwID0gTlpfREVGQVVMVF9TQ0FMRV9TVEVQO1xuICByZWFkb25seSBfZGVmYXVsdE56Um90YXRlID0gTlpfREVGQVVMVF9ST1RBVEU7XG5cbiAgaW1hZ2VzOiBOekltYWdlW10gPSBbXTtcbiAgaW5kZXggPSAwO1xuICBpc0RyYWdnaW5nID0gZmFsc2U7XG4gIHZpc2libGUgPSB0cnVlO1xuICBhbmltYXRpb25TdGF0ZUNoYW5nZWQgPSBuZXcgRXZlbnRFbWl0dGVyPEFuaW1hdGlvbkV2ZW50PigpO1xuICBzY2FsZVN0ZXBNYXA6IE1hcDxOekltYWdlVXJsLCBOekltYWdlU2NhbGVTdGVwPiA9IG5ldyBNYXA8TnpJbWFnZVVybCwgTnpJbWFnZVNjYWxlU3RlcD4oKTtcblxuICBwcmV2aWV3SW1hZ2VUcmFuc2Zvcm0gPSAnJztcbiAgcHJldmlld0ltYWdlV3JhcHBlclRyYW5zZm9ybSA9ICcnO1xuICBvcGVyYXRpb25zOiBOekltYWdlQ29udGFpbmVyT3BlcmF0aW9uW10gPSBbXG4gICAge1xuICAgICAgaWNvbjogJ2Nsb3NlJyxcbiAgICAgIG9uQ2xpY2s6ICgpID0+IHtcbiAgICAgICAgdGhpcy5vbkNsb3NlKCk7XG4gICAgICB9LFxuICAgICAgdHlwZTogJ2Nsb3NlJ1xuICAgIH0sXG4gICAge1xuICAgICAgaWNvbjogJ3pvb20taW4nLFxuICAgICAgb25DbGljazogKCkgPT4ge1xuICAgICAgICB0aGlzLm9uWm9vbUluKCk7XG4gICAgICB9LFxuICAgICAgdHlwZTogJ3pvb21JbidcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246ICd6b29tLW91dCcsXG4gICAgICBvbkNsaWNrOiAoKSA9PiB7XG4gICAgICAgIHRoaXMub25ab29tT3V0KCk7XG4gICAgICB9LFxuICAgICAgdHlwZTogJ3pvb21PdXQnXG4gICAgfSxcbiAgICB7XG4gICAgICBpY29uOiAncm90YXRlLXJpZ2h0JyxcbiAgICAgIG9uQ2xpY2s6ICgpID0+IHtcbiAgICAgICAgdGhpcy5vblJvdGF0ZVJpZ2h0KCk7XG4gICAgICB9LFxuICAgICAgdHlwZTogJ3JvdGF0ZVJpZ2h0J1xuICAgIH0sXG4gICAge1xuICAgICAgaWNvbjogJ3JvdGF0ZS1sZWZ0JyxcbiAgICAgIG9uQ2xpY2s6ICgpID0+IHtcbiAgICAgICAgdGhpcy5vblJvdGF0ZUxlZnQoKTtcbiAgICAgIH0sXG4gICAgICB0eXBlOiAncm90YXRlTGVmdCdcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246ICdzd2FwJyxcbiAgICAgIG9uQ2xpY2s6ICgpID0+IHtcbiAgICAgICAgdGhpcy5vbkhvcml6b250YWxGbGlwKCk7XG4gICAgICB9LFxuICAgICAgdHlwZTogJ2ZsaXBIb3Jpem9udGFsbHknXG4gICAgfSxcbiAgICB7XG4gICAgICBpY29uOiAnc3dhcCcsXG4gICAgICBvbkNsaWNrOiAoKSA9PiB7XG4gICAgICAgIHRoaXMub25WZXJ0aWNhbEZsaXAoKTtcbiAgICAgIH0sXG4gICAgICB0eXBlOiAnZmxpcFZlcnRpY2FsbHknLFxuICAgICAgcm90YXRlOiA5MFxuICAgIH1cbiAgXTtcblxuICB6b29tT3V0RGlzYWJsZWQgPSBmYWxzZTtcbiAgcG9zaXRpb24gPSB7IC4uLmluaXRpYWxQb3NpdGlvbiB9O1xuICBwcmV2aWV3UmVmITogTnpJbWFnZVByZXZpZXdSZWY7XG4gIGNsb3NlQ2xpY2sgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgQFZpZXdDaGlsZCgnaW1nUmVmJykgaW1hZ2VSZWYhOiBFbGVtZW50UmVmPEhUTUxJbWFnZUVsZW1lbnQ+O1xuICBAVmlld0NoaWxkKCdpbWFnZVByZXZpZXdXcmFwcGVyJywgeyBzdGF0aWM6IHRydWUgfSkgaW1hZ2VQcmV2aWV3V3JhcHBlciE6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+O1xuXG4gIHByaXZhdGUgem9vbTogbnVtYmVyO1xuICBwcml2YXRlIHJvdGF0ZTogbnVtYmVyO1xuICBwcml2YXRlIHNjYWxlU3RlcDogbnVtYmVyO1xuICBwcml2YXRlIGZsaXBIb3Jpem9udGFsbHk6IGJvb2xlYW47XG4gIHByaXZhdGUgZmxpcFZlcnRpY2FsbHk6IGJvb2xlYW47XG5cbiAgZ2V0IGFuaW1hdGlvbkRpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy5uek5vQW5pbWF0aW9uID8/IGZhbHNlO1xuICB9XG5cbiAgZ2V0IG1hc2tDbG9zYWJsZSgpOiBib29sZWFuIHtcbiAgICBjb25zdCBkZWZhdWx0Q29uZmlnOiBOelNhZmVBbnkgPSB0aGlzLm56Q29uZmlnU2VydmljZS5nZXRDb25maWdGb3JDb21wb25lbnQoTlpfQ09ORklHX01PRFVMRV9OQU1FKSB8fCB7fTtcbiAgICByZXR1cm4gdGhpcy5jb25maWcubnpNYXNrQ2xvc2FibGUgPz8gZGVmYXVsdENvbmZpZy5uek1hc2tDbG9zYWJsZSA/PyB0cnVlO1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBuZ1pvbmU6IE5nWm9uZSxcbiAgICBwcml2YXRlIGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHVibGljIG56Q29uZmlnU2VydmljZTogTnpDb25maWdTZXJ2aWNlLFxuICAgIHB1YmxpYyBjb25maWc6IE56SW1hZ2VQcmV2aWV3T3B0aW9ucyxcbiAgICBwcml2YXRlIGRlc3Ryb3kkOiBOekRlc3Ryb3lTZXJ2aWNlLFxuICAgIHByaXZhdGUgc2FuaXRpemVyOiBEb21TYW5pdGl6ZXJcbiAgKSB7XG4gICAgdGhpcy56b29tID0gdGhpcy5jb25maWcubnpab29tID8/IHRoaXMuX2RlZmF1bHROelpvb207XG4gICAgdGhpcy5zY2FsZVN0ZXAgPSB0aGlzLmNvbmZpZy5uelNjYWxlU3RlcCA/PyB0aGlzLl9kZWZhdWx0TnpTY2FsZVN0ZXA7XG4gICAgdGhpcy5yb3RhdGUgPSB0aGlzLmNvbmZpZy5uelJvdGF0ZSA/PyB0aGlzLl9kZWZhdWx0TnpSb3RhdGU7XG4gICAgdGhpcy5mbGlwSG9yaXpvbnRhbGx5ID0gdGhpcy5jb25maWcubnpGbGlwSG9yaXpvbnRhbGx5ID8/IGZhbHNlO1xuICAgIHRoaXMuZmxpcFZlcnRpY2FsbHkgPSB0aGlzLmNvbmZpZy5uekZsaXBWZXJ0aWNhbGx5ID8/IGZhbHNlO1xuICAgIHRoaXMudXBkYXRlWm9vbU91dERpc2FibGVkKCk7XG4gICAgdGhpcy51cGRhdGVQcmV2aWV3SW1hZ2VUcmFuc2Zvcm0oKTtcbiAgICB0aGlzLnVwZGF0ZVByZXZpZXdJbWFnZVdyYXBwZXJUcmFuc2Zvcm0oKTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgIGZyb21FdmVudCh0aGlzLmltYWdlUHJldmlld1dyYXBwZXIubmF0aXZlRWxlbWVudCwgJ21vdXNlZG93bicpXG4gICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcbiAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgdGhpcy5pc0RyYWdnaW5nID0gdHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgIGZyb21FdmVudDxXaGVlbEV2ZW50Pih0aGlzLmltYWdlUHJldmlld1dyYXBwZXIubmF0aXZlRWxlbWVudCwgJ3doZWVsJylcbiAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgICAuc3Vic2NyaWJlKGV2ZW50ID0+IHtcbiAgICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4gdGhpcy53aGVlbFpvb21FdmVudEhhbmRsZXIoZXZlbnQpKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBzZXRJbWFnZXMoaW1hZ2VzOiBOekltYWdlW10sIHNjYWxlU3RlcE1hcD86IE1hcDxzdHJpbmcsIG51bWJlcj4pOiB2b2lkIHtcbiAgICBpZiAoc2NhbGVTdGVwTWFwKSB0aGlzLnNjYWxlU3RlcE1hcCA9IHNjYWxlU3RlcE1hcDtcbiAgICB0aGlzLmltYWdlcyA9IGltYWdlcztcbiAgICB0aGlzLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgc3dpdGNoVG8oaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuaW5kZXggPSBpbmRleDtcbiAgICB0aGlzLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgbmV4dCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pbmRleCA8IHRoaXMuaW1hZ2VzLmxlbmd0aCAtIDEpIHtcbiAgICAgIHRoaXMucmVzZXQoKTtcbiAgICAgIHRoaXMuaW5kZXgrKztcbiAgICAgIHRoaXMudXBkYXRlUHJldmlld0ltYWdlVHJhbnNmb3JtKCk7XG4gICAgICB0aGlzLnVwZGF0ZVByZXZpZXdJbWFnZVdyYXBwZXJUcmFuc2Zvcm0oKTtcbiAgICAgIHRoaXMudXBkYXRlWm9vbU91dERpc2FibGVkKCk7XG4gICAgICB0aGlzLm1hcmtGb3JDaGVjaygpO1xuICAgIH1cbiAgfVxuXG4gIHByZXYoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaW5kZXggPiAwKSB7XG4gICAgICB0aGlzLnJlc2V0KCk7XG4gICAgICB0aGlzLmluZGV4LS07XG4gICAgICB0aGlzLnVwZGF0ZVByZXZpZXdJbWFnZVRyYW5zZm9ybSgpO1xuICAgICAgdGhpcy51cGRhdGVQcmV2aWV3SW1hZ2VXcmFwcGVyVHJhbnNmb3JtKCk7XG4gICAgICB0aGlzLnVwZGF0ZVpvb21PdXREaXNhYmxlZCgpO1xuICAgICAgdGhpcy5tYXJrRm9yQ2hlY2soKTtcbiAgICB9XG4gIH1cblxuICBtYXJrRm9yQ2hlY2soKTogdm9pZCB7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBvbkNsb3NlKCk6IHZvaWQge1xuICAgIHRoaXMudmlzaWJsZSA9IGZhbHNlO1xuICAgIHRoaXMuY2xvc2VDbGljay5lbWl0KCk7XG4gIH1cblxuICBvblpvb21JbigpOiB2b2lkIHtcbiAgICBjb25zdCB6b29tU3RlcCA9XG4gICAgICB0aGlzLnNjYWxlU3RlcE1hcC5nZXQodGhpcy5pbWFnZXNbdGhpcy5pbmRleF0uc3JjID8/IHRoaXMuaW1hZ2VzW3RoaXMuaW5kZXhdLnNyY3NldCkgPz8gdGhpcy5zY2FsZVN0ZXA7XG4gICAgdGhpcy56b29tICs9IHpvb21TdGVwO1xuICAgIHRoaXMudXBkYXRlUHJldmlld0ltYWdlVHJhbnNmb3JtKCk7XG4gICAgdGhpcy51cGRhdGVab29tT3V0RGlzYWJsZWQoKTtcbiAgfVxuXG4gIG9uWm9vbU91dCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy56b29tID4gMSkge1xuICAgICAgY29uc3Qgem9vbVN0ZXAgPVxuICAgICAgICB0aGlzLnNjYWxlU3RlcE1hcC5nZXQodGhpcy5pbWFnZXNbdGhpcy5pbmRleF0uc3JjID8/IHRoaXMuaW1hZ2VzW3RoaXMuaW5kZXhdLnNyY3NldCkgPz8gdGhpcy5zY2FsZVN0ZXA7XG4gICAgICB0aGlzLnpvb20gLT0gem9vbVN0ZXA7XG4gICAgICB0aGlzLnVwZGF0ZVByZXZpZXdJbWFnZVRyYW5zZm9ybSgpO1xuICAgICAgdGhpcy51cGRhdGVab29tT3V0RGlzYWJsZWQoKTtcblxuICAgICAgaWYgKHRoaXMuem9vbSA8PSAxKSB7XG4gICAgICAgIHRoaXMucmVDZW50ZXJJbWFnZSgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIG9uUm90YXRlUmlnaHQoKTogdm9pZCB7XG4gICAgdGhpcy5yb3RhdGUgKz0gOTA7XG4gICAgdGhpcy51cGRhdGVQcmV2aWV3SW1hZ2VUcmFuc2Zvcm0oKTtcbiAgfVxuXG4gIG9uUm90YXRlTGVmdCgpOiB2b2lkIHtcbiAgICB0aGlzLnJvdGF0ZSAtPSA5MDtcbiAgICB0aGlzLnVwZGF0ZVByZXZpZXdJbWFnZVRyYW5zZm9ybSgpO1xuICB9XG5cbiAgb25Td2l0Y2hMZWZ0KGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoK