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