@ks89/angular-modal-gallery 11.1.2 → 13.0.0
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.
- package/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +20 -24
- package/LICENSE +1 -1
- package/README.md +11 -6
- package/fesm2022/ks89-angular-modal-gallery.mjs +151 -139
- package/fesm2022/ks89-angular-modal-gallery.mjs.map +1 -1
- package/lib/components/components.d.ts +1 -1
- package/lib/model/action.enum.d.ts +2 -2
- package/package.json +9 -11
- package/public-api.d.ts +23 -18
- package/esm2022/ks89-angular-modal-gallery.mjs +0 -5
- package/esm2022/lib/components/accessibility-default.mjs +0 -41
- package/esm2022/lib/components/accessible.component.mjs +0 -130
- package/esm2022/lib/components/carousel/carousel-previews/carousel-previews.component.mjs +0 -456
- package/esm2022/lib/components/carousel/carousel.component.mjs +0 -738
- package/esm2022/lib/components/components.mjs +0 -50
- package/esm2022/lib/components/current-image/current-image.component.mjs +0 -607
- package/esm2022/lib/components/current-image/loading-spinner/loading-spinner.component.mjs +0 -80
- package/esm2022/lib/components/dots/dots.component.mjs +0 -124
- package/esm2022/lib/components/modal-gallery/attach-to-overlay.service.mjs +0 -42
- package/esm2022/lib/components/modal-gallery/modal-gallery-ref.mjs +0 -103
- package/esm2022/lib/components/modal-gallery/modal-gallery.component.mjs +0 -499
- package/esm2022/lib/components/modal-gallery/modal-gallery.service.mjs +0 -168
- package/esm2022/lib/components/modal-gallery/modal-gallery.tokens.mjs +0 -26
- package/esm2022/lib/components/plain-gallery/plain-gallery.component.mjs +0 -249
- package/esm2022/lib/components/previews/previews.component.mjs +0 -263
- package/esm2022/lib/components/upper-buttons/upper-buttons-default.mjs +0 -76
- package/esm2022/lib/components/upper-buttons/upper-buttons.component.mjs +0 -243
- package/esm2022/lib/directives/a-tag-bg-image.directive.mjs +0 -78
- package/esm2022/lib/directives/click-outside.directive.mjs +0 -91
- package/esm2022/lib/directives/description.directive.mjs +0 -98
- package/esm2022/lib/directives/direction.directive.mjs +0 -73
- package/esm2022/lib/directives/directives.mjs +0 -51
- package/esm2022/lib/directives/fallback-image.directive.mjs +0 -59
- package/esm2022/lib/directives/keyboard-navigation.directive.mjs +0 -64
- package/esm2022/lib/directives/margin.directive.mjs +0 -84
- package/esm2022/lib/directives/max-size.directive.mjs +0 -75
- package/esm2022/lib/directives/size.directive.mjs +0 -76
- package/esm2022/lib/directives/swipe.directive.mjs +0 -116
- package/esm2022/lib/directives/wrap.directive.mjs +0 -74
- package/esm2022/lib/modal-gallery.module.mjs +0 -88
- package/esm2022/lib/model/accessibility.interface.mjs +0 -25
- package/esm2022/lib/model/action.enum.mjs +0 -36
- package/esm2022/lib/model/buttons-config.interface.mjs +0 -62
- package/esm2022/lib/model/carousel-config.interface.mjs +0 -25
- package/esm2022/lib/model/carousel-image-config.interface.mjs +0 -25
- package/esm2022/lib/model/carousel-preview-config.interface.mjs +0 -25
- package/esm2022/lib/model/current-image-config.interface.mjs +0 -25
- package/esm2022/lib/model/description.interface.mjs +0 -33
- package/esm2022/lib/model/dots-config.interface.mjs +0 -25
- package/esm2022/lib/model/image-internal.class.mjs +0 -35
- package/esm2022/lib/model/image.class.mjs +0 -56
- package/esm2022/lib/model/interaction-event.interface.mjs +0 -2
- package/esm2022/lib/model/keyboard-config.interface.mjs +0 -25
- package/esm2022/lib/model/keyboard.enum.mjs +0 -35
- package/esm2022/lib/model/lib-config.interface.mjs +0 -25
- package/esm2022/lib/model/loading-config.interface.mjs +0 -37
- package/esm2022/lib/model/max-size.interface.mjs +0 -25
- package/esm2022/lib/model/modal-gallery-config.interface.mjs +0 -25
- package/esm2022/lib/model/plain-gallery-config.interface.mjs +0 -55
- package/esm2022/lib/model/play-config.interface.mjs +0 -25
- package/esm2022/lib/model/preview-config.interface.mjs +0 -25
- package/esm2022/lib/model/size.interface.mjs +0 -25
- package/esm2022/lib/model/slide-config.interface.mjs +0 -25
- package/esm2022/lib/services/config.service.mjs +0 -388
- package/esm2022/lib/services/id-validator.service.mjs +0 -71
- package/esm2022/lib/utils/image.util.mjs +0 -48
- package/esm2022/lib/utils/user-input.util.mjs +0 -104
- package/esm2022/public-api.mjs +0 -42
|
@@ -1,499 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, HostListener, Inject, PLATFORM_ID, SecurityContext, ViewChild } from '@angular/core';
|
|
2
|
-
import { isPlatformBrowser } from '@angular/common';
|
|
3
|
-
import { DIALOG_DATA } from './modal-gallery.tokens';
|
|
4
|
-
import { ImageModalEvent } from '../../model/image.class';
|
|
5
|
-
import { ButtonType } from '../../model/buttons-config.interface';
|
|
6
|
-
import { Action } from '../../model/action.enum';
|
|
7
|
-
import { CurrentImageComponent } from '../current-image/current-image.component';
|
|
8
|
-
import { KS_DEFAULT_ACCESSIBILITY_CONFIG } from '../accessibility-default';
|
|
9
|
-
import * as i0 from "@angular/core";
|
|
10
|
-
import * as i1 from "./modal-gallery.service";
|
|
11
|
-
import * as i2 from "../../services/id-validator.service";
|
|
12
|
-
import * as i3 from "../../services/config.service";
|
|
13
|
-
import * as i4 from "@angular/platform-browser";
|
|
14
|
-
import * as i5 from "../upper-buttons/upper-buttons.component";
|
|
15
|
-
import * as i6 from "../dots/dots.component";
|
|
16
|
-
import * as i7 from "../previews/previews.component";
|
|
17
|
-
import * as i8 from "../current-image/current-image.component";
|
|
18
|
-
import * as i9 from "../../directives/click-outside.directive";
|
|
19
|
-
export class ModalGalleryComponent {
|
|
20
|
-
/**
|
|
21
|
-
* HostListener to catch browser's back button and destroy the gallery.
|
|
22
|
-
* This prevents weired behaviour about scrolling.
|
|
23
|
-
* Added to fix this issue: https://github.com/Ks89/angular-modal-gallery/issues/159
|
|
24
|
-
*/
|
|
25
|
-
onPopState() {
|
|
26
|
-
this.closeGallery();
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* HostListener to catch ctrl+s/meta+s and download the current image.
|
|
30
|
-
* Inspired by https://netbasal.com/add-keyboard-shortcuts-to-your-angular-app-9bf2e89862b3
|
|
31
|
-
*/
|
|
32
|
-
onSaveListener(event) {
|
|
33
|
-
event.preventDefault();
|
|
34
|
-
this.downloadImage();
|
|
35
|
-
}
|
|
36
|
-
constructor(dialogContent, modalGalleryService,
|
|
37
|
-
// tslint:disable-next-line:ban-types
|
|
38
|
-
platformId, changeDetectorRef, idValidatorService, configService, sanitizer) {
|
|
39
|
-
this.dialogContent = dialogContent;
|
|
40
|
-
this.modalGalleryService = modalGalleryService;
|
|
41
|
-
this.platformId = platformId;
|
|
42
|
-
this.changeDetectorRef = changeDetectorRef;
|
|
43
|
-
this.idValidatorService = idValidatorService;
|
|
44
|
-
this.configService = configService;
|
|
45
|
-
this.sanitizer = sanitizer;
|
|
46
|
-
/**
|
|
47
|
-
* Boolean to enable modal-gallery close behaviour when clicking
|
|
48
|
-
* on the semi-transparent background. Enabled by default.
|
|
49
|
-
*/
|
|
50
|
-
this.enableCloseOutside = true;
|
|
51
|
-
/**
|
|
52
|
-
* Object of type `AccessibilityConfig` to init custom accessibility features.
|
|
53
|
-
* For instance, it contains titles, alt texts, aria-labels and so on.
|
|
54
|
-
*/
|
|
55
|
-
this.accessibilityConfig = KS_DEFAULT_ACCESSIBILITY_CONFIG;
|
|
56
|
-
/**
|
|
57
|
-
* Boolean to open the modal gallery. False by default.
|
|
58
|
-
*/
|
|
59
|
-
this.showGallery = false;
|
|
60
|
-
this.id = this.dialogContent.id;
|
|
61
|
-
this.images = this.dialogContent.images;
|
|
62
|
-
this.currentImage = this.dialogContent.currentImage;
|
|
63
|
-
this.libConfig = this.dialogContent.libConfig;
|
|
64
|
-
this.customPreviewsTemplate = this.dialogContent.previewsTemplate;
|
|
65
|
-
this.configService.setConfig(this.id, this.libConfig);
|
|
66
|
-
this.updateImagesSubscription = this.modalGalleryService.updateImages$.subscribe((images) => {
|
|
67
|
-
this.images = images.map((image) => {
|
|
68
|
-
const newImage = Object.assign({}, image, { previouslyLoaded: false });
|
|
69
|
-
return newImage;
|
|
70
|
-
});
|
|
71
|
-
this.initImages();
|
|
72
|
-
this.images.forEach((image) => {
|
|
73
|
-
if (image.id === this.currentImage.id) {
|
|
74
|
-
this.currentImage = image;
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
this.changeDetectorRef.markForCheck();
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Method ´ngOnInit´ to init images calling `initImages()`.
|
|
82
|
-
* This is an angular lifecycle hook, so its called automatically by Angular itself.
|
|
83
|
-
* In particular, it's called only one time!!!
|
|
84
|
-
*/
|
|
85
|
-
ngOnInit() {
|
|
86
|
-
this.idValidatorService.checkAndAdd(this.id);
|
|
87
|
-
// id is a mandatory input and must a number > 0
|
|
88
|
-
if ((!this.id && this.id !== 0) || this.id < 0) {
|
|
89
|
-
throw new Error(`'[id]="a number >= 0"' is a mandatory input in angular-modal-gallery.` +
|
|
90
|
-
`If you are using multiple instances of this library, please be sure to use different ids`);
|
|
91
|
-
}
|
|
92
|
-
const libConfig = this.configService.getConfig(this.id);
|
|
93
|
-
if (!libConfig || !libConfig.dotsConfig) {
|
|
94
|
-
throw new Error('Internal library error - libConfig and dotsConfig must be defined');
|
|
95
|
-
}
|
|
96
|
-
this.dotsConfig = libConfig.dotsConfig;
|
|
97
|
-
setTimeout(() => {
|
|
98
|
-
this.initImages();
|
|
99
|
-
}, 0);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Method called by custom upper buttons.
|
|
103
|
-
* @param event ButtonEvent event payload
|
|
104
|
-
*/
|
|
105
|
-
onCustomEmit(event) {
|
|
106
|
-
const eventToEmit = this.getButtonEventToEmit(event);
|
|
107
|
-
this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
|
|
108
|
-
this.modalGalleryService.emitButtonAfterHook(eventToEmit);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Method called by the full-screen upper button.
|
|
112
|
-
* @param event ButtonEvent event payload
|
|
113
|
-
*/
|
|
114
|
-
onFullScreen(event) {
|
|
115
|
-
const eventToEmit = this.getButtonEventToEmit(event);
|
|
116
|
-
this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
|
|
117
|
-
// tslint:disable-next-line:no-any
|
|
118
|
-
const doc = document;
|
|
119
|
-
// tslint:disable-next-line:no-any
|
|
120
|
-
const docEl = document.documentElement;
|
|
121
|
-
const fullscreenDisabled = !doc.fullscreenElement && !doc.webkitFullscreenElement;
|
|
122
|
-
// In Safari `requestFullscreen` and `exitFullscreen` are undefined. Safari requires the prefixed version `webkit-`
|
|
123
|
-
// and it doesn't return promises.
|
|
124
|
-
// I cannot call `emitButtonAfterHook` only if requestFullScreen is successful, because there are no guarantees across browsers and
|
|
125
|
-
// I should also handle the case with keyboard "esc" button.
|
|
126
|
-
if (fullscreenDisabled) {
|
|
127
|
-
if (docEl.requestFullscreen) {
|
|
128
|
-
docEl.requestFullscreen()
|
|
129
|
-
.then(() => {
|
|
130
|
-
})
|
|
131
|
-
.catch(() => {
|
|
132
|
-
console.error('Cannot request full screen');
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
else if (docEl.webkitRequestFullscreen) {
|
|
136
|
-
// For Safari and it doesn't return a promise
|
|
137
|
-
docEl.webkitRequestFullscreen();
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
if (doc.exitFullscreen) {
|
|
142
|
-
doc.exitFullscreen()
|
|
143
|
-
.then(() => {
|
|
144
|
-
})
|
|
145
|
-
.catch(() => {
|
|
146
|
-
console.error('Cannot request exit full screen');
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
else if (doc.webkitExitFullscreen) {
|
|
150
|
-
// For Safari and it doesn't return a promise
|
|
151
|
-
doc.webkitExitFullscreen();
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
this.modalGalleryService.emitButtonAfterHook(eventToEmit);
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Method called by the delete upper button.
|
|
158
|
-
* @param event ButtonEvent event payload
|
|
159
|
-
*/
|
|
160
|
-
onDelete(event) {
|
|
161
|
-
const eventToEmit = this.getButtonEventToEmit(event);
|
|
162
|
-
this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
|
|
163
|
-
if (this.images.length === 1) {
|
|
164
|
-
this.closeGallery();
|
|
165
|
-
}
|
|
166
|
-
if (!this.currentImageComponent) {
|
|
167
|
-
throw new Error('currentImageComponent must be defined');
|
|
168
|
-
}
|
|
169
|
-
const imageIndexToDelete = this.currentImageComponent.getIndexToDelete(event.image);
|
|
170
|
-
if (imageIndexToDelete === this.images.length - 1) {
|
|
171
|
-
// last image
|
|
172
|
-
this.currentImageComponent.prevImage();
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
this.currentImageComponent.nextImage();
|
|
176
|
-
}
|
|
177
|
-
this.modalGalleryService.emitButtonAfterHook(eventToEmit);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Method called by the navigate upper button.
|
|
181
|
-
* @param event ButtonEvent event payload
|
|
182
|
-
*/
|
|
183
|
-
onNavigate(event) {
|
|
184
|
-
const eventToEmit = this.getButtonEventToEmit(event);
|
|
185
|
-
this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
|
|
186
|
-
// To support SSR
|
|
187
|
-
if (isPlatformBrowser(this.platformId)) {
|
|
188
|
-
if (eventToEmit.image && eventToEmit.image.modal.extUrl) {
|
|
189
|
-
// where I should open this link? The current tab or another one?
|
|
190
|
-
if (eventToEmit.button && eventToEmit.button.extUrlInNewTab) {
|
|
191
|
-
// in this case I should use target _blank to open the url in a new tab, however these is a security issue.
|
|
192
|
-
// Prevent Reverse Tabnabbing's attacks (https://www.owasp.org/index.php/Reverse_Tabnabbing)
|
|
193
|
-
// Some resources:
|
|
194
|
-
// - https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Tabnabbing
|
|
195
|
-
// - https://medium.com/@jitbit/target-blank-the-most-underestimated-vulnerability-ever-96e328301f4c
|
|
196
|
-
// - https://developer.mozilla.org/en-US/docs/Web/API/Window/open
|
|
197
|
-
const newWindow = window.open(eventToEmit.image.modal.extUrl, 'noopener,noreferrer,');
|
|
198
|
-
// it returns null if the call failed, so I have to do this check
|
|
199
|
-
if (newWindow) {
|
|
200
|
-
newWindow.opener = null; // required to prevent security issues
|
|
201
|
-
// emit only in case of success
|
|
202
|
-
this.modalGalleryService.emitButtonAfterHook(eventToEmit);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
this.updateLocationHref(eventToEmit.image.modal.extUrl);
|
|
207
|
-
// emit only in case of success
|
|
208
|
-
this.modalGalleryService.emitButtonAfterHook(eventToEmit);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* This method is defined to be spied and replaced in unit testing with a fake method call.
|
|
215
|
-
* It must be public to be able to use jasmine spyOn method.
|
|
216
|
-
* @param newHref string new url
|
|
217
|
-
*/
|
|
218
|
-
updateLocationHref(newHref) {
|
|
219
|
-
window.location.href = newHref;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Method called by the download upper button.
|
|
223
|
-
* @param event ButtonEvent event payload
|
|
224
|
-
*/
|
|
225
|
-
onDownload(event) {
|
|
226
|
-
const eventToEmit = this.getButtonEventToEmit(event);
|
|
227
|
-
this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
|
|
228
|
-
this.downloadImage();
|
|
229
|
-
this.modalGalleryService.emitButtonAfterHook(eventToEmit);
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Method called by the close upper button.
|
|
233
|
-
* @param event ButtonEvent event payload
|
|
234
|
-
* @param action Action that triggered the close method. `Action.NORMAL` by default
|
|
235
|
-
*/
|
|
236
|
-
onCloseGalleryButton(event, action = Action.NORMAL) {
|
|
237
|
-
const eventToEmit = this.getButtonEventToEmit(event);
|
|
238
|
-
this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
|
|
239
|
-
this.closeGallery(action, false);
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Method called by CurrentImageComponent.
|
|
243
|
-
* @param event ImageModalEvent event payload
|
|
244
|
-
* @param action Action that triggered the close method. `Action.NORMAL` by default
|
|
245
|
-
*/
|
|
246
|
-
onCloseGallery(event, action = Action.NORMAL) {
|
|
247
|
-
// remap ImageModalEvent to ButtonEvent
|
|
248
|
-
const buttonEvent = {
|
|
249
|
-
button: {
|
|
250
|
-
type: ButtonType.CLOSE
|
|
251
|
-
},
|
|
252
|
-
image: null,
|
|
253
|
-
action: event.action,
|
|
254
|
-
galleryId: event.galleryId
|
|
255
|
-
};
|
|
256
|
-
this.modalGalleryService.emitButtonBeforeHook(buttonEvent);
|
|
257
|
-
this.closeGallery(action, false);
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Method to close the modal gallery specifying the action.
|
|
261
|
-
* @param action Action action type. `Action.NORMAL` by default
|
|
262
|
-
* @param clickOutside boolean that is true if called clicking on the modal background. False by default.
|
|
263
|
-
*/
|
|
264
|
-
closeGallery(action = Action.NORMAL, clickOutside = false) {
|
|
265
|
-
const libConfig = this.configService.getConfig(this.id);
|
|
266
|
-
if (!libConfig) {
|
|
267
|
-
throw new Error('Internal library error - libConfig must be defined');
|
|
268
|
-
}
|
|
269
|
-
this.modalGalleryService.emitClose(new ImageModalEvent(this.id, action, true));
|
|
270
|
-
this.modalGalleryService.close(this.id, clickOutside);
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Method called when the image changes and used to update the `currentImage` object.
|
|
274
|
-
* @param event ImageModalEvent event payload
|
|
275
|
-
*/
|
|
276
|
-
onChangeCurrentImage(event) {
|
|
277
|
-
const newIndex = event.result;
|
|
278
|
-
if (newIndex < 0 || newIndex >= this.images.length) {
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
this.currentImage = this.images[newIndex];
|
|
282
|
-
// emit current visible image index
|
|
283
|
-
this.modalGalleryService.emitShow(new ImageModalEvent(this.id, event.action, newIndex + 1));
|
|
284
|
-
// emit first/last event based on newIndex value
|
|
285
|
-
this.emitBoundaryEvent(event.action, newIndex);
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Method called when you click 'outside' (i.e. on the semi-transparent background)
|
|
289
|
-
* to close the modal gallery if `enableCloseOutside` is true.
|
|
290
|
-
* @param event boolean that is true to close the modal gallery, false otherwise
|
|
291
|
-
*/
|
|
292
|
-
onClickOutside(event) {
|
|
293
|
-
if (event && this.enableCloseOutside) {
|
|
294
|
-
this.closeGallery(Action.CLICK, true);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Method called when an image is loaded and the loading spinner has gone.
|
|
299
|
-
* It sets the previouslyLoaded flag inside the Image to hide loading spinner when displayed again.
|
|
300
|
-
* @param event ImageLoadEvent event payload
|
|
301
|
-
*/
|
|
302
|
-
onImageLoad(event) {
|
|
303
|
-
// sets as previously loaded the image with index specified by `event.status`
|
|
304
|
-
this.images = this.images.map((img) => {
|
|
305
|
-
if (img && img.id === event.id) {
|
|
306
|
-
return Object.assign({}, img, { previouslyLoaded: event.status });
|
|
307
|
-
}
|
|
308
|
-
return img;
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Method called when a dot is clicked and used to update the current image.
|
|
313
|
-
* @param index number index of the clicked dot
|
|
314
|
-
*/
|
|
315
|
-
onClickDot(index) {
|
|
316
|
-
this.currentImage = this.images[index];
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Method called when an image preview is clicked and used to update the current image.
|
|
320
|
-
* @param event ImageModalEvent preview image
|
|
321
|
-
*/
|
|
322
|
-
onClickPreview(event) {
|
|
323
|
-
this.onChangeCurrentImage(event);
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Method to cleanup resources.
|
|
327
|
-
* This is an angular lifecycle hook that is called when this component is destroyed.
|
|
328
|
-
*/
|
|
329
|
-
ngOnDestroy() {
|
|
330
|
-
if (this.updateImagesSubscription) {
|
|
331
|
-
this.updateImagesSubscription.unsubscribe();
|
|
332
|
-
}
|
|
333
|
-
this.idValidatorService.remove(this.id);
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Method to download the current image, only if `downloadable` is true.
|
|
337
|
-
* @private
|
|
338
|
-
*/
|
|
339
|
-
downloadImage() {
|
|
340
|
-
if (this.id === null || this.id === undefined) {
|
|
341
|
-
throw new Error('Internal library error - id must be defined');
|
|
342
|
-
}
|
|
343
|
-
const libConfig = this.configService.getConfig(this.id);
|
|
344
|
-
if (!libConfig) {
|
|
345
|
-
throw new Error('Internal library error - libConfig must be defined');
|
|
346
|
-
}
|
|
347
|
-
const currentImageConfig = libConfig.currentImageConfig;
|
|
348
|
-
if (currentImageConfig && !currentImageConfig.downloadable) {
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
this.downloadImageAllBrowsers();
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Method to convert a base64 to a Blob
|
|
355
|
-
* @param base64Data string with base64 data
|
|
356
|
-
* @param contentType string with the MIME type
|
|
357
|
-
* @return Blob converted from the input base64Data
|
|
358
|
-
* @private
|
|
359
|
-
*/
|
|
360
|
-
base64toBlob(base64Data, contentType = '') {
|
|
361
|
-
const sliceSize = 1024;
|
|
362
|
-
const byteCharacters = atob(base64Data);
|
|
363
|
-
const bytesLength = byteCharacters.length;
|
|
364
|
-
const slicesCount = Math.ceil(bytesLength / sliceSize);
|
|
365
|
-
const byteArrays = new Array(slicesCount);
|
|
366
|
-
for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
|
|
367
|
-
const begin = sliceIndex * sliceSize;
|
|
368
|
-
const end = Math.min(begin + sliceSize, bytesLength);
|
|
369
|
-
const bytes = new Array(end - begin);
|
|
370
|
-
for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
|
|
371
|
-
bytes[i] = byteCharacters[offset].charCodeAt(0);
|
|
372
|
-
}
|
|
373
|
-
byteArrays[sliceIndex] = new Uint8Array(bytes);
|
|
374
|
-
}
|
|
375
|
-
return new Blob(byteArrays, { type: contentType });
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Private method to download the current image for all browsers.
|
|
379
|
-
* @private
|
|
380
|
-
*/
|
|
381
|
-
downloadImageAllBrowsers() {
|
|
382
|
-
const link = document.createElement('a');
|
|
383
|
-
let isBase64 = false;
|
|
384
|
-
let img;
|
|
385
|
-
// convert a SafeResourceUrl to a string
|
|
386
|
-
if (typeof this.currentImage.modal.img === 'string') {
|
|
387
|
-
img = this.currentImage.modal.img;
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
// if it's a SafeResourceUrl
|
|
391
|
-
img = this.sanitizer.sanitize(SecurityContext.RESOURCE_URL, this.currentImage.modal.img);
|
|
392
|
-
}
|
|
393
|
-
if (img.includes('data:image/') || img.includes(';base64,')) {
|
|
394
|
-
const extension = img.replace('data:image/', '').split(';base64,')[0];
|
|
395
|
-
const pureBase64 = img.split(';base64,')[1];
|
|
396
|
-
const blob = this.base64toBlob(pureBase64, 'image/' + extension);
|
|
397
|
-
link.href = URL.createObjectURL(blob);
|
|
398
|
-
isBase64 = true;
|
|
399
|
-
link.setAttribute('download', this.getFileName(this.currentImage, isBase64, extension));
|
|
400
|
-
}
|
|
401
|
-
else {
|
|
402
|
-
link.href = img;
|
|
403
|
-
link.setAttribute('download', this.getFileName(this.currentImage, isBase64));
|
|
404
|
-
}
|
|
405
|
-
document.body.appendChild(link);
|
|
406
|
-
link.click();
|
|
407
|
-
document.body.removeChild(link);
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* Private method to get the `ButtonEvent` to emit, merging the input `ButtonEvent`
|
|
411
|
-
* with the current image.
|
|
412
|
-
* @param event ButtonEvent event payload to return
|
|
413
|
-
* @returns ButtonEvent event payload with the current image included
|
|
414
|
-
* @private
|
|
415
|
-
*/
|
|
416
|
-
getButtonEventToEmit(event) {
|
|
417
|
-
return Object.assign(event, { image: this.currentImage });
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Private method to get the file name from an input path.
|
|
421
|
-
* This is used either to get the image's name from its path or from the Image itself,
|
|
422
|
-
* if specified as 'downloadFileName' by the user.
|
|
423
|
-
* @param image Image image to extract its file name
|
|
424
|
-
* @param isBase64 boolean to set if the image is a base64 file or not. False by default.
|
|
425
|
-
* @param base64Extension string to force the extension of the base64 image. Empty string by default.
|
|
426
|
-
* @returns string string file name of the input image.
|
|
427
|
-
* @private
|
|
428
|
-
*/
|
|
429
|
-
getFileName(image, isBase64 = false, base64Extension = '') {
|
|
430
|
-
if (!image.modal.downloadFileName || image.modal.downloadFileName.length === 0) {
|
|
431
|
-
if (isBase64) {
|
|
432
|
-
return `Image-${image.id}.${base64Extension !== '' ? base64Extension : 'png'}`;
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
return image.modal.img.replace(/^.*[\\\/]/, '');
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
return image.modal.downloadFileName;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* Private method to initialize `images` as array of `Image`s.
|
|
444
|
-
* Also, it will emit ImageModalEvent to say that images are loaded.
|
|
445
|
-
* @private
|
|
446
|
-
*/
|
|
447
|
-
initImages() {
|
|
448
|
-
this.modalGalleryService.emitHasData(new ImageModalEvent(this.id, Action.LOAD, true));
|
|
449
|
-
const currentIndex = this.images.indexOf(this.currentImage);
|
|
450
|
-
// emit a new ImageModalEvent with the index of the current image
|
|
451
|
-
this.modalGalleryService.emitShow(new ImageModalEvent(this.id, Action.LOAD, currentIndex + 1));
|
|
452
|
-
// emit first/last event based on newIndex value
|
|
453
|
-
this.emitBoundaryEvent(Action.NORMAL, currentIndex);
|
|
454
|
-
this.showGallery = this.images.length > 0;
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Private method to emit events when either the last or the first image are visible.
|
|
458
|
-
* @param action Action Enum of type Action that represents the source of the event that changed the
|
|
459
|
-
* current image to the first one or the last one.
|
|
460
|
-
* @param indexToCheck number is the index number of the image (the first or the last one).
|
|
461
|
-
* @private
|
|
462
|
-
*/
|
|
463
|
-
emitBoundaryEvent(action, indexToCheck) {
|
|
464
|
-
// to emit first/last event
|
|
465
|
-
switch (indexToCheck) {
|
|
466
|
-
case 0:
|
|
467
|
-
this.modalGalleryService.emitFirstImage(new ImageModalEvent(this.id, action, true));
|
|
468
|
-
break;
|
|
469
|
-
case this.images.length - 1:
|
|
470
|
-
this.modalGalleryService.emitLastImage(new ImageModalEvent(this.id, action, true));
|
|
471
|
-
break;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.5", ngImport: i0, type: ModalGalleryComponent, deps: [{ token: DIALOG_DATA }, { token: i1.ModalGalleryService }, { token: PLATFORM_ID }, { token: i0.ChangeDetectorRef }, { token: i2.IdValidatorService }, { token: i3.ConfigService }, { token: i4.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
475
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.5", type: ModalGalleryComponent, selector: "ks-modal-gallery", host: { listeners: { "window:popstate": "onPopState()", "document:keydown.code.control.keyS": "onSaveListener($event)", "document:keydown.code.meta.keyS": "onSaveListener($event)" } }, viewQueries: [{ propertyName: "currentImageComponent", first: true, predicate: CurrentImageComponent, descendants: true, static: true }], ngImport: i0, template: "<div id=\"modal-gallery-wrapper\"\n [attr.aria-label]=\"accessibilityConfig.modalGalleryContentAriaLabel\"\n [title]=\"accessibilityConfig.modalGalleryContentTitle\"\n ksClickOutside [clickOutsideEnable]=\"enableCloseOutside\"\n (clickOutside)=\"onClickOutside($event)\">\n\n <div id=\"flex-min-height-ie-fix\">\n <div id=\"modal-gallery-container\">\n\n <ks-upper-buttons [id]=\"id\"\n [currentImage]=\"currentImage\"\n (delete)=\"onDelete($event)\"\n (navigate)=\"onNavigate($event)\"\n (download)=\"onDownload($event)\"\n (closeButton)=\"onCloseGalleryButton($event)\"\n (fullscreen)=\"onFullScreen($event)\"\n (customEmit)=\"onCustomEmit($event)\"></ks-upper-buttons>\n\n <ks-current-image [id]=\"id\"\n [images]=\"images\"\n [currentImage]=\"currentImage\"\n [isOpen]=\"true\"\n (loadImage)=\"onImageLoad($event)\"\n (changeImage)=\"onChangeCurrentImage($event)\"\n (closeGallery)=\"onCloseGallery($event)\"></ks-current-image>\n\n <div>\n <ks-dots [id]=\"id\"\n [images]=\"images\"\n [currentImage]=\"currentImage\"\n [dotsConfig]=\"dotsConfig\"\n (clickDot)=\"onClickDot($event)\"></ks-dots>\n\n <ks-previews [id]=\"id\"\n [images]=\"images\"\n [currentImage]=\"currentImage\"\n [customTemplate]=\"customPreviewsTemplate\"\n (clickPreview)=\"onClickPreview($event)\"></ks-previews>\n </div>\n </div>\n </div>\n</div>\n", styles: ["#flex-min-height-ie-fix{display:flex;flex-direction:column;justify-content:center}#modal-gallery-container{display:flex;flex-direction:column;justify-content:space-between;min-width:100vw;min-height:100vh}\n"], dependencies: [{ kind: "component", type: i5.UpperButtonsComponent, selector: "ks-upper-buttons", inputs: ["id", "currentImage"], outputs: ["refresh", "delete", "navigate", "download", "closeButton", "fullscreen", "customEmit"] }, { kind: "component", type: i6.DotsComponent, selector: "ks-dots", inputs: ["id", "currentImage", "images", "dotsConfig"], outputs: ["clickDot"] }, { kind: "component", type: i7.PreviewsComponent, selector: "ks-previews", inputs: ["id", "currentImage", "images", "customTemplate"], outputs: ["clickPreview"] }, { kind: "component", type: i8.CurrentImageComponent, selector: "ks-current-image", inputs: ["id", "currentImage", "images", "isOpen"], outputs: ["loadImage", "changeImage", "closeGallery"] }, { kind: "directive", type: i9.ClickOutsideDirective, selector: "[ksClickOutside]", inputs: ["clickOutsideEnable"], outputs: ["clickOutside"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
476
|
-
}
|
|
477
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.5", ngImport: i0, type: ModalGalleryComponent, decorators: [{
|
|
478
|
-
type: Component,
|
|
479
|
-
args: [{ selector: 'ks-modal-gallery', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div id=\"modal-gallery-wrapper\"\n [attr.aria-label]=\"accessibilityConfig.modalGalleryContentAriaLabel\"\n [title]=\"accessibilityConfig.modalGalleryContentTitle\"\n ksClickOutside [clickOutsideEnable]=\"enableCloseOutside\"\n (clickOutside)=\"onClickOutside($event)\">\n\n <div id=\"flex-min-height-ie-fix\">\n <div id=\"modal-gallery-container\">\n\n <ks-upper-buttons [id]=\"id\"\n [currentImage]=\"currentImage\"\n (delete)=\"onDelete($event)\"\n (navigate)=\"onNavigate($event)\"\n (download)=\"onDownload($event)\"\n (closeButton)=\"onCloseGalleryButton($event)\"\n (fullscreen)=\"onFullScreen($event)\"\n (customEmit)=\"onCustomEmit($event)\"></ks-upper-buttons>\n\n <ks-current-image [id]=\"id\"\n [images]=\"images\"\n [currentImage]=\"currentImage\"\n [isOpen]=\"true\"\n (loadImage)=\"onImageLoad($event)\"\n (changeImage)=\"onChangeCurrentImage($event)\"\n (closeGallery)=\"onCloseGallery($event)\"></ks-current-image>\n\n <div>\n <ks-dots [id]=\"id\"\n [images]=\"images\"\n [currentImage]=\"currentImage\"\n [dotsConfig]=\"dotsConfig\"\n (clickDot)=\"onClickDot($event)\"></ks-dots>\n\n <ks-previews [id]=\"id\"\n [images]=\"images\"\n [currentImage]=\"currentImage\"\n [customTemplate]=\"customPreviewsTemplate\"\n (clickPreview)=\"onClickPreview($event)\"></ks-previews>\n </div>\n </div>\n </div>\n</div>\n", styles: ["#flex-min-height-ie-fix{display:flex;flex-direction:column;justify-content:center}#modal-gallery-container{display:flex;flex-direction:column;justify-content:space-between;min-width:100vw;min-height:100vh}\n"] }]
|
|
480
|
-
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
481
|
-
type: Inject,
|
|
482
|
-
args: [DIALOG_DATA]
|
|
483
|
-
}] }, { type: i1.ModalGalleryService }, { type: Object, decorators: [{
|
|
484
|
-
type: Inject,
|
|
485
|
-
args: [PLATFORM_ID]
|
|
486
|
-
}] }, { type: i0.ChangeDetectorRef }, { type: i2.IdValidatorService }, { type: i3.ConfigService }, { type: i4.DomSanitizer }], propDecorators: { currentImageComponent: [{
|
|
487
|
-
type: ViewChild,
|
|
488
|
-
args: [CurrentImageComponent, { static: true }]
|
|
489
|
-
}], onPopState: [{
|
|
490
|
-
type: HostListener,
|
|
491
|
-
args: ['window:popstate']
|
|
492
|
-
}], onSaveListener: [{
|
|
493
|
-
type: HostListener,
|
|
494
|
-
args: ['document:keydown.code.control.keyS', ['$event']]
|
|
495
|
-
}, {
|
|
496
|
-
type: HostListener,
|
|
497
|
-
args: ['document:keydown.code.meta.keyS', ['$event']]
|
|
498
|
-
}] } });
|
|
499
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kYWwtZ2FsbGVyeS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9rczg5L2FuZ3VsYXItbW9kYWwtZ2FsbGVyeS9zcmMvbGliL2NvbXBvbmVudHMvbW9kYWwtZ2FsbGVyeS9tb2RhbC1nYWxsZXJ5LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2tzODkvYW5ndWxhci1tb2RhbC1nYWxsZXJ5L3NyYy9saWIvY29tcG9uZW50cy9tb2RhbC1nYWxsZXJ5L21vZGFsLWdhbGxlcnkuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUFxQixTQUFTLEVBQ3JELFlBQVksRUFBRSxNQUFNLEVBQXFCLFdBQVcsRUFBRSxlQUFlLEVBQUUsU0FBUyxFQUNqRixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUtwRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDckQsT0FBTyxFQUFTLGVBQWUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBR2pFLE9BQU8sRUFBNEMsVUFBVSxFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFFNUcsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ2pELE9BQU8sRUFBRSxxQkFBcUIsRUFBa0IsTUFBTSwwQ0FBMEMsQ0FBQztBQU9qRyxPQUFPLEVBQUUsK0JBQStCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQzs7Ozs7Ozs7Ozs7QUFZM0UsTUFBTSxPQUFPLHFCQUFxQjtJQXdFaEM7Ozs7T0FJRztJQUVILFVBQVU7UUFDUixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDdEIsQ0FBQztJQUVEOzs7T0FHRztJQUdILGNBQWMsQ0FBQyxLQUFvQjtRQUNqQyxLQUFLLENB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RSxTQUFTO3VCQUFDLHFCQUFxQixFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkEwRWxELFVBQVU7c0JBRFQsWUFBWTt1QkFBQyxpQkFBaUI7Z0JBVy9CLGNBQWM7c0JBRmIsWUFBWTt1QkFBQyxvQ0FBb0MsRUFBRSxDQUFDLFFBQVEsQ0FBQzs7c0JBQzdELFlBQVk7dUJBQUMsaUNBQWlDLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ2hhbmdlRGV0ZWN0b3JSZWYsIENvbXBvbmVudCxcbiAgSG9zdExpc3RlbmVyLCBJbmplY3QsIE9uRGVzdHJveSwgT25Jbml0LCBQTEFURk9STV9JRCwgU2VjdXJpdHlDb250ZXh0LCBWaWV3Q2hpbGQsIFRlbXBsYXRlUmVmXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRG9tU2FuaXRpemVyIH0gZnJvbSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XG5cbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBESUFMT0dfREFUQSB9IGZyb20gJy4vbW9kYWwtZ2FsbGVyeS50b2tlbnMnO1xuaW1wb3J0IHsgSW1hZ2UsIEltYWdlTW9kYWxFdmVudCB9IGZyb20gJy4uLy4uL21vZGVsL2ltYWdlLmNsYXNzJztcbmltcG9ydCB7IENvbmZpZ1NlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9jb25maWcuc2VydmljZSc7XG5pbXBvcnQgeyBEb3RzQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvZG90cy1jb25maWcuaW50ZXJmYWNlJztcbmltcG9ydCB7IEJ1dHRvbkNvbmZpZywgQnV0dG9uRXZlbnQsIEJ1dHRvbnNDb25maWcsIEJ1dHRvblR5cGUgfSBmcm9tICcuLi8uLi9tb2RlbC9idXR0b25zLWNvbmZpZy5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgSW50ZXJuYWxMaWJJbWFnZSB9IGZyb20gJy4uLy4uL21vZGVsL2ltYWdlLWludGVybmFsLmNsYXNzJztcbmltcG9ydCB7IEFjdGlvbiB9IGZyb20gJy4uLy4uL21vZGVsL2FjdGlvbi5lbnVtJztcbmltcG9ydCB7IEN1cnJlbnRJbWFnZUNvbXBvbmVudCwgSW1hZ2VMb2FkRXZlbnQgfSBmcm9tICcuLi9jdXJyZW50LWltYWdlL2N1cnJlbnQtaW1hZ2UuY29tcG9uZW50JztcbmltcG9ydCB7IElkVmFsaWRhdG9yU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2lkLXZhbGlkYXRvci5zZXJ2aWNlJztcbmltcG9ydCB7IEtleWJvYXJkQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwva2V5Ym9hcmQtY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBQcmV2aWV3Q29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvcHJldmlldy1jb25maWcuaW50ZXJmYWNlJztcbmltcG9ydCB7IFNsaWRlQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvc2xpZGUtY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBBY2Nlc3NpYmlsaXR5Q29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvYWNjZXNzaWJpbGl0eS5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgUGxhaW5HYWxsZXJ5Q29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvcGxhaW4tZ2FsbGVyeS1jb25maWcuaW50ZXJmYWNlJztcbmltcG9ydCB7IEtTX0RFRkFVTFRfQUNDRVNTSUJJTElUWV9DT05GSUcgfSBmcm9tICcuLi9hY2Nlc3NpYmlsaXR5LWRlZmF1bHQnO1xuaW1wb3J0IHsgQ3VycmVudEltYWdlQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvY3VycmVudC1pbWFnZS1jb25maWcuaW50ZXJmYWNlJztcbmltcG9ydCB7IE1vZGFsR2FsbGVyeVNlcnZpY2UgfSBmcm9tICcuL21vZGFsLWdhbGxlcnkuc2VydmljZSc7XG5pbXBvcnQgeyBMaWJDb25maWcgfSBmcm9tICcuLi8uLi9tb2RlbC9saWItY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBNb2RhbEdhbGxlcnlDb25maWcgfSBmcm9tICcuLi8uLi9tb2RlbC9tb2RhbC1nYWxsZXJ5LWNvbmZpZy5pbnRlcmZhY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdrcy1tb2RhbC1nYWxsZXJ5JyxcbiAgdGVtcGxhdGVVcmw6ICcuL21vZGFsLWdhbGxlcnkuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9tb2RhbC1nYWxsZXJ5LmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoXG59KVxuZXhwb3J0IGNsYXNzIE1vZGFsR2FsbGVyeUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgLyoqXG4gICAqIFJlZmVyZW5jZSB0byB0aGUgQ3VycmVudEltYWdlQ29tcG9uZW50IHRvIGludm9rZSBtZXRob2RzIG9uIGl0LlxuICAgKi9cbiAgQFZpZXdDaGlsZChDdXJyZW50SW1hZ2VDb21wb25lbnQsIHsgc3RhdGljOiB0cnVlIH0pIGN1cnJlbnRJbWFnZUNvbXBvbmVudDogQ3VycmVudEltYWdlQ29tcG9uZW50IHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBVbmlxdWUgaWQgKD49MCkgb2YgdGhlIGN1cnJlbnQgaW5zdGFuY2Ugb2YgdGhpcyBsaWJyYXJ5LiBUaGlzIGlzIHVzZWZ1bCB3aGVuIHlvdSBhcmUgdXNpbmdcbiAgICogdGhlIHNlcnZpY2UgdG8gY2FsbCBtb2RhbCBnYWxsZXJ5IHdpdGhvdXQgb3BlbiBpdCBtYW51YWxseS5cbiAgICovXG4gIGlkOiBudW1iZXI7XG4gIC8qKlxuICAgKiBPYmplY3Qgb2YgdHlwZSBgQnV0dG9uc0NvbmZpZ2AgdG8gc2hvdy9oaWRlIGJ1dHRvbnMuXG4gICAqL1xuICBidXR0b25zQ29uZmlnOiBCdXR0b25zQ29uZmlnIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogQm9vbGVhbiB0byBlbmFibGUgbW9kYWwtZ2FsbGVyeSBjbG9zZSBiZWhhdmlvdXIgd2hlbiBjbGlja2luZ1xuICAgKiBvbiB0aGUgc2VtaS10cmFuc3BhcmVudCBiYWNrZ3JvdW5kLiBFbmFibGVkIGJ5IGRlZmF1bHQuXG4gICAqL1xuICBlbmFibGVDbG9zZU91dHNpZGUgPSB0cnVlO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYERvdHNDb25maWdgIHRvIGluaXQgRG90c0NvbXBvbmVudCdzIGZlYXR1cmVzLlxuICAgKiBGb3IgaW5zdGFuY2UsIGl0IGNvbnRhaW5zIGEgcGFyYW0gdG8gc2hvdy9oaWRlIGRvdHMuXG4gICAqL1xuICBkb3RzQ29uZmlnOiBEb3RzQ29uZmlnIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYFByZXZpZXdDb25maWdgIHRvIGluaXQgUHJldmlld3NDb21wb25lbnQncyBmZWF0dXJlcy5cbiAgICogRm9yIGluc3RhbmNlLCBpdCBjb250YWlucyBhIHBhcmFtIHRvIHNob3cvaGlkZSBwcmV2aWV3cy5cbiAgICovXG4gIHByZXZpZXdDb25maWc6IFByZXZpZXdDb25maWcgfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBPYmplY3Qgb2YgdHlwZSBgU2xpZGVDb25maWdgIHRvIGluaXQgc2lkZSBwcmV2aWV3cyBhbmQgYGluZmluaXRlIHNsaWRpbmdgLlxuICAgKi9cbiAgc2xpZGVDb25maWc6IFNsaWRlQ29uZmlnIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYEFjY2Vzc2liaWxpdHlDb25maWdgIHRvIGluaXQgY3VzdG9tIGFjY2Vzc2liaWxpdHkgZmVhdHVyZXMuXG4gICAqIEZvciBpbnN0YW5jZSwgaXQgY29udGFpbnMgdGl0bGVzLCBhbHQgdGV4dHMsIGFyaWEtbGFiZWxzIGFuZCBzbyBvbi5cbiAgICovXG4gIGFjY2Vzc2liaWxpdHlDb25maWc6IEFjY2Vzc2liaWxpdHlDb25maWcgPSBLU19ERUZBVUxUX0FDQ0VTU0lCSUxJVFlfQ09ORklHO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYEtleWJvYXJkQ29uZmlnYCB0byBhc3NpZ24gY3VzdG9tIGtleXMgdG8gRVNDLCBSSUdIVCBhbmQgTEVGVCBrZXlib2FyZCdzIGFjdGlvbnMuXG4gICAqL1xuICBrZXlib2FyZENvbmZpZzogS2V5Ym9hcmRDb25maWcgfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBPYmplY3Qgb2YgdHlwZSBgUGxhaW5HYWxsZXJ5Q29uZmlnYCB0byBjb25maWd1cmUgdGhlIHBsYWluIGdhbGxlcnkuXG4gICAqL1xuICBwbGFpbkdhbGxlcnlDb25maWc6IFBsYWluR2FsbGVyeUNvbmZpZyB8IHVuZGVmaW5lZDtcbiAgLyoqXG4gICAqIEFycmF5IG9mIGBJbnRlcm5hbExpYkltYWdlYCByZXByZXNlbnRpbmcgdGhlIG1vZGVsIG9mIHRoaXMgbGlicmFyeSB3aXRoIGFsbCBpbWFnZXMsIHRodW1icyBhbmQgc28gb24uXG4gICAqL1xuICBpbWFnZXM6IEludGVybmFsTGliSW1hZ2VbXTtcblxuICAvKipcbiAgICogT3B0aW9uYWwgdGVtcGxhdGUgcmVmZXJlbmNlIHRvIHVzZSB0byByZW5kZXIgcHJldmlld3MuXG4gICAqL1xuICBjdXN0b21QcmV2aWV3c1RlbXBsYXRlPzogVGVtcGxhdGVSZWY8SFRNTEVsZW1lbnQ+O1xuXG4gIC8qKlxuICAgKiBgSW1hZ2VgIHRoYXQgaXMgdmlzaWJsZSByaWdodCBub3cuXG4gICAqL1xuICBjdXJyZW50SW1hZ2U6IEludGVybmFsTGliSW1hZ2U7XG4gIC8qKlxuICAgKiBCb29sZWFuIHRvIG9wZW4gdGhlIG1vZGFsIGdhbGxlcnkuIEZhbHNlIGJ5IGRlZmF1bHQuXG4gICAqL1xuICBzaG93R2FsbGVyeSA9IGZhbHNlO1xuICAvKipcbiAgICogT2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGlzIGNvbXBvbmVudC5cbiAgICovXG4gIGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkO1xuXG4gIHByaXZhdGUgdXBkYXRlSW1hZ2VzU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb24gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEhvc3RMaXN0ZW5lciB0byBjYXRjaCBicm93c2VyJ3MgYmFjayBidXR0b24gYW5kIGRlc3Ryb3kgdGhlIGdhbGxlcnkuXG4gICAqIFRoaXMgcHJldmVudHMgd2VpcmVkIGJlaGF2aW91ciBhYm91dCBzY3JvbGxpbmcuXG4gICAqIEFkZGVkIHRvIGZpeCB0aGlzIGlzc3VlOiBodHRwczovL2dpdGh1Yi5jb20vS3M4OS9hbmd1bGFyLW1vZGFsLWdhbGxlcnkvaXNzdWVzLzE1OVxuICAgKi9cbiAgQEhvc3RMaXN0ZW5lcignd2luZG93OnBvcHN0YXRlJylcbiAgb25Qb3BTdGF0ZSgpOiB2b2lkIHtcbiAgICB0aGlzLmNsb3NlR2FsbGVyeSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEhvc3RMaXN0ZW5lciB0byBjYXRjaCBjdHJsK3MvbWV0YStzIGFuZCBkb3dubG9hZCB0aGUgY3VycmVudCBpbWFnZS5cbiAgICogSW5zcGlyZWQgYnkgaHR0cHM6Ly9uZXRiYXNhbC5jb20vYWRkLWtleWJvYXJkLXNob3J0Y3V0cy10by15b3VyLWFuZ3VsYXItYXBwLTliZjJlODk4NjJiM1xuICAgKi9cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6a2V5ZG93bi5jb2RlLmNvbnRyb2wua2V5UycsIFsnJGV2ZW50J10pIC8vIHdpbmRvd3NcbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6a2V5ZG93bi5jb2RlLm1ldGEua2V5UycsIFsnJGV2ZW50J10pIC8vIG1hY09TXG4gIG9uU2F2ZUxpc3RlbmVyKGV2ZW50OiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB0aGlzLmRvd25sb2FkSW1hZ2UoKTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBJbmplY3QoRElBTE9HX0RBVEEpIHByaXZhdGUgZGlhbG9nQ29udGVudDogTW9kYWxHYWxsZXJ5Q29uZmlnLFxuICAgIHByaXZhdGUgbW9kYWxHYWxsZXJ5U2VydmljZTogTW9kYWxHYWxsZXJ5U2VydmljZSxcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6YmFuLXR5cGVzXG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJpdmF0ZSBwbGF0Zm9ybUlkOiBPYmplY3QsXG4gICAgcHJpdmF0ZSBjaGFuZ2VEZXRlY3RvclJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJpdmF0ZSBpZFZhbGlkYXRvclNlcnZpY2U6IElkVmFsaWRhdG9yU2VydmljZSxcbiAgICBwcml2YXRlIGNvbmZpZ1NlcnZpY2U6IENvbmZpZ1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBzYW5pdGl6ZXI6IERvbVNhbml0aXplclxuICApIHtcbiAgICB0aGlzLmlkID0gKHRoaXMuZGlhbG9nQ29udGVudCBhcyBNb2RhbEdhbGxlcnlDb25maWcpLmlkO1xuICAgIHRoaXMuaW1hZ2VzID0gKHRoaXMuZGlhbG9nQ29udGVudCBhcyBNb2RhbEdhbGxlcnlDb25maWcpLmltYWdlcyBhcyBJbnRlcm5hbExpYkltYWdlW107XG4gICAgdGhpcy5jdXJyZW50SW1hZ2UgPSAodGhpcy5kaWFsb2dDb250ZW50IGFzIE1vZGFsR2FsbGVyeUNvbmZpZykuY3VycmVudEltYWdlIGFzIEludGVybmFsTGliSW1hZ2U7XG4gICAgdGhpcy5saWJDb25maWcgPSAodGhpcy5kaWFsb2dDb250ZW50IGFzIE1vZGFsR2FsbGVyeUNvbmZpZykubGliQ29uZmlnO1xuICAgIHRoaXMuY3VzdG9tUHJldmlld3NUZW1wbGF0ZSA9ICh0aGlzLmRpYWxvZ0NvbnRlbnQgYXMgTW9kYWxHYWxsZXJ5Q29uZmlnKS5wcmV2aWV3c1RlbXBsYXRlO1xuICAgIHRoaXMuY29uZmlnU2VydmljZS5zZXRDb25maWcodGhpcy5pZCwgdGhpcy5saWJDb25maWcpO1xuXG4gICAgdGhpcy51cGRhdGVJbWFnZXNTdWJzY3JpcHRpb24gPSB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UudXBkYXRlSW1hZ2VzJC5zdWJzY3JpYmUoKGltYWdlczogSW1hZ2VbXSkgPT4ge1xuICAgICAgdGhpcy5pbWFnZXMgPSBpbWFnZXMubWFwKChpbWFnZTogSW1hZ2UpID0+IHtcbiAgICAgICAgY29uc3QgbmV3SW1hZ2U6IEludGVybmFsTGliSW1hZ2UgPSBPYmplY3QuYXNzaWduKHt9LCBpbWFnZSwgeyBwcmV2aW91c2x5TG9hZGVkOiBmYWxzZSB9KTtcbiAgICAgICAgcmV0dXJuIG5ld0ltYWdlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmluaXRJbWFnZXMoKTtcbiAgICAgIHRoaXMuaW1hZ2VzLmZvckVhY2goKGltYWdlOiBJbnRlcm5hbExpYkltYWdlKSA9PiB7XG4gICAgICAgIGlmIChpbWFnZS5pZCA9PT0gdGhpcy5jdXJyZW50SW1hZ2UuaWQpIHtcbiAgICAgICAgICB0aGlzLmN1cnJlbnRJbWFnZSA9IGltYWdlO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYubWFya0ZvckNoZWNrKCk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIMK0bmdPbkluaXTCtCB0byBpbml0IGltYWdlcyBjYWxsaW5nIGBpbml0SW1hZ2VzKClgLlxuICAgKiBUaGlzIGlzIGFuIGFuZ3VsYXIgbGlmZWN5Y2xlIGhvb2ssIHNvIGl0cyBjYWxsZWQgYXV0b21hdGljYWxseSBieSBBbmd1bGFyIGl0c2VsZi5cbiAgICogSW4gcGFydGljdWxhciwgaXQncyBjYWxsZWQgb25seSBvbmUgdGltZSEhIVxuICAgKi9cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5pZFZhbGlkYXRvclNlcnZpY2UuY2hlY2tBbmRBZGQodGhpcy5pZCk7XG5cbiAgICAvLyBpZCBpcyBhIG1hbmRhdG9yeSBpbnB1dCBhbmQgbXVzdCBhIG51bWJlciA+IDBcbiAgICBpZiAoKCF0aGlzLmlkICYmIHRoaXMuaWQgIT09IDApIHx8IHRoaXMuaWQgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAnW2lkXT1cImEgbnVtYmVyID49IDBcIicgaXMgYSBtYW5kYXRvcnkgaW5wdXQgaW4gYW5ndWxhci1tb2RhbC1nYWxsZXJ5LmAgK1xuICAgICAgICBgSWYgeW91IGFyZSB1c2luZyBtdWx0aXBsZSBpbnN0YW5jZXMgb2YgdGhpcyBsaWJyYXJ5LCBwbGVhc2UgYmUgc3VyZSB0byB1c2UgZGlmZmVyZW50IGlkc2BcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgbGliQ29uZmlnOiBMaWJDb25maWcgfCB1bmRlZmluZWQgPSB0aGlzLmNvbmZpZ1NlcnZpY2UuZ2V0Q29uZmlnKHRoaXMuaWQpO1xuICAgIGlmICghbGliQ29uZmlnIHx8ICFsaWJDb25maWcuZG90c0NvbmZpZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gbGliQ29uZmlnIGFuZCBkb3RzQ29uZmlnIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cblxuICAgIHRoaXMuZG90c0NvbmZpZyA9IGxpYkNvbmZpZy5kb3RzQ29uZmlnO1xuXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmluaXRJbWFnZXMoKTtcbiAgICB9LCAwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgY2FsbGVkIGJ5IGN1c3RvbSB1cHBlciBidXR0b25zLlxuICAgKiBAcGFyYW0gZXZlbnQgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZFxuICAgKi9cbiAgb25DdXN0b21FbWl0KGV2ZW50OiBCdXR0b25FdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGV2ZW50VG9FbWl0OiBCdXR0b25FdmVudCA9IHRoaXMuZ2V0QnV0dG9uRXZlbnRUb0VtaXQoZXZlbnQpO1xuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0QnV0dG9uQmVmb3JlSG9vayhldmVudFRvRW1pdCk7XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25BZnRlckhvb2soZXZlbnRUb0VtaXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgYnkgdGhlIGZ1bGwtc2NyZWVuIHVwcGVyIGJ1dHRvbi5cbiAgICogQHBhcmFtIGV2ZW50IEJ1dHRvbkV2ZW50IGV2ZW50IHBheWxvYWRcbiAgICovXG4gIG9uRnVsbFNjcmVlbihldmVudDogQnV0dG9uRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBldmVudFRvRW1pdDogQnV0dG9uRXZlbnQgPSB0aGlzLmdldEJ1dHRvbkV2ZW50VG9FbWl0KGV2ZW50KTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkJlZm9yZUhvb2soZXZlbnRUb0VtaXQpO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWFueVxuICAgIGNvbnN0IGRvYzogYW55ID0gZG9jdW1lbnQgYXMgYW55O1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1hbnlcbiAgICBjb25zdCBkb2NFbDogYW55ID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50IGFzIGFueTtcblxuICAgIGNvbnN0IGZ1bGxzY3JlZW5EaXNhYmxlZDogYm9vbGVhbiA9ICFkb2MuZnVsbHNjcmVlbkVsZW1lbnQgJiYgIWRvYy53ZWJraXRGdWxsc2NyZWVuRWxlbWVudDtcblxuICAgIC8vIEluIFNhZmFyaSBgcmVxdWVzdEZ1bGxzY3JlZW5gIGFuZCBgZXhpdEZ1bGxzY3JlZW5gIGFyZSB1bmRlZmluZWQuIFNhZmFyaSByZXF1aXJlcyB0aGUgcHJlZml4ZWQgdmVyc2lvbiBgd2Via2l0LWBcbiAgICAvLyBhbmQgaXQgZG9lc24ndCByZXR1cm4gcHJvbWlzZXMuXG5cbiAgICAvLyBJIGNhbm5vdCBjYWxsIGBlbWl0QnV0dG9uQWZ0ZXJIb29rYCBvbmx5IGlmIHJlcXVlc3RGdWxsU2NyZWVuIGlzIHN1Y2Nlc3NmdWwsIGJlY2F1c2UgdGhlcmUgYXJlIG5vIGd1YXJhbnRlZXMgYWNyb3NzIGJyb3dzZXJzIGFuZFxuICAgIC8vIEkgc2hvdWxkIGFsc28gaGFuZGxlIHRoZSBjYXNlIHdpdGgga2V5Ym9hcmQgXCJlc2NcIiBidXR0b24uXG5cbiAgICBpZiAoZnVsbHNjcmVlbkRpc2FibGVkKSB7XG4gICAgICBpZiAoZG9jRWwucmVxdWVzdEZ1bGxzY3JlZW4pIHtcbiAgICAgICAgZG9jRWwucmVxdWVzdEZ1bGxzY3JlZW4oKVxuICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5jYXRjaCgoKSA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdDYW5ub3QgcmVxdWVzdCBmdWxsIHNjcmVlbicpO1xuICAgICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChkb2NFbC53ZWJraXRSZXF1ZXN0RnVsbHNjcmVlbikge1xuICAgICAgICAvLyBGb3IgU2FmYXJpIGFuZCBpdCBkb2Vzbid0IHJldHVybiBhIHByb21pc2VcbiAgICAgICAgZG9jRWwud2Via2l0UmVxdWVzdEZ1bGxzY3JlZW4oKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGRvYy5leGl0RnVsbHNjcmVlbikge1xuICAgICAgICBkb2MuZXhpdEZ1bGxzY3JlZW4oKVxuICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5jYXRjaCgoKSA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdDYW5ub3QgcmVxdWVzdCBleGl0IGZ1bGwgc2NyZWVuJyk7XG4gICAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGRvYy53ZWJraXRFeGl0RnVsbHNjcmVlbikge1xuICAgICAgICAvLyBGb3IgU2FmYXJpIGFuZCBpdCBkb2Vzbid0IHJldHVybiBhIHByb21pc2VcbiAgICAgICAgZG9jLndlYmtpdEV4aXRGdWxsc2NyZWVuKCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25BZnRlckhvb2soZXZlbnRUb0VtaXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgYnkgdGhlIGRlbGV0ZSB1cHBlciBidXR0b24uXG4gICAqIEBwYXJhbSBldmVudCBCdXR0b25FdmVudCBldmVudCBwYXlsb2FkXG4gICAqL1xuICBvbkRlbGV0ZShldmVudDogQnV0dG9uRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBldmVudFRvRW1pdDogQnV0dG9uRXZlbnQgPSB0aGlzLmdldEJ1dHRvbkV2ZW50VG9FbWl0KGV2ZW50KTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkJlZm9yZUhvb2soZXZlbnRUb0VtaXQpO1xuXG4gICAgaWYgKHRoaXMuaW1hZ2VzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgdGhpcy5jbG9zZUdhbGxlcnkoKTtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMuY3VycmVudEltYWdlQ29tcG9uZW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2N1cnJlbnRJbWFnZUNvbXBvbmVudCBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG5cbiAgICBjb25zdCBpbWFnZUluZGV4VG9EZWxldGU6IG51bWJlciA9IHRoaXMuY3VycmVudEltYWdlQ29tcG9uZW50LmdldEluZGV4VG9EZWxldGUoZXZlbnQuaW1hZ2UgYXMgSW50ZXJuYWxMaWJJbWFnZSk7XG4gICAgaWYgKGltYWdlSW5kZXhUb0RlbGV0ZSA9PT0gdGhpcy5pbWFnZXMubGVuZ3RoIC0gMSkge1xuICAgICAgLy8gbGFzdCBpbWFnZVxuICAgICAgdGhpcy5jdXJyZW50SW1hZ2VDb21wb25lbnQucHJldkltYWdlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY3VycmVudEltYWdlQ29tcG9uZW50Lm5leHRJbWFnZSgpO1xuICAgIH1cblxuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0QnV0dG9uQWZ0ZXJIb29rKGV2ZW50VG9FbWl0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgY2FsbGVkIGJ5IHRoZSBuYXZpZ2F0ZSB1cHBlciBidXR0b24uXG4gICAqIEBwYXJhbSBldmVudCBCdXR0b25FdmVudCBldmVudCBwYXlsb2FkXG4gICAqL1xuICBvbk5hdmlnYXRlKGV2ZW50OiBCdXR0b25FdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGV2ZW50VG9FbWl0OiBCdXR0b25FdmVudCA9IHRoaXMuZ2V0QnV0dG9uRXZlbnRUb0VtaXQoZXZlbnQpO1xuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0QnV0dG9uQmVmb3JlSG9vayhldmVudFRvRW1pdCk7XG4gICAgLy8gVG8gc3VwcG9ydCBTU1JcbiAgICBpZiAoaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybUlkKSkge1xuICAgICAgaWYgKGV2ZW50VG9FbWl0LmltYWdlICYmIGV2ZW50VG9FbWl0LmltYWdlLm1vZGFsLmV4dFVybCkge1xuICAgICAgICAvLyB3aGVyZSBJIHNob3VsZCBvcGVuIHRoaXMgbGluaz8gVGhlIGN1cnJlbnQgdGFiIG9yIGFub3RoZXIgb25lP1xuICAgICAgICBpZiAoZXZlbnRUb0VtaXQuYnV0dG9uICYmIGV2ZW50VG9FbWl0LmJ1dHRvbi5leHRVcmxJbk5ld1RhYikge1xuICAgICAgICAgIC8vIGluIHRoaXMgY2FzZSBJIHNob3VsZCB1c2UgdGFyZ2V0IF9ibGFuayB0byBvcGVuIHRoZSB1cmwgaW4gYSBuZXcgdGFiLCBob3dldmVyIHRoZXNlIGlzIGEgc2VjdXJpdHkgaXNzdWUuXG4gICAgICAgICAgLy8gUHJldmVudCBSZXZlcnNlIFRhYm5hYmJpbmcncyBhdHRhY2tzIChodHRwczovL3d3dy5vd2FzcC5vcmcvaW5kZXgucGhwL1JldmVyc2VfVGFibmFiYmluZylcbiAgICAgICAgICAvLyBTb21lIHJlc291cmNlczpcbiAgICAgICAgICAvLyAtIGh0dHBzOi8vd3d3Lm93YXNwLm9yZy9pbmRleC5waHAvSFRNTDVfU2VjdXJpdHlfQ2hlYXRfU2hlZXQjVGFibmFiYmluZ1xuICAgICAgICAgIC8vIC0gaHR0cHM6Ly9tZWRpdW0uY29tL0BqaXRiaXQvdGFyZ2V0LWJsYW5rLXRoZS1tb3N0LXVuZGVyZXN0aW1hdGVkLXZ1bG5lcmFiaWxpdHktZXZlci05NmUzMjgzMDFmNGNcbiAgICAgICAgICAvLyAtIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9XaW5kb3cvb3BlblxuICAgICAgICAgIGNvbnN0IG5ld1dpbmRvdzogV2luZG93IHwgbnVsbCA9IHdpbmRvdy5vcGVuKGV2ZW50VG9FbWl0LmltYWdlLm1vZGFsLmV4dFVybCwgJ25vb3BlbmVyLG5vcmVmZXJyZXIsJyk7XG4gICAgICAgICAgLy8gaXQgcmV0dXJucyBudWxsIGlmIHRoZSBjYWxsIGZhaWxlZCwgc28gSSBoYXZlIHRvIGRvIHRoaXMgY2hlY2tcbiAgICAgICAgICBpZiAobmV3V2luZG93KSB7XG4gICAgICAgICAgICBuZXdXaW5kb3cub3BlbmVyID0gbnVsbDsgLy8gcmVxdWlyZWQgdG8gcHJldmVudCBzZWN1cml0eSBpc3N1ZXNcbiAgICAgICAgICAgIC8vIGVtaXQgb25seSBpbiBjYXNlIG9mIHN1Y2Nlc3NcbiAgICAgICAgICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0QnV0dG9uQWZ0ZXJIb29rKGV2ZW50VG9FbWl0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy51cGRhdGVMb2NhdGlvbkhyZWYoZXZlbnRUb0VtaXQuaW1hZ2UubW9kYWwuZXh0VXJsKTtcbiAgICAgICAgICAvLyBlbWl0IG9ubHkgaW4gY2FzZSBvZiBzdWNjZXNzXG4gICAgICAgICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25BZnRlckhvb2soZXZlbnRUb0VtaXQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRoaXMgbWV0aG9kIGlzIGRlZmluZWQgdG8gYmUgc3BpZWQgYW5kIHJlcGxhY2VkIGluIHVuaXQgdGVzdGluZyB3aXRoIGEgZmFrZSBtZXRob2QgY2FsbC5cbiAgICogSXQgbXVzdCBiZSBwdWJsaWMgdG8gYmUgYWJsZSB0byB1c2UgamFzbWluZSBzcHlPbiBtZXRob2QuXG4gICAqIEBwYXJhbSBuZXdIcmVmIHN0cmluZyBuZXcgdXJsXG4gICAqL1xuICB1cGRhdGVMb2NhdGlvbkhyZWYobmV3SHJlZjogc3RyaW5nKSB7XG4gICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSBuZXdIcmVmO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgYnkgdGhlIGRvd25sb2FkIHVwcGVyIGJ1dHRvbi5cbiAgICogQHBhcmFtIGV2ZW50IEJ1dHRvbkV2ZW50IGV2ZW50IHBheWxvYWRcbiAgICovXG4gIG9uRG93bmxvYWQoZXZlbnQ6IEJ1dHRvbkV2ZW50KTogdm9pZCB7XG4gICAgY29uc3QgZXZlbnRUb0VtaXQ6IEJ1dHRvbkV2ZW50ID0gdGhpcy5nZXRCdXR0b25FdmVudFRvRW1pdChldmVudCk7XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25CZWZvcmVIb29rKGV2ZW50VG9FbWl0KTtcbiAgICB0aGlzLmRvd25sb2FkSW1hZ2UoKTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkFmdGVySG9vayhldmVudFRvRW1pdCk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCBieSB0aGUgY2xvc2UgdXBwZXIgYnV0dG9uLlxuICAgKiBAcGFyYW0gZXZlbnQgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZFxuICAgKiBAcGFyYW0gYWN0aW9uIEFjdGlvbiB0aGF0IHRyaWdnZXJlZCB0aGUgY2xvc2UgbWV0aG9kLiBgQWN0aW9uLk5PUk1BTGAgYnkgZGVmYXVsdFxuICAgKi9cbiAgb25DbG9zZUdhbGxlcnlCdXR0b24oZXZlbnQ6IEJ1dHRvbkV2ZW50LCBhY3Rpb246IEFjdGlvbiA9IEFjdGlvbi5OT1JNQUwpOiB2b2lkIHtcbiAgICBjb25zdCBldmVudFRvRW1pdDogQnV0dG9uRXZlbnQgPSB0aGlzLmdldEJ1dHRvbkV2ZW50VG9FbWl0KGV2ZW50KTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkJlZm9yZUhvb2soZXZlbnRUb0VtaXQpO1xuICAgIHRoaXMuY2xvc2VHYWxsZXJ5KGFjdGlvbiwgZmFsc2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgYnkgQ3VycmVudEltYWdlQ29tcG9uZW50LlxuICAgKiBAcGFyYW0gZXZlbnQgSW1hZ2VNb2RhbEV2ZW50IGV2ZW50IHBheWxvYWRcbiAgICogQHBhcmFtIGFjdGlvbiBBY3Rpb24gdGhhdCB0cmlnZ2VyZWQgdGhlIGNsb3NlIG1ldGhvZC4gYEFjdGlvbi5OT1JNQUxgIGJ5IGRlZmF1bHRcbiAgICovXG4gIG9uQ2xvc2VHYWxsZXJ5KGV2ZW50OiBJbWFnZU1vZGFsRXZlbnQsIGFjdGlvbjogQWN0aW9uID0gQWN0aW9uLk5PUk1BTCk6IHZvaWQge1xuICAgIC8vIHJlbWFwIEltYWdlTW9kYWxFdmVudCB0byBCdXR0b25FdmVudFxuICAgIGNvbnN0IGJ1dHRvbkV2ZW50OiBCdXR0b25FdmVudCA9IHtcbiAgICAgIGJ1dHRvbjoge1xuICAgICAgICB0eXBlOiBCdXR0b25UeXBlLkNMT1NFXG4gICAgICB9IGFzIEJ1dHRvbkNvbmZpZyxcbiAgICAgIGltYWdlOiBudWxsLFxuICAgICAgYWN0aW9uOiBldmVudC5hY3Rpb24sXG4gICAgICBnYWxsZXJ5SWQ6IGV2ZW50LmdhbGxlcnlJZFxuICAgIH07XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25CZWZvcmVIb29rKGJ1dHRvbkV2ZW50KTtcbiAgICB0aGlzLmNsb3NlR2FsbGVyeShhY3Rpb24sIGZhbHNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gY2xvc2UgdGhlIG1vZGFsIGdhbGxlcnkgc3BlY2lmeWluZyB0aGUgYWN0aW9uLlxuICAgKiBAcGFyYW0gYWN0aW9uIEFjdGlvbiBhY3Rpb24gdHlwZS4gYEFjdGlvbi5OT1JNQUxgIGJ5IGRlZmF1bHRcbiAgICogQHBhcmFtIGNsaWNrT3V0c2lkZSBib29sZWFuIHRoYXQgaXMgdHJ1ZSBpZiBjYWxsZWQgY2xpY2tpbmcgb24gdGhlIG1vZGFsIGJhY2tncm91bmQuIEZhbHNlIGJ5IGRlZmF1bHQuXG4gICAqL1xuICBjbG9zZUdhbGxlcnkoYWN0aW9uOiBBY3Rpb24gPSBBY3Rpb24uTk9STUFMLCBjbGlja091dHNpZGU6IGJvb2xlYW4gPSBmYWxzZSk6IHZvaWQge1xuICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICBpZiAoIWxpYkNvbmZpZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gbGliQ29uZmlnIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cblxuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0Q2xvc2UobmV3IEltYWdlTW9kYWxFdmVudCh0aGlzLmlkLCBhY3Rpb24sIHRydWUpKTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuY2xvc2UodGhpcy5pZCwgY2xpY2tPdXRzaWRlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgY2FsbGVkIHdoZW4gdGhlIGltYWdlIGNoYW5nZXMgYW5kIHVzZWQgdG8gdXBkYXRlIHRoZSBgY3VycmVudEltYWdlYCBvYmplY3QuXG4gICAqIEBwYXJhbSBldmVudCBJbWFnZU1vZGFsRXZlbnQgZXZlbnQgcGF5bG9hZFxuICAgKi9cbiAgb25DaGFuZ2VDdXJyZW50SW1hZ2UoZXZlbnQ6IEltYWdlTW9kYWxFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IG5ld0luZGV4OiBudW1iZXIgPSBldmVudC5yZXN1bHQgYXMgbnVtYmVyO1xuICAgIGlmIChuZXdJbmRleCA8IDAgfHwgbmV3SW5kZXggPj0gdGhpcy5pbWFnZXMubGVuZ3RoKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5jdXJyZW50SW1hZ2UgPSB0aGlzLmltYWdlc1tuZXdJbmRleF07XG5cbiAgICAvLyBlbWl0IGN1cnJlbnQgdmlzaWJsZSBpbWFnZSBpbmRleFxuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0U2hvdyhuZXcgSW1hZ2VNb2RhbEV2ZW50KHRoaXMuaWQsIGV2ZW50LmFjdGlvbiwgbmV3SW5kZXggKyAxKSk7XG5cbiAgICAvLyBlbWl0IGZpcnN0L2xhc3QgZXZlbnQgYmFzZWQgb24gbmV3SW5kZXggdmFsdWVcbiAgICB0aGlzLmVtaXRCb3VuZGFyeUV2ZW50KGV2ZW50LmFjdGlvbiwgbmV3SW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgd2hlbiB5b3UgY2xpY2sgJ291dHNpZGUnIChpLmUuIG9uIHRoZSBzZW1pLXRyYW5zcGFyZW50IGJhY2tncm91bmQpXG4gICAqIHRvIGNsb3NlIHRoZSBtb2RhbCBnYWxsZXJ5IGlmIGBlbmFibGVDbG9zZU91dHNpZGVgIGlzIHRydWUuXG4gICAqIEBwYXJhbSBldmVudCBib29sZWFuIHRoYXQgaXMgdHJ1ZSB0byBjbG9zZSB0aGUgbW9kYWwgZ2FsbGVyeSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBvbkNsaWNrT3V0c2lkZShldmVudDogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmIChldmVudCAmJiB0aGlzLmVuYWJsZUNsb3NlT3V0c2lkZSkge1xuICAgICAgdGhpcy5jbG9zZUdhbGxlcnkoQWN0aW9uLkNMSUNLLCB0cnVlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCB3aGVuIGFuIGltYWdlIGlzIGxvYWRlZCBhbmQgdGhlIGxvYWRpbmcgc3Bpbm5lciBoYXMgZ29uZS5cbiAgICogSXQgc2V0cyB0aGUgcHJldmlvdXNseUxvYWRlZCBmbGFnIGluc2lkZSB0aGUgSW1hZ2UgdG8gaGlkZSBsb2FkaW5nIHNwaW5uZXIgd2hlbiBkaXNwbGF5ZWQgYWdhaW4uXG4gICAqIEBwYXJhbSBldmVudCBJbWFnZUxvYWRFdmVudCBldmVudCBwYXlsb2FkXG4gICAqL1xuICBvbkltYWdlTG9hZChldmVudDogSW1hZ2VMb2FkRXZlbnQpOiB2b2lkIHtcbiAgICAvLyBzZXRzIGFzIHByZXZpb3VzbHkgbG9hZGVkIHRoZSBpbWFnZSB3aXRoIGluZGV4IHNwZWNpZmllZCBieSBgZXZlbnQuc3RhdHVzYFxuICAgIHRoaXMuaW1hZ2VzID0gdGhpcy5pbWFnZXMubWFwKChpbWc6IEludGVybmFsTGliSW1hZ2UpID0+IHtcbiAgICAgIGlmIChpbWcgJiYgaW1nLmlkID09PSBldmVudC5pZCkge1xuICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgaW1nLCB7IHByZXZpb3VzbHlMb2FkZWQ6IGV2ZW50LnN0YXR1cyB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBpbWc7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCB3aGVuIGEgZG90IGlzIGNsaWNrZWQgYW5kIHVzZWQgdG8gdXBkYXRlIHRoZSBjdXJyZW50IGltYWdlLlxuICAgKiBAcGFyYW0gaW5kZXggbnVtYmVyIGluZGV4IG9mIHRoZSBjbGlja2VkIGRvdFxuICAgKi9cbiAgb25DbGlja0RvdChpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50SW1hZ2UgPSB0aGlzLmltYWdlc1tpbmRleF07XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCB3aGVuIGFuIGltYWdlIHByZXZpZXcgaXMgY2xpY2tlZCBhbmQgdXNlZCB0byB1cGRhdGUgdGhlIGN1cnJlbnQgaW1hZ2UuXG4gICAqIEBwYXJhbSBldmVudCBJbWFnZU1vZGFsRXZlbnQgcHJldmlldyBpbWFnZVxuICAgKi9cbiAgb25DbGlja1ByZXZpZXcoZXZlbnQ6IEltYWdlTW9kYWxFdmVudCk6IHZvaWQge1xuICAgIHRoaXMub25DaGFuZ2VDdXJyZW50SW1hZ2UoZXZlbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0byBjbGVhbnVwIHJlc291cmNlcy5cbiAgICogVGhpcyBpcyBhbiBhbmd1bGFyIGxpZmVjeWNsZSBob29rIHRoYXQgaXMgY2FsbGVkIHdoZW4gdGhpcyBjb21wb25lbnQgaXMgZGVzdHJveWVkLlxuICAgKi9cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgaWYgKHRoaXMudXBkYXRlSW1hZ2VzU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLnVwZGF0ZUltYWdlc1N1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIH1cbiAgICB0aGlzLmlkVmFsaWRhdG9yU2VydmljZS5yZW1vdmUodGhpcy5pZCk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIHRvIGRvd25sb2FkIHRoZSBjdXJyZW50IGltYWdlLCBvbmx5IGlmIGBkb3dubG9hZGFibGVgIGlzIHRydWUuXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGRvd25sb2FkSW1hZ2UoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaWQgPT09IG51bGwgfHwgdGhpcy5pZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBpZCBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgY29uc3QgbGliQ29uZmlnOiBMaWJDb25maWcgfCB1bmRlZmluZWQgPSB0aGlzLmNvbmZpZ1NlcnZpY2UuZ2V0Q29uZmlnKHRoaXMuaWQpO1xuICAgIGlmICghbGliQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBsaWJDb25maWcgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuXG4gICAgY29uc3QgY3VycmVudEltYWdlQ29uZmlnOiBDdXJyZW50SW1hZ2VDb25maWcgfCB1bmRlZmluZWQgPSBsaWJDb25maWcuY3VycmVudEltYWdlQ29uZmlnO1xuICAgIGlmIChjdXJyZW50SW1hZ2VDb25maWcgJiYgIWN1cnJlbnRJbWFnZUNvbmZpZy5kb3dubG9hZGFibGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5kb3dubG9hZEltYWdlQWxsQnJvd3NlcnMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gY29udmVydCBhIGJhc2U2NCB0byBhIEJsb2JcbiAgICogQHBhcmFtIGJhc2U2NERhdGEgc3RyaW5nIHdpdGggYmFzZTY0IGRhdGFcbiAgICogQHBhcmFtIGNvbnRlbnRUeXBlIHN0cmluZyB3aXRoIHRoZSBNSU1FIHR5cGVcbiAgICogQHJldHVybiBCbG9iIGNvbnZlcnRlZCBmcm9tIHRoZSBpbnB1dCBiYXNlNjREYXRhXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGJhc2U2NHRvQmxvYihiYXNlNjREYXRhOiBzdHJpbmcsIGNvbnRlbnRUeXBlOiBzdHJpbmcgPSAnJyk6IEJsb2Ige1xuICAgIGNvbnN0IHNsaWNlU2l6ZSA9IDEwMjQ7XG4gICAgY29uc3QgYnl0ZUNoYXJhY3RlcnM6IHN0cmluZyA9IGF0b2IoYmFzZTY0RGF0YSk7XG4gICAgY29uc3QgYnl0ZXNMZW5ndGg6IG51bWJlciA9IGJ5dGVDaGFyYWN0ZXJzLmxlbmd0aDtcbiAgICBjb25zdCBzbGljZXNDb3VudDogbnVtYmVyID0gTWF0aC5jZWlsKGJ5dGVzTGVuZ3RoIC8gc2xpY2VTaXplKTtcbiAgICBjb25zdCBieXRlQXJyYXlzOiBBcnJheTxVaW50OEFycmF5PiA9IG5ldyBBcnJheShzbGljZXNDb3VudCk7XG4gICAgZm9yIChsZXQgc2xpY2VJbmRleCA9IDA7IHNsaWNlSW5kZXggPCBzbGljZXNDb3VudDsgKytzbGljZUluZGV4KSB7XG4gICAgICBjb25zdCBiZWdpbjogbnVtYmVyID0gc2xpY2VJbmRleCAqIHNsaWNlU2l6ZTtcbiAgICAgIGNvbnN0IGVuZDogbnVtYmVyID0gTWF0aC5taW4oYmVnaW4gKyBzbGljZVNpemUsIGJ5dGVzTGVuZ3RoKTtcbiAgICAgIGNvbnN0IGJ5dGVzOiBBcnJheTxudW1iZXI+ID0gbmV3IEFycmF5KGVuZCAtIGJlZ2luKTtcbiAgICAgIGZvciAobGV0IG9mZnNldCA9IGJlZ2luLCBpID0gMDsgb2Zmc2V0IDwgZW5kOyArK2ksICsrb2Zmc2V0KSB7XG4gICAgICAgIGJ5dGVzW2ldID0gYnl0ZUNoYXJhY3RlcnNbb2Zmc2V0XS5jaGFyQ29kZUF0KDApO1xuICAgICAgfVxuICAgICAgYnl0ZUFycmF5c1tzbGljZUluZGV4XSA9IG5ldyBVaW50OEFycmF5KGJ5dGVzKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBCbG9iKGJ5dGVBcnJheXMsIHsgdHlwZTogY29udGVudFR5cGUgfSk7XG4gIH1cblxuICAvKipcbiAgICogUHJpdmF0ZSBtZXRob2QgdG8gZG93bmxvYWQgdGhlIGN1cnJlbnQgaW1hZ2UgZm9yIGFsbCBicm93c2Vycy5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgZG93bmxvYWRJbWFnZUFsbEJyb3dzZXJzKCk6IHZvaWQge1xuICAgIGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgbGV0IGlzQmFzZTY0ID0gZmFsc2U7XG4gICAgbGV0IGltZzogc3RyaW5nO1xuICAgIC8vIGNvbnZlcnQgYSBTYWZlUmVzb3VyY2VVcmwgdG8gYSBzdHJpbmdcbiAgICBpZiAodHlwZW9mIHRoaXMuY3VycmVudEltYWdlLm1vZGFsLmltZyA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGltZyA9IHRoaXMuY3VycmVudEltYWdlLm1vZGFsLmltZyBhcyBzdHJpbmc7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGlmIGl0J3MgYSBTYWZlUmVzb3VyY2VVcmxcbiAgICAgIGltZyA9IHRoaXMuc2FuaXRpemVyLnNhbml0aXplKFNlY3VyaXR5Q29udGV4dC5SRVNPVVJDRV9VUkwsIHRoaXMuY3VycmVudEltYWdlLm1vZGFsLmltZykgYXMgc3RyaW5nO1xuICAgIH1cbiAgICBpZiAoaW1nLmluY2x1ZGVzKCdkYXRhOmltYWdlLycpIHx8IGltZy5pbmNsdWRlcygnO2Jhc2U2NCwnKSkge1xuICAgICAgY29uc3QgZXh0ZW5zaW9uOiBzdHJpbmcgPSBpbWcucmVwbGFjZSgnZGF0YTppbWFnZS8nLCAnJykuc3BsaXQoJztiYXNlNjQsJylbMF07XG4gICAgICBjb25zdCBwdXJlQmFzZTY0OiBzdHJpbmcgPSBpbWcuc3BsaXQoJztiYXNlNjQsJylbMV07XG4gICAgICBjb25zdCBibG9iOiBCbG9iID0gdGhpcy5iYXNlNjR0b0Jsb2IocHVyZUJhc2U2NCwgJ2ltYWdlLycgKyBleHRlbnNpb24pO1xuICAgICAgbGluay5ocmVmID0gVVJMLmNyZWF0ZU9iamVjdFVSTChibG9iKTtcbiAgICAgIGlzQmFzZTY0ID0gdHJ1ZTtcbiAgICAgIGxpbmsuc2V0QXR0cmlidXRlKCdkb3dubG9hZCcsIHRoaXMuZ2V0RmlsZU5hbWUodGhpcy5jdXJyZW50SW1hZ2UsIGlzQmFzZTY0LCBleHRlbnNpb24pKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbGluay5ocmVmID0gaW1nO1xuICAgICAgbGluay5zZXRBdHRyaWJ1dGUoJ2Rvd25sb2FkJywgdGhpcy5nZXRGaWxlTmFtZSh0aGlzLmN1cnJlbnRJbWFnZSwgaXNCYXNlNjQpKTtcbiAgICB9XG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChsaW5rKTtcbiAgICBsaW5rLmNsaWNrKCk7XG4gICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChsaW5rKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcml2YXRlIG1ldGhvZCB0byBnZXQgdGhlIGBCdXR0b25FdmVudGAgdG8gZW1pdCwgbWVyZ2luZyB0aGUgaW5wdXQgYEJ1dHRvbkV2ZW50YFxuICAgKiB3aXRoIHRoZSBjdXJyZW50IGltYWdlLlxuICAgKiBAcGFyYW0gZXZlbnQgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZCB0byByZXR1cm5cbiAgICogQHJldHVybnMgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZCB3aXRoIHRoZSBjdXJyZW50IGltYWdlIGluY2x1ZGVkXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGdldEJ1dHRvbkV2ZW50VG9FbWl0KGV2ZW50OiBCdXR0b25FdmVudCk6IEJ1dHRvbkV2ZW50IHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihldmVudCwgeyBpbWFnZTogdGhpcy5jdXJyZW50SW1hZ2UgfSk7XG4gIH1cblxuICAvKipcbiAgICogUHJpdmF0ZSBtZXRob2QgdG8gZ2V0IHRoZSBmaWxlIG5hbWUgZnJvbSBhbiBpbnB1dCBwYXRoLlxuICAgKiBUaGlzIGlzIHVzZWQgZWl0aGVyIHRvIGdldCB0aGUgaW1hZ2UncyBuYW1lIGZyb20gaXRzIHBhdGggb3IgZnJvbSB0aGUgSW1hZ2UgaXRzZWxmLFxuICAgKiBpZiBzcGVjaWZpZWQgYXMgJ2Rvd25sb2FkRmlsZU5hbWUnIGJ5IHRoZSB1c2VyLlxuICAgKiBAcGFyYW0gaW1hZ2UgSW1hZ2UgaW1hZ2UgdG8gZXh0cmFjdCBpdHMgZmlsZSBuYW1lXG4gICAqIEBwYXJhbSBpc0Jhc2U2NCBib29sZWFuIHRvIHNldCBpZiB0aGUgaW1hZ2UgaXMgYSBiYXNlNjQgZmlsZSBvciBub3QuIEZhbHNlIGJ5IGRlZmF1bHQuXG4gICAqIEBwYXJhbSBiYXNlNjRFeHRlbnNpb24gc3RyaW5nIHRvIGZvcmNlIHRoZSBleHRlbnNpb24gb2YgdGhlIGJhc2U2NCBpbWFnZS4gRW1wdHkgc3RyaW5nIGJ5IGRlZmF1bHQuXG4gICAqIEByZXR1cm5zIHN0cmluZyBzdHJpbmcgZmlsZSBuYW1lIG9mIHRoZSBpbnB1dCBpbWFnZS5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgZ2V0RmlsZU5hbWUoaW1hZ2U6IEltYWdlLCBpc0Jhc2U2NDogYm9vbGVhbiA9IGZhbHNlLCBiYXNlNjRFeHRlbnNpb246IHN0cmluZyA9ICcnKTogc3RyaW5nIHtcbiAgICBpZiAoIWltYWdlLm1vZGFsLmRvd25sb2FkRmlsZU5hbWUgfHwgaW1hZ2UubW9kYWwuZG93bmxvYWRGaWxlTmFtZS5sZW5ndGggPT09IDApIHtcbiAgICAgIGlmIChpc0Jhc2U2NCkge1xuICAgICAgICByZXR1cm4gYEltYWdlLSR7aW1hZ2UuaWR9LiR7YmFzZTY0RXh0ZW5zaW9uICE9PSAnJyA/IGJhc2U2NEV4dGVuc2lvbiA6ICdwbmcnfWA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gKGltYWdlLm1vZGFsLmltZyBhcyBzdHJpbmcpLnJlcGxhY2UoL14uKltcXFxcXFwvXS8sICcnKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGltYWdlLm1vZGFsLmRvd25sb2FkRmlsZU5hbWU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFByaXZhdGUgbWV0aG9kIHRvIGluaXRpYWxpemUgYGltYWdlc2AgYXMgYXJyYXkgb2YgYEltYWdlYHMuXG4gICAqIEFsc28sIGl0IHdpbGwgZW1pdCBJbWFnZU1vZGFsRXZlbnQgdG8gc2F5IHRoYXQgaW1hZ2VzIGFyZSBsb2FkZWQuXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGluaXRJbWFnZXMoKTogdm9pZCB7XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRIYXNEYXRhKG5ldyBJbWFnZU1vZGFsRXZlbnQodGhpcy5pZCwgQWN0aW9uLkxPQUQsIHRydWUpKTtcblxuICAgIGNvbnN0IGN1cnJlbnRJbmRleDogbnVtYmVyID0gdGhpcy5pbWFnZXMuaW5kZXhPZih0aGlzLmN1cnJlbnRJbWFnZSk7XG4gICAgLy8gZW1pdCBhIG5ldyBJbWFnZU1vZGFsRXZlbnQgd2l0aCB0aGUgaW5kZXggb2YgdGhlIGN1cnJlbnQgaW1hZ2VcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdFNob3cobmV3IEltYWdlTW9kYWxFdmVudCh0aGlzLmlkLCBBY3Rpb24uTE9BRCwgY3VycmVudEluZGV4ICsgMSkpO1xuXG4gICAgLy8gZW1pdCBmaXJzdC9sYXN0IGV2ZW50IGJhc2VkIG9uIG5ld0luZGV4IHZhbHVlXG4gICAgdGhpcy5lbWl0Qm91bmRhcnlFdmVudChBY3Rpb24uTk9STUFMLCBjdXJyZW50SW5kZXgpO1xuXG4gICAgdGhpcy5zaG93R2FsbGVyeSA9IHRoaXMuaW1hZ2VzLmxlbmd0aCA+IDA7XG4gIH1cblxuICAvKipcbiAgICogUHJpdmF0ZSBtZXRob2QgdG8gZW1pdCBldmVudHMgd2hlbiBlaXRoZXIgdGhlIGxhc3Qgb3IgdGhlIGZpcnN0IGltYWdlIGFyZSB2aXNpYmxlLlxuICAgKiBAcGFyYW0gYWN0aW9uIEFjdGlvbiBFbnVtIG9mIHR5cGUgQWN0aW9uIHRoYXQgcmVwcmVzZW50cyB0aGUgc291cmNlIG9mIHRoZSBldmVudCB0aGF0IGNoYW5nZWQgdGhlXG4gICAqICBjdXJyZW50IGltYWdlIHRvIHRoZSBmaXJzdCBvbmUgb3IgdGhlIGxhc3Qgb25lLlxuICAgKiBAcGFyYW0gaW5kZXhUb0NoZWNrIG51bWJlciBpcyB0aGUgaW5kZXggbnVtYmVyIG9mIHRoZSBpbWFnZSAodGhlIGZpcnN0IG9yIHRoZSBsYXN0IG9uZSkuXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGVtaXRCb3VuZGFyeUV2ZW50KGFjdGlvbjogQWN0aW9uLCBpbmRleFRvQ2hlY2s6IG51bWJlcik6IHZvaWQge1xuICAgIC8vIHRvIGVtaXQgZmlyc3QvbGFzdCBldmVudFxuICAgIHN3aXRjaCAoaW5kZXhUb0NoZWNrKSB7XG4gICAgICBjYXNlIDA6XG4gICAgICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0Rmlyc3RJbWFnZShuZXcgSW1hZ2VNb2RhbEV2ZW50KHRoaXMuaWQsIGFjdGlvbiwgdHJ1ZSkpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdGhpcy5pbWFnZXMubGVuZ3RoIC0gMTpcbiAgICAgICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRMYXN0SW1hZ2UobmV3IEltYWdlTW9kYWxFdmVudCh0aGlzLmlkLCBhY3Rpb24sIHRydWUpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG59XG4iLCI8ZGl2IGlkPVwibW9kYWwtZ2FsbGVyeS13cmFwcGVyXCJcbiAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJhY2Nlc3NpYmlsaXR5Q29uZmlnLm1vZGFsR2FsbGVyeUNvbnRlbnRBcmlhTGFiZWxcIlxuICAgICBbdGl0bGVdPVwiYWNjZXNzaWJpbGl0eUNvbmZpZy5tb2RhbEdhbGxlcnlDb250ZW50VGl0bGVcIlxuICAgICBrc0NsaWNrT3V0c2lkZSBbY2xpY2tPdXRzaWRlRW5hYmxlXT1cImVuYWJsZUNsb3NlT3V0c2lkZVwiXG4gICAgIChjbGlja091dHNpZGUpPVwib25DbGlja091dHNpZGUoJGV2ZW50KVwiPlxuXG4gIDxkaXYgaWQ9XCJmbGV4LW1pbi1oZWlnaHQtaWUtZml4XCI+XG4gICAgPGRpdiBpZD1cIm1vZGFsLWdhbGxlcnktY29udGFpbmVyXCI+XG5cbiAgICAgIDxrcy11cHBlci1idXR0b25zIFtpZF09XCJpZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbY3VycmVudEltYWdlXT1cImN1cnJlbnRJbWFnZVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAoZGVsZXRlKT1cIm9uRGVsZXRlKCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKG5hdmlnYXRlKT1cIm9uTmF2aWdhdGUoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAoZG93bmxvYWQpPVwib25Eb3dubG9hZCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChjbG9zZUJ1dHRvbik9XCJvbkNsb3NlR2FsbGVyeUJ1dHRvbigkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChmdWxsc2NyZWVuKT1cIm9uRnVsbFNjcmVlbigkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChjdXN0b21FbWl0KT1cIm9uQ3VzdG9tRW1pdCgkZXZlbnQpXCI+PC9rcy11cHBlci1idXR0b25zPlxuXG4gICAgICA8a3MtY3VycmVudC1pbWFnZSBbaWRdPVwiaWRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgW2ltYWdlc109XCJpbWFnZXNcIlxuICAgICAgICAgICAgICAgICAgICAgICAgW2N1cnJlbnRJbWFnZV09XCJjdXJyZW50SW1hZ2VcIlxuICAgICAgICAgICAgICAgICAgICAgICAgW2lzT3Blbl09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChsb2FkSW1hZ2UpPVwib25JbWFnZUxvYWQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAoY2hhbmdlSW1hZ2UpPVwib25DaGFuZ2VDdXJyZW50SW1hZ2UoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAoY2xvc2VHYWxsZXJ5KT1cIm9uQ2xvc2VHYWxsZXJ5KCRldmVudClcIj48L2tzLWN1cnJlbnQtaW1hZ2U+XG5cbiAgICAgIDxkaXY+XG4gICAgICAgIDxrcy1kb3RzIFtpZF09XCJpZFwiXG4gICAgICAgICAgICAgICAgIFtpbWFnZXNdPVwiaW1hZ2VzXCJcbiAgICAgICAgICAgICAgICAgW2N1cnJlbnRJbWFnZV09XCJjdXJyZW50SW1hZ2VcIlxuICAgICAgICAgICAgICAgICBbZG90c0NvbmZpZ109XCJkb3RzQ29uZmlnXCJcbiAgICAgICAgICAgICAgICAgKGNsaWNrRG90KT1cIm9uQ2xpY2tEb3QoJGV2ZW50KVwiPjwva3MtZG90cz5cblxuICAgICAgICA8a3MtcHJldmlld3MgW2lkXT1cImlkXCJcbiAgICAgICAgICAgICAgICAgICAgIFtpbWFnZXNdPVwiaW1hZ2VzXCJcbiAgICAgICAgICAgICAgICAgICAgIFtjdXJyZW50SW1hZ2VdPVwiY3VycmVudEltYWdlXCJcbiAgICAgICAgICAgICAgICAgICAgIFtjdXN0b21UZW1wbGF0ZV09XCJjdXN0b21QcmV2aWV3c1RlbXBsYXRlXCJcbiAgICAgICAgICAgICAgICAgICAgIChjbGlja1ByZXZpZXcpPVwib25DbGlja1ByZXZpZXcoJGV2ZW50KVwiPjwva3MtcHJldmlld3M+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==
|