@ks89/angular-modal-gallery 10.0.1 → 11.0.0

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