@sumaris-net/ngx-components 18.26.13 → 18.26.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -734,11 +734,11 @@ export class AppImageGallerySlideshowComponent {
734
734
  this.cd.markForCheck();
735
735
  }
736
736
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AppImageGallerySlideshowComponent, deps: [{ token: i1.AlertController }, { token: i2.TranslateService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
737
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AppImageGallerySlideshowComponent, selector: "app-image-gallery-slideshow", inputs: { rows: "rows", selectedIndex: "selectedIndex", mobile: ["mobile", "mobile", booleanAttribute], readOnly: ["readOnly", "readOnly", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], debug: ["debug", "debug", booleanAttribute], enableMouseZoom: ["enableMouseZoom", "enableMouseZoom", booleanAttribute], wheelZoomStep: "wheelZoomStep", maxZoomRatio: "maxZoomRatio", enableRotate: ["enableRotate", "enableRotate", booleanAttribute], enableCrop: ["enableCrop", "enableCrop", booleanAttribute], editionFormat: "editionFormat", editionQuality: "editionQuality", imageSizeQueryParam: "imageSizeQueryParam", modalImageSize: "modalImageSize", enableLoop: ["enableLoop", "enableLoop", booleanAttribute], canFetchMore: ["canFetchMore", "canFetchMore", booleanAttribute] }, outputs: { deleteRequested: "deleteRequested", closeRequested: "closeRequested", afterEditImage: "afterEditImage", afterEditRow: "afterEditRow", previousSlide: "previousSlide", nextSlide: "nextSlide", fetchMore: "fetchMore" }, host: { listeners: { "window:resize": "onWindowResize()" } }, viewQueries: [{ propertyName: "swiperRef", first: true, predicate: ["swiperContainer"], descendants: true }], ngImport: i0, template: "<ion-content\n class=\"ion-no-padding ion-no-margin\"\n (mousedown)=\"onPointerDown($event, swiperContainer)\"\n (mousemove)=\"onPointerMove($event, swiperContainer)\"\n (mouseup)=\"onPointerUp($event, swiperContainer)\"\n (mouseleave)=\"onPointerUp($event, swiperContainer)\"\n (touchmove)=\"onCropPointerMove($event, swiperContainer)\"\n (touchend)=\"onCropPointerUp($event, swiperContainer)\"\n (touchcancel)=\"onCropPointerUp($event, swiperContainer)\"\n>\n @let count = rows?.length || 0;\n <!-- Counter -->\n <div class=\"top-left\">\n <ion-label color=\"light\">{{ _activeIndex + 1 }} / {{ count }}</ion-label>\n </div>\n\n <!-- zoom / rotation / crop buttons: all shown together, no \"enter edit mode\" step needed -->\n <div class=\"top-right\">\n @if (!mobile) {\n <ion-fab-button size=\"small\" (click)=\"zoom(swiperContainer, true)\" color=\"light\">\n <ion-icon name=\"search\"></ion-icon>\n <ion-icon class=\"icon-secondary\" name=\"add\"></ion-icon>\n </ion-fab-button>\n <ion-fab-button size=\"small\" (click)=\"zoom(swiperContainer, false)\" color=\"light\">\n <ion-icon name=\"search\"></ion-icon>\n <ion-icon class=\"icon-secondary\" name=\"remove\"></ion-icon>\n </ion-fab-button>\n }\n @if (!readOnly && enableRotate) {\n <ion-fab-button\n size=\"small\"\n (click)=\"rotate(swiperContainer, 'left')\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_LEFT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_LEFT' | translate) : ''\"\n >\n <mat-icon>rotate_left</mat-icon>\n </ion-fab-button>\n <ion-fab-button\n size=\"small\"\n (click)=\"rotate(swiperContainer, 'right')\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_RIGHT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_RIGHT' | translate) : ''\"\n >\n <mat-icon>rotate_right</mat-icon>\n </ion-fab-button>\n }\n @if (!readOnly && enableCrop) {\n <ion-fab-button\n size=\"small\"\n (click)=\"toggleCropTool(swiperContainer)\"\n [color]=\"_cropToolActive ? 'tertiary' : 'light'\"\n [title]=\"\n !showTooltip\n ? ((_cropToolActive ? 'IMAGE.GALLERY.BTN_CROP_DEACTIVATE' : 'IMAGE.GALLERY.BTN_CROP_ACTIVATE') | translate)\n : ''\n \"\n [matTooltip]=\"\n showTooltip\n ? ((_cropToolActive ? 'IMAGE.GALLERY.BTN_CROP_DEACTIVATE' : 'IMAGE.GALLERY.BTN_CROP_ACTIVATE') | translate)\n : ''\n \"\n >\n <mat-icon>crop</mat-icon>\n </ion-fab-button>\n @if (_cropToolActive) {\n <ion-fab-button\n size=\"small\"\n (click)=\"resetCrop(swiperContainer)\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_CROP_RESET' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_CROP_RESET' | translate) : ''\"\n >\n <mat-icon>crop_free</mat-icon>\n </ion-fab-button>\n }\n }\n </div>\n\n <!-- navigation side buttons next/back: hidden while a crop/rotation edit is pending, to keep the focus on validating/cancelling it -->\n <ng-container *ngIf=\"!mobile && !hasPendingEdit && (rows | isArrayLength: { greaterThan: 1 })\">\n <div class=\"side-buttons prev\" [class.disabled]=\"isPrevDisabled\" (click)=\"slidePrev(swiperContainer)\">\n <ion-icon name=\"chevron-back\"></ion-icon>\n </div>\n <div class=\"side-buttons next\" [class.disabled]=\"isNextDisabled\" (click)=\"slideNext(swiperContainer)\">\n <ion-icon name=\"chevron-forward\"></ion-icon>\n </div>\n </ng-container>\n\n <!-- image slides -->\n <swiper-container\n #swiperContainer\n [modules]=\"swiperModules\"\n [zoom]=\"!enableMouseZoom\"\n [initialSlide]=\"selectedIndex\"\n (swiperslidechange)=\"onSlideChange(swiperContainer)\"\n (swiperinit)=\"onSwiperInit(swiperContainer)\"\n >\n @for (row of rows; track row.id; let index = $index) {\n <ng-container *ngTemplateOutlet=\"slideTemplate; context: { image: row.currentData, index }\"></ng-container>\n }\n </swiper-container>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar color=\"light\">\n @if (!hasPendingEdit) {\n <ion-row>\n <ion-col size=\"4\" class=\"ion-text-start\">\n @if (!readOnly) {\n <ion-button\n (click)=\"requestDelete(swiperContainer)\"\n [disabled]=\"disabled\"\n fill=\"clear\"\n color=\"danger\"\n >\n <mat-icon slot=\"start\">delete</mat-icon>\n {{ 'COMMON.BTN_DELETE' | translate }}\n </ion-button>\n }\n </ion-col>\n <ion-col size=\"4\"></ion-col>\n <ion-col size=\"4\" class=\"ion-text-end\">\n <ion-button (click)=\"closeRequested.emit()\" color=\"tertiary\" fill=\"clear\" *ngIf=\"mobile; else desktop\">\n <ion-icon slot=\"start\" name=\"close\"></ion-icon>\n {{ 'COMMON.BTN_CLOSE' | translate }}\n </ion-button>\n <ng-template #desktop>\n <ion-button (click)=\"closeRequested.emit()\" color=\"tertiary\">\n {{ 'COMMON.BTN_CLOSE' | translate }}\n </ion-button>\n </ng-template>\n </ion-col>\n </ion-row>\n } @else {\n <!-- A crop or rotation change is pending: ask for an explicit validation before exporting the image -->\n <ion-row>\n <ion-col size=\"12\" class=\"ion-text-end\">\n <ion-button\n (click)=\"discardEdit(swiperContainer)\"\n color=\"dark\"\n fill=\"clear\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_CANCEL_EDIT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_CANCEL_EDIT' | translate) : ''\"\n >\n <ion-icon slot=\"start\" name=\"arrow-undo\"></ion-icon>\n {{ 'COMMON.BTN_CANCEL' | translate }}\n </ion-button>\n <ion-button (click)=\"validateEdit(swiperContainer)\" color=\"danger\">\n <ion-icon slot=\"start\" name=\"checkmark\"></ion-icon>\n {{ 'COMMON.BTN_VALIDATE' | translate }}\n </ion-button>\n </ion-col>\n </ion-row>\n }\n </ion-toolbar>\n</ion-footer>\n\n<ng-template #slideTemplate let-image=\"image\" let-index=\"index\">\n <swiper-slide>\n <div class=\"swiper-zoom-container\" [class.cdk-visually-hidden]=\"!_swiper && index !== selectedIndex\">\n\n <!-- the image -->\n @if (image?.url) {\n <ion-img class=\"swiper-zoom-target\" [src]=\"image.url | appendQueryParams: getImageSizeQueryParams()\" />\n } @else {\n <img [src]=\"image.dataUrl\" [alt]=\"image.title\" />\n }\n\n <!-- crop overlay: only rendered for the active slide -->\n @if (!readOnly && enableCrop && _cropToolActive && index === _activeIndex) {\n <div\n class=\"crop-overlay\"\n (mousedown)=\"onCropPointerDown($event, swiperContainer, 'move')\"\n (touchstart)=\"onCropPointerDown($event, swiperContainer, 'move')\"\n >\n <!-- darkened mask around the selection: clipped to the image bounds -->\n <div class=\"crop-mask\">\n <div\n class=\"crop-mask-rect\"\n [style.left.%]=\"_cropRect.x * 100\"\n [style.top.%]=\"_cropRect.y * 100\"\n [style.width.%]=\"_cropRect.width * 100\"\n [style.height.%]=\"_cropRect.height * 100\"\n ></div>\n </div>\n\n <!-- interactive selection border, grid & drag handles: never clipped, so corner/edge handles\n remain fully grabbable even when the selection touches the image bounds -->\n <div\n class=\"crop-rect\"\n [style.left.%]=\"_cropRect.x * 100\"\n [style.top.%]=\"_cropRect.y * 100\"\n [style.width.%]=\"_cropRect.width * 100\"\n [style.height.%]=\"_cropRect.height * 100\"\n >\n <div class=\"crop-grid\">\n <span class=\"line v\" style=\"left: 33.333%\"></span>\n <span class=\"line v\" style=\"left: 66.666%\"></span>\n <span class=\"line h\" style=\"top: 33.333%\"></span>\n <span class=\"line h\" style=\"top: 66.666%\"></span>\n </div>\n @for (handle of _cropHandles; track handle) {\n <div\n class=\"crop-handle {{ handle }}\"\n (mousedown)=\"onCropPointerDown($event, swiperContainer, handle)\"\n (touchstart)=\"onCropPointerDown($event, swiperContainer, handle)\"\n ></div>\n }\n </div>\n </div>\n }\n </div>\n </swiper-slide>\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column;height:100%;-webkit-user-select:none;user-select:none}:host ion-content{flex:1 1 auto}:host .top-left{z-index:14;position:absolute;display:inline-grid;left:var(--ion-padding-start, 8px);top:var(--ion-padding-start, 8px)}:host .top-right{z-index:14;position:absolute;display:inline-grid;right:var(--ion-padding-start, 8px);top:var(--ion-padding-start, 8px)}:host .side-buttons{--side-buttons-width: 120px;--side-buttons-margin: calc(var(--side-buttons-width) / 3);z-index:13;position:absolute;top:0;bottom:0;width:var(--side-buttons-width)}:host .side-buttons ion-icon{top:50%;color:#fff;background:#00000080;padding:4px;border-radius:50%;font-size:2.5rem;position:absolute;opacity:0;transition-duration:.15s;transition-timing-function:ease-in}:host .side-buttons:hover{cursor:pointer}:host .side-buttons:hover ion-icon{opacity:1}:host .side-buttons.prev{left:0}:host .side-buttons.prev ion-icon{left:var(--side-buttons-margin)}:host .side-buttons.next{right:0}:host .side-buttons.next ion-icon{right:var(--side-buttons-margin)}:host .side-buttons.disabled{pointer-events:none}:host swiper-container{height:100%;background:#000}:host .swiper-zoom-container{position:relative}:host ion-fab-button .icon-secondary{top:11px;left:6px;height:14px}:host .crop-overlay{position:absolute;z-index:15;cursor:move;touch-action:none;animation:crop-overlay-fade-in .15s ease-in}:host .crop-overlay .crop-mask{position:absolute;inset:0;overflow:hidden;pointer-events:none}:host .crop-overlay .crop-mask .crop-mask-rect{position:absolute;box-shadow:0 0 0 2000px #0009}:host .crop-overlay .crop-rect{position:absolute;box-sizing:border-box;border:1px solid rgba(255,255,255,.95);cursor:move;touch-action:none}:host .crop-overlay .crop-rect .crop-grid{position:absolute;inset:0;pointer-events:none}:host .crop-overlay .crop-rect .crop-grid .line{position:absolute;background:#ffffff73}:host .crop-overlay .crop-rect .crop-grid .line.v{top:0;bottom:0;width:1px}:host .crop-overlay .crop-rect .crop-grid .line.h{left:0;right:0;height:1px}:host .crop-overlay .crop-rect .crop-handle{position:absolute;width:16px;height:16px;margin:-8px;background:#fff;border:1px solid rgba(0,0,0,.45);border-radius:50%;box-shadow:0 1px 4px #00000080;transition:transform .12s ease;touch-action:none}:host .crop-overlay .crop-rect .crop-handle:hover{transform:scale(1.3)}:host .crop-overlay .crop-rect .crop-handle.nw{left:0;top:0;cursor:nwse-resize}:host .crop-overlay .crop-rect .crop-handle.n{left:50%;top:0;cursor:ns-resize}:host .crop-overlay .crop-rect .crop-handle.ne{left:100%;top:0;cursor:nesw-resize}:host .crop-overlay .crop-rect .crop-handle.e{left:100%;top:50%;cursor:ew-resize}:host .crop-overlay .crop-rect .crop-handle.se{left:100%;top:100%;cursor:nwse-resize}:host .crop-overlay .crop-rect .crop-handle.s{left:50%;top:100%;cursor:ns-resize}:host .crop-overlay .crop-rect .crop-handle.sw{left:0;top:100%;cursor:nesw-resize}:host .crop-overlay .crop-rect .crop-handle.w{left:0;top:50%;cursor:ew-resize}@keyframes crop-overlay-fade-in{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i1.IonFabButton, selector: "ion-fab-button", inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }, { kind: "component", type: i1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i1.IonRow, selector: "ion-row" }, { kind: "component", type: i1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: i6.ArrayLengthPipe, name: "isArrayLength" }, { kind: "pipe", type: i7.AppendQueryParamsPipePipe, name: "appendQueryParams" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
737
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AppImageGallerySlideshowComponent, selector: "app-image-gallery-slideshow", inputs: { rows: "rows", selectedIndex: "selectedIndex", mobile: ["mobile", "mobile", booleanAttribute], readOnly: ["readOnly", "readOnly", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], debug: ["debug", "debug", booleanAttribute], enableMouseZoom: ["enableMouseZoom", "enableMouseZoom", booleanAttribute], wheelZoomStep: "wheelZoomStep", maxZoomRatio: "maxZoomRatio", enableRotate: ["enableRotate", "enableRotate", booleanAttribute], enableCrop: ["enableCrop", "enableCrop", booleanAttribute], editionFormat: "editionFormat", editionQuality: "editionQuality", imageSizeQueryParam: "imageSizeQueryParam", modalImageSize: "modalImageSize", enableLoop: ["enableLoop", "enableLoop", booleanAttribute], canFetchMore: ["canFetchMore", "canFetchMore", booleanAttribute] }, outputs: { deleteRequested: "deleteRequested", closeRequested: "closeRequested", afterEditImage: "afterEditImage", afterEditRow: "afterEditRow", previousSlide: "previousSlide", nextSlide: "nextSlide", fetchMore: "fetchMore" }, host: { listeners: { "window:resize": "onWindowResize()" } }, viewQueries: [{ propertyName: "swiperRef", first: true, predicate: ["swiperContainer"], descendants: true }], ngImport: i0, template: "<ion-content\n class=\"ion-no-padding ion-no-margin\"\n (mousedown)=\"onPointerDown($event, swiperContainer)\"\n (mousemove)=\"onPointerMove($event, swiperContainer)\"\n (mouseup)=\"onPointerUp($event, swiperContainer)\"\n (mouseleave)=\"onPointerUp($event, swiperContainer)\"\n (touchmove)=\"onCropPointerMove($event, swiperContainer)\"\n (touchend)=\"onCropPointerUp($event, swiperContainer)\"\n (touchcancel)=\"onCropPointerUp($event, swiperContainer)\"\n>\n @let count = rows?.length || 0;\n <!-- Counter -->\n <div class=\"top-left\">\n <ion-label color=\"light\">{{ _activeIndex + 1 }} / {{ count }}</ion-label>\n </div>\n\n <!-- zoom / rotation / crop buttons: all shown together, no \"enter edit mode\" step needed -->\n <div class=\"top-right\">\n @if (!mobile) {\n <ion-fab-button size=\"small\" (click)=\"zoom(swiperContainer, true)\" color=\"light\">\n <ion-icon name=\"search\"></ion-icon>\n <ion-icon class=\"icon-secondary\" name=\"add\"></ion-icon>\n </ion-fab-button>\n <ion-fab-button size=\"small\" (click)=\"zoom(swiperContainer, false)\" color=\"light\">\n <ion-icon name=\"search\"></ion-icon>\n <ion-icon class=\"icon-secondary\" name=\"remove\"></ion-icon>\n </ion-fab-button>\n }\n @if (!readOnly && enableRotate) {\n <ion-fab-button\n size=\"small\"\n (click)=\"rotate(swiperContainer, 'left')\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_LEFT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_LEFT' | translate) : ''\"\n >\n <mat-icon>rotate_left</mat-icon>\n </ion-fab-button>\n <ion-fab-button\n size=\"small\"\n (click)=\"rotate(swiperContainer, 'right')\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_RIGHT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_RIGHT' | translate) : ''\"\n >\n <mat-icon>rotate_right</mat-icon>\n </ion-fab-button>\n }\n @if (!readOnly && enableCrop) {\n <ion-fab-button\n size=\"small\"\n (click)=\"toggleCropTool(swiperContainer)\"\n [color]=\"_cropToolActive ? 'tertiary' : 'light'\"\n [title]=\"\n !showTooltip\n ? ((_cropToolActive ? 'IMAGE.GALLERY.BTN_CROP_DEACTIVATE' : 'IMAGE.GALLERY.BTN_CROP_ACTIVATE') | translate)\n : ''\n \"\n [matTooltip]=\"\n showTooltip\n ? ((_cropToolActive ? 'IMAGE.GALLERY.BTN_CROP_DEACTIVATE' : 'IMAGE.GALLERY.BTN_CROP_ACTIVATE') | translate)\n : ''\n \"\n >\n <mat-icon>crop</mat-icon>\n </ion-fab-button>\n @if (_cropToolActive) {\n <ion-fab-button\n size=\"small\"\n (click)=\"resetCrop(swiperContainer)\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_CROP_RESET' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_CROP_RESET' | translate) : ''\"\n >\n <mat-icon>crop_free</mat-icon>\n </ion-fab-button>\n }\n }\n </div>\n\n <!-- navigation side buttons next/back: hidden while a crop/rotation edit is pending, to keep the focus on validating/cancelling it -->\n <ng-container *ngIf=\"!mobile && !hasPendingEdit && (rows | isArrayLength: { greaterThan: 1 })\">\n <div class=\"side-buttons prev\" [class.disabled]=\"isPrevDisabled\" (click)=\"slidePrev(swiperContainer)\">\n <ion-icon name=\"chevron-back\"></ion-icon>\n </div>\n <div class=\"side-buttons next\" [class.disabled]=\"isNextDisabled\" (click)=\"slideNext(swiperContainer)\">\n <ion-icon name=\"chevron-forward\"></ion-icon>\n </div>\n </ng-container>\n\n <!-- image slides -->\n <swiper-container\n #swiperContainer\n [modules]=\"swiperModules\"\n [zoom]=\"!enableMouseZoom\"\n [initialSlide]=\"selectedIndex\"\n (swiperslidechange)=\"onSlideChange(swiperContainer)\"\n (swiperinit)=\"onSwiperInit(swiperContainer)\"\n >\n @for (row of rows; track row.id; let index = $index) {\n <ng-container *ngTemplateOutlet=\"slideTemplate; context: { image: row.currentData, index }\"></ng-container>\n }\n </swiper-container>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar color=\"light\">\n @if (!hasPendingEdit) {\n <ion-row>\n <ion-col size=\"4\" class=\"ion-text-start\">\n @if (!readOnly) {\n <ion-button\n (click)=\"requestDelete(swiperContainer)\"\n [disabled]=\"disabled\"\n fill=\"clear\"\n color=\"danger\"\n >\n <mat-icon slot=\"start\">delete</mat-icon>\n {{ 'COMMON.BTN_DELETE' | translate }}\n </ion-button>\n }\n </ion-col>\n <ion-col size=\"4\"></ion-col>\n <ion-col size=\"4\" class=\"ion-text-end\">\n <ion-button (click)=\"closeRequested.emit()\" color=\"tertiary\" fill=\"clear\" *ngIf=\"mobile; else desktop\">\n <ion-icon slot=\"start\" name=\"close\"></ion-icon>\n {{ 'COMMON.BTN_CLOSE' | translate }}\n </ion-button>\n <ng-template #desktop>\n <ion-button (click)=\"closeRequested.emit()\" color=\"tertiary\">\n {{ 'COMMON.BTN_CLOSE' | translate }}\n </ion-button>\n </ng-template>\n </ion-col>\n </ion-row>\n } @else {\n <!-- A crop or rotation change is pending: ask for an explicit validation before exporting the image -->\n <ion-row>\n <ion-col size=\"12\" class=\"ion-text-end\">\n <ion-button\n (click)=\"discardEdit(swiperContainer)\"\n color=\"dark\"\n fill=\"clear\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_CANCEL_EDIT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_CANCEL_EDIT' | translate) : ''\"\n >\n <ion-icon slot=\"start\" name=\"arrow-undo\"></ion-icon>\n {{ 'COMMON.BTN_CANCEL' | translate }}\n </ion-button>\n <ion-button (click)=\"validateEdit(swiperContainer)\" color=\"danger\">\n <ion-icon slot=\"start\" name=\"checkmark\"></ion-icon>\n {{ 'COMMON.BTN_VALIDATE' | translate }}\n </ion-button>\n </ion-col>\n </ion-row>\n }\n </ion-toolbar>\n</ion-footer>\n\n<ng-template #slideTemplate let-image=\"image\" let-index=\"index\">\n <swiper-slide>\n <div class=\"swiper-zoom-container\" [class.cdk-visually-hidden]=\"!_swiper && index !== selectedIndex\">\n\n <!-- the image -->\n @if (image?.url) {\n <ion-img class=\"swiper-zoom-target\" [src]=\"image.url | appendQueryParams: getImageSizeQueryParams()\" />\n } @else {\n <img [src]=\"image.dataUrl\" [alt]=\"image.title\" />\n }\n\n <!-- crop overlay: only rendered for the active slide -->\n @if (!readOnly && enableCrop && _cropToolActive && index === _activeIndex) {\n <div\n class=\"crop-overlay\"\n (mousedown)=\"onCropPointerDown($event, swiperContainer, 'move')\"\n (touchstart)=\"onCropPointerDown($event, swiperContainer, 'move')\"\n >\n <!-- darkened mask around the selection: clipped to the image bounds -->\n <div class=\"crop-mask\">\n <div\n class=\"crop-mask-rect\"\n [style.left.%]=\"_cropRect.x * 100\"\n [style.top.%]=\"_cropRect.y * 100\"\n [style.width.%]=\"_cropRect.width * 100\"\n [style.height.%]=\"_cropRect.height * 100\"\n ></div>\n </div>\n\n <!-- interactive selection border, grid & drag handles: never clipped, so corner/edge handles\n remain fully grabbable even when the selection touches the image bounds -->\n <div\n class=\"crop-rect\"\n [style.left.%]=\"_cropRect.x * 100\"\n [style.top.%]=\"_cropRect.y * 100\"\n [style.width.%]=\"_cropRect.width * 100\"\n [style.height.%]=\"_cropRect.height * 100\"\n >\n <div class=\"crop-grid\">\n <span class=\"line v\" style=\"left: 33.333%\"></span>\n <span class=\"line v\" style=\"left: 66.666%\"></span>\n <span class=\"line h\" style=\"top: 33.333%\"></span>\n <span class=\"line h\" style=\"top: 66.666%\"></span>\n </div>\n @for (handle of _cropHandles; track handle) {\n <div\n class=\"crop-handle {{ handle }}\"\n (mousedown)=\"onCropPointerDown($event, swiperContainer, handle)\"\n (touchstart)=\"onCropPointerDown($event, swiperContainer, handle)\"\n ></div>\n }\n </div>\n </div>\n }\n </div>\n </swiper-slide>\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column;height:100%;-webkit-user-select:none;user-select:none}:host ion-content{flex:1 1 auto}:host .top-left{z-index:14;position:absolute;display:inline-grid;left:var(--ion-padding-start, 8px);top:var(--ion-padding-start, 8px)}:host .top-right{z-index:14;position:absolute;display:inline-grid;right:var(--ion-padding-start, 8px);top:var(--ion-padding-start, 8px)}:host .side-buttons{--side-buttons-width: 120px;--side-buttons-margin: calc(var(--side-buttons-width) / 3);z-index:13;position:absolute;top:0;bottom:0;width:var(--side-buttons-width)}:host .side-buttons ion-icon{top:50%;color:#fff;background:rgba(0,0,0,.5);padding:4px;border-radius:50%;font-size:2.5rem;position:absolute;opacity:0;transition-duration:.15s;transition-timing-function:ease-in}:host .side-buttons:hover{cursor:pointer}:host .side-buttons:hover ion-icon{opacity:1}:host .side-buttons.prev{left:0}:host .side-buttons.prev ion-icon{left:var(--side-buttons-margin)}:host .side-buttons.next{right:0}:host .side-buttons.next ion-icon{right:var(--side-buttons-margin)}:host .side-buttons.disabled{pointer-events:none}:host swiper-container{height:100%;background:#000}:host .swiper-zoom-container{position:relative}:host ion-fab-button .icon-secondary{top:11px;left:6px;height:14px}:host .crop-overlay{position:absolute;z-index:15;cursor:move;touch-action:none;animation:crop-overlay-fade-in .15s ease-in}:host .crop-overlay .crop-mask{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;pointer-events:none}:host .crop-overlay .crop-mask .crop-mask-rect{position:absolute;box-shadow:0 0 0 2000px rgba(0,0,0,.6)}:host .crop-overlay .crop-rect{position:absolute;box-sizing:border-box;border:1px solid rgba(255,255,255,.95);cursor:move;touch-action:none}:host .crop-overlay .crop-rect .crop-grid{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}:host .crop-overlay .crop-rect .crop-grid .line{position:absolute;background:rgba(255,255,255,.45)}:host .crop-overlay .crop-rect .crop-grid .line.v{top:0;bottom:0;width:1px}:host .crop-overlay .crop-rect .crop-grid .line.h{left:0;right:0;height:1px}:host .crop-overlay .crop-rect .crop-handle{position:absolute;width:16px;height:16px;margin:-8px;background:#fff;border:1px solid rgba(0,0,0,.45);border-radius:50%;box-shadow:0 1px 4px rgba(0,0,0,.5);transition:transform .12s ease;touch-action:none}:host .crop-overlay .crop-rect .crop-handle:hover{transform:scale(1.3)}:host .crop-overlay .crop-rect .crop-handle.nw{left:0;top:0;cursor:nwse-resize}:host .crop-overlay .crop-rect .crop-handle.n{left:50%;top:0;cursor:ns-resize}:host .crop-overlay .crop-rect .crop-handle.ne{left:100%;top:0;cursor:nesw-resize}:host .crop-overlay .crop-rect .crop-handle.e{left:100%;top:50%;cursor:ew-resize}:host .crop-overlay .crop-rect .crop-handle.se{left:100%;top:100%;cursor:nwse-resize}:host .crop-overlay .crop-rect .crop-handle.s{left:50%;top:100%;cursor:ns-resize}:host .crop-overlay .crop-rect .crop-handle.sw{left:0;top:100%;cursor:nesw-resize}:host .crop-overlay .crop-rect .crop-handle.w{left:0;top:50%;cursor:ew-resize}@keyframes crop-overlay-fade-in{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i1.IonFabButton, selector: "ion-fab-button", inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }, { kind: "component", type: i1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i1.IonRow, selector: "ion-row" }, { kind: "component", type: i1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: i6.ArrayLengthPipe, name: "isArrayLength" }, { kind: "pipe", type: i7.AppendQueryParamsPipePipe, name: "appendQueryParams" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
738
738
  }
739
739
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AppImageGallerySlideshowComponent, decorators: [{
740
740
  type: Component,
741
- args: [{ selector: 'app-image-gallery-slideshow', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-content\n class=\"ion-no-padding ion-no-margin\"\n (mousedown)=\"onPointerDown($event, swiperContainer)\"\n (mousemove)=\"onPointerMove($event, swiperContainer)\"\n (mouseup)=\"onPointerUp($event, swiperContainer)\"\n (mouseleave)=\"onPointerUp($event, swiperContainer)\"\n (touchmove)=\"onCropPointerMove($event, swiperContainer)\"\n (touchend)=\"onCropPointerUp($event, swiperContainer)\"\n (touchcancel)=\"onCropPointerUp($event, swiperContainer)\"\n>\n @let count = rows?.length || 0;\n <!-- Counter -->\n <div class=\"top-left\">\n <ion-label color=\"light\">{{ _activeIndex + 1 }} / {{ count }}</ion-label>\n </div>\n\n <!-- zoom / rotation / crop buttons: all shown together, no \"enter edit mode\" step needed -->\n <div class=\"top-right\">\n @if (!mobile) {\n <ion-fab-button size=\"small\" (click)=\"zoom(swiperContainer, true)\" color=\"light\">\n <ion-icon name=\"search\"></ion-icon>\n <ion-icon class=\"icon-secondary\" name=\"add\"></ion-icon>\n </ion-fab-button>\n <ion-fab-button size=\"small\" (click)=\"zoom(swiperContainer, false)\" color=\"light\">\n <ion-icon name=\"search\"></ion-icon>\n <ion-icon class=\"icon-secondary\" name=\"remove\"></ion-icon>\n </ion-fab-button>\n }\n @if (!readOnly && enableRotate) {\n <ion-fab-button\n size=\"small\"\n (click)=\"rotate(swiperContainer, 'left')\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_LEFT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_LEFT' | translate) : ''\"\n >\n <mat-icon>rotate_left</mat-icon>\n </ion-fab-button>\n <ion-fab-button\n size=\"small\"\n (click)=\"rotate(swiperContainer, 'right')\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_RIGHT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_RIGHT' | translate) : ''\"\n >\n <mat-icon>rotate_right</mat-icon>\n </ion-fab-button>\n }\n @if (!readOnly && enableCrop) {\n <ion-fab-button\n size=\"small\"\n (click)=\"toggleCropTool(swiperContainer)\"\n [color]=\"_cropToolActive ? 'tertiary' : 'light'\"\n [title]=\"\n !showTooltip\n ? ((_cropToolActive ? 'IMAGE.GALLERY.BTN_CROP_DEACTIVATE' : 'IMAGE.GALLERY.BTN_CROP_ACTIVATE') | translate)\n : ''\n \"\n [matTooltip]=\"\n showTooltip\n ? ((_cropToolActive ? 'IMAGE.GALLERY.BTN_CROP_DEACTIVATE' : 'IMAGE.GALLERY.BTN_CROP_ACTIVATE') | translate)\n : ''\n \"\n >\n <mat-icon>crop</mat-icon>\n </ion-fab-button>\n @if (_cropToolActive) {\n <ion-fab-button\n size=\"small\"\n (click)=\"resetCrop(swiperContainer)\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_CROP_RESET' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_CROP_RESET' | translate) : ''\"\n >\n <mat-icon>crop_free</mat-icon>\n </ion-fab-button>\n }\n }\n </div>\n\n <!-- navigation side buttons next/back: hidden while a crop/rotation edit is pending, to keep the focus on validating/cancelling it -->\n <ng-container *ngIf=\"!mobile && !hasPendingEdit && (rows | isArrayLength: { greaterThan: 1 })\">\n <div class=\"side-buttons prev\" [class.disabled]=\"isPrevDisabled\" (click)=\"slidePrev(swiperContainer)\">\n <ion-icon name=\"chevron-back\"></ion-icon>\n </div>\n <div class=\"side-buttons next\" [class.disabled]=\"isNextDisabled\" (click)=\"slideNext(swiperContainer)\">\n <ion-icon name=\"chevron-forward\"></ion-icon>\n </div>\n </ng-container>\n\n <!-- image slides -->\n <swiper-container\n #swiperContainer\n [modules]=\"swiperModules\"\n [zoom]=\"!enableMouseZoom\"\n [initialSlide]=\"selectedIndex\"\n (swiperslidechange)=\"onSlideChange(swiperContainer)\"\n (swiperinit)=\"onSwiperInit(swiperContainer)\"\n >\n @for (row of rows; track row.id; let index = $index) {\n <ng-container *ngTemplateOutlet=\"slideTemplate; context: { image: row.currentData, index }\"></ng-container>\n }\n </swiper-container>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar color=\"light\">\n @if (!hasPendingEdit) {\n <ion-row>\n <ion-col size=\"4\" class=\"ion-text-start\">\n @if (!readOnly) {\n <ion-button\n (click)=\"requestDelete(swiperContainer)\"\n [disabled]=\"disabled\"\n fill=\"clear\"\n color=\"danger\"\n >\n <mat-icon slot=\"start\">delete</mat-icon>\n {{ 'COMMON.BTN_DELETE' | translate }}\n </ion-button>\n }\n </ion-col>\n <ion-col size=\"4\"></ion-col>\n <ion-col size=\"4\" class=\"ion-text-end\">\n <ion-button (click)=\"closeRequested.emit()\" color=\"tertiary\" fill=\"clear\" *ngIf=\"mobile; else desktop\">\n <ion-icon slot=\"start\" name=\"close\"></ion-icon>\n {{ 'COMMON.BTN_CLOSE' | translate }}\n </ion-button>\n <ng-template #desktop>\n <ion-button (click)=\"closeRequested.emit()\" color=\"tertiary\">\n {{ 'COMMON.BTN_CLOSE' | translate }}\n </ion-button>\n </ng-template>\n </ion-col>\n </ion-row>\n } @else {\n <!-- A crop or rotation change is pending: ask for an explicit validation before exporting the image -->\n <ion-row>\n <ion-col size=\"12\" class=\"ion-text-end\">\n <ion-button\n (click)=\"discardEdit(swiperContainer)\"\n color=\"dark\"\n fill=\"clear\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_CANCEL_EDIT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_CANCEL_EDIT' | translate) : ''\"\n >\n <ion-icon slot=\"start\" name=\"arrow-undo\"></ion-icon>\n {{ 'COMMON.BTN_CANCEL' | translate }}\n </ion-button>\n <ion-button (click)=\"validateEdit(swiperContainer)\" color=\"danger\">\n <ion-icon slot=\"start\" name=\"checkmark\"></ion-icon>\n {{ 'COMMON.BTN_VALIDATE' | translate }}\n </ion-button>\n </ion-col>\n </ion-row>\n }\n </ion-toolbar>\n</ion-footer>\n\n<ng-template #slideTemplate let-image=\"image\" let-index=\"index\">\n <swiper-slide>\n <div class=\"swiper-zoom-container\" [class.cdk-visually-hidden]=\"!_swiper && index !== selectedIndex\">\n\n <!-- the image -->\n @if (image?.url) {\n <ion-img class=\"swiper-zoom-target\" [src]=\"image.url | appendQueryParams: getImageSizeQueryParams()\" />\n } @else {\n <img [src]=\"image.dataUrl\" [alt]=\"image.title\" />\n }\n\n <!-- crop overlay: only rendered for the active slide -->\n @if (!readOnly && enableCrop && _cropToolActive && index === _activeIndex) {\n <div\n class=\"crop-overlay\"\n (mousedown)=\"onCropPointerDown($event, swiperContainer, 'move')\"\n (touchstart)=\"onCropPointerDown($event, swiperContainer, 'move')\"\n >\n <!-- darkened mask around the selection: clipped to the image bounds -->\n <div class=\"crop-mask\">\n <div\n class=\"crop-mask-rect\"\n [style.left.%]=\"_cropRect.x * 100\"\n [style.top.%]=\"_cropRect.y * 100\"\n [style.width.%]=\"_cropRect.width * 100\"\n [style.height.%]=\"_cropRect.height * 100\"\n ></div>\n </div>\n\n <!-- interactive selection border, grid & drag handles: never clipped, so corner/edge handles\n remain fully grabbable even when the selection touches the image bounds -->\n <div\n class=\"crop-rect\"\n [style.left.%]=\"_cropRect.x * 100\"\n [style.top.%]=\"_cropRect.y * 100\"\n [style.width.%]=\"_cropRect.width * 100\"\n [style.height.%]=\"_cropRect.height * 100\"\n >\n <div class=\"crop-grid\">\n <span class=\"line v\" style=\"left: 33.333%\"></span>\n <span class=\"line v\" style=\"left: 66.666%\"></span>\n <span class=\"line h\" style=\"top: 33.333%\"></span>\n <span class=\"line h\" style=\"top: 66.666%\"></span>\n </div>\n @for (handle of _cropHandles; track handle) {\n <div\n class=\"crop-handle {{ handle }}\"\n (mousedown)=\"onCropPointerDown($event, swiperContainer, handle)\"\n (touchstart)=\"onCropPointerDown($event, swiperContainer, handle)\"\n ></div>\n }\n </div>\n </div>\n }\n </div>\n </swiper-slide>\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column;height:100%;-webkit-user-select:none;user-select:none}:host ion-content{flex:1 1 auto}:host .top-left{z-index:14;position:absolute;display:inline-grid;left:var(--ion-padding-start, 8px);top:var(--ion-padding-start, 8px)}:host .top-right{z-index:14;position:absolute;display:inline-grid;right:var(--ion-padding-start, 8px);top:var(--ion-padding-start, 8px)}:host .side-buttons{--side-buttons-width: 120px;--side-buttons-margin: calc(var(--side-buttons-width) / 3);z-index:13;position:absolute;top:0;bottom:0;width:var(--side-buttons-width)}:host .side-buttons ion-icon{top:50%;color:#fff;background:#00000080;padding:4px;border-radius:50%;font-size:2.5rem;position:absolute;opacity:0;transition-duration:.15s;transition-timing-function:ease-in}:host .side-buttons:hover{cursor:pointer}:host .side-buttons:hover ion-icon{opacity:1}:host .side-buttons.prev{left:0}:host .side-buttons.prev ion-icon{left:var(--side-buttons-margin)}:host .side-buttons.next{right:0}:host .side-buttons.next ion-icon{right:var(--side-buttons-margin)}:host .side-buttons.disabled{pointer-events:none}:host swiper-container{height:100%;background:#000}:host .swiper-zoom-container{position:relative}:host ion-fab-button .icon-secondary{top:11px;left:6px;height:14px}:host .crop-overlay{position:absolute;z-index:15;cursor:move;touch-action:none;animation:crop-overlay-fade-in .15s ease-in}:host .crop-overlay .crop-mask{position:absolute;inset:0;overflow:hidden;pointer-events:none}:host .crop-overlay .crop-mask .crop-mask-rect{position:absolute;box-shadow:0 0 0 2000px #0009}:host .crop-overlay .crop-rect{position:absolute;box-sizing:border-box;border:1px solid rgba(255,255,255,.95);cursor:move;touch-action:none}:host .crop-overlay .crop-rect .crop-grid{position:absolute;inset:0;pointer-events:none}:host .crop-overlay .crop-rect .crop-grid .line{position:absolute;background:#ffffff73}:host .crop-overlay .crop-rect .crop-grid .line.v{top:0;bottom:0;width:1px}:host .crop-overlay .crop-rect .crop-grid .line.h{left:0;right:0;height:1px}:host .crop-overlay .crop-rect .crop-handle{position:absolute;width:16px;height:16px;margin:-8px;background:#fff;border:1px solid rgba(0,0,0,.45);border-radius:50%;box-shadow:0 1px 4px #00000080;transition:transform .12s ease;touch-action:none}:host .crop-overlay .crop-rect .crop-handle:hover{transform:scale(1.3)}:host .crop-overlay .crop-rect .crop-handle.nw{left:0;top:0;cursor:nwse-resize}:host .crop-overlay .crop-rect .crop-handle.n{left:50%;top:0;cursor:ns-resize}:host .crop-overlay .crop-rect .crop-handle.ne{left:100%;top:0;cursor:nesw-resize}:host .crop-overlay .crop-rect .crop-handle.e{left:100%;top:50%;cursor:ew-resize}:host .crop-overlay .crop-rect .crop-handle.se{left:100%;top:100%;cursor:nwse-resize}:host .crop-overlay .crop-rect .crop-handle.s{left:50%;top:100%;cursor:ns-resize}:host .crop-overlay .crop-rect .crop-handle.sw{left:0;top:100%;cursor:nesw-resize}:host .crop-overlay .crop-rect .crop-handle.w{left:0;top:50%;cursor:ew-resize}@keyframes crop-overlay-fade-in{0%{opacity:0}to{opacity:1}}\n"] }]
741
+ args: [{ selector: 'app-image-gallery-slideshow', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-content\n class=\"ion-no-padding ion-no-margin\"\n (mousedown)=\"onPointerDown($event, swiperContainer)\"\n (mousemove)=\"onPointerMove($event, swiperContainer)\"\n (mouseup)=\"onPointerUp($event, swiperContainer)\"\n (mouseleave)=\"onPointerUp($event, swiperContainer)\"\n (touchmove)=\"onCropPointerMove($event, swiperContainer)\"\n (touchend)=\"onCropPointerUp($event, swiperContainer)\"\n (touchcancel)=\"onCropPointerUp($event, swiperContainer)\"\n>\n @let count = rows?.length || 0;\n <!-- Counter -->\n <div class=\"top-left\">\n <ion-label color=\"light\">{{ _activeIndex + 1 }} / {{ count }}</ion-label>\n </div>\n\n <!-- zoom / rotation / crop buttons: all shown together, no \"enter edit mode\" step needed -->\n <div class=\"top-right\">\n @if (!mobile) {\n <ion-fab-button size=\"small\" (click)=\"zoom(swiperContainer, true)\" color=\"light\">\n <ion-icon name=\"search\"></ion-icon>\n <ion-icon class=\"icon-secondary\" name=\"add\"></ion-icon>\n </ion-fab-button>\n <ion-fab-button size=\"small\" (click)=\"zoom(swiperContainer, false)\" color=\"light\">\n <ion-icon name=\"search\"></ion-icon>\n <ion-icon class=\"icon-secondary\" name=\"remove\"></ion-icon>\n </ion-fab-button>\n }\n @if (!readOnly && enableRotate) {\n <ion-fab-button\n size=\"small\"\n (click)=\"rotate(swiperContainer, 'left')\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_LEFT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_LEFT' | translate) : ''\"\n >\n <mat-icon>rotate_left</mat-icon>\n </ion-fab-button>\n <ion-fab-button\n size=\"small\"\n (click)=\"rotate(swiperContainer, 'right')\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_RIGHT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_ROTATE_RIGHT' | translate) : ''\"\n >\n <mat-icon>rotate_right</mat-icon>\n </ion-fab-button>\n }\n @if (!readOnly && enableCrop) {\n <ion-fab-button\n size=\"small\"\n (click)=\"toggleCropTool(swiperContainer)\"\n [color]=\"_cropToolActive ? 'tertiary' : 'light'\"\n [title]=\"\n !showTooltip\n ? ((_cropToolActive ? 'IMAGE.GALLERY.BTN_CROP_DEACTIVATE' : 'IMAGE.GALLERY.BTN_CROP_ACTIVATE') | translate)\n : ''\n \"\n [matTooltip]=\"\n showTooltip\n ? ((_cropToolActive ? 'IMAGE.GALLERY.BTN_CROP_DEACTIVATE' : 'IMAGE.GALLERY.BTN_CROP_ACTIVATE') | translate)\n : ''\n \"\n >\n <mat-icon>crop</mat-icon>\n </ion-fab-button>\n @if (_cropToolActive) {\n <ion-fab-button\n size=\"small\"\n (click)=\"resetCrop(swiperContainer)\"\n color=\"light\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_CROP_RESET' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_CROP_RESET' | translate) : ''\"\n >\n <mat-icon>crop_free</mat-icon>\n </ion-fab-button>\n }\n }\n </div>\n\n <!-- navigation side buttons next/back: hidden while a crop/rotation edit is pending, to keep the focus on validating/cancelling it -->\n <ng-container *ngIf=\"!mobile && !hasPendingEdit && (rows | isArrayLength: { greaterThan: 1 })\">\n <div class=\"side-buttons prev\" [class.disabled]=\"isPrevDisabled\" (click)=\"slidePrev(swiperContainer)\">\n <ion-icon name=\"chevron-back\"></ion-icon>\n </div>\n <div class=\"side-buttons next\" [class.disabled]=\"isNextDisabled\" (click)=\"slideNext(swiperContainer)\">\n <ion-icon name=\"chevron-forward\"></ion-icon>\n </div>\n </ng-container>\n\n <!-- image slides -->\n <swiper-container\n #swiperContainer\n [modules]=\"swiperModules\"\n [zoom]=\"!enableMouseZoom\"\n [initialSlide]=\"selectedIndex\"\n (swiperslidechange)=\"onSlideChange(swiperContainer)\"\n (swiperinit)=\"onSwiperInit(swiperContainer)\"\n >\n @for (row of rows; track row.id; let index = $index) {\n <ng-container *ngTemplateOutlet=\"slideTemplate; context: { image: row.currentData, index }\"></ng-container>\n }\n </swiper-container>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar color=\"light\">\n @if (!hasPendingEdit) {\n <ion-row>\n <ion-col size=\"4\" class=\"ion-text-start\">\n @if (!readOnly) {\n <ion-button\n (click)=\"requestDelete(swiperContainer)\"\n [disabled]=\"disabled\"\n fill=\"clear\"\n color=\"danger\"\n >\n <mat-icon slot=\"start\">delete</mat-icon>\n {{ 'COMMON.BTN_DELETE' | translate }}\n </ion-button>\n }\n </ion-col>\n <ion-col size=\"4\"></ion-col>\n <ion-col size=\"4\" class=\"ion-text-end\">\n <ion-button (click)=\"closeRequested.emit()\" color=\"tertiary\" fill=\"clear\" *ngIf=\"mobile; else desktop\">\n <ion-icon slot=\"start\" name=\"close\"></ion-icon>\n {{ 'COMMON.BTN_CLOSE' | translate }}\n </ion-button>\n <ng-template #desktop>\n <ion-button (click)=\"closeRequested.emit()\" color=\"tertiary\">\n {{ 'COMMON.BTN_CLOSE' | translate }}\n </ion-button>\n </ng-template>\n </ion-col>\n </ion-row>\n } @else {\n <!-- A crop or rotation change is pending: ask for an explicit validation before exporting the image -->\n <ion-row>\n <ion-col size=\"12\" class=\"ion-text-end\">\n <ion-button\n (click)=\"discardEdit(swiperContainer)\"\n color=\"dark\"\n fill=\"clear\"\n [title]=\"!showTooltip ? ('IMAGE.GALLERY.BTN_CANCEL_EDIT' | translate) : ''\"\n [matTooltip]=\"showTooltip ? ('IMAGE.GALLERY.BTN_CANCEL_EDIT' | translate) : ''\"\n >\n <ion-icon slot=\"start\" name=\"arrow-undo\"></ion-icon>\n {{ 'COMMON.BTN_CANCEL' | translate }}\n </ion-button>\n <ion-button (click)=\"validateEdit(swiperContainer)\" color=\"danger\">\n <ion-icon slot=\"start\" name=\"checkmark\"></ion-icon>\n {{ 'COMMON.BTN_VALIDATE' | translate }}\n </ion-button>\n </ion-col>\n </ion-row>\n }\n </ion-toolbar>\n</ion-footer>\n\n<ng-template #slideTemplate let-image=\"image\" let-index=\"index\">\n <swiper-slide>\n <div class=\"swiper-zoom-container\" [class.cdk-visually-hidden]=\"!_swiper && index !== selectedIndex\">\n\n <!-- the image -->\n @if (image?.url) {\n <ion-img class=\"swiper-zoom-target\" [src]=\"image.url | appendQueryParams: getImageSizeQueryParams()\" />\n } @else {\n <img [src]=\"image.dataUrl\" [alt]=\"image.title\" />\n }\n\n <!-- crop overlay: only rendered for the active slide -->\n @if (!readOnly && enableCrop && _cropToolActive && index === _activeIndex) {\n <div\n class=\"crop-overlay\"\n (mousedown)=\"onCropPointerDown($event, swiperContainer, 'move')\"\n (touchstart)=\"onCropPointerDown($event, swiperContainer, 'move')\"\n >\n <!-- darkened mask around the selection: clipped to the image bounds -->\n <div class=\"crop-mask\">\n <div\n class=\"crop-mask-rect\"\n [style.left.%]=\"_cropRect.x * 100\"\n [style.top.%]=\"_cropRect.y * 100\"\n [style.width.%]=\"_cropRect.width * 100\"\n [style.height.%]=\"_cropRect.height * 100\"\n ></div>\n </div>\n\n <!-- interactive selection border, grid & drag handles: never clipped, so corner/edge handles\n remain fully grabbable even when the selection touches the image bounds -->\n <div\n class=\"crop-rect\"\n [style.left.%]=\"_cropRect.x * 100\"\n [style.top.%]=\"_cropRect.y * 100\"\n [style.width.%]=\"_cropRect.width * 100\"\n [style.height.%]=\"_cropRect.height * 100\"\n >\n <div class=\"crop-grid\">\n <span class=\"line v\" style=\"left: 33.333%\"></span>\n <span class=\"line v\" style=\"left: 66.666%\"></span>\n <span class=\"line h\" style=\"top: 33.333%\"></span>\n <span class=\"line h\" style=\"top: 66.666%\"></span>\n </div>\n @for (handle of _cropHandles; track handle) {\n <div\n class=\"crop-handle {{ handle }}\"\n (mousedown)=\"onCropPointerDown($event, swiperContainer, handle)\"\n (touchstart)=\"onCropPointerDown($event, swiperContainer, handle)\"\n ></div>\n }\n </div>\n </div>\n }\n </div>\n </swiper-slide>\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column;height:100%;-webkit-user-select:none;user-select:none}:host ion-content{flex:1 1 auto}:host .top-left{z-index:14;position:absolute;display:inline-grid;left:var(--ion-padding-start, 8px);top:var(--ion-padding-start, 8px)}:host .top-right{z-index:14;position:absolute;display:inline-grid;right:var(--ion-padding-start, 8px);top:var(--ion-padding-start, 8px)}:host .side-buttons{--side-buttons-width: 120px;--side-buttons-margin: calc(var(--side-buttons-width) / 3);z-index:13;position:absolute;top:0;bottom:0;width:var(--side-buttons-width)}:host .side-buttons ion-icon{top:50%;color:#fff;background:rgba(0,0,0,.5);padding:4px;border-radius:50%;font-size:2.5rem;position:absolute;opacity:0;transition-duration:.15s;transition-timing-function:ease-in}:host .side-buttons:hover{cursor:pointer}:host .side-buttons:hover ion-icon{opacity:1}:host .side-buttons.prev{left:0}:host .side-buttons.prev ion-icon{left:var(--side-buttons-margin)}:host .side-buttons.next{right:0}:host .side-buttons.next ion-icon{right:var(--side-buttons-margin)}:host .side-buttons.disabled{pointer-events:none}:host swiper-container{height:100%;background:#000}:host .swiper-zoom-container{position:relative}:host ion-fab-button .icon-secondary{top:11px;left:6px;height:14px}:host .crop-overlay{position:absolute;z-index:15;cursor:move;touch-action:none;animation:crop-overlay-fade-in .15s ease-in}:host .crop-overlay .crop-mask{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;pointer-events:none}:host .crop-overlay .crop-mask .crop-mask-rect{position:absolute;box-shadow:0 0 0 2000px rgba(0,0,0,.6)}:host .crop-overlay .crop-rect{position:absolute;box-sizing:border-box;border:1px solid rgba(255,255,255,.95);cursor:move;touch-action:none}:host .crop-overlay .crop-rect .crop-grid{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}:host .crop-overlay .crop-rect .crop-grid .line{position:absolute;background:rgba(255,255,255,.45)}:host .crop-overlay .crop-rect .crop-grid .line.v{top:0;bottom:0;width:1px}:host .crop-overlay .crop-rect .crop-grid .line.h{left:0;right:0;height:1px}:host .crop-overlay .crop-rect .crop-handle{position:absolute;width:16px;height:16px;margin:-8px;background:#fff;border:1px solid rgba(0,0,0,.45);border-radius:50%;box-shadow:0 1px 4px rgba(0,0,0,.5);transition:transform .12s ease;touch-action:none}:host .crop-overlay .crop-rect .crop-handle:hover{transform:scale(1.3)}:host .crop-overlay .crop-rect .crop-handle.nw{left:0;top:0;cursor:nwse-resize}:host .crop-overlay .crop-rect .crop-handle.n{left:50%;top:0;cursor:ns-resize}:host .crop-overlay .crop-rect .crop-handle.ne{left:100%;top:0;cursor:nesw-resize}:host .crop-overlay .crop-rect .crop-handle.e{left:100%;top:50%;cursor:ew-resize}:host .crop-overlay .crop-rect .crop-handle.se{left:100%;top:100%;cursor:nwse-resize}:host .crop-overlay .crop-rect .crop-handle.s{left:50%;top:100%;cursor:ns-resize}:host .crop-overlay .crop-rect .crop-handle.sw{left:0;top:100%;cursor:nesw-resize}:host .crop-overlay .crop-rect .crop-handle.w{left:0;top:50%;cursor:ew-resize}@keyframes crop-overlay-fade-in{0%{opacity:0}to{opacity:1}}\n"] }]
742
742
  }], ctorParameters: () => [{ type: i1.AlertController }, { type: i2.TranslateService }, { type: i0.ChangeDetectorRef }], propDecorators: { rows: [{
743
743
  type: Input
744
744
  }], selectedIndex: [{
@@ -78,4 +78,26 @@ export function isMobile(win) {
78
78
  export function isPrint(win) {
79
79
  return matchMedia(win, 'print');
80
80
  }
81
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxhdGZvcm1zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9zaGFyZWQvcGxhdGZvcm1zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztTQUVTO0FBRVQsTUFBTSxNQUFNLEdBQUc7SUFDYixTQUFTLEVBQUUsSUFBSTtJQUNmLE1BQU0sRUFBRSxJQUFJO0lBQ1osT0FBTyxFQUFFLElBQUk7SUFDYixTQUFTLEVBQUUsSUFBSTtDQUNoQixDQUFDO0FBRUYsTUFBTSxVQUFVLFVBQVUsQ0FBQyxHQUFXLEVBQUUsS0FBYTtJQUNuRCxPQUFPLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxDQUFDO0FBQ3ZDLENBQUM7QUFFRCxNQUFNLFVBQVUsWUFBWSxDQUFDLEdBQVc7SUFDdEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUN0QixNQUFNLENBQUMsU0FBUyxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUMsU0FBUyxJQUFJLEdBQUcsQ0FBQyxTQUFTLENBQUMsTUFBTSxJQUFLLE1BQWMsQ0FBQyxLQUFLLENBQUM7SUFDOUYsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLFNBQVMsQ0FBQztBQUMxQixDQUFDO0FBRUQsTUFBTSxVQUFVLGFBQWEsQ0FBQyxHQUFXLEVBQUUsSUFBWTtJQUNyRCxNQUFNLFNBQVMsR0FBVyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDNUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQzlCLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFDLEdBQVk7SUFDcEMsT0FBTyxhQUFhLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0FBQ3hDLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFDLEdBQVk7SUFDcEMsT0FBTyxhQUFhLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDO0FBQzNDLENBQUM7QUFFRCxNQUFNLFVBQVUsUUFBUSxDQUFDLEdBQVk7SUFDbkMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxvQkFBb0IsSUFBSSxhQUFhLENBQUMsR0FBRyxFQUFFLFlBQVksQ0FBQyxDQUFDO0FBQ2pGLENBQUM7QUFFRCxNQUFNLFVBQVUsUUFBUSxDQUFDLEdBQVk7SUFDbkMsT0FBTyxhQUFhLENBQUMsR0FBRyxFQUFFLFlBQVksQ0FBQyxDQUFDO0FBQzFDLENBQUM7QUFFRCxNQUFNLFVBQVUsTUFBTSxDQUFDLEdBQVk7SUFDakMsT0FBTyxhQUFhLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBQ3JDLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFDLEdBQVk7SUFDcEMsT0FBTyxVQUFVLENBQUMsR0FBRyxFQUFFLHNCQUFzQixDQUFDLENBQUM7QUFDakQsQ0FBQztBQUVELE1BQU0sVUFBVSxNQUFNLENBQUMsR0FBVztJQUNoQyxtQkFBbUI7SUFDbkIsSUFBSSxhQUFhLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDaEMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsVUFBVTtJQUNWLElBQUksYUFBYSxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsSUFBSSxTQUFTLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN2RCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxNQUFNLFVBQVUsT0FBTyxDQUFDLEdBQVc7SUFDakMscUJBQXFCO0lBQ3JCLE9BQU8sYUFBYSxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUM3RCxDQUFDO0FBRUQsTUFBTSxVQUFVLEtBQUssQ0FBQyxHQUFXO0lBQy9CLE9BQU8sYUFBYSxDQUFDLEdBQUcsRUFBRSxjQUFjLENBQUMsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDM0QsQ0FBQztBQUVELE1BQU0sVUFBVSxTQUFTLENBQUMsR0FBVztJQUNuQyxPQUFPLGFBQWEsQ0FBQyxHQUFHLEVBQUUsZUFBZSxDQUFDLENBQUM7QUFDN0MsQ0FBQztBQUVELE1BQU0sVUFBVSxXQUFXLENBQUMsR0FBUTtJQUNsQyxJQUFJLE1BQU0sQ0FBQyxTQUFTLEtBQUssSUFBSSxJQUFJLE1BQU0sQ0FBQyxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDaEUsTUFBTSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLElBQUksR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLFNBQVMsQ0FBQztBQUMxQixDQUFDO0FBRUQsTUFBTSxVQUFVLFFBQVEsQ0FBQyxHQUFXO0lBQ2xDLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxJQUFJLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUMxRCxNQUFNLENBQUMsTUFBTTtZQUNYLFNBQVMsQ0FBQyxHQUFHLENBQUM7Z0JBQ2QsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNqQyxzRkFBc0Y7Z0JBQ3RGLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDeEMsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQztBQUN2QixDQUFDO0FBRUQsTUFBTSxVQUFVLE9BQU8sQ0FBQyxHQUFZO0lBQ2xDLE9BQU8sVUFBVSxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztBQUNsQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogLS0tXG4gKiBTb3VyY2U6IGh0dHBzOi8vZ2l0aHViLmNvbS9pb25pYy10ZWFtL2lvbmljLWZyYW1ld29yay9ibG9iL2IwZDUzY2E3MzYxOTU4NTY3MWQ4Y2Y0ZGMyNGU0N2Y4MjY0OTVhMGEvY29yZS9zcmMvdXRpbHMvcGxhdGZvcm0udHNcbiAqIC0tLSAqL1xuXG5jb25zdCBfY2FjaGUgPSB7XG4gIHVzZXJBZ2VudDogbnVsbCxcbiAgbW9iaWxlOiBudWxsLFxuICBjb3Jkb3ZhOiBudWxsLFxuICBjYXBhY2l0b3I6IG51bGwsXG59O1xuXG5leHBvcnQgZnVuY3Rpb24gbWF0Y2hNZWRpYSh3aW46IFdpbmRvdywgcXVlcnk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gd2luLm1hdGNoTWVkaWEocXVlcnkpLm1hdGNoZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRVc2VyQWdlbnQod2luOiBXaW5kb3cpOiBzdHJpbmcge1xuICBpZiAoIV9jYWNoZS51c2VyQWdlbnQpIHtcbiAgICBfY2FjaGUudXNlckFnZW50ID0gd2luLm5hdmlnYXRvci51c2VyQWdlbnQgfHwgd2luLm5hdmlnYXRvci52ZW5kb3IgfHwgKHdpbmRvdyBhcyBhbnkpLm9wZXJhO1xuICB9XG4gIHJldHVybiBfY2FjaGUudXNlckFnZW50O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGVzdFVzZXJBZ2VudCh3aW46IFdpbmRvdywgZXhwcjogUmVnRXhwKSB7XG4gIGNvbnN0IHVzZXJBZ2VudDogc3RyaW5nID0gZ2V0VXNlckFnZW50KHdpbik7XG4gIHJldHVybiBleHByLnRlc3QodXNlckFnZW50KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzV2luZG93cyh3aW4/OiBXaW5kb3cpIHtcbiAgcmV0dXJuIHRlc3RVc2VyQWdlbnQod2luLCAvd2luZG93cy9pKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzRmlyZWZveCh3aW4/OiBXaW5kb3cpIHtcbiAgcmV0dXJuIHRlc3RVc2VyQWdlbnQod2luLCAvIGZpcmVmb3hcXC8vaSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1NhZmFyaSh3aW4/OiBXaW5kb3cpIHtcbiAgcmV0dXJuICFpc0Nocm9tZSh3aW4pIC8qRXhjbHVkZSBjaHJvbWl1bSovICYmIHRlc3RVc2VyQWdlbnQod2luLCAvIHNhZmFyaVxcLy9pKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzQ2hyb21lKHdpbj86IFdpbmRvdykge1xuICByZXR1cm4gdGVzdFVzZXJBZ2VudCh3aW4sIC8gY2hyb21lXFwvL2kpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNFZGdlKHdpbj86IFdpbmRvdykge1xuICByZXR1cm4gdGVzdFVzZXJBZ2VudCh3aW4sIC9lZGdlL2kpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNUb3VjaFVpKHdpbj86IFdpbmRvdykge1xuICByZXR1cm4gbWF0Y2hNZWRpYSh3aW4sICcoYW55LXBvaW50ZXI6Y29hcnNlKScpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNJcGFkKHdpbjogV2luZG93KSB7XG4gIC8vIGlPUyAxMiBhbmQgYmVsb3dcbiAgaWYgKHRlc3RVc2VyQWdlbnQod2luLCAvaVBhZC9pKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gaU9TIDEzK1xuICBpZiAodGVzdFVzZXJBZ2VudCh3aW4sIC9NYWNpbnRvc2gvaSkgJiYgaXNUb3VjaFVpKHdpbikpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzTWFjT1Mod2luOiBXaW5kb3cpIHtcbiAgLy8gaU9TIChidXQgbm90IGlQYWQpXG4gIHJldHVybiB0ZXN0VXNlckFnZW50KHdpbiwgL01hY2ludG9zaC9pKSAmJiAhaXNUb3VjaFVpKHdpbik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0lPUyh3aW46IFdpbmRvdykge1xuICByZXR1cm4gdGVzdFVzZXJBZ2VudCh3aW4sIC9pUGhvbmV8aVBvZC9pKSB8fCBpc0lwYWQod2luKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzQW5kcm9pZCh3aW46IFdpbmRvdykge1xuICByZXR1cm4gdGVzdFVzZXJBZ2VudCh3aW4sIC9hbmRyb2lkfHNpbmsvaSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0NhcGFjaXRvcih3aW46IGFueSk6IGJvb2xlYW4ge1xuICBpZiAoX2NhY2hlLmNhcGFjaXRvciA9PT0gbnVsbCB8fCBfY2FjaGUuY2FwYWNpdG9yID09PSB1bmRlZmluZWQpIHtcbiAgICBfY2FjaGUuY2FwYWNpdG9yID0gISEod2luWydDYXBhY2l0b3InXSB8fCB3aW5bJ2NhcGFjaXRvciddKTtcbiAgfVxuICByZXR1cm4gX2NhY2hlLmNhcGFjaXRvcjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzTW9iaWxlKHdpbjogV2luZG93KSB7XG4gIGlmIChfY2FjaGUubW9iaWxlID09PSBudWxsIHx8IF9jYWNoZS5tb2JpbGUgPT09IHVuZGVmaW5lZCkge1xuICAgIF9jYWNoZS5tb2JpbGUgPVxuICAgICAgaXNBbmRyb2lkKHdpbikgfHxcbiAgICAgIChpc0lPUyh3aW5kb3cpICYmIGlzVG91Y2hVaSh3aW4pKSB8fFxuICAgICAgLy8gV29ya2Fyb3VuZCwgZm9yIE1TIFdpbmRvd3MgdG91Y2ggc2NyZWVuIChkZXRlY3RlZCBhcyBtb2JpbGUsIGJ1dCBmb3JjZWQgYXMgZGVza3RvcClcbiAgICAgIChpc1RvdWNoVWkod2luKSAmJiAhaXNXaW5kb3dzKHdpbikpO1xuICB9XG4gIHJldHVybiBfY2FjaGUubW9iaWxlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNQcmludCh3aW4/OiBXaW5kb3cpIHtcbiAgcmV0dXJuIG1hdGNoTWVkaWEod2luLCAncHJpbnQnKTtcbn1cbiJdfQ==
81
+ export function isWebAnimationsSupported() {
82
+ if (typeof document === 'undefined' || typeof Element === 'undefined') {
83
+ return false;
84
+ }
85
+ if (typeof Element.prototype.animate !== 'function') {
86
+ return false;
87
+ }
88
+ try {
89
+ // Test minimal
90
+ const el = document.createElement('div');
91
+ // On n’append plus forcément au body
92
+ const animation = el.animate([{ opacity: 0.5, offset: 0.5 }, { opacity: 1 }], { duration: 1 });
93
+ animation.cancel();
94
+ console.debug('[app] Web animations are well supported');
95
+ return true;
96
+ }
97
+ catch {
98
+ // Continue
99
+ }
100
+ console.warn('[app] Web animations are not supported');
101
+ return false;
102
+ }
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxhdGZvcm1zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9zaGFyZWQvcGxhdGZvcm1zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztTQUVTO0FBRVQsTUFBTSxNQUFNLEdBQUc7SUFDYixTQUFTLEVBQUUsSUFBSTtJQUNmLE1BQU0sRUFBRSxJQUFJO0lBQ1osT0FBTyxFQUFFLElBQUk7SUFDYixTQUFTLEVBQUUsSUFBSTtDQUNoQixDQUFDO0FBRUYsTUFBTSxVQUFVLFVBQVUsQ0FBQyxHQUFXLEVBQUUsS0FBYTtJQUNuRCxPQUFPLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxDQUFDO0FBQ3ZDLENBQUM7QUFFRCxNQUFNLFVBQVUsWUFBWSxDQUFDLEdBQVc7SUFDdEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUN0QixNQUFNLENBQUMsU0FBUyxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUMsU0FBUyxJQUFJLEdBQUcsQ0FBQyxTQUFTLENBQUMsTUFBTSxJQUFLLE1BQWMsQ0FBQyxLQUFLLENBQUM7SUFDOUYsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLFNBQVMsQ0FBQztBQUMxQixDQUFDO0FBRUQsTUFBTSxVQUFVLGFBQWEsQ0FBQyxHQUFXLEVBQUUsSUFBWTtJQUNyRCxNQUFNLFNBQVMsR0FBVyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDNUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQzlCLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFDLEdBQVk7SUFDcEMsT0FBTyxhQUFhLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0FBQ3hDLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFDLEdBQVk7SUFDcEMsT0FBTyxhQUFhLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDO0FBQzND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QUNmLENBQUM7SUFFRCxJQUFJLE9BQU8sT0FBTyxDQUFDLFNBQVMsQ0FBQyxPQUFPLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDcEQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsSUFBSSxDQUFDO1FBQ0gsZUFBZTtRQUNmLE1BQU0sRUFBRSxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFekMscUNBQXFDO1FBQ3JDLE1BQU0sU0FBUyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQzFCLENBQUMsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUMvQyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsQ0FDaEIsQ0FBQztRQUNGLFNBQVMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUVuQixPQUFPLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxDQUFDLENBQUM7UUFDekQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsV0FBVztJQUNiLENBQUM7SUFFRCxPQUFPLENBQUMsSUFBSSxDQUFDLHdDQUF3QyxDQUFDLENBQUM7SUFDdkQsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogLS0tXG4gKiBTb3VyY2U6IGh0dHBzOi8vZ2l0aHViLmNvbS9pb25pYy10ZWFtL2lvbmljLWZyYW1ld29yay9ibG9iL2IwZDUzY2E3MzYxOTU4NTY3MWQ4Y2Y0ZGMyNGU0N2Y4MjY0OTVhMGEvY29yZS9zcmMvdXRpbHMvcGxhdGZvcm0udHNcbiAqIC0tLSAqL1xuXG5jb25zdCBfY2FjaGUgPSB7XG4gIHVzZXJBZ2VudDogbnVsbCxcbiAgbW9iaWxlOiBudWxsLFxuICBjb3Jkb3ZhOiBudWxsLFxuICBjYXBhY2l0b3I6IG51bGwsXG59O1xuXG5leHBvcnQgZnVuY3Rpb24gbWF0Y2hNZWRpYSh3aW46IFdpbmRvdywgcXVlcnk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gd2luLm1hdGNoTWVkaWEocXVlcnkpLm1hdGNoZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRVc2VyQWdlbnQod2luOiBXaW5kb3cpOiBzdHJpbmcge1xuICBpZiAoIV9jYWNoZS51c2VyQWdlbnQpIHtcbiAgICBfY2FjaGUudXNlckFnZW50ID0gd2luLm5hdmlnYXRvci51c2VyQWdlbnQgfHwgd2luLm5hdmlnYXRvci52ZW5kb3IgfHwgKHdpbmRvdyBhcyBhbnkpLm9wZXJhO1xuICB9XG4gIHJldHVybiBfY2FjaGUudXNlckFnZW50O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGVzdFVzZXJBZ2VudCh3aW46IFdpbmRvdywgZXhwcjogUmVnRXhwKSB7XG4gIGNvbnN0IHVzZXJBZ2VudDogc3RyaW5nID0gZ2V0VXNlckFnZW50KHdpbik7XG4gIHJldHVybiBleHByLnRlc3QodXNlckFnZW50KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzV2luZG93cyh3aW4/OiBXaW5kb3cpIHtcbiAgcmV0dXJuIHRlc3RVc2VyQWdlbnQod2luLCAvd2luZG93cy9pKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzRmlyZWZveCh3aW4/OiBXaW5kb3cpIHtcbiAgcmV0dXJuIHRlc3RVc2VyQWdlbnQod2luLCAvIGZpcmVmb3hcXC8vaSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1NhZmFyaSh3aW4/OiBXaW5kb3cpIHtcbiAgcmV0dXJuICFpc0Nocm9tZSh3aW4pIC8qRXhjbHVkZSBjaHJvbWl1bSovICYmIHRlc3RVc2VyQWdlbnQod2luLCAvIHNhZmFyaVxcLy9pKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzQ2hyb21lKHdpbj86IFdpbmRvdykge1xuICByZXR1cm4gdGVzdFVzZXJBZ2VudCh3aW4sIC8gY2hyb21lXFwvL2kpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNFZGdlKHdpbj86IFdpbmRvdykge1xuICByZXR1cm4gdGVzdFVzZXJBZ2VudCh3aW4sIC9lZGdlL2kpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNUb3VjaFVpKHdpbj86IFdpbmRvdykge1xuICByZXR1cm4gbWF0Y2hNZWRpYSh3aW4sICcoYW55LXBvaW50ZXI6Y29hcnNlKScpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNJcGFkKHdpbjogV2luZG93KSB7XG4gIC8vIGlPUyAxMiBhbmQgYmVsb3dcbiAgaWYgKHRlc3RVc2VyQWdlbnQod2luLCAvaVBhZC9pKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gaU9TIDEzK1xuICBpZiAodGVzdFVzZXJBZ2VudCh3aW4sIC9NYWNpbnRvc2gvaSkgJiYgaXNUb3VjaFVpKHdpbikpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzTWFjT1Mod2luOiBXaW5kb3cpIHtcbiAgLy8gaU9TIChidXQgbm90IGlQYWQpXG4gIHJldHVybiB0ZXN0VXNlckFnZW50KHdpbiwgL01hY2ludG9zaC9pKSAmJiAhaXNUb3VjaFVpKHdpbik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0lPUyh3aW46IFdpbmRvdykge1xuICByZXR1cm4gdGVzdFVzZXJBZ2VudCh3aW4sIC9pUGhvbmV8aVBvZC9pKSB8fCBpc0lwYWQod2luKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzQW5kcm9pZCh3aW46IFdpbmRvdykge1xuICByZXR1cm4gdGVzdFVzZXJBZ2VudCh3aW4sIC9hbmRyb2lkfHNpbmsvaSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0NhcGFjaXRvcih3aW46IGFueSk6IGJvb2xlYW4ge1xuICBpZiAoX2NhY2hlLmNhcGFjaXRvciA9PT0gbnVsbCB8fCBfY2FjaGUuY2FwYWNpdG9yID09PSB1bmRlZmluZWQpIHtcbiAgICBfY2FjaGUuY2FwYWNpdG9yID0gISEod2luWydDYXBhY2l0b3InXSB8fCB3aW5bJ2NhcGFjaXRvciddKTtcbiAgfVxuICByZXR1cm4gX2NhY2hlLmNhcGFjaXRvcjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzTW9iaWxlKHdpbjogV2luZG93KSB7XG4gIGlmIChfY2FjaGUubW9iaWxlID09PSBudWxsIHx8IF9jYWNoZS5tb2JpbGUgPT09IHVuZGVmaW5lZCkge1xuICAgIF9jYWNoZS5tb2JpbGUgPVxuICAgICAgaXNBbmRyb2lkKHdpbikgfHxcbiAgICAgIChpc0lPUyh3aW5kb3cpICYmIGlzVG91Y2hVaSh3aW4pKSB8fFxuICAgICAgLy8gV29ya2Fyb3VuZCwgZm9yIE1TIFdpbmRvd3MgdG91Y2ggc2NyZWVuIChkZXRlY3RlZCBhcyBtb2JpbGUsIGJ1dCBmb3JjZWQgYXMgZGVza3RvcClcbiAgICAgIChpc1RvdWNoVWkod2luKSAmJiAhaXNXaW5kb3dzKHdpbikpO1xuICB9XG4gIHJldHVybiBfY2FjaGUubW9iaWxlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNQcmludCh3aW4/OiBXaW5kb3cpIHtcbiAgcmV0dXJuIG1hdGNoTWVkaWEod2luLCAncHJpbnQnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzV2ViQW5pbWF0aW9uc1N1cHBvcnRlZCgpOiBib29sZWFuIHtcbiAgaWYgKHR5cGVvZiBkb2N1bWVudCA9PT0gJ3VuZGVmaW5lZCcgfHwgdHlwZW9mIEVsZW1lbnQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBFbGVtZW50LnByb3RvdHlwZS5hbmltYXRlICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBUZXN0IG1pbmltYWxcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuXG4gICAgLy8gT24gbuKAmWFwcGVuZCBwbHVzIGZvcmPDqW1lbnQgYXUgYm9keVxuICAgIGNvbnN0IGFuaW1hdGlvbiA9IGVsLmFuaW1hdGUoXG4gICAgICBbeyBvcGFjaXR5OiAwLjUsIG9mZnNldDogMC41IH0sIHsgb3BhY2l0eTogMSB9XSxcbiAgICAgIHsgZHVyYXRpb246IDEgfVxuICAgICk7XG4gICAgYW5pbWF0aW9uLmNhbmNlbCgpO1xuXG4gICAgY29uc29sZS5kZWJ1ZygnW2FwcF0gV2ViIGFuaW1hdGlvbnMgYXJlIHdlbGwgc3VwcG9ydGVkJyk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH0gY2F0Y2gge1xuICAgIC8vIENvbnRpbnVlXG4gIH1cblxuICBjb25zb2xlLndhcm4oJ1thcHBdIFdlYiBhbmltYXRpb25zIGFyZSBub3Qgc3VwcG9ydGVkJyk7XG4gIHJldHVybiBmYWxzZTtcbn1cbiJdfQ==
@@ -12,8 +12,15 @@ export class VersionUtils {
12
12
  * @returns {number} -1 if v1 < v2, 0 if equal, 1 if v1 > v2
13
13
  */
14
14
  export function compareVersionNumbers(v1, v2, comparePrerelease = false) {
15
- const m1 = v1.match(SEMVER_2_REGEXP);
16
- const m2 = v2.match(SEMVER_2_REGEXP);
15
+ const padVersion = (v) => {
16
+ const parts = v.split('.');
17
+ while (parts.length < 3) {
18
+ parts.push('0');
19
+ }
20
+ return parts.join('.');
21
+ };
22
+ const m1 = padVersion(v1).match(SEMVER_2_REGEXP);
23
+ const m2 = padVersion(v2).match(SEMVER_2_REGEXP);
17
24
  if (!m1 || !m2) {
18
25
  return NaN;
19
26
  }
@@ -77,4 +84,4 @@ export function isVersionCompatible(minVersion, actualVersion) {
77
84
  export function isSameVersion(v1, v2) {
78
85
  return compareVersionNumbers(v1, v2) === 0;
79
86
  }
80
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL3NoYXJlZC92ZXJzaW9uL3ZlcnNpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtEQUErRDtBQUMvRCxNQUFNLGVBQWUsR0FDbkIsa09BQWtPLENBQUM7QUFFck8sTUFBTSxPQUFPLFlBQVk7SUFDdkIsTUFBTSxDQUFDLE9BQU8sR0FBRyxxQkFBcUIsQ0FBQztJQUN2QyxNQUFNLENBQUMsWUFBWSxHQUFHLG1CQUFtQixDQUFDO0lBQzFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsYUFBYSxDQUFDOztBQUdoQzs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxxQkFBcUIsQ0FBQyxFQUFVLEVBQUUsRUFBVSxFQUFFLGlCQUFpQixHQUFHLEtBQUs7SUFDckYsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUNyQyxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBRXJDLElBQUksQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNmLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVELE1BQU0sQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUV4QywyQ0FBMkM7SUFDM0MsS0FBSyxNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUM5QyxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDM0IsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzNCLElBQUksRUFBRSxL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YUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQy9ELENBQUM7QUFFRCxNQUFNLFVBQVUsYUFBYSxDQUFDLEVBQUUsRUFBRSxFQUFFO0lBQ2xDLE9BQU8scUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUM3QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gUGFyc2UgdmVyc2lvbiBzdHJpbmcgb24gc3RhbmRhcmQgXCJTZW1hbnRpYyBWZXJzaW9uaW5nIDIuMC4wXCJcbmNvbnN0IFNFTVZFUl8yX1JFR0VYUCA9XG4gIC9eKD88bWFqb3I+MHxbMS05XVxcZCopXFwuKD88bWlub3I+MHxbMS05XVxcZCopXFwuKD88cGF0Y2g+MHxbMS05XVxcZCopKD86LSg/PHByZXJlbGVhc2U+KD86MHxbMS05XVxcZCp8XFxkKlthLXpBLVotXVswLTlhLXpBLVotXSopKD86XFwuKD86MHxbMS05XVxcZCp8XFxkKlthLXpBLVotXVswLTlhLXpBLVotXSopKSopKT8oPzpcXCsoPzxidWlsZD5bMC05YS16QS1aLV0rKD86XFwuWzAtOWEtekEtWi1dKykqKSk/JC87XG5cbmV4cG9ydCBjbGFzcyBWZXJzaW9uVXRpbHMge1xuICBzdGF0aWMgY29tcGFyZSA9IGNvbXBhcmVWZXJzaW9uTnVtYmVycztcbiAgc3RhdGljIGlzQ29tcGF0aWJsZSA9IGlzVmVyc2lvbkNvbXBhdGlibGU7XG4gIHN0YXRpYyBpc1NhbWUgPSBpc1NhbWVWZXJzaW9uO1xufVxuXG4vKipcbiAqIENvbXBhcmVzIHR3byBTZW1hbnRpYyBWZXJzaW9uaW5nIDIuMC4wIHN0cmluZ3NcbiAqIEBwYXJhbSB7c3RyaW5nfSB2MSAtIEZpcnN0IHZlcnNpb24gc3RyaW5nXG4gKiBAcGFyYW0ge3N0cmluZ30gdjIgLSBTZWNvbmQgdmVyc2lvbiBzdHJpbmdcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0xIGlmIHYxIDwgdjIsIDAgaWYgZXF1YWwsIDEgaWYgdjEgPiB2MlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcGFyZVZlcnNpb25OdW1iZXJzKHYxOiBzdHJpbmcsIHYyOiBzdHJpbmcsIGNvbXBhcmVQcmVyZWxlYXNlID0gZmFsc2UpOiBudW1iZXIge1xuICBjb25zdCBtMSA9IHYxLm1hdGNoKFNFTVZFUl8yX1JFR0VYUCk7XG4gIGNvbnN0IG0yID0gdjIubWF0Y2goU0VNVkVSXzJfUkVHRVhQKTtcblxuICBpZiAoIW0xIHx8ICFtMikge1xuICAgIHJldHVybiBOYU47XG4gIH1cblxuICBjb25zdCBbcDEsIHAyXSA9IFttMS5ncm91cHMsIG0yLmdyb3Vwc107XG5cbiAgLy8gMS4gQ29tcGFyZSBtYWpvci5taW5vci5wYXRjaCBudW1lcmljYWxseVxuICBmb3IgKGNvbnN0IGtleSBvZiBbJ21ham9yJywgJ21pbm9yJywgJ3BhdGNoJ10pIHtcbiAgICBjb25zdCBuMSA9IE51bWJlcihwMVtrZXldKTtcbiAgICBjb25zdCBuMiA9IE51bWJlcihwMltrZXldKTtcbiAgICBpZiAobjEgIT09IG4yKSByZXR1cm4gbjEgPiBuMiA/IDEgOiAtMTtcbiAgfVxuXG4gIC8vIElmIGRvIG5vdCBjb21wYXJlIHByZS1yZWxlYXNlIHBhcnQgcmV0dXJuIGVxdWFscyB2ZXJzaW9uIG9uIHNhbWUgbWFqb3IubWlub3IucGF0Y2hcbiAgaWYgKCFjb21wYXJlUHJlcmVsZWFzZSkgcmV0dXJuIDA7XG5cbiAgLy8gMi4gRXh0cmFjdCBwcmVyZWxlYXNlIGlkZW50aWZpZXJzIChidWlsZCBtZXRhZGF0YSBpcyBpZ25vcmVkKVxuICBjb25zdCBwcmUxID0gcDEucHJlcmVsZWFzZSA/IHAxLnByZXJlbGVhc2Uuc3BsaXQoJy4nKSA6IFtdO1xuICBjb25zdCBwcmUyID0gcDIucHJlcmVsZWFzZSA/IHAyLnByZXJlbGVhc2Uuc3BsaXQoJy4nKSA6IFtdO1xuXG4gIC8vIElmIGJvdGggaGF2ZSBubyBwcmVyZWxlYXNlLCB0aGV5IGFyZSBlcXVhbFxuICBpZiAocHJlMS5sZW5ndGggPT09IDAgJiYgcHJlMi5sZW5ndGggPT09IDApIHJldHVybiAwO1xuXG4gIC8vIEEgdmVyc2lvbiB3aXRob3V0IHByZXJlbGVhc2UgaGFzIGhpZ2hlciBwcmVjZWRlbmNlIHRoYW4gb25lIHdpdGggcHJlcmVsZWFzZVxuICBpZiAocHJlMS5sZW5ndGggPT09IDApIHJldHVybiAxOyAvLyB2MSBzdGFibGUsIHYyIHByZS1yZWxlYXNlIOKGkiB2MSA+IHYyXG4gIGlmIChwcmUyLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xOyAvLyB2MSBwcmUtcmVsZWFzZSwgdjIgc3RhYmxlIOKGkiB2MSA8IHYyXG5cbiAgLy8gMy4gQ29tcGFyZSBpZGVudGlmaWVyIGJ5IGlkZW50aWZpZXJcbiAgY29uc3QgbWF4TGVuID0gTWF0aC5tYXgocHJlMS5sZW5ndGgsIHByZTIubGVuZ3RoKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBtYXhMZW47IGkrKykge1xuICAgIGNvbnN0IGlkMSA9IHByZTFbaV07XG4gICAgY29uc3QgaWQyID0gcHJlMltpXTtcblxuICAgIC8vIElmIG9uZSBoYXMgbW9yZSBmaWVsZHMsIGl0IGhhcyBoaWdoZXIgcHJlY2VkZW5jZSBpZiBwcmV2aW91cyBmaWVsZHMgd2VyZSBlcXVhbFxuICAgIGlmIChpZDEgPT09IHVuZGVmaW5lZCkgcmV0dXJuIC0xO1xuICAgIGlmIChpZDIgPT09IHVuZGVmaW5lZCkgcmV0dXJuIDE7XG5cbiAgICBjb25zdCBpc051bTEgPSAvXlxcZCskLy50ZXN0KGlkMSk7XG4gICAgY29uc3QgaXNOdW0yID0gL15cXGQrJC8udGVzdChpZDIpO1xuXG4gICAgaWYgKGlzTnVtMSAmJiBpc051bTIpIHtcbiAgICAgIC8vIE51bWVyaWMgY29tcGFyaXNvblxuICAgICAgY29uc3QgbjEgPSBOdW1iZXIoaWQxKSxcbiAgICAgICAgbjIgPSBOdW1iZXIoaWQyKTtcbiAgICAgIGlmIChuMSAhPT0gbjIpIHJldHVybiBuMSA+IG4yID8gMSA6IC0xO1xuICAgIH0gZWxzZSBpZiAoIWlzTnVtMSAmJiAhaXNOdW0yKSB7XG4gICAgICAvLyBMZXhpY29ncmFwaGljIGNvbXBhcmlzb24gKEFTQ0lJIG9yZGVyKVxuICAgICAgaWYgKGlkMSAhPT0gaWQyKSByZXR1cm4gaWQxID4gaWQyID8gMSA6IC0xO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBOdW1lcmljIGlkZW50aWZpZXJzIGFsd2F5cyBoYXZlIGxvd2VyIHByZWNlZGVuY2UgdGhhbiBhbHBoYW51bWVyaWNcbiAgICAgIHJldHVybiBpc051bTEgPyAtMSA6IDE7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIDA7IC8vIFNhbWUgdmVyc2lvblxufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNWZXJzaW9uQ29tcGF0aWJsZShtaW5WZXJzaW9uLCBhY3R1YWxWZXJzaW9uKTogYm9vbGVhbiB7XG4gIC8vIERFViBPTkxZXG4gIC8vY29uc29sZS5kZWJ1ZyhgW2h0dHBdIENoZWNraW5nIGFjdHVhbCB2ZXJzaW9uIHske2FjdHVhbFZlcnNpb259fSBpcyBjb21wYXRpYmxlIHdpdGggbWluIGV4cGVjdGVkIHZlcnNpb24geyR7bWluVmVyc2lvbn19YCk7XG4gIHJldHVybiBjb21wYXJlVmVyc2lvbk51bWJlcnMobWluVmVyc2lvbiwgYWN0dWFsVmVyc2lvbikgPD0gMDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzU2FtZVZlcnNpb24odjEsIHYyKTogYm9vbGVhbiB7XG4gIHJldHVybiBjb21wYXJlVmVyc2lvbk51bWJlcnModjEsIHYyKSA9PT0gMDtcbn1cbiJdfQ==
87
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL3NoYXJlZC92ZXJzaW9uL3ZlcnNpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtEQUErRDtBQUMvRCxNQUFNLGVBQWUsR0FDbkIsa09BQWtPLENBQUM7QUFFck8sTUFBTSxPQUFPLFlBQVk7SUFDdkIsTUFBTSxDQUFDLE9BQU8sR0FBRyxxQkFBcUIsQ0FBQztJQUN2QyxNQUFNLENBQUMsWUFBWSxHQUFHLG1CQUFtQixDQUFDO0lBQzFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsYUFBYSxDQUFDOztBQUdoQzs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxxQkFBcUIsQ0FBQyxFQUFVLEVBQUUsRUFBVSxFQUFFLGlCQUFpQixHQUFHLEtBQUs7SUFDckYsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFTLEVBQVUsRUFBRTtRQUN2QyxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzNCLE9BQU8sS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4QixLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2xCLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDekIsQ0FBQyxDQUFDO0lBRUYsTUFBTSxFQUFFLEdBQUcsVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUNqRCxNQUFNLEVBQUUsR0FBRyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBRWpELElBQUksQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNmLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVELE1BQU0sQ0FBQyxFQUFFLEVBQUUsRUFB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LENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM3QyxDQUFDO2FBQU0sQ0FBQztZQUNOLHFFQUFxRTtZQUNyRSxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6QixDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sQ0FBQyxDQUFDLENBQUMsZUFBZTtBQUMzQixDQUFDO0FBRUQsTUFBTSxVQUFVLG1CQUFtQixDQUFDLFVBQVUsRUFBRSxhQUFhO0lBQzNELFdBQVc7SUFDWCw2SEFBNkg7SUFDN0gsT0FBTyxxQkFBcUIsQ0FBQyxVQUFVLEVBQUUsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQy9ELENBQUM7QUFFRCxNQUFNLFVBQVUsYUFBYSxDQUFDLEVBQUUsRUFBRSxFQUFFO0lBQ2xDLE9BQU8scUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUM3QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gUGFyc2UgdmVyc2lvbiBzdHJpbmcgb24gc3RhbmRhcmQgXCJTZW1hbnRpYyBWZXJzaW9uaW5nIDIuMC4wXCJcbmNvbnN0IFNFTVZFUl8yX1JFR0VYUCA9XG4gIC9eKD88bWFqb3I+MHxbMS05XVxcZCopXFwuKD88bWlub3I+MHxbMS05XVxcZCopXFwuKD88cGF0Y2g+MHxbMS05XVxcZCopKD86LSg/PHByZXJlbGVhc2U+KD86MHxbMS05XVxcZCp8XFxkKlthLXpBLVotXVswLTlhLXpBLVotXSopKD86XFwuKD86MHxbMS05XVxcZCp8XFxkKlthLXpBLVotXVswLTlhLXpBLVotXSopKSopKT8oPzpcXCsoPzxidWlsZD5bMC05YS16QS1aLV0rKD86XFwuWzAtOWEtekEtWi1dKykqKSk/JC87XG5cbmV4cG9ydCBjbGFzcyBWZXJzaW9uVXRpbHMge1xuICBzdGF0aWMgY29tcGFyZSA9IGNvbXBhcmVWZXJzaW9uTnVtYmVycztcbiAgc3RhdGljIGlzQ29tcGF0aWJsZSA9IGlzVmVyc2lvbkNvbXBhdGlibGU7XG4gIHN0YXRpYyBpc1NhbWUgPSBpc1NhbWVWZXJzaW9uO1xufVxuXG4vKipcbiAqIENvbXBhcmVzIHR3byBTZW1hbnRpYyBWZXJzaW9uaW5nIDIuMC4wIHN0cmluZ3NcbiAqIEBwYXJhbSB7c3RyaW5nfSB2MSAtIEZpcnN0IHZlcnNpb24gc3RyaW5nXG4gKiBAcGFyYW0ge3N0cmluZ30gdjIgLSBTZWNvbmQgdmVyc2lvbiBzdHJpbmdcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0xIGlmIHYxIDwgdjIsIDAgaWYgZXF1YWwsIDEgaWYgdjEgPiB2MlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcGFyZVZlcnNpb25OdW1iZXJzKHYxOiBzdHJpbmcsIHYyOiBzdHJpbmcsIGNvbXBhcmVQcmVyZWxlYXNlID0gZmFsc2UpOiBudW1iZXIge1xuICBjb25zdCBwYWRWZXJzaW9uID0gKHY6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gICAgY29uc3QgcGFydHMgPSB2LnNwbGl0KCcuJyk7XG4gICAgd2hpbGUgKHBhcnRzLmxlbmd0aCA8IDMpIHtcbiAgICAgIHBhcnRzLnB1c2goJzAnKTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcnRzLmpvaW4oJy4nKTtcbiAgfTtcblxuICBjb25zdCBtMSA9IHBhZFZlcnNpb24odjEpLm1hdGNoKFNFTVZFUl8yX1JFR0VYUCk7XG4gIGNvbnN0IG0yID0gcGFkVmVyc2lvbih2MikubWF0Y2goU0VNVkVSXzJfUkVHRVhQKTtcblxuICBpZiAoIW0xIHx8ICFtMikge1xuICAgIHJldHVybiBOYU47XG4gIH1cblxuICBjb25zdCBbcDEsIHAyXSA9IFttMS5ncm91cHMsIG0yLmdyb3Vwc107XG5cbiAgLy8gMS4gQ29tcGFyZSBtYWpvci5taW5vci5wYXRjaCBudW1lcmljYWxseVxuICBmb3IgKGNvbnN0IGtleSBvZiBbJ21ham9yJywgJ21pbm9yJywgJ3BhdGNoJ10pIHtcbiAgICBjb25zdCBuMSA9IE51bWJlcihwMVtrZXldKTtcbiAgICBjb25zdCBuMiA9IE51bWJlcihwMltrZXldKTtcbiAgICBpZiAobjEgIT09IG4yKSByZXR1cm4gbjEgPiBuMiA/IDEgOiAtMTtcbiAgfVxuXG4gIC8vIElmIGRvIG5vdCBjb21wYXJlIHByZS1yZWxlYXNlIHBhcnQgcmV0dXJuIGVxdWFscyB2ZXJzaW9uIG9uIHNhbWUgbWFqb3IubWlub3IucGF0Y2hcbiAgaWYgKCFjb21wYXJlUHJlcmVsZWFzZSkgcmV0dXJuIDA7XG5cbiAgLy8gMi4gRXh0cmFjdCBwcmVyZWxlYXNlIGlkZW50aWZpZXJzIChidWlsZCBtZXRhZGF0YSBpcyBpZ25vcmVkKVxuICBjb25zdCBwcmUxID0gcDEucHJlcmVsZWFzZSA/IHAxLnByZXJlbGVhc2Uuc3BsaXQoJy4nKSA6IFtdO1xuICBjb25zdCBwcmUyID0gcDIucHJlcmVsZWFzZSA/IHAyLnByZXJlbGVhc2Uuc3BsaXQoJy4nKSA6IFtdO1xuXG4gIC8vIElmIGJvdGggaGF2ZSBubyBwcmVyZWxlYXNlLCB0aGV5IGFyZSBlcXVhbFxuICBpZiAocHJlMS5sZW5ndGggPT09IDAgJiYgcHJlMi5sZW5ndGggPT09IDApIHJldHVybiAwO1xuXG4gIC8vIEEgdmVyc2lvbiB3aXRob3V0IHByZXJlbGVhc2UgaGFzIGhpZ2hlciBwcmVjZWRlbmNlIHRoYW4gb25lIHdpdGggcHJlcmVsZWFzZVxuICBpZiAocHJlMS5sZW5ndGggPT09IDApIHJldHVybiAxOyAvLyB2MSBzdGFibGUsIHYyIHByZS1yZWxlYXNlIOKGkiB2MSA+IHYyXG4gIGlmIChwcmUyLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xOyAvLyB2MSBwcmUtcmVsZWFzZSwgdjIgc3RhYmxlIOKGkiB2MSA8IHYyXG5cbiAgLy8gMy4gQ29tcGFyZSBpZGVudGlmaWVyIGJ5IGlkZW50aWZpZXJcbiAgY29uc3QgbWF4TGVuID0gTWF0aC5tYXgocHJlMS5sZW5ndGgsIHByZTIubGVuZ3RoKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBtYXhMZW47IGkrKykge1xuICAgIGNvbnN0IGlkMSA9IHByZTFbaV07XG4gICAgY29uc3QgaWQyID0gcHJlMltpXTtcblxuICAgIC8vIElmIG9uZSBoYXMgbW9yZSBmaWVsZHMsIGl0IGhhcyBoaWdoZXIgcHJlY2VkZW5jZSBpZiBwcmV2aW91cyBmaWVsZHMgd2VyZSBlcXVhbFxuICAgIGlmIChpZDEgPT09IHVuZGVmaW5lZCkgcmV0dXJuIC0xO1xuICAgIGlmIChpZDIgPT09IHVuZGVmaW5lZCkgcmV0dXJuIDE7XG5cbiAgICBjb25zdCBpc051bTEgPSAvXlxcZCskLy50ZXN0KGlkMSk7XG4gICAgY29uc3QgaXNOdW0yID0gL15cXGQrJC8udGVzdChpZDIpO1xuXG4gICAgaWYgKGlzTnVtMSAmJiBpc051bTIpIHtcbiAgICAgIC8vIE51bWVyaWMgY29tcGFyaXNvblxuICAgICAgY29uc3QgbjEgPSBOdW1iZXIoaWQxKSxcbiAgICAgICAgbjIgPSBOdW1iZXIoaWQyKTtcbiAgICAgIGlmIChuMSAhPT0gbjIpIHJldHVybiBuMSA+IG4yID8gMSA6IC0xO1xuICAgIH0gZWxzZSBpZiAoIWlzTnVtMSAmJiAhaXNOdW0yKSB7XG4gICAgICAvLyBMZXhpY29ncmFwaGljIGNvbXBhcmlzb24gKEFTQ0lJIG9yZGVyKVxuICAgICAgaWYgKGlkMSAhPT0gaWQyKSByZXR1cm4gaWQxID4gaWQyID8gMSA6IC0xO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBOdW1lcmljIGlkZW50aWZpZXJzIGFsd2F5cyBoYXZlIGxvd2VyIHByZWNlZGVuY2UgdGhhbiBhbHBoYW51bWVyaWNcbiAgICAgIHJldHVybiBpc051bTEgPyAtMSA6IDE7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIDA7IC8vIFNhbWUgdmVyc2lvblxufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNWZXJzaW9uQ29tcGF0aWJsZShtaW5WZXJzaW9uLCBhY3R1YWxWZXJzaW9uKTogYm9vbGVhbiB7XG4gIC8vIERFViBPTkxZXG4gIC8vY29uc29sZS5kZWJ1ZyhgW2h0dHBdIENoZWNraW5nIGFjdHVhbCB2ZXJzaW9uIHske2FjdHVhbFZlcnNpb259fSBpcyBjb21wYXRpYmxlIHdpdGggbWluIGV4cGVjdGVkIHZlcnNpb24geyR7bWluVmVyc2lvbn19YCk7XG4gIHJldHVybiBjb21wYXJlVmVyc2lvbk51bWJlcnMobWluVmVyc2lvbiwgYWN0dWFsVmVyc2lvbikgPD0gMDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzU2FtZVZlcnNpb24odjEsIHYyKTogYm9vbGVhbiB7XG4gIHJldHVybiBjb21wYXJlVmVyc2lvbk51bWJlcnModjEsIHYyKSA9PT0gMDtcbn1cbiJdfQ==