@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.
Files changed (102) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/CONTRIBUTING.md +3 -3
  3. package/README.md +22 -26
  4. package/{esm2015/ks89-angular-modal-gallery.js → esm2020/ks89-angular-modal-gallery.mjs} +0 -0
  5. package/{esm2015/lib/components/accessibility-default.js → esm2020/lib/components/accessibility-default.mjs} +0 -0
  6. package/{esm2015/lib/components/accessible.component.js → esm2020/lib/components/accessible.component.mjs} +6 -6
  7. package/esm2020/lib/components/carousel/carousel-previews/carousel-previews.component.mjs +462 -0
  8. package/esm2020/lib/components/carousel/carousel.component.mjs +747 -0
  9. package/{esm2015/lib/components/components.js → esm2020/lib/components/components.mjs} +0 -0
  10. package/esm2020/lib/components/current-image/current-image.component.mjs +616 -0
  11. package/esm2020/lib/components/current-image/loading-spinner/loading-spinner.component.mjs +80 -0
  12. package/esm2020/lib/components/dots/dots.component.mjs +127 -0
  13. package/{esm2015/lib/components/modal-gallery/modal-gallery-ref.js → esm2020/lib/components/modal-gallery/modal-gallery-ref.mjs} +0 -0
  14. package/esm2020/lib/components/modal-gallery/modal-gallery.component.mjs +524 -0
  15. package/esm2020/lib/components/modal-gallery/modal-gallery.service.mjs +187 -0
  16. package/{esm2015/lib/components/modal-gallery/modal-gallery.tokens.js → esm2020/lib/components/modal-gallery/modal-gallery.tokens.mjs} +0 -0
  17. package/esm2020/lib/components/plain-gallery/plain-gallery.component.mjs +249 -0
  18. package/esm2020/lib/components/previews/previews.component.mjs +337 -0
  19. package/{esm2015/lib/components/upper-buttons/upper-buttons-default.js → esm2020/lib/components/upper-buttons/upper-buttons-default.mjs} +0 -0
  20. package/esm2020/lib/components/upper-buttons/upper-buttons.component.mjs +249 -0
  21. package/{esm2015/lib/directives/a-tag-bg-image.directive.js → esm2020/lib/directives/a-tag-bg-image.directive.mjs} +3 -3
  22. package/{esm2015/lib/directives/click-outside.directive.js → esm2020/lib/directives/click-outside.directive.mjs} +3 -3
  23. package/{esm2015/lib/directives/description.directive.js → esm2020/lib/directives/description.directive.mjs} +3 -3
  24. package/{esm2015/lib/directives/direction.directive.js → esm2020/lib/directives/direction.directive.mjs} +3 -3
  25. package/{esm2015/lib/directives/directives.js → esm2020/lib/directives/directives.mjs} +0 -0
  26. package/{esm2015/lib/directives/fallback-image.directive.js → esm2020/lib/directives/fallback-image.directive.mjs} +3 -3
  27. package/{esm2015/lib/directives/keyboard-navigation.directive.js → esm2020/lib/directives/keyboard-navigation.directive.mjs} +5 -5
  28. package/{esm2015/lib/directives/margin.directive.js → esm2020/lib/directives/margin.directive.mjs} +3 -3
  29. package/{esm2015/lib/directives/max-size.directive.js → esm2020/lib/directives/max-size.directive.mjs} +3 -3
  30. package/{esm2015/lib/directives/size.directive.js → esm2020/lib/directives/size.directive.mjs} +3 -3
  31. package/{esm2015/lib/directives/wrap.directive.js → esm2020/lib/directives/wrap.directive.mjs} +3 -3
  32. package/{esm2015/lib/modal-gallery.module.js → esm2020/lib/modal-gallery.module.mjs} +7 -7
  33. package/{esm2015/lib/model/accessibility.interface.js → esm2020/lib/model/accessibility.interface.mjs} +0 -0
  34. package/{esm2015/lib/model/action.enum.js → esm2020/lib/model/action.enum.mjs} +0 -0
  35. package/{esm2015/lib/model/buttons-config.interface.js → esm2020/lib/model/buttons-config.interface.mjs} +0 -0
  36. package/{esm2015/lib/model/carousel-config.interface.js → esm2020/lib/model/carousel-config.interface.mjs} +1 -1
  37. package/{esm2015/lib/model/carousel-image-config.interface.js → esm2020/lib/model/carousel-image-config.interface.mjs} +0 -0
  38. package/{esm2015/lib/model/carousel-preview-config.interface.js → esm2020/lib/model/carousel-preview-config.interface.mjs} +0 -0
  39. package/{esm2015/lib/model/current-image-config.interface.js → esm2020/lib/model/current-image-config.interface.mjs} +0 -0
  40. package/{esm2015/lib/model/description.interface.js → esm2020/lib/model/description.interface.mjs} +0 -0
  41. package/{esm2015/lib/model/dots-config.interface.js → esm2020/lib/model/dots-config.interface.mjs} +0 -0
  42. package/{esm2015/lib/model/image-internal.class.js → esm2020/lib/model/image-internal.class.mjs} +0 -0
  43. package/{esm2015/lib/model/image.class.js → esm2020/lib/model/image.class.mjs} +0 -0
  44. package/{esm2015/lib/model/interaction-event.interface.js → esm2020/lib/model/interaction-event.interface.mjs} +0 -0
  45. package/{esm2015/lib/model/keyboard-config.interface.js → esm2020/lib/model/keyboard-config.interface.mjs} +1 -1
  46. package/{esm2015/lib/model/keyboard-service-config.interface.js → esm2020/lib/model/keyboard-service-config.interface.mjs} +0 -0
  47. package/esm2020/lib/model/keyboard.enum.mjs +35 -0
  48. package/{esm2015/lib/model/lib-config.interface.js → esm2020/lib/model/lib-config.interface.mjs} +1 -1
  49. package/{esm2015/lib/model/loading-config.interface.js → esm2020/lib/model/loading-config.interface.mjs} +0 -0
  50. package/{esm2015/lib/model/max-size.interface.js → esm2020/lib/model/max-size.interface.mjs} +0 -0
  51. package/{esm2015/lib/model/modal-gallery-config.interface.js → esm2020/lib/model/modal-gallery-config.interface.mjs} +1 -1
  52. package/esm2020/lib/model/plain-gallery-config.interface.mjs +55 -0
  53. package/{esm2015/lib/model/play-config.interface.js → esm2020/lib/model/play-config.interface.mjs} +0 -0
  54. package/{esm2015/lib/model/preview-config.interface.js → esm2020/lib/model/preview-config.interface.mjs} +0 -0
  55. package/{esm2015/lib/model/size.interface.js → esm2020/lib/model/size.interface.mjs} +0 -0
  56. package/{esm2015/lib/model/slide-config.interface.js → esm2020/lib/model/slide-config.interface.mjs} +0 -0
  57. package/esm2020/lib/services/config.service.mjs +396 -0
  58. package/{esm2015/lib/services/id-validator.service.js → esm2020/lib/services/id-validator.service.mjs} +3 -3
  59. package/{esm2015/lib/services/keyboard.service.js → esm2020/lib/services/keyboard.service.mjs} +3 -3
  60. package/{esm2015/lib/utils/image.util.js → esm2020/lib/utils/image.util.mjs} +0 -0
  61. package/esm2020/lib/utils/user-input.util.mjs +104 -0
  62. package/esm2020/public-api.mjs +42 -0
  63. package/fesm2015/ks89-angular-modal-gallery.mjs +5788 -0
  64. package/fesm2015/ks89-angular-modal-gallery.mjs.map +1 -0
  65. package/{fesm2015/ks89-angular-modal-gallery.js → fesm2020/ks89-angular-modal-gallery.mjs} +270 -432
  66. package/fesm2020/ks89-angular-modal-gallery.mjs.map +1 -0
  67. package/lib/components/accessible.component.d.ts +2 -2
  68. package/lib/components/carousel/carousel-previews/carousel-previews.component.d.ts +0 -7
  69. package/lib/components/carousel/carousel.component.d.ts +25 -67
  70. package/lib/components/current-image/current-image.component.d.ts +3 -3
  71. package/lib/components/modal-gallery/modal-gallery.component.d.ts +8 -21
  72. package/lib/components/modal-gallery/modal-gallery.service.d.ts +1 -0
  73. package/lib/components/plain-gallery/plain-gallery.component.d.ts +6 -10
  74. package/lib/components/previews/previews.component.d.ts +9 -2
  75. package/lib/directives/keyboard-navigation.directive.d.ts +1 -1
  76. package/lib/model/carousel-config.interface.d.ts +0 -1
  77. package/lib/model/keyboard-config.interface.d.ts +4 -4
  78. package/lib/model/keyboard.enum.d.ts +11 -8
  79. package/lib/model/lib-config.interface.d.ts +20 -7
  80. package/lib/model/modal-gallery-config.interface.d.ts +10 -2
  81. package/lib/model/plain-gallery-config.interface.d.ts +1 -9
  82. package/lib/utils/user-input.util.d.ts +35 -26
  83. package/package.json +27 -14
  84. package/public-api.d.ts +2 -2
  85. package/bundles/ks89-angular-modal-gallery.umd.js +0 -6221
  86. package/bundles/ks89-angular-modal-gallery.umd.js.map +0 -1
  87. package/esm2015/lib/components/carousel/carousel-previews/carousel-previews.component.js +0 -480
  88. package/esm2015/lib/components/carousel/carousel.component.js +0 -800
  89. package/esm2015/lib/components/current-image/current-image.component.js +0 -621
  90. package/esm2015/lib/components/current-image/loading-spinner/loading-spinner.component.js +0 -93
  91. package/esm2015/lib/components/dots/dots.component.js +0 -132
  92. package/esm2015/lib/components/modal-gallery/modal-gallery.component.js +0 -576
  93. package/esm2015/lib/components/modal-gallery/modal-gallery.service.js +0 -186
  94. package/esm2015/lib/components/plain-gallery/plain-gallery.component.js +0 -259
  95. package/esm2015/lib/components/previews/previews.component.js +0 -337
  96. package/esm2015/lib/components/upper-buttons/upper-buttons.component.js +0 -254
  97. package/esm2015/lib/model/keyboard.enum.js +0 -35
  98. package/esm2015/lib/model/plain-gallery-config.interface.js +0 -64
  99. package/esm2015/lib/services/config.service.js +0 -395
  100. package/esm2015/lib/utils/user-input.util.js +0 -95
  101. package/esm2015/public-api.js +0 -42
  102. package/fesm2015/ks89-angular-modal-gallery.js.map +0 -1
@@ -1,576 +0,0 @@
1
- import { Component, HostListener, Inject, PLATFORM_ID, SecurityContext, ViewChild } from '@angular/core';
2
- import { isPlatformBrowser, isPlatformServer } 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.configService.setConfig(this.id, this.libConfig);
51
- this.updateImagesSubscription = this.modalGalleryService.updateImages$.subscribe((images) => {
52
- this.images = images.map((image) => {
53
- const newImage = Object.assign({}, image, { previouslyLoaded: false });
54
- return newImage;
55
- });
56
- this.initImages();
57
- this.images.forEach((image) => {
58
- if (image.id === this.currentImage.id) {
59
- this.currentImage = image;
60
- }
61
- });
62
- this.changeDetectorRef.markForCheck();
63
- });
64
- }
65
- /**
66
- * HostListener to catch browser's back button and destroy the gallery.
67
- * This prevents weired behaviour about scrolling.
68
- * Added to fix this issue: https://github.com/Ks89/angular-modal-gallery/issues/159
69
- */
70
- onPopState(e) {
71
- this.closeGallery();
72
- }
73
- /**
74
- * Method ´ngOnInit´ to init images calling `initImages()`.
75
- * This is an Angular's lifecycle hook, so its called automatically by Angular itself.
76
- * In particular, it's called only one time!!!
77
- */
78
- ngOnInit() {
79
- this.idValidatorService.checkAndAdd(this.id);
80
- // id is a mandatory input and must a number > 0
81
- if ((!this.id && this.id !== 0) || this.id < 0) {
82
- throw new Error(`'[id]="a number >= 0"' is a mandatory input in angular-modal-gallery.` +
83
- `If you are using multiple instances of this library, please be sure to use different ids`);
84
- }
85
- const libConfig = this.configService.getConfig(this.id);
86
- if (!libConfig || !libConfig.dotsConfig) {
87
- throw new Error('Internal library error - libConfig and dotsConfig must be defined');
88
- }
89
- this.dotsConfig = libConfig.dotsConfig;
90
- // call initImages to init images and to emit `hasData` event
91
- this.initImages();
92
- this.showModalGallery();
93
- }
94
- /**
95
- * Method called by custom upper buttons.
96
- * @param event ButtonEvent event payload
97
- */
98
- onCustomEmit(event) {
99
- const eventToEmit = this.getButtonEventToEmit(event);
100
- this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
101
- this.modalGalleryService.emitButtonAfterHook(eventToEmit);
102
- }
103
- /**
104
- * Method called by the full-screen upper button.
105
- * @param event ButtonEvent event payload
106
- */
107
- onFullScreen(event) {
108
- const eventToEmit = this.getButtonEventToEmit(event);
109
- this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
110
- // tslint:disable-next-line:no-any
111
- const doc = document;
112
- // tslint:disable-next-line:no-any
113
- const docEl = document.documentElement;
114
- const fullscreenDisabled = !doc.fullscreenElement && !doc.webkitFullscreenElement && !doc.mozFullScreenElement && !doc.msFullscreenElement;
115
- // TODO add .then to promises, for instance requestFullscreen() returns a Promise
116
- if (fullscreenDisabled) {
117
- if (docEl.requestFullscreen) {
118
- docEl.requestFullscreen();
119
- }
120
- else if (docEl.webkitRequestFullscreen) {
121
- docEl.webkitRequestFullscreen();
122
- }
123
- else if (docEl.mozRequestFullScreen) {
124
- docEl.mozRequestFullScreen();
125
- }
126
- else if (docEl.msRequestFullscreen) {
127
- docEl.msRequestFullscreen();
128
- }
129
- }
130
- else {
131
- if (doc.exitFullscreen) {
132
- doc.exitFullscreen();
133
- }
134
- else if (doc.msExitFullscreen) {
135
- doc.msExitFullscreen();
136
- }
137
- else if (doc.mozCancelFullScreen) {
138
- doc.mozCancelFullScreen();
139
- }
140
- else if (doc.webkitExitFullscreen) {
141
- doc.webkitExitFullscreen();
142
- }
143
- }
144
- this.modalGalleryService.emitButtonAfterHook(eventToEmit);
145
- }
146
- /**
147
- * Method called by the delete upper button.
148
- * @param event ButtonEvent event payload
149
- */
150
- onDelete(event) {
151
- const eventToEmit = this.getButtonEventToEmit(event);
152
- this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
153
- if (this.images.length === 1) {
154
- this.closeGallery();
155
- }
156
- if (!this.currentImageComponent) {
157
- throw new Error('currentImageComponent must be defined');
158
- }
159
- const imageIndexToDelete = this.currentImageComponent.getIndexToDelete(event.image);
160
- if (imageIndexToDelete === this.images.length - 1) {
161
- // last image
162
- this.currentImageComponent.prevImage();
163
- }
164
- else {
165
- this.currentImageComponent.nextImage();
166
- }
167
- this.modalGalleryService.emitButtonAfterHook(eventToEmit);
168
- }
169
- /**
170
- * Method called by the navigate upper button.
171
- * @param event ButtonEvent event payload
172
- */
173
- onNavigate(event) {
174
- const eventToEmit = this.getButtonEventToEmit(event);
175
- this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
176
- // To support SSR
177
- if (isPlatformBrowser(this.platformId)) {
178
- if (eventToEmit.image && eventToEmit.image.modal.extUrl) {
179
- // where I should open this link? The current tab or another one?
180
- if (eventToEmit.button && eventToEmit.button.extUrlInNewTab) {
181
- // in this case I should use target _blank to open the url in a new tab, however these is a security issue.
182
- // Prevent Reverse Tabnabbing's attacks (https://www.owasp.org/index.php/Reverse_Tabnabbing)
183
- // Some resources:
184
- // - https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Tabnabbing
185
- // - https://medium.com/@jitbit/target-blank-the-most-underestimated-vulnerability-ever-96e328301f4c
186
- // - https://developer.mozilla.org/en-US/docs/Web/API/Window/open
187
- const newWindow = window.open(eventToEmit.image.modal.extUrl, 'noopener,noreferrer,');
188
- // it returns null if the call failed, so I have to do this check
189
- if (newWindow) {
190
- newWindow.opener = null; // required to prevent security issues
191
- // emit only in case of success
192
- this.modalGalleryService.emitButtonAfterHook(eventToEmit);
193
- }
194
- }
195
- else {
196
- this.updateLocationHref(eventToEmit.image.modal.extUrl);
197
- // emit only in case of success
198
- this.modalGalleryService.emitButtonAfterHook(eventToEmit);
199
- }
200
- }
201
- }
202
- }
203
- /**
204
- * This method is defined to be spied and replaced in unit testing with a fake method call.
205
- * It must be public to be able to use jasmine spyOn method.
206
- * @param newHref string new url
207
- */
208
- updateLocationHref(newHref) {
209
- window.location.href = newHref;
210
- }
211
- /**
212
- * Method called by the download upper button.
213
- * @param event ButtonEvent event payload
214
- */
215
- onDownload(event) {
216
- const eventToEmit = this.getButtonEventToEmit(event);
217
- this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
218
- this.downloadImage();
219
- this.modalGalleryService.emitButtonAfterHook(eventToEmit);
220
- }
221
- /**
222
- * Method called by the close upper button.
223
- * @param event ButtonEvent event payload
224
- * @param action Action that triggered the close method. `Action.NORMAL` by default
225
- */
226
- onCloseGalleryButton(event, action = Action.NORMAL) {
227
- const eventToEmit = this.getButtonEventToEmit(event);
228
- this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
229
- this.closeGallery(action, false);
230
- this.modalGalleryService.emitButtonAfterHook(eventToEmit);
231
- }
232
- /**
233
- * Method called by CurrentImageComponent and triggered via KeyboardService.
234
- * @param event ImageModalEvent event payload
235
- * @param action Action that triggered the close method. `Action.NORMAL` by default
236
- */
237
- onCloseGallery(event, action = Action.NORMAL) {
238
- // remap ImageModalEvent to ButtonEvent
239
- const buttonEvent = {
240
- button: {
241
- type: ButtonType.CLOSE
242
- },
243
- image: null,
244
- action: event.action,
245
- galleryId: event.galleryId
246
- };
247
- this.modalGalleryService.emitButtonBeforeHook(buttonEvent);
248
- this.closeGallery(action, false);
249
- this.modalGalleryService.emitButtonAfterHook(buttonEvent);
250
- }
251
- /**
252
- * Method to close the modal gallery specifying the action.
253
- * It also reset the `keyboardService` to prevent multiple listeners.
254
- * @param action Action action type. `Action.NORMAL` by default
255
- * @param clickOutside boolean that is true if called clicking on the modal background. False by default.
256
- * @param isCalledByService boolean isCalledByService is true if called by gallery.service, otherwise false. False by default.
257
- */
258
- closeGallery(action = Action.NORMAL, clickOutside = false, isCalledByService = false) {
259
- const libConfig = this.configService.getConfig(this.id);
260
- if (!libConfig) {
261
- throw new Error('Internal library error - libConfig must be defined');
262
- }
263
- this.modalGalleryService.emitClose(new ImageModalEvent(this.id, action, true));
264
- this.keyboardService.reset(libConfig);
265
- this.modalGalleryService.close(this.id, clickOutside);
266
- if (isCalledByService) {
267
- // the following is required, otherwise the view will not be updated
268
- // this happens only if called by gallery.service
269
- this.changeDetectorRef.markForCheck();
270
- }
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 first/last event based on newIndex value
283
- this.emitBoundaryEvent(event.action, newIndex);
284
- // emit current visible image index
285
- this.modalGalleryService.emitShow(new ImageModalEvent(this.id, event.action, newIndex + 1));
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. In fact, this will reset keyboard's service.
327
- * This is an Angular's lifecycle hook that is called when this component is destroyed.
328
- */
329
- ngOnDestroy() {
330
- if (this.keyboardService) {
331
- const libConfig = this.configService.getConfig(this.id);
332
- if (this.id && libConfig) {
333
- this.keyboardService.reset(libConfig);
334
- }
335
- }
336
- if (this.updateImagesSubscription) {
337
- this.updateImagesSubscription.unsubscribe();
338
- }
339
- this.idValidatorService.remove(this.id);
340
- }
341
- /**
342
- * Method to show the modal gallery displaying the currentImage.
343
- * It will also register a new `keyboardService` to catch keyboard's events to download the current
344
- * image with keyboard's shortcuts. This service, will be removed either when modal gallery component
345
- * will be destroyed or when the gallery is closed invoking the `closeGallery` method.
346
- * @private
347
- */
348
- showModalGallery() {
349
- if (this.id === null || this.id === undefined) {
350
- throw new Error('Internal library error - id must be defined');
351
- }
352
- const libConfig = this.configService.getConfig(this.id);
353
- if (!libConfig) {
354
- throw new Error('Internal library error - libConfig must be defined');
355
- }
356
- this.keyboardService.init(libConfig).then(() => {
357
- this.keyboardService.add((event, combo) => {
358
- if (event.preventDefault) {
359
- event.preventDefault();
360
- }
361
- else {
362
- // internet explorer
363
- event.returnValue = false;
364
- }
365
- this.downloadImage();
366
- }, libConfig);
367
- const currentIndex = this.images.indexOf(this.currentImage);
368
- // emit a new ImageModalEvent with the index of the current image
369
- this.modalGalleryService.emitShow(new ImageModalEvent(this.id, Action.LOAD, currentIndex + 1));
370
- this.changeDetectorRef.markForCheck();
371
- });
372
- }
373
- /**
374
- * Method to download the current image, only if `downloadable` is true.
375
- * It contains also a logic to enable downloading features also for IE11.
376
- * @private
377
- */
378
- downloadImage() {
379
- if (this.id === null || this.id === undefined) {
380
- throw new Error('Internal library error - id must be defined');
381
- }
382
- const libConfig = this.configService.getConfig(this.id);
383
- if (!libConfig) {
384
- throw new Error('Internal library error - libConfig must be defined');
385
- }
386
- const currentImageConfig = libConfig.currentImageConfig;
387
- if (currentImageConfig && !currentImageConfig.downloadable) {
388
- return;
389
- }
390
- // If IE11 or Microsoft Edge use msSaveBlob(...)
391
- if (this.isIEorEdge()) {
392
- // I cannot use fetch API because IE11 doesn't support it,
393
- // so I have to switch to XMLHttpRequest
394
- this.downloadImageOnlyIEorEdge();
395
- }
396
- else {
397
- // for all other browsers
398
- this.downloadImageAllBrowsers();
399
- }
400
- }
401
- /**
402
- * Method to convert a base64 to a Blob
403
- * @param base64Data string with base64 data
404
- * @param contentType string with the MIME type
405
- * @return Blob converted from the input base64Data
406
- * @private
407
- */
408
- base64toBlob(base64Data, contentType = '') {
409
- const sliceSize = 1024;
410
- const byteCharacters = atob(base64Data);
411
- const bytesLength = byteCharacters.length;
412
- const slicesCount = Math.ceil(bytesLength / sliceSize);
413
- const byteArrays = new Array(slicesCount);
414
- for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
415
- const begin = sliceIndex * sliceSize;
416
- const end = Math.min(begin + sliceSize, bytesLength);
417
- const bytes = new Array(end - begin);
418
- for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
419
- bytes[i] = byteCharacters[offset].charCodeAt(0);
420
- }
421
- byteArrays[sliceIndex] = new Uint8Array(bytes);
422
- }
423
- return new Blob(byteArrays, { type: contentType });
424
- }
425
- /**
426
- * Private method to download the current image for all browsers except for IE11.
427
- * @private
428
- */
429
- downloadImageAllBrowsers() {
430
- const link = document.createElement('a');
431
- let isBase64 = false;
432
- let img;
433
- // convert a SafeResourceUrl to a string
434
- if (typeof this.currentImage.modal.img === 'string') {
435
- img = this.currentImage.modal.img;
436
- }
437
- else {
438
- // if it's a SafeResourceUrl
439
- img = this.sanitizer.sanitize(SecurityContext.RESOURCE_URL, this.currentImage.modal.img);
440
- }
441
- if (img.includes('data:image/') || img.includes(';base64,')) {
442
- const extension = img.replace('data:image/', '').split(';base64,')[0];
443
- const pureBase64 = img.split(';base64,')[1];
444
- const blob = this.base64toBlob(pureBase64, 'image/' + extension);
445
- link.href = URL.createObjectURL(blob);
446
- isBase64 = true;
447
- link.setAttribute('download', this.getFileName(this.currentImage, isBase64, extension));
448
- }
449
- else {
450
- link.href = img;
451
- link.setAttribute('download', this.getFileName(this.currentImage, isBase64));
452
- }
453
- document.body.appendChild(link);
454
- link.click();
455
- document.body.removeChild(link);
456
- }
457
- /**
458
- * Private method to download the current image only for IE11 using
459
- * custom javascript's methods available only on IE.
460
- * @private
461
- */
462
- downloadImageOnlyIEorEdge() {
463
- if (isPlatformBrowser(this.platformId)) {
464
- const req = new XMLHttpRequest();
465
- req.open('GET', this.currentImage.modal.img, true);
466
- req.responseType = 'arraybuffer';
467
- req.onload = event => {
468
- const blob = new Blob([req.response], { type: 'image/png' });
469
- window.navigator.msSaveBlob(blob, this.getFileName(this.currentImage));
470
- };
471
- req.send();
472
- }
473
- }
474
- /**
475
- * Private method to get the `ButtonEvent` to emit, merging the input `ButtonEvent`
476
- * with the current image.
477
- * @param event ButtonEvent event payload to return
478
- * @returns ButtonEvent event payload with the current image included
479
- * @private
480
- */
481
- getButtonEventToEmit(event) {
482
- return Object.assign(event, { image: this.currentImage });
483
- }
484
- /**
485
- * Private method to get the file name from an input path.
486
- * This is used either to get the image's name from its path or from the Image itself,
487
- * if specified as 'downloadFileName' by the user.
488
- * @param image Image image to extract its file name
489
- * @param isBase64 boolean to set if the image is a base64 file or not. False by default.
490
- * @param base64Extension string to force the extension of the base64 image. Empty string by default.
491
- * @returns string string file name of the input image.
492
- * @private
493
- */
494
- getFileName(image, isBase64 = false, base64Extension = '') {
495
- if (!image.modal.downloadFileName || image.modal.downloadFileName.length === 0) {
496
- if (isBase64) {
497
- return `Image-${image.id}.${base64Extension !== '' ? base64Extension : 'png'}`;
498
- }
499
- else {
500
- return image.modal.img.replace(/^.*[\\\/]/, '');
501
- }
502
- }
503
- else {
504
- return image.modal.downloadFileName;
505
- }
506
- }
507
- /**
508
- * Private method to initialize `images` as array of `Image`s.
509
- * Also, it will emit ImageModalEvent to say that images are loaded.
510
- * @private
511
- */
512
- initImages() {
513
- this.modalGalleryService.emitHasData(new ImageModalEvent(this.id, Action.LOAD, true));
514
- this.showGallery = this.images.length > 0;
515
- }
516
- /**
517
- * Private method to emit events when either the last or the first image are visible.
518
- * @param action Action Enum of type Action that represents the source of the event that changed the
519
- * current image to the first one or the last one.
520
- * @param indexToCheck number is the index number of the image (the first or the last one).
521
- * @private
522
- */
523
- emitBoundaryEvent(action, indexToCheck) {
524
- // to emit first/last event
525
- switch (indexToCheck) {
526
- case 0:
527
- this.modalGalleryService.emitFirstImage(new ImageModalEvent(this.id, action, true));
528
- break;
529
- case this.images.length - 1:
530
- this.modalGalleryService.emitLastImage(new ImageModalEvent(this.id, action, true));
531
- break;
532
- }
533
- }
534
- /**
535
- * Private method to check if this library is running on
536
- * Microsoft browsers or not (i.e. it detects both IE11 and Edge)
537
- * supporting also Server-Side Rendering.
538
- * Inspired by https://msdn.microsoft.com/it-it/library/hh779016(v=vs.85).aspx
539
- * @returns boolean true if IE11 or Edge, false otherwise
540
- * @private
541
- */
542
- isIEorEdge() {
543
- if (isPlatformBrowser(this.platformId)) {
544
- // if both Blob constructor and msSaveOrOpenBlob are supported by the current browser
545
- return !!window.Blob && !!window.navigator.msSaveOrOpenBlob;
546
- }
547
- if (isPlatformServer(this.platformId)) {
548
- // server only
549
- return true;
550
- }
551
- return false;
552
- }
553
- }
554
- ModalGalleryComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.1", 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 });
555
- ModalGalleryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.1", 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 (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}"], 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"], outputs: ["clickPreview"] }], directives: [{ type: i10.ClickOutsideDirective, selector: "[ksClickOutside]", inputs: ["clickOutsideEnable"], outputs: ["clickOutside"] }] });
556
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.1", ngImport: i0, type: ModalGalleryComponent, decorators: [{
557
- type: Component,
558
- args: [{
559
- selector: 'ks-modal-gallery',
560
- templateUrl: './modal-gallery.component.html',
561
- styleUrls: ['./modal-gallery.component.scss']
562
- }]
563
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
564
- type: Inject,
565
- args: [DIALOG_DATA]
566
- }] }, { type: i1.ModalGalleryService }, { type: i2.KeyboardService }, { type: Object, decorators: [{
567
- type: Inject,
568
- args: [PLATFORM_ID]
569
- }] }, { type: i0.ChangeDetectorRef }, { type: i3.IdValidatorService }, { type: i4.ConfigService }, { type: i5.DomSanitizer }]; }, propDecorators: { currentImageComponent: [{
570
- type: ViewChild,
571
- args: [CurrentImageComponent, { static: true }]
572
- }], onPopState: [{
573
- type: HostListener,
574
- args: ['window:popstate', ['$event']]
575
- }] } });
576
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kYWwtZ2FsbGVyeS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9rczg5L2FuZ3VsYXItbW9kYWwtZ2FsbGVyeS9zcmMvbGliL2NvbXBvbmVudHMvbW9kYWwtZ2FsbGVyeS9tb2RhbC1nYWxsZXJ5LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2tzODkvYW5ndWxhci1tb2RhbC1nYWxsZXJ5L3NyYy9saWIvY29tcG9uZW50cy9tb2RhbC1nYWxsZXJ5L21vZGFsLWdhbGxlcnkuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFxQixTQUFTLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBcUIsV0FBVyxFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0ksT0FBTyxFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFLdEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sRUFBUyxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUdqRSxPQUFPLEVBQTRDLFVBQVUsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBRTVHLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNqRCxPQUFPLEVBQUUscUJBQXFCLEVBQWtCLE1BQU0sMENBQTBDLENBQUM7QUFRakcsT0FBTyxFQUFFLCtCQUErQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7Ozs7Ozs7Ozs7OztBQVczRSxNQUFNLE9BQU8scUJBQXFCO0lBNEVoQyxZQUMrQixhQUFpQyxFQUN0RCxtQkFBd0MsRUFDeEMsZUFBZ0M7SUFDeEMscUNBQXFDO0lBQ1IsVUFBa0IsRUFDdkMsaUJBQW9DLEVBQ3BDLGtCQUFzQyxFQUN0QyxhQUE0QixFQUM1QixT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WCxXQUFXO3NHQWpGVixxQkFBcUIsaUxBSXJCLHFCQUFxQiw4RENwQ2xDLGt1REF5Q0E7MkZEVGEscUJBQXFCO2tCQUxqQyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxrQkFBa0I7b0JBQzVCLFdBQVcsRUFBRSxnQ0FBZ0M7b0JBQzdDLFNBQVMsRUFBRSxDQUFDLGdDQUFnQyxDQUFDO2lCQUM5Qzs7MEJBOEVJLE1BQU07MkJBQUMsV0FBVzs4RkFJc0IsTUFBTTswQkFBOUMsTUFBTTsyQkFBQyxXQUFXO29LQTdFK0IscUJBQXFCO3NCQUF4RSxTQUFTO3VCQUFDLHFCQUFxQixFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFvRWxELFVBQVU7c0JBRFQsWUFBWTt1QkFBQyxpQkFBaUIsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdG9yUmVmLCBDb21wb25lbnQsIEhvc3RMaXN0ZW5lciwgSW5qZWN0LCBPbkRlc3Ryb3ksIE9uSW5pdCwgUExBVEZPUk1fSUQsIFNlY3VyaXR5Q29udGV4dCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciwgaXNQbGF0Zm9ybVNlcnZlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBEb21TYW5pdGl6ZXIgfSBmcm9tICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcblxuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IERJQUxPR19EQVRBIH0gZnJvbSAnLi9tb2RhbC1nYWxsZXJ5LnRva2Vucyc7XG5pbXBvcnQgeyBJbWFnZSwgSW1hZ2VNb2RhbEV2ZW50IH0gZnJvbSAnLi4vLi4vbW9kZWwvaW1hZ2UuY2xhc3MnO1xuaW1wb3J0IHsgQ29uZmlnU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2NvbmZpZy5zZXJ2aWNlJztcbmltcG9ydCB7IERvdHNDb25maWcgfSBmcm9tICcuLi8uLi9tb2RlbC9kb3RzLWNvbmZpZy5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgQnV0dG9uQ29uZmlnLCBCdXR0b25FdmVudCwgQnV0dG9uc0NvbmZpZywgQnV0dG9uVHlwZSB9IGZyb20gJy4uLy4uL21vZGVsL2J1dHRvbnMtY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBJbnRlcm5hbExpYkltYWdlIH0gZnJvbSAnLi4vLi4vbW9kZWwvaW1hZ2UtaW50ZXJuYWwuY2xhc3MnO1xuaW1wb3J0IHsgQWN0aW9uIH0gZnJvbSAnLi4vLi4vbW9kZWwvYWN0aW9uLmVudW0nO1xuaW1wb3J0IHsgQ3VycmVudEltYWdlQ29tcG9uZW50LCBJbWFnZUxvYWRFdmVudCB9IGZyb20gJy4uL2N1cnJlbnQtaW1hZ2UvY3VycmVudC1pbWFnZS5jb21wb25lbnQnO1xuaW1wb3J0IHsgS2V5Ym9hcmRTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMva2V5Ym9hcmQuc2VydmljZSc7XG5pbXBvcnQgeyBJZFZhbGlkYXRvclNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9pZC12YWxpZGF0b3Iuc2VydmljZSc7XG5pbXBvcnQgeyBLZXlib2FyZENvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVsL2tleWJvYXJkLWNvbmZpZy5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgUHJldmlld0NvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVsL3ByZXZpZXctY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBTbGlkZUNvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVsL3NsaWRlLWNvbmZpZy5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgQWNjZXNzaWJpbGl0eUNvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVsL2FjY2Vzc2liaWxpdHkuaW50ZXJmYWNlJztcbmltcG9ydCB7IFBsYWluR2FsbGVyeUNvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVsL3BsYWluLWdhbGxlcnktY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBLU19ERUZBVUxUX0FDQ0VTU0lCSUxJVFlfQ09ORklHIH0gZnJvbSAnLi4vYWNjZXNzaWJpbGl0eS1kZWZhdWx0JztcbmltcG9ydCB7IEN1cnJlbnRJbWFnZUNvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVsL2N1cnJlbnQtaW1hZ2UtY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBNb2RhbEdhbGxlcnlTZXJ2aWNlIH0gZnJvbSAnLi9tb2RhbC1nYWxsZXJ5LnNlcnZpY2UnO1xuaW1wb3J0IHsgTGliQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvbGliLWNvbmZpZy5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgTW9kYWxHYWxsZXJ5Q29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvbW9kYWwtZ2FsbGVyeS1jb25maWcuaW50ZXJmYWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAna3MtbW9kYWwtZ2FsbGVyeScsXG4gIHRlbXBsYXRlVXJsOiAnLi9tb2RhbC1nYWxsZXJ5LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vbW9kYWwtZ2FsbGVyeS5jb21wb25lbnQuc2NzcyddXG59KVxuZXhwb3J0IGNsYXNzIE1vZGFsR2FsbGVyeUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgLyoqXG4gICAqIFJlZmVyZW5jZSB0byB0aGUgQ3VycmVudEltYWdlQ29tcG9uZW50IHRvIGludm9rZSBtZXRob2RzIG9uIGl0LlxuICAgKi9cbiAgQFZpZXdDaGlsZChDdXJyZW50SW1hZ2VDb21wb25lbnQsIHsgc3RhdGljOiB0cnVlIH0pIGN1cnJlbnRJbWFnZUNvbXBvbmVudDogQ3VycmVudEltYWdlQ29tcG9uZW50IHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBVbmlxdWUgaWQgKD49MCkgb2YgdGhlIGN1cnJlbnQgaW5zdGFuY2Ugb2YgdGhpcyBsaWJyYXJ5LiBUaGlzIGlzIHVzZWZ1bCB3aGVuIHlvdSBhcmUgdXNpbmdcbiAgICogdGhlIHNlcnZpY2UgdG8gY2FsbCBtb2RhbCBnYWxsZXJ5IHdpdGhvdXQgb3BlbiBpdCBtYW51YWxseS5cbiAgICovXG4gIGlkOiBudW1iZXI7XG4gIC8qKlxuICAgKiBPYmplY3Qgb2YgdHlwZSBgQnV0dG9uc0NvbmZpZ2AgdG8gc2hvdy9oaWRlIGJ1dHRvbnMuXG4gICAqL1xuICBidXR0b25zQ29uZmlnOiBCdXR0b25zQ29uZmlnIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogQm9vbGVhbiB0byBlbmFibGUgbW9kYWwtZ2FsbGVyeSBjbG9zZSBiZWhhdmlvdXIgd2hlbiBjbGlja2luZ1xuICAgKiBvbiB0aGUgc2VtaS10cmFuc3BhcmVudCBiYWNrZ3JvdW5kLiBFbmFibGVkIGJ5IGRlZmF1bHQuXG4gICAqL1xuICBlbmFibGVDbG9zZU91dHNpZGUgPSB0cnVlO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYERvdHNDb25maWdgIHRvIGluaXQgRG90c0NvbXBvbmVudCdzIGZlYXR1cmVzLlxuICAgKiBGb3IgaW5zdGFuY2UsIGl0IGNvbnRhaW5zIGEgcGFyYW0gdG8gc2hvdy9oaWRlIGRvdHMuXG4gICAqL1xuICBkb3RzQ29uZmlnOiBEb3RzQ29uZmlnIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYFByZXZpZXdDb25maWdgIHRvIGluaXQgUHJldmlld3NDb21wb25lbnQncyBmZWF0dXJlcy5cbiAgICogRm9yIGluc3RhbmNlLCBpdCBjb250YWlucyBhIHBhcmFtIHRvIHNob3cvaGlkZSBwcmV2aWV3cy5cbiAgICovXG4gIHByZXZpZXdDb25maWc6IFByZXZpZXdDb25maWcgfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBPYmplY3Qgb2YgdHlwZSBgU2xpZGVDb25maWdgIHRvIGluaXQgc2lkZSBwcmV2aWV3cyBhbmQgYGluZmluaXRlIHNsaWRpbmdgLlxuICAgKi9cbiAgc2xpZGVDb25maWc6IFNsaWRlQ29uZmlnIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYEFjY2Vzc2liaWxpdHlDb25maWdgIHRvIGluaXQgY3VzdG9tIGFjY2Vzc2liaWxpdHkgZmVhdHVyZXMuXG4gICAqIEZvciBpbnN0YW5jZSwgaXQgY29udGFpbnMgdGl0bGVzLCBhbHQgdGV4dHMsIGFyaWEtbGFiZWxzIGFuZCBzbyBvbi5cbiAgICovXG4gIGFjY2Vzc2liaWxpdHlDb25maWc6IEFjY2Vzc2liaWxpdHlDb25maWcgPSBLU19ERUZBVUxUX0FDQ0VTU0lCSUxJVFlfQ09ORklHO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYEtleWJvYXJkQ29uZmlnYCB0byBhc3NpZ24gY3VzdG9tIGtleXMgdG8gRVNDLCBSSUdIVCBhbmQgTEVGVCBrZXlib2FyZCdzIGFjdGlvbnMuXG4gICAqL1xuICBrZXlib2FyZENvbmZpZzogS2V5Ym9hcmRDb25maWcgfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBPYmplY3Qgb2YgdHlwZSBgUGxhaW5HYWxsZXJ5Q29uZmlnYCB0byBjb25maWd1cmUgdGhlIHBsYWluIGdhbGxlcnkuXG4gICAqL1xuICBwbGFpbkdhbGxlcnlDb25maWc6IFBsYWluR2FsbGVyeUNvbmZpZyB8IHVuZGVmaW5lZDtcbiAgLyoqXG4gICAqIEFycmF5IG9mIGBJbnRlcm5hbExpYkltYWdlYCByZXByZXNlbnRpbmcgdGhlIG1vZGVsIG9mIHRoaXMgbGlicmFyeSB3aXRoIGFsbCBpbWFnZXMsIHRodW1icyBhbmQgc28gb24uXG4gICAqL1xuICBpbWFnZXM6IEludGVybmFsTGliSW1hZ2VbXTtcbiAgLyoqXG4gICAqIGBJbWFnZWAgdGhhdCBpcyB2aXNpYmxlIHJpZ2h0IG5vdy5cbiAgICovXG4gIGN1cnJlbnRJbWFnZTogSW50ZXJuYWxMaWJJbWFnZTtcbiAgLyoqXG4gICAqIEJvb2xlYW4gdG8gb3BlbiB0aGUgbW9kYWwgZ2FsbGVyeS4gRmFsc2UgYnkgZGVmYXVsdC5cbiAgICovXG4gIHNob3dHYWxsZXJ5ID0gZmFsc2U7XG4gIC8qKlxuICAgKiBPYmplY3QgdG8gY29uZmlndXJlIHRoaXMgY29tcG9uZW50LlxuICAgKi9cbiAgbGliQ29uZmlnOiBMaWJDb25maWcgfCB1bmRlZmluZWQ7XG5cbiAgcHJpdmF0ZSB1cGRhdGVJbWFnZXNTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogSG9zdExpc3RlbmVyIHRvIGNhdGNoIGJyb3dzZXIncyBiYWNrIGJ1dHRvbiBhbmQgZGVzdHJveSB0aGUgZ2FsbGVyeS5cbiAgICogVGhpcyBwcmV2ZW50cyB3ZWlyZWQgYmVoYXZpb3VyIGFib3V0IHNjcm9sbGluZy5cbiAgICogQWRkZWQgdG8gZml4IHRoaXMgaXNzdWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9Lczg5L2FuZ3VsYXItbW9kYWwtZ2FsbGVyeS9pc3N1ZXMvMTU5XG4gICAqL1xuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6cG9wc3RhdGUnLCBbJyRldmVudCddKVxuICBvblBvcFN0YXRlKGU6IEV2ZW50KTogdm9pZCB7XG4gICAgdGhpcy5jbG9zZUdhbGxlcnkoKTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBJbmplY3QoRElBTE9HX0RBVEEpIHByaXZhdGUgZGlhbG9nQ29udGVudDogTW9kYWxHYWxsZXJ5Q29uZmlnLFxuICAgIHByaXZhdGUgbW9kYWxHYWxsZXJ5U2VydmljZTogTW9kYWxHYWxsZXJ5U2VydmljZSxcbiAgICBwcml2YXRlIGtleWJvYXJkU2VydmljZTogS2V5Ym9hcmRTZXJ2aWNlLFxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpiYW4tdHlwZXNcbiAgICBASW5qZWN0KFBMQVRGT1JNX0lEKSBwcml2YXRlIHBsYXRmb3JtSWQ6IE9iamVjdCxcbiAgICBwcml2YXRlIGNoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBwcml2YXRlIGlkVmFsaWRhdG9yU2VydmljZTogSWRWYWxpZGF0b3JTZXJ2aWNlLFxuICAgIHByaXZhdGUgY29uZmlnU2VydmljZTogQ29uZmlnU2VydmljZSxcbiAgICBwcml2YXRlIHNhbml0aXplcjogRG9tU2FuaXRpemVyXG4gICkge1xuICAgIHRoaXMuaWQgPSAodGhpcy5kaWFsb2dDb250ZW50IGFzIE1vZGFsR2FsbGVyeUNvbmZpZykuaWQ7XG4gICAgdGhpcy5pbWFnZXMgPSAodGhpcy5kaWFsb2dDb250ZW50IGFzIE1vZGFsR2FsbGVyeUNvbmZpZykuaW1hZ2VzIGFzIEludGVybmFsTGliSW1hZ2VbXTtcbiAgICB0aGlzLmN1cnJlbnRJbWFnZSA9ICh0aGlzLmRpYWxvZ0NvbnRlbnQgYXMgTW9kYWxHYWxsZXJ5Q29uZmlnKS5jdXJyZW50SW1hZ2UgYXMgSW50ZXJuYWxMaWJJbWFnZTtcbiAgICB0aGlzLmxpYkNvbmZpZyA9ICh0aGlzLmRpYWxvZ0NvbnRlbnQgYXMgTW9kYWxHYWxsZXJ5Q29uZmlnKS5saWJDb25maWc7XG4gICAgdGhpcy5jb25maWdTZXJ2aWNlLnNldENvbmZpZyh0aGlzLmlkLCB0aGlzLmxpYkNvbmZpZyk7XG5cbiAgICB0aGlzLnVwZGF0ZUltYWdlc1N1YnNjcmlwdGlvbiA9IHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS51cGRhdGVJbWFnZXMkLnN1YnNjcmliZSgoaW1hZ2VzOiBJbWFnZVtdKSA9PiB7XG4gICAgICB0aGlzLmltYWdlcyA9IGltYWdlcy5tYXAoKGltYWdlOiBJbWFnZSkgPT4ge1xuICAgICAgICBjb25zdCBuZXdJbWFnZTogSW50ZXJuYWxMaWJJbWFnZSA9IE9iamVjdC5hc3NpZ24oe30sIGltYWdlLCB7IHByZXZpb3VzbHlMb2FkZWQ6IGZhbHNlIH0pO1xuICAgICAgICByZXR1cm4gbmV3SW1hZ2U7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuaW5pdEltYWdlcygpO1xuICAgICAgdGhpcy5pbWFnZXMuZm9yRWFjaCgoaW1hZ2U6IEludGVybmFsTGliSW1hZ2UpID0+IHtcbiAgICAgICAgaWYgKGltYWdlLmlkID09PSB0aGlzLmN1cnJlbnRJbWFnZS5pZCkge1xuICAgICAgICAgIHRoaXMuY3VycmVudEltYWdlID0gaW1hZ2U7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgwrRuZ09uSW5pdMK0IHRvIGluaXQgaW1hZ2VzIGNhbGxpbmcgYGluaXRJbWFnZXMoKWAuXG4gICAqIFRoaXMgaXMgYW4gQW5ndWxhcidzIGxpZmVjeWNsZSBob29rLCBzbyBpdHMgY2FsbGVkIGF1dG9tYXRpY2FsbHkgYnkgQW5ndWxhciBpdHNlbGYuXG4gICAqIEluIHBhcnRpY3VsYXIsIGl0J3MgY2FsbGVkIG9ubHkgb25lIHRpbWUhISFcbiAgICovXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuaWRWYWxpZGF0b3JTZXJ2aWNlLmNoZWNrQW5kQWRkKHRoaXMuaWQpO1xuXG4gICAgLy8gaWQgaXMgYSBtYW5kYXRvcnkgaW5wdXQgYW5kIG11c3QgYSBudW1iZXIgPiAwXG4gICAgaWYgKCghdGhpcy5pZCAmJiB0aGlzLmlkICE9PSAwKSB8fCB0aGlzLmlkIDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJ1tpZF09XCJhIG51bWJlciA+PSAwXCInIGlzIGEgbWFuZGF0b3J5IGlucHV0IGluIGFuZ3VsYXItbW9kYWwtZ2FsbGVyeS5gICtcbiAgICAgICAgYElmIHlvdSBhcmUgdXNpbmcgbXVsdGlwbGUgaW5zdGFuY2VzIG9mIHRoaXMgbGlicmFyeSwgcGxlYXNlIGJlIHN1cmUgdG8gdXNlIGRpZmZlcmVudCBpZHNgXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICBpZiAoIWxpYkNvbmZpZyB8fCAhbGliQ29uZmlnLmRvdHNDb25maWcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGxpYkNvbmZpZyBhbmQgZG90c0NvbmZpZyBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG5cbiAgICB0aGlzLmRvdHNDb25maWcgPSBsaWJDb25maWcuZG90c0NvbmZpZztcblxuICAgIC8vIGNhbGwgaW5pdEltYWdlcyB0byBpbml0IGltYWdlcyBhbmQgdG8gZW1pdCBgaGFzRGF0YWAgZXZlbnRcbiAgICB0aGlzLmluaXRJbWFnZXMoKTtcbiAgICB0aGlzLnNob3dNb2RhbEdhbGxlcnkoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgY2FsbGVkIGJ5IGN1c3RvbSB1cHBlciBidXR0b25zLlxuICAgKiBAcGFyYW0gZXZlbnQgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZFxuICAgKi9cbiAgb25DdXN0b21FbWl0KGV2ZW50OiBCdXR0b25FdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGV2ZW50VG9FbWl0OiBCdXR0b25FdmVudCA9IHRoaXMuZ2V0QnV0dG9uRXZlbnRUb0VtaXQoZXZlbnQpO1xuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0QnV0dG9uQmVmb3JlSG9vayhldmVudFRvRW1pdCk7XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25BZnRlckhvb2soZXZlbnRUb0VtaXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgYnkgdGhlIGZ1bGwtc2NyZWVuIHVwcGVyIGJ1dHRvbi5cbiAgICogQHBhcmFtIGV2ZW50IEJ1dHRvbkV2ZW50IGV2ZW50IHBheWxvYWRcbiAgICovXG4gIG9uRnVsbFNjcmVlbihldmVudDogQnV0dG9uRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBldmVudFRvRW1pdDogQnV0dG9uRXZlbnQgPSB0aGlzLmdldEJ1dHRvbkV2ZW50VG9FbWl0KGV2ZW50KTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkJlZm9yZUhvb2soZXZlbnRUb0VtaXQpO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWFueVxuICAgIGNvbnN0IGRvYzogYW55ID0gZG9jdW1lbnQgYXMgYW55O1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1hbnlcbiAgICBjb25zdCBkb2NFbDogYW55ID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50IGFzIGFueTtcblxuICAgIGNvbnN0IGZ1bGxzY3JlZW5EaXNhYmxlZDogYm9vbGVhbiA9ICFkb2MuZnVsbHNjcmVlbkVsZW1lbnQgJiYgIWRvYy53ZWJraXRGdWxsc2NyZWVuRWxlbWVudCAmJiAhZG9jLm1vekZ1bGxTY3JlZW5FbGVtZW50ICYmICFkb2MubXNGdWxsc2NyZWVuRWxlbWVudDtcblxuICAgIC8vIFRPRE8gYWRkIC50aGVuIHRvIHByb21pc2VzLCBmb3IgaW5zdGFuY2UgcmVxdWVzdEZ1bGxzY3JlZW4oKSByZXR1cm5zIGEgUHJvbWlzZVxuICAgIGlmIChmdWxsc2NyZWVuRGlzYWJsZWQpIHtcbiAgICAgIGlmIChkb2NFbC5yZXF1ZXN0RnVsbHNjcmVlbikge1xuICAgICAgICBkb2NFbC5yZXF1ZXN0RnVsbHNjcmVlbigpO1xuICAgICAgfSBlbHNlIGlmIChkb2NFbC53ZWJraXRSZXF1ZXN0RnVsbHNjcmVlbikge1xuICAgICAgICBkb2NFbC53ZWJraXRSZXF1ZXN0RnVsbHNjcmVlbigpO1xuICAgICAgfSBlbHNlIGlmIChkb2NFbC5tb3pSZXF1ZXN0RnVsbFNjcmVlbikge1xuICAgICAgICBkb2NFbC5tb3pSZXF1ZXN0RnVsbFNjcmVlbigpO1xuICAgICAgfSBlbHNlIGlmIChkb2NFbC5tc1JlcXVlc3RGdWxsc2NyZWVuKSB7XG4gICAgICAgIGRvY0VsLm1zUmVxdWVzdEZ1bGxzY3JlZW4oKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGRvYy5leGl0RnVsbHNjcmVlbikge1xuICAgICAgICBkb2MuZXhpdEZ1bGxzY3JlZW4oKTtcbiAgICAgIH0gZWxzZSBpZiAoZG9jLm1zRXhpdEZ1bGxzY3JlZW4pIHtcbiAgICAgICAgZG9jLm1zRXhpdEZ1bGxzY3JlZW4oKTtcbiAgICAgIH0gZWxzZSBpZiAoZG9jLm1vekNhbmNlbEZ1bGxTY3JlZW4pIHtcbiAgICAgICAgZG9jLm1vekNhbmNlbEZ1bGxTY3JlZW4oKTtcbiAgICAgIH0gZWxzZSBpZiAoZG9jLndlYmtpdEV4aXRGdWxsc2NyZWVuKSB7XG4gICAgICAgIGRvYy53ZWJraXRFeGl0RnVsbHNjcmVlbigpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0QnV0dG9uQWZ0ZXJIb29rKGV2ZW50VG9FbWl0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgY2FsbGVkIGJ5IHRoZSBkZWxldGUgdXBwZXIgYnV0dG9uLlxuICAgKiBAcGFyYW0gZXZlbnQgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZFxuICAgKi9cbiAgb25EZWxldGUoZXZlbnQ6IEJ1dHRvbkV2ZW50KTogdm9pZCB7XG4gICAgY29uc3QgZXZlbnRUb0VtaXQ6IEJ1dHRvbkV2ZW50ID0gdGhpcy5nZXRCdXR0b25FdmVudFRvRW1pdChldmVudCk7XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25CZWZvcmVIb29rKGV2ZW50VG9FbWl0KTtcblxuICAgIGlmICh0aGlzLmltYWdlcy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHRoaXMuY2xvc2VHYWxsZXJ5KCk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmN1cnJlbnRJbWFnZUNvbXBvbmVudCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjdXJyZW50SW1hZ2VDb21wb25lbnQgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuXG4gICAgY29uc3QgaW1hZ2VJbmRleFRvRGVsZXRlOiBudW1iZXIgPSB0aGlzLmN1cnJlbnRJbWFnZUNvbXBvbmVudC5nZXRJbmRleFRvRGVsZXRlKGV2ZW50LmltYWdlIGFzIEludGVybmFsTGliSW1hZ2UpO1xuICAgIGlmIChpbWFnZUluZGV4VG9EZWxldGUgPT09IHRoaXMuaW1hZ2VzLmxlbmd0aCAtIDEpIHtcbiAgICAgIC8vIGxhc3QgaW1hZ2VcbiAgICAgIHRoaXMuY3VycmVudEltYWdlQ29tcG9uZW50LnByZXZJbWFnZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmN1cnJlbnRJbWFnZUNvbXBvbmVudC5uZXh0SW1hZ2UoKTtcbiAgICB9XG5cbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkFmdGVySG9vayhldmVudFRvRW1pdCk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCBieSB0aGUgbmF2aWdhdGUgdXBwZXIgYnV0dG9uLlxuICAgKiBAcGFyYW0gZXZlbnQgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZFxuICAgKi9cbiAgb25OYXZpZ2F0ZShldmVudDogQnV0dG9uRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBldmVudFRvRW1pdDogQnV0dG9uRXZlbnQgPSB0aGlzLmdldEJ1dHRvbkV2ZW50VG9FbWl0KGV2ZW50KTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkJlZm9yZUhvb2soZXZlbnRUb0VtaXQpO1xuICAgIC8vIFRvIHN1cHBvcnQgU1NSXG4gICAgaWYgKGlzUGxhdGZvcm1Ccm93c2VyKHRoaXMucGxhdGZvcm1JZCkpIHtcbiAgICAgIGlmIChldmVudFRvRW1pdC5pbWFnZSAmJiBldmVudFRvRW1pdC5pbWFnZS5tb2RhbC5leHRVcmwpIHtcbiAgICAgICAgLy8gd2hlcmUgSSBzaG91bGQgb3BlbiB0aGlzIGxpbms/IFRoZSBjdXJyZW50IHRhYiBvciBhbm90aGVyIG9uZT9cbiAgICAgICAgaWYgKGV2ZW50VG9FbWl0LmJ1dHRvbiAmJiBldmVudFRvRW1pdC5idXR0b24uZXh0VXJsSW5OZXdUYWIpIHtcbiAgICAgICAgICAvLyBpbiB0aGlzIGNhc2UgSSBzaG91bGQgdXNlIHRhcmdldCBfYmxhbmsgdG8gb3BlbiB0aGUgdXJsIGluIGEgbmV3IHRhYiwgaG93ZXZlciB0aGVzZSBpcyBhIHNlY3VyaXR5IGlzc3VlLlxuICAgICAgICAgIC8vIFByZXZlbnQgUmV2ZXJzZSBUYWJuYWJiaW5nJ3MgYXR0YWNrcyAoaHR0cHM6Ly93d3cub3dhc3Aub3JnL2luZGV4LnBocC9SZXZlcnNlX1RhYm5hYmJpbmcpXG4gICAgICAgICAgLy8gU29tZSByZXNvdXJjZXM6XG4gICAgICAgICAgLy8gLSBodHRwczovL3d3dy5vd2FzcC5vcmcvaW5kZXgucGhwL0hUTUw1X1NlY3VyaXR5X0NoZWF0X1NoZWV0I1RhYm5hYmJpbmdcbiAgICAgICAgICAvLyAtIGh0dHBzOi8vbWVkaXVtLmNvbS9Aaml0Yml0L3RhcmdldC1ibGFuay10aGUtbW9zdC11bmRlcmVzdGltYXRlZC12dWxuZXJhYmlsaXR5LWV2ZXItOTZlMzI4MzAxZjRjXG4gICAgICAgICAgLy8gLSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvV2luZG93L29wZW5cbiAgICAgICAgICBjb25zdCBuZXdXaW5kb3c6IFdpbmRvdyB8IG51bGwgPSB3aW5kb3cub3BlbihldmVudFRvRW1pdC5pbWFnZS5tb2RhbC5leHRVcmwsICdub29wZW5lcixub3JlZmVycmVyLCcpO1xuICAgICAgICAgIC8vIGl0IHJldHVybnMgbnVsbCBpZiB0aGUgY2FsbCBmYWlsZWQsIHNvIEkgaGF2ZSB0byBkbyB0aGlzIGNoZWNrXG4gICAgICAgICAgaWYgKG5ld1dpbmRvdykge1xuICAgICAgICAgICAgbmV3V2luZG93Lm9wZW5lciA9IG51bGw7IC8vIHJlcXVpcmVkIHRvIHByZXZlbnQgc2VjdXJpdHkgaXNzdWVzXG4gICAgICAgICAgICAvLyBlbWl0IG9ubHkgaW4gY2FzZSBvZiBzdWNjZXNzXG4gICAgICAgICAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkFmdGVySG9vayhldmVudFRvRW1pdCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMudXBkYXRlTG9jYXRpb25IcmVmKGV2ZW50VG9FbWl0LmltYWdlLm1vZGFsLmV4dFVybCk7XG4gICAgICAgICAgLy8gZW1pdCBvbmx5IGluIGNhc2Ugb2Ygc3VjY2Vzc1xuICAgICAgICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0QnV0dG9uQWZ0ZXJIb29rKGV2ZW50VG9FbWl0KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIG1ldGhvZCBpcyBkZWZpbmVkIHRvIGJlIHNwaWVkIGFuZCByZXBsYWNlZCBpbiB1bml0IHRlc3Rpbmcgd2l0aCBhIGZha2UgbWV0aG9kIGNhbGwuXG4gICAqIEl0IG11c3QgYmUgcHVibGljIHRvIGJlIGFibGUgdG8gdXNlIGphc21pbmUgc3B5T24gbWV0aG9kLlxuICAgKiBAcGFyYW0gbmV3SHJlZiBzdHJpbmcgbmV3IHVybFxuICAgKi9cbiAgdXBkYXRlTG9jYXRpb25IcmVmKG5ld0hyZWY6IHN0cmluZykge1xuICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gbmV3SHJlZjtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgY2FsbGVkIGJ5IHRoZSBkb3dubG9hZCB1cHBlciBidXR0b24uXG4gICAqIEBwYXJhbSBldmVudCBCdXR0b25FdmVudCBldmVudCBwYXlsb2FkXG4gICAqL1xuICBvbkRvd25sb2FkKGV2ZW50OiBCdXR0b25FdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGV2ZW50VG9FbWl0OiBCdXR0b25FdmVudCA9IHRoaXMuZ2V0QnV0dG9uRXZlbnRUb0VtaXQoZXZlbnQpO1xuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0QnV0dG9uQmVmb3JlSG9vayhldmVudFRvRW1pdCk7XG4gICAgdGhpcy5kb3dubG9hZEltYWdlKCk7XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25BZnRlckhvb2soZXZlbnRUb0VtaXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgYnkgdGhlIGNsb3NlIHVwcGVyIGJ1dHRvbi5cbiAgICogQHBhcmFtIGV2ZW50IEJ1dHRvbkV2ZW50IGV2ZW50IHBheWxvYWRcbiAgICogQHBhcmFtIGFjdGlvbiBBY3Rpb24gdGhhdCB0cmlnZ2VyZWQgdGhlIGNsb3NlIG1ldGhvZC4gYEFjdGlvbi5OT1JNQUxgIGJ5IGRlZmF1bHRcbiAgICovXG4gIG9uQ2xvc2VHYWxsZXJ5QnV0dG9uKGV2ZW50OiBCdXR0b25FdmVudCwgYWN0aW9uOiBBY3Rpb24gPSBBY3Rpb24uTk9STUFMKTogdm9pZCB7XG4gICAgY29uc3QgZXZlbnRUb0VtaXQ6IEJ1dHRvbkV2ZW50ID0gdGhpcy5nZXRCdXR0b25FdmVudFRvRW1pdChldmVudCk7XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25CZWZvcmVIb29rKGV2ZW50VG9FbWl0KTtcbiAgICB0aGlzLmNsb3NlR2FsbGVyeShhY3Rpb24sIGZhbHNlKTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkFmdGVySG9vayhldmVudFRvRW1pdCk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCBieSBDdXJyZW50SW1hZ2VDb21wb25lbnQgYW5kIHRyaWdnZXJlZCB2aWEgS2V5Ym9hcmRTZXJ2aWNlLlxuICAgKiBAcGFyYW0gZXZlbnQgSW1hZ2VNb2RhbEV2ZW50IGV2ZW50IHBheWxvYWRcbiAgICogQHBhcmFtIGFjdGlvbiBBY3Rpb24gdGhhdCB0cmlnZ2VyZWQgdGhlIGNsb3NlIG1ldGhvZC4gYEFjdGlvbi5OT1JNQUxgIGJ5IGRlZmF1bHRcbiAgICovXG4gIG9uQ2xvc2VHYWxsZXJ5KGV2ZW50OiBJbWFnZU1vZGFsRXZlbnQsIGFjdGlvbjogQWN0aW9uID0gQWN0aW9uLk5PUk1BTCk6IHZvaWQge1xuICAgIC8vIHJlbWFwIEltYWdlTW9kYWxFdmVudCB0byBCdXR0b25FdmVudFxuICAgIGNvbnN0IGJ1dHRvbkV2ZW50OiBCdXR0b25FdmVudCA9IHtcbiAgICAgIGJ1dHRvbjoge1xuICAgICAgICB0eXBlOiBCdXR0b25UeXBlLkNMT1NFXG4gICAgICB9IGFzIEJ1dHRvbkNvbmZpZyxcbiAgICAgIGltYWdlOiBudWxsLFxuICAgICAgYWN0aW9uOiBldmVudC5hY3Rpb24sXG4gICAgICBnYWxsZXJ5SWQ6IGV2ZW50LmdhbGxlcnlJZFxuICAgIH07XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRCdXR0b25CZWZvcmVIb29rKGJ1dHRvbkV2ZW50KTtcbiAgICB0aGlzLmNsb3NlR2FsbGVyeShhY3Rpb24sIGZhbHNlKTtcbiAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdEJ1dHRvbkFmdGVySG9vayhidXR0b25FdmVudCk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIHRvIGNsb3NlIHRoZSBtb2RhbCBnYWxsZXJ5IHNwZWNpZnlpbmcgdGhlIGFjdGlvbi5cbiAgICogSXQgYWxzbyByZXNldCB0aGUgYGtleWJvYXJkU2VydmljZWAgdG8gcHJldmVudCBtdWx0aXBsZSBsaXN0ZW5lcnMuXG4gICAqIEBwYXJhbSBhY3Rpb24gQWN0aW9uIGFjdGlvbiB0eXBlLiBgQWN0aW9uLk5PUk1BTGAgYnkgZGVmYXVsdFxuICAgKiBAcGFyYW0gY2xpY2tPdXRzaWRlIGJvb2xlYW4gdGhhdCBpcyB0cnVlIGlmIGNhbGxlZCBjbGlja2luZyBvbiB0aGUgbW9kYWwgYmFja2dyb3VuZC4gRmFsc2UgYnkgZGVmYXVsdC5cbiAgICogQHBhcmFtIGlzQ2FsbGVkQnlTZXJ2aWNlIGJvb2xlYW4gaXNDYWxsZWRCeVNlcnZpY2UgaXMgdHJ1ZSBpZiBjYWxsZWQgYnkgZ2FsbGVyeS5zZXJ2aWNlLCBvdGhlcndpc2UgZmFsc2UuIEZhbHNlIGJ5IGRlZmF1bHQuXG4gICAqL1xuICBjbG9zZUdhbGxlcnkoYWN0aW9uOiBBY3Rpb24gPSBBY3Rpb24uTk9STUFMLCBjbGlja091dHNpZGU6IGJvb2xlYW4gPSBmYWxzZSwgaXNDYWxsZWRCeVNlcnZpY2U6IGJvb2xlYW4gPSBmYWxzZSk6IHZvaWQge1xuICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICBpZiAoIWxpYkNvbmZpZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gbGliQ29uZmlnIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cblxuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5lbWl0Q2xvc2UobmV3IEltYWdlTW9kYWxFdmVudCh0aGlzLmlkLCBhY3Rpb24sIHRydWUpKTtcbiAgICB0aGlzLmtleWJvYXJkU2VydmljZS5yZXNldChsaWJDb25maWcpO1xuICAgIHRoaXMubW9kYWxHYWxsZXJ5U2VydmljZS5jbG9zZSh0aGlzLmlkLCBjbGlja091dHNpZGUpO1xuXG4gICAgaWYgKGlzQ2FsbGVkQnlTZXJ2aWNlKSB7XG4gICAgICAvLyB0aGUgZm9sbG93aW5nIGlzIHJlcXVpcmVkLCBvdGhlcndpc2UgdGhlIHZpZXcgd2lsbCBub3QgYmUgdXBkYXRlZFxuICAgICAgLy8gdGhpcyBoYXBwZW5zIG9ubHkgaWYgY2FsbGVkIGJ5IGdhbGxlcnkuc2VydmljZVxuICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCB3aGVuIHRoZSBpbWFnZSBjaGFuZ2VzIGFuZCB1c2VkIHRvIHVwZGF0ZSB0aGUgYGN1cnJlbnRJbWFnZWAgb2JqZWN0LlxuICAgKiBAcGFyYW0gZXZlbnQgSW1hZ2VNb2RhbEV2ZW50IGV2ZW50IHBheWxvYWRcbiAgICovXG4gIG9uQ2hhbmdlQ3VycmVudEltYWdlKGV2ZW50OiBJbWFnZU1vZGFsRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBuZXdJbmRleDogbnVtYmVyID0gZXZlbnQucmVzdWx0IGFzIG51bWJlcjtcbiAgICBpZiAobmV3SW5kZXggPCAwIHx8IG5ld0luZGV4ID49IHRoaXMuaW1hZ2VzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuY3VycmVudEltYWdlID0gdGhpcy5pbWFnZXNbbmV3SW5kZXhdO1xuXG4gICAgLy8gZW1pdCBmaXJzdC9sYXN0IGV2ZW50IGJhc2VkIG9uIG5ld0luZGV4IHZhbHVlXG4gICAgdGhpcy5lbWl0Qm91bmRhcnlFdmVudChldmVudC5hY3Rpb24sIG5ld0luZGV4KTtcblxuICAgIC8vIGVtaXQgY3VycmVudCB2aXNpYmxlIGltYWdlIGluZGV4XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRTaG93KG5ldyBJbWFnZU1vZGFsRXZlbnQodGhpcy5pZCwgZXZlbnQuYWN0aW9uLCBuZXdJbmRleCArIDEpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgY2FsbGVkIHdoZW4geW91IGNsaWNrICdvdXRzaWRlJyAoaS5lLiBvbiB0aGUgc2VtaS10cmFuc3BhcmVudCBiYWNrZ3JvdW5kKVxuICAgKiB0byBjbG9zZSB0aGUgbW9kYWwgZ2FsbGVyeSBpZiBgZW5hYmxlQ2xvc2VPdXRzaWRlYCBpcyB0cnVlLlxuICAgKiBAcGFyYW0gZXZlbnQgYm9vbGVhbiB0aGF0IGlzIHRydWUgdG8gY2xvc2UgdGhlIG1vZGFsIGdhbGxlcnksIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgb25DbGlja091dHNpZGUoZXZlbnQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoZXZlbnQgJiYgdGhpcy5lbmFibGVDbG9zZU91dHNpZGUpIHtcbiAgICAgIHRoaXMuY2xvc2VHYWxsZXJ5KEFjdGlvbi5DTElDSywgdHJ1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgd2hlbiBhbiBpbWFnZSBpcyBsb2FkZWQgYW5kIHRoZSBsb2FkaW5nIHNwaW5uZXIgaGFzIGdvbmUuXG4gICAqIEl0IHNldHMgdGhlIHByZXZpb3VzbHlMb2FkZWQgZmxhZyBpbnNpZGUgdGhlIEltYWdlIHRvIGhpZGUgbG9hZGluZyBzcGlubmVyIHdoZW4gZGlzcGxheWVkIGFnYWluLlxuICAgKiBAcGFyYW0gZXZlbnQgSW1hZ2VMb2FkRXZlbnQgZXZlbnQgcGF5bG9hZFxuICAgKi9cbiAgb25JbWFnZUxvYWQoZXZlbnQ6IEltYWdlTG9hZEV2ZW50KTogdm9pZCB7XG4gICAgLy8gc2V0cyBhcyBwcmV2aW91c2x5IGxvYWRlZCB0aGUgaW1hZ2Ugd2l0aCBpbmRleCBzcGVjaWZpZWQgYnkgYGV2ZW50LnN0YXR1c2BcbiAgICB0aGlzLmltYWdlcyA9IHRoaXMuaW1hZ2VzLm1hcCgoaW1nOiBJbnRlcm5hbExpYkltYWdlKSA9PiB7XG4gICAgICBpZiAoaW1nICYmIGltZy5pZCA9PT0gZXZlbnQuaWQpIHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oe30sIGltZywgeyBwcmV2aW91c2x5TG9hZGVkOiBldmVudC5zdGF0dXMgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gaW1nO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgd2hlbiBhIGRvdCBpcyBjbGlja2VkIGFuZCB1c2VkIHRvIHVwZGF0ZSB0aGUgY3VycmVudCBpbWFnZS5cbiAgICogQHBhcmFtIGluZGV4IG51bWJlciBpbmRleCBvZiB0aGUgY2xpY2tlZCBkb3RcbiAgICovXG4gIG9uQ2xpY2tEb3QoaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuY3VycmVudEltYWdlID0gdGhpcy5pbWFnZXNbaW5kZXhdO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCBjYWxsZWQgd2hlbiBhbiBpbWFnZSBwcmV2aWV3IGlzIGNsaWNrZWQgYW5kIHVzZWQgdG8gdXBkYXRlIHRoZSBjdXJyZW50IGltYWdlLlxuICAgKiBAcGFyYW0gZXZlbnQgSW1hZ2VNb2RhbEV2ZW50IHByZXZpZXcgaW1hZ2VcbiAgICovXG4gIG9uQ2xpY2tQcmV2aWV3KGV2ZW50OiBJbWFnZU1vZGFsRXZlbnQpOiB2b2lkIHtcbiAgICB0aGlzLm9uQ2hhbmdlQ3VycmVudEltYWdlKGV2ZW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gY2xlYW51cCByZXNvdXJjZXMuIEluIGZhY3QsIHRoaXMgd2lsbCByZXNldCBrZXlib2FyZCdzIHNlcnZpY2UuXG4gICAqIFRoaXMgaXMgYW4gQW5ndWxhcidzIGxpZmVjeWNsZSBob29rIHRoYXQgaXMgY2FsbGVkIHdoZW4gdGhpcyBjb21wb25lbnQgaXMgZGVzdHJveWVkLlxuICAgKi9cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgaWYgKHRoaXMua2V5Ym9hcmRTZXJ2aWNlKSB7XG4gICAgICBjb25zdCBsaWJDb25maWc6IExpYkNvbmZpZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlnU2VydmljZS5nZXRDb25maWcodGhpcy5pZCk7XG4gICAgICBpZiAodGhpcy5pZCAmJiBsaWJDb25maWcpIHtcbiAgICAgICAgdGhpcy5rZXlib2FyZFNlcnZpY2UucmVzZXQobGliQ29uZmlnKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHRoaXMudXBkYXRlSW1hZ2VzU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLnVwZGF0ZUltYWdlc1N1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIH1cbiAgICB0aGlzLmlkVmFsaWRhdG9yU2VydmljZS5yZW1vdmUodGhpcy5pZCk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIHRvIHNob3cgdGhlIG1vZGFsIGdhbGxlcnkgZGlzcGxheWluZyB0aGUgY3VycmVudEltYWdlLlxuICAgKiBJdCB3aWxsIGFsc28gcmVnaXN0ZXIgYSBuZXcgYGtleWJvYXJkU2VydmljZWAgdG8gY2F0Y2gga2V5Ym9hcmQncyBldmVudHMgdG8gZG93bmxvYWQgdGhlIGN1cnJlbnRcbiAgICogaW1hZ2Ugd2l0aCBrZXlib2FyZCdzIHNob3J0Y3V0cy4gVGhpcyBzZXJ2aWNlLCB3aWxsIGJlIHJlbW92ZWQgZWl0aGVyIHdoZW4gbW9kYWwgZ2FsbGVyeSBjb21wb25lbnRcbiAgICogd2lsbCBiZSBkZXN0cm95ZWQgb3Igd2hlbiB0aGUgZ2FsbGVyeSBpcyBjbG9zZWQgaW52b2tpbmcgdGhlIGBjbG9zZUdhbGxlcnlgIG1ldGhvZC5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgc2hvd01vZGFsR2FsbGVyeSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pZCA9PT0gbnVsbCB8fCB0aGlzLmlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGlkIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBjb25zdCBsaWJDb25maWc6IExpYkNvbmZpZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlnU2VydmljZS5nZXRDb25maWcodGhpcy5pZCk7XG4gICAgaWYgKCFsaWJDb25maWcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGxpYkNvbmZpZyBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG5cbiAgICB0aGlzLmtleWJvYXJkU2VydmljZS5pbml0KGxpYkNvbmZpZykudGhlbigoKSA9PiB7XG4gICAgICB0aGlzLmtleWJvYXJkU2VydmljZS5hZGQoKGV2ZW50OiBLZXlib2FyZEV2ZW50LCBjb21ibzogc3RyaW5nKSA9PiB7XG4gICAgICAgIGlmIChldmVudC5wcmV2ZW50RGVmYXVsdCkge1xuICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gaW50ZXJuZXQgZXhwbG9yZXJcbiAgICAgICAgICBldmVudC5yZXR1cm5WYWx1ZSA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuZG93bmxvYWRJbWFnZSgpO1xuICAgICAgfSwgbGliQ29uZmlnKTtcblxuICAgICAgY29uc3QgY3VycmVudEluZGV4OiBudW1iZXIgPSB0aGlzLmltYWdlcy5pbmRleE9mKHRoaXMuY3VycmVudEltYWdlKTtcbiAgICAgIC8vIGVtaXQgYSBuZXcgSW1hZ2VNb2RhbEV2ZW50IHdpdGggdGhlIGluZGV4IG9mIHRoZSBjdXJyZW50IGltYWdlXG4gICAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdFNob3cobmV3IEltYWdlTW9kYWxFdmVudCh0aGlzLmlkLCBBY3Rpb24uTE9BRCwgY3VycmVudEluZGV4ICsgMSkpO1xuICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gZG93bmxvYWQgdGhlIGN1cnJlbnQgaW1hZ2UsIG9ubHkgaWYgYGRvd25sb2FkYWJsZWAgaXMgdHJ1ZS5cbiAgICogSXQgY29udGFpbnMgYWxzbyBhIGxvZ2ljIHRvIGVuYWJsZSBkb3dubG9hZGluZyBmZWF0dXJlcyBhbHNvIGZvciBJRTExLlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBkb3dubG9hZEltYWdlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlkID09PSBudWxsIHx8IHRoaXMuaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gaWQgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICBpZiAoIWxpYkNvbmZpZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gbGliQ29uZmlnIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnJlbnRJbWFnZUNvbmZpZzogQ3VycmVudEltYWdlQ29uZmlnIHwgdW5kZWZpbmVkID0gbGliQ29uZmlnLmN1cnJlbnRJbWFnZUNvbmZpZztcbiAgICBpZiAoY3VycmVudEltYWdlQ29uZmlnICYmICFjdXJyZW50SW1hZ2VDb25maWcuZG93bmxvYWRhYmxlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIElmIElFMTEgb3IgTWljcm9zb2Z0IEVkZ2UgdXNlIG1zU2F2ZUJsb2IoLi4uKVxuICAgIGlmICh0aGlzLmlzSUVvckVkZ2UoKSkge1xuICAgICAgLy8gSSBjYW5ub3QgdXNlIGZldGNoIEFQSSBiZWNhdXNlIElFMTEgZG9lc24ndCBzdXBwb3J0IGl0LFxuICAgICAgLy8gc28gSSBoYXZlIHRvIHN3aXRjaCB0byBYTUxIdHRwUmVxdWVzdFxuICAgICAgdGhpcy5kb3dubG9hZEltYWdlT25seUlFb3JFZGdlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGZvciBhbGwgb3RoZXIgYnJvd3NlcnNcbiAgICAgIHRoaXMuZG93bmxvYWRJbWFnZUFsbEJyb3dzZXJzKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0byBjb252ZXJ0IGEgYmFzZTY0IHRvIGEgQmxvYlxuICAgKiBAcGFyYW0gYmFzZTY0RGF0YSBzdHJpbmcgd2l0aCBiYXNlNjQgZGF0YVxuICAgKiBAcGFyYW0gY29udGVudFR5cGUgc3RyaW5nIHdpdGggdGhlIE1JTUUgdHlwZVxuICAgKiBAcmV0dXJuIEJsb2IgY29udmVydGVkIGZyb20gdGhlIGlucHV0IGJhc2U2NERhdGFcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgYmFzZTY0dG9CbG9iKGJhc2U2NERhdGE6IHN0cmluZywgY29udGVudFR5cGU6IHN0cmluZyA9ICcnKTogQmxvYiB7XG4gICAgY29uc3Qgc2xpY2VTaXplID0gMTAyNDtcbiAgICBjb25zdCBieXRlQ2hhcmFjdGVyczogc3RyaW5nID0gYXRvYihiYXNlNjREYXRhKTtcbiAgICBjb25zdCBieXRlc0xlbmd0aDogbnVtYmVyID0gYnl0ZUNoYXJhY3RlcnMubGVuZ3RoO1xuICAgIGNvbnN0IHNsaWNlc0NvdW50OiBudW1iZXIgPSBNYXRoLmNlaWwoYnl0ZXNMZW5ndGggLyBzbGljZVNpemUpO1xuICAgIGNvbnN0IGJ5dGVBcnJheXM6IEFycmF5PFVpbnQ4QXJyYXk+ID0gbmV3IEFycmF5KHNsaWNlc0NvdW50KTtcbiAgICBmb3IgKGxldCBzbGljZUluZGV4ID0gMDsgc2xpY2VJbmRleCA8IHNsaWNlc0NvdW50OyArK3NsaWNlSW5kZXgpIHtcbiAgICAgIGNvbnN0IGJlZ2luOiBudW1iZXIgPSBzbGljZUluZGV4ICogc2xpY2VTaXplO1xuICAgICAgY29uc3QgZW5kOiBudW1iZXIgPSBNYXRoLm1pbihiZWdpbiArIHNsaWNlU2l6ZSwgYnl0ZXNMZW5ndGgpO1xuICAgICAgY29uc3QgYnl0ZXM6IEFycmF5PG51bWJlcj4gPSBuZXcgQXJyYXkoZW5kIC0gYmVnaW4pO1xuICAgICAgZm9yIChsZXQgb2Zmc2V0ID0gYmVnaW4sIGkgPSAwOyBvZmZzZXQgPCBlbmQ7ICsraSwgKytvZmZzZXQpIHtcbiAgICAgICAgYnl0ZXNbaV0gPSBieXRlQ2hhcmFjdGVyc1tvZmZzZXRdLmNoYXJDb2RlQXQoMCk7XG4gICAgICB9XG4gICAgICBieXRlQXJyYXlzW3NsaWNlSW5kZXhdID0gbmV3IFVpbnQ4QXJyYXkoYnl0ZXMpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IEJsb2IoYnl0ZUFycmF5cywgeyB0eXBlOiBjb250ZW50VHlwZSB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcml2YXRlIG1ldGhvZCB0byBkb3dubG9hZCB0aGUgY3VycmVudCBpbWFnZSBmb3IgYWxsIGJyb3dzZXJzIGV4Y2VwdCBmb3IgSUUxMS5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgZG93bmxvYWRJbWFnZUFsbEJyb3dzZXJzKCk6IHZvaWQge1xuICAgIGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgbGV0IGlzQmFzZTY0ID0gZmFsc2U7XG4gICAgbGV0IGltZzogc3RyaW5nO1xuICAgIC8vIGNvbnZlcnQgYSBTYWZlUmVzb3VyY2VVcmwgdG8gYSBzdHJpbmdcbiAgICBpZiAodHlwZW9mIHRoaXMuY3VycmVudEltYWdlLm1vZGFsLmltZyA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGltZyA9IHRoaXMuY3VycmVudEltYWdlLm1vZGFsLmltZyBhcyBzdHJpbmc7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGlmIGl0J3MgYSBTYWZlUmVzb3VyY2VVcmxcbiAgICAgIGltZyA9IHRoaXMuc2FuaXRpemVyLnNhbml0aXplKFNlY3VyaXR5Q29udGV4dC5SRVNPVVJDRV9VUkwsIHRoaXMuY3VycmVudEltYWdlLm1vZGFsLmltZykgYXMgc3RyaW5nO1xuICAgIH1cbiAgICBpZiAoaW1nLmluY2x1ZGVzKCdkYXRhOmltYWdlLycpIHx8IGltZy5pbmNsdWRlcygnO2Jhc2U2NCwnKSkge1xuICAgICAgY29uc3QgZXh0ZW5zaW9uOiBzdHJpbmcgPSBpbWcucmVwbGFjZSgnZGF0YTppbWFnZS8nLCAnJykuc3BsaXQoJztiYXNlNjQsJylbMF07XG4gICAgICBjb25zdCBwdXJlQmFzZTY0OiBzdHJpbmcgPSBpbWcuc3BsaXQoJztiYXNlNjQsJylbMV07XG4gICAgICBjb25zdCBibG9iOiBCbG9iID0gdGhpcy5iYXNlNjR0b0Jsb2IocHVyZUJhc2U2NCwgJ2ltYWdlLycgKyBleHRlbnNpb24pO1xuICAgICAgbGluay5ocmVmID0gVVJMLmNyZWF0ZU9iamVjdFVSTChibG9iKTtcbiAgICAgIGlzQmFzZTY0ID0gdHJ1ZTtcbiAgICAgIGxpbmsuc2V0QXR0cmlidXRlKCdkb3dubG9hZCcsIHRoaXMuZ2V0RmlsZU5hbWUodGhpcy5jdXJyZW50SW1hZ2UsIGlzQmFzZTY0LCBleHRlbnNpb24pKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbGluay5ocmVmID0gaW1nO1xuICAgICAgbGluay5zZXRBdHRyaWJ1dGUoJ2Rvd25sb2FkJywgdGhpcy5nZXRGaWxlTmFtZSh0aGlzLmN1cnJlbnRJbWFnZSwgaXNCYXNlNjQpKTtcbiAgICB9XG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChsaW5rKTtcbiAgICBsaW5rLmNsaWNrKCk7XG4gICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChsaW5rKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcml2YXRlIG1ldGhvZCB0byBkb3dubG9hZCB0aGUgY3VycmVudCBpbWFnZSBvbmx5IGZvciBJRTExIHVzaW5nXG4gICAqIGN1c3RvbSBqYXZhc2NyaXB0J3MgbWV0aG9kcyBhdmFpbGFibGUgb25seSBvbiBJRS5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgZG93bmxvYWRJbWFnZU9ubHlJRW9yRWRnZSgpOiB2b2lkIHtcbiAgICBpZiAoaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybUlkKSkge1xuICAgICAgY29uc3QgcmVxID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgICByZXEub3BlbignR0VUJywgdGhpcy5jdXJyZW50SW1hZ2UubW9kYWwuaW1nIGFzIHN0cmluZywgdHJ1ZSk7XG4gICAgICByZXEucmVzcG9uc2VUeXBlID0gJ2FycmF5YnVmZmVyJztcbiAgICAgIHJlcS5vbmxvYWQgPSBldmVudCA9PiB7XG4gICAgICAgIGNvbnN0IGJsb2IgPSBuZXcgQmxvYihbcmVxLnJlc3BvbnNlXSwgeyB0eXBlOiAnaW1hZ2UvcG5nJyB9KTtcbiAgICAgICAgd2luZG93Lm5hdmlnYXRvci5tc1NhdmVCbG9iKGJsb2IsIHRoaXMuZ2V0RmlsZU5hbWUodGhpcy5jdXJyZW50SW1hZ2UpKTtcbiAgICAgIH07XG4gICAgICByZXEuc2VuZCgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQcml2YXRlIG1ldGhvZCB0byBnZXQgdGhlIGBCdXR0b25FdmVudGAgdG8gZW1pdCwgbWVyZ2luZyB0aGUgaW5wdXQgYEJ1dHRvbkV2ZW50YFxuICAgKiB3aXRoIHRoZSBjdXJyZW50IGltYWdlLlxuICAgKiBAcGFyYW0gZXZlbnQgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZCB0byByZXR1cm5cbiAgICogQHJldHVybnMgQnV0dG9uRXZlbnQgZXZlbnQgcGF5bG9hZCB3aXRoIHRoZSBjdXJyZW50IGltYWdlIGluY2x1ZGVkXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGdldEJ1dHRvbkV2ZW50VG9FbWl0KGV2ZW50OiBCdXR0b25FdmVudCk6IEJ1dHRvbkV2ZW50IHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihldmVudCwgeyBpbWFnZTogdGhpcy5jdXJyZW50SW1hZ2UgfSk7XG4gIH1cblxuICAvKipcbiAgICogUHJpdmF0ZSBtZXRob2QgdG8gZ2V0IHRoZSBmaWxlIG5hbWUgZnJvbSBhbiBpbnB1dCBwYXRoLlxuICAgKiBUaGlzIGlzIHVzZWQgZWl0aGVyIHRvIGdldCB0aGUgaW1hZ2UncyBuYW1lIGZyb20gaXRzIHBhdGggb3IgZnJvbSB0aGUgSW1hZ2UgaXRzZWxmLFxuICAgKiBpZiBzcGVjaWZpZWQgYXMgJ2Rvd25sb2FkRmlsZU5hbWUnIGJ5IHRoZSB1c2VyLlxuICAgKiBAcGFyYW0gaW1hZ2UgSW1hZ2UgaW1hZ2UgdG8gZXh0cmFjdCBpdHMgZmlsZSBuYW1lXG4gICAqIEBwYXJhbSBpc0Jhc2U2NCBib29sZWFuIHRvIHNldCBpZiB0aGUgaW1hZ2UgaXMgYSBiYXNlNjQgZmlsZSBvciBub3QuIEZhbHNlIGJ5IGRlZmF1bHQuXG4gICAqIEBwYXJhbSBiYXNlNjRFeHRlbnNpb24gc3RyaW5nIHRvIGZvcmNlIHRoZSBleHRlbnNpb24gb2YgdGhlIGJhc2U2NCBpbWFnZS4gRW1wdHkgc3RyaW5nIGJ5IGRlZmF1bHQuXG4gICAqIEByZXR1cm5zIHN0cmluZyBzdHJpbmcgZmlsZSBuYW1lIG9mIHRoZSBpbnB1dCBpbWFnZS5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgZ2V0RmlsZU5hbWUoaW1hZ2U6IEltYWdlLCBpc0Jhc2U2NDogYm9vbGVhbiA9IGZhbHNlLCBiYXNlNjRFeHRlbnNpb246IHN0cmluZyA9ICcnKTogc3RyaW5nIHtcbiAgICBpZiAoIWltYWdlLm1vZGFsLmRvd25sb2FkRmlsZU5hbWUgfHwgaW1hZ2UubW9kYWwuZG93bmxvYWRGaWxlTmFtZS5sZW5ndGggPT09IDApIHtcbiAgICAgIGlmIChpc0Jhc2U2NCkge1xuICAgICAgICByZXR1cm4gYEltYWdlLSR7aW1hZ2UuaWR9LiR7YmFzZTY0RXh0ZW5zaW9uICE9PSAnJyA/IGJhc2U2NEV4dGVuc2lvbiA6ICdwbmcnfWA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gKGltYWdlLm1vZGFsLmltZyBhcyBzdHJpbmcpLnJlcGxhY2UoL14uKltcXFxcXFwvXS8sICcnKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGltYWdlLm1vZGFsLmRvd25sb2FkRmlsZU5hbWU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFByaXZhdGUgbWV0aG9kIHRvIGluaXRpYWxpemUgYGltYWdlc2AgYXMgYXJyYXkgb2YgYEltYWdlYHMuXG4gICAqIEFsc28sIGl0IHdpbGwgZW1pdCBJbWFnZU1vZGFsRXZlbnQgdG8gc2F5IHRoYXQgaW1hZ2VzIGFyZSBsb2FkZWQuXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGluaXRJbWFnZXMoKTogdm9pZCB7XG4gICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRIYXNEYXRhKG5ldyBJbWFnZU1vZGFsRXZlbnQodGhpcy5pZCwgQWN0aW9uLkxPQUQsIHRydWUpKTtcbiAgICB0aGlzLnNob3dHYWxsZXJ5ID0gdGhpcy5pbWFnZXMubGVuZ3RoID4gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcml2YXRlIG1ldGhvZCB0byBlbWl0IGV2ZW50cyB3aGVuIGVpdGhlciB0aGUgbGFzdCBvciB0aGUgZmlyc3QgaW1hZ2UgYXJlIHZpc2libGUuXG4gICAqIEBwYXJhbSBhY3Rpb24gQWN0aW9uIEVudW0gb2YgdHlwZSBBY3Rpb24gdGhhdCByZXByZXNlbnRzIHRoZSBzb3VyY2Ugb2YgdGhlIGV2ZW50IHRoYXQgY2hhbmdlZCB0aGVcbiAgICogIGN1cnJlbnQgaW1hZ2UgdG8gdGhlIGZpcnN0IG9uZSBvciB0aGUgbGFzdCBvbmUuXG4gICAqIEBwYXJhbSBpbmRleFRvQ2hlY2sgbnVtYmVyIGlzIHRoZSBpbmRleCBudW1iZXIgb2YgdGhlIGltYWdlICh0aGUgZmlyc3Qgb3IgdGhlIGxhc3Qgb25lKS5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgZW1pdEJvdW5kYXJ5RXZlbnQoYWN0aW9uOiBBY3Rpb24sIGluZGV4VG9DaGVjazogbnVtYmVyKTogdm9pZCB7XG4gICAgLy8gdG8gZW1pdCBmaXJzdC9sYXN0IGV2ZW50XG4gICAgc3dpdGNoIChpbmRleFRvQ2hlY2spIHtcbiAgICAgIGNhc2UgMDpcbiAgICAgICAgdGhpcy5tb2RhbEdhbGxlcnlTZXJ2aWNlLmVtaXRGaXJzdEltYWdlKG5ldyBJbWFnZU1vZGFsRXZlbnQodGhpcy5pZCwgYWN0aW9uLCB0cnVlKSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0aGlzLmltYWdlcy5sZW5ndGggLSAxOlxuICAgICAgICB0aGlzLm1vZGFsR2FsbGVyeVNlcnZpY2UuZW1pdExhc3RJbWFnZShuZXcgSW1hZ2VNb2RhbEV2ZW50KHRoaXMuaWQsIGFjdGlvbiwgdHJ1ZSkpO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUHJpdmF0ZSBtZXRob2QgdG8gY2hlY2sgaWYgdGhpcyBsaWJyYXJ5IGlzIHJ1bm5pbmcgb25cbiAgICogTWljcm9zb2Z0IGJyb3dzZXJzIG9yIG5vdCAoaS5lLiBpdCBkZXRlY3RzIGJvdGggSUUxMSBhbmQgRWRnZSlcbiAgICogc3VwcG9ydGluZyBhbHNvIFNlcnZlci1TaWRlIFJlbmRlcmluZy5cbiAgICogSW5zcGlyZWQgYnkgaHR0cHM6Ly9tc2RuLm1pY3Jvc29mdC5jb20vaXQtaXQvbGlicmFyeS9oaDc3OTAxNih2PXZzLjg1KS5hc3B4XG4gICAqIEByZXR1cm5zIGJvb2xlYW4gdHJ1ZSBpZiBJRTExIG9yIEVkZ2UsIGZhbHNlIG90aGVyd2lzZVxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBpc0lFb3JFZGdlKCk6IGJvb2xlYW4ge1xuICAgIGlmIChpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpKSB7XG4gICAgICAvLyBpZiBib3RoIEJsb2IgY29uc3RydWN0b3IgYW5kIG1zU2F2ZU9yT3BlbkJsb2IgYXJlIHN1cHBvcnRlZCBieSB0aGUgY3VycmVudCBicm93c2VyXG4gICAgICByZXR1cm4gISF3aW5kb3cuQmxvYiAmJiAhIXdpbmRvdy5uYXZpZ2F0b3IubXNTYXZlT3JPcGVuQmxvYjtcbiAgICB9XG4gICAgaWYgKGlzUGxhdGZvcm1TZXJ2ZXIodGhpcy5wbGF0Zm9ybUlkKSkge1xuICAgICAgLy8gc2VydmVyIG9ubHlcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cbiIsIjxkaXYgaWQ9XCJtb2RhbC1nYWxsZXJ5LXdyYXBwZXJcIlxuICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImFjY2Vzc2liaWxpdHlDb25maWcubW9kYWxHYWxsZXJ5Q29udGVudEFyaWFMYWJlbFwiXG4gICAgIFt0aXRsZV09XCJhY2Nlc3NpYmlsaXR5Q29uZmlnLm1vZGFsR2FsbGVyeUNvbnRlbnRUaXRsZVwiXG4gICAgIGtzQ2xpY2tPdXRzaWRlIFtjbGlja091dHNpZGVFbmFibGVdPVwiZW5hYmxlQ2xvc2VPdXRzaWRlXCJcbiAgICAgKGNsaWNrT3V0c2lkZSk9XCJvbkNsaWNrT3V0c2lkZSgkZXZlbnQpXCI+XG5cbiAgPGRpdiBpZD1cImZsZXgtbWluLWhlaWdodC1pZS1maXhcIj5cbiAgICA8ZGl2IGlkPVwibW9kYWwtZ2FsbGVyeS1jb250YWluZXJcIj5cblxuICAgICAgPGtzLXVwcGVyLWJ1dHRvbnMgW2lkXT1cImlkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIFtjdXJyZW50SW1hZ2VdPVwiY3VycmVudEltYWdlXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChkZWxldGUpPVwib25EZWxldGUoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAobmF2aWdhdGUpPVwib25OYXZpZ2F0ZSgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChkb3dubG9hZCk9XCJvbkRvd25sb2FkKCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKGNsb3NlQnV0dG9uKT1cIm9uQ2xvc2VHYWxsZXJ5QnV0dG9uKCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKGZ1bGxzY3JlZW4pPVwib25GdWxsU2NyZWVuKCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKGN1c3RvbUVtaXQpPVwib25DdXN0b21FbWl0KCRldmVudClcIj48L2tzLXVwcGVyLWJ1dHRvbnM+XG5cbiAgICAgIDxrcy1jdXJyZW50LWltYWdlIFtpZF09XCJpZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbaW1hZ2VzXT1cImltYWdlc1wiXG4gICAgICAgICAgICAgICAgICAgICAgICBbY3VycmVudEltYWdlXT1cImN1cnJlbnRJbWFnZVwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbaXNPcGVuXT1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKGxvYWRJbWFnZSk9XCJvbkltYWdlTG9hZCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChjaGFuZ2VJbWFnZSk9XCJvbkNoYW5nZUN1cnJlbnRJbWFnZSgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChjbG9zZUdhbGxlcnkpPVwib25DbG9zZUdhbGxlcnkoJGV2ZW50KVwiPjwva3MtY3VycmVudC1pbWFnZT5cblxuICAgICAgPGRpdj5cbiAgICAgICAgPGtzLWRvdHMgW2lkXT1cImlkXCJcbiAgICAgICAgICAgICAgICAgW2ltYWdlc109XCJpbWFnZXNcIlxuICAgICAgICAgICAgICAgICBbY3VycmVudEltYWdlXT1cImN1cnJlbnRJbWFnZVwiXG4gICAgICAgICAgICAgICAgIFtkb3RzQ29uZmlnXT1cImRvdHNDb25maWdcIlxuICAgICAgICAgICAgICAgICAoY2xpY2tEb3QpPVwib25DbGlja0RvdCgkZXZlbnQpXCI+PC9rcy1kb3RzPlxuXG4gICAgICAgIDxrcy1wcmV2aWV3cyBbaWRdPVwiaWRcIlxuICAgICAgICAgICAgICAgICAgICAgW2ltYWdlc109XCJpbWFnZXNcIlxuICAgICAgICAgICAgICAgICAgICAgW2N1cnJlbnRJbWFnZV09XCJjdXJyZW50SW1hZ2VcIlxuICAgICAgICAgICAgICAgICAgICAgKGNsaWNrUHJldmlldyk9XCJvbkNsaWNrUHJldmlldygkZXZlbnQpXCI+PC9rcy1wcmV2aWV3cz5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19