@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
@@ -0,0 +1,747 @@
1
+ /*
2
+ The MIT License (MIT)
3
+
4
+ Copyright (C) 2017-2021 Stefano Cappa (Ks89)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ */
24
+ // The idea to create a carousel with two Subjects came from ng-bootstrap
25
+ // So a big thank you to the ng-bootstrap team for the interesting implementation that I used here with some customizations.
26
+ import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, HostListener, Inject, Input, Output, PLATFORM_ID } from '@angular/core';
27
+ import { isPlatformBrowser } from '@angular/common';
28
+ import { Subject, timer } from 'rxjs';
29
+ import { filter, map, switchMap, takeUntil } from 'rxjs/operators';
30
+ import { AccessibleComponent } from '../accessible.component';
31
+ import { ImageEvent } from '../../model/image.class';
32
+ import { Action } from '../../model/action.enum';
33
+ import { getIndex } from '../../utils/image.util';
34
+ import { NEXT, PREV } from '../../utils/user-input.util';
35
+ import { DescriptionStrategy } from '../../model/description.interface';
36
+ import { ConfigService } from '../../services/config.service';
37
+ import * as i0 from "@angular/core";
38
+ import * as i1 from "../modal-gallery/modal-gallery.service";
39
+ import * as i2 from "../../services/config.service";
40
+ import * as i3 from "../dots/dots.component";
41
+ import * as i4 from "./carousel-previews/carousel-previews.component";
42
+ import * as i5 from "../../directives/max-size.directive";
43
+ import * as i6 from "@angular/common";
44
+ import * as i7 from "../../directives/size.directive";
45
+ import * as i8 from "../../directives/fallback-image.directive";
46
+ import * as i9 from "../../directives/description.directive";
47
+ /**
48
+ * Component with configurable inline/plain carousel.
49
+ */
50
+ export class CarouselComponent extends AccessibleComponent {
51
+ constructor(
52
+ // tslint:disable-next-line:no-any
53
+ platformId, ngZone, modalGalleryService, configService, ref) {
54
+ super();
55
+ this.platformId = platformId;
56
+ this.ngZone = ngZone;
57
+ this.modalGalleryService = modalGalleryService;
58
+ this.configService = configService;
59
+ this.ref = ref;
60
+ /**
61
+ * Attribute to set ariaLabel of the host component
62
+ */
63
+ this.ariaLabel = `Carousel`;
64
+ /**
65
+ * Array of `InternalLibImage` that represent the model of this library with all images,
66
+ * thumbs and so on.
67
+ */
68
+ this.images = [];
69
+ /**
70
+ * Output to emit an event when an image is clicked.
71
+ */
72
+ this.clickImage = new EventEmitter();
73
+ /**
74
+ * Output to emit an event when current image is changed.
75
+ */
76
+ this.changeImage = new EventEmitter();
77
+ /**
78
+ * Output to emit an event when the current image is the first one.
79
+ */
80
+ this.firstImage = new EventEmitter();
81
+ /**
82
+ * Output to emit an event when the current image is the last one.
83
+ */
84
+ this.lastImage = new EventEmitter();
85
+ /**
86
+ * Enum of type `Action` that represents a mouse click on a button.
87
+ * Declared here to be used inside the template.
88
+ */
89
+ this.clickAction = Action.CLICK;
90
+ /**
91
+ * Enum of type `Action` that represents a keyboard action.
92
+ * Declared here to be used inside the template.
93
+ */
94
+ this.keyboardAction = Action.KEYBOARD;
95
+ /**
96
+ * Boolean that it's true when you are watching the first image (currently visible).
97
+ * False by default
98
+ */
99
+ this.isFirstImage = false;
100
+ /**
101
+ * Boolean that it's true when you are watching the last image (currently visible).
102
+ * False by default
103
+ */
104
+ this.isLastImage = false;
105
+ /**
106
+ * Subject to play the carousel.
107
+ */
108
+ this.start$ = new Subject();
109
+ /**
110
+ * Subject to stop the carousel.
111
+ */
112
+ this.stop$ = new Subject();
113
+ /**
114
+ * Private object without type to define all swipe actions used by hammerjs.
115
+ */
116
+ this.SWIPE_ACTION = {
117
+ LEFT: 'swipeleft',
118
+ RIGHT: 'swiperight',
119
+ UP: 'swipeup',
120
+ DOWN: 'swipedown'
121
+ };
122
+ }
123
+ /**
124
+ * Listener to stop the gallery when the mouse pointer is over the current image.
125
+ */
126
+ onMouseEnter() {
127
+ if (this.id === null || this.id === undefined) {
128
+ throw new Error('Internal library error - id must be defined');
129
+ }
130
+ const libConfig = this.configService.getConfig(this.id);
131
+ if (!libConfig) {
132
+ throw new Error('Internal library error - libConfig must be defined');
133
+ }
134
+ if (!libConfig.carouselPlayConfig || !libConfig.carouselPlayConfig.pauseOnHover) {
135
+ return;
136
+ }
137
+ this.stopCarousel();
138
+ }
139
+ /**
140
+ * Listener to play the gallery when the mouse pointer leave the current image.
141
+ */
142
+ onMouseLeave() {
143
+ if (this.id === null || this.id === undefined) {
144
+ throw new Error('Internal library error - id must be defined');
145
+ }
146
+ const libConfig = this.configService.getConfig(this.id);
147
+ if (!libConfig) {
148
+ throw new Error('Internal library error - libConfig must be defined');
149
+ }
150
+ if (!libConfig.carouselPlayConfig || !libConfig.carouselPlayConfig.pauseOnHover || !libConfig.carouselPlayConfig.autoPlay) {
151
+ return;
152
+ }
153
+ this.playCarousel();
154
+ }
155
+ /**
156
+ * Listener to navigate carousel images with keyboard (left).
157
+ */
158
+ onKeyDownLeft() {
159
+ if (this.id === null || this.id === undefined) {
160
+ throw new Error('Internal library error - id must be defined');
161
+ }
162
+ const libConfig = this.configService.getConfig(this.id);
163
+ if (!libConfig) {
164
+ throw new Error('Internal library error - libConfig must be defined');
165
+ }
166
+ if (!libConfig.carouselConfig || !libConfig.carouselConfig.keyboardEnable) {
167
+ return;
168
+ }
169
+ this.prevImage();
170
+ }
171
+ /**
172
+ * Listener to navigate carousel images with keyboard (right).
173
+ */
174
+ onKeyDownLRight() {
175
+ if (this.id === null || this.id === undefined) {
176
+ throw new Error('Internal library error - id must be defined');
177
+ }
178
+ const libConfig = this.configService.getConfig(this.id);
179
+ if (!libConfig) {
180
+ throw new Error('Internal library error - libConfig must be defined');
181
+ }
182
+ if (!libConfig.carouselConfig || !libConfig.carouselConfig.keyboardEnable) {
183
+ return;
184
+ }
185
+ this.nextImage();
186
+ }
187
+ ngOnInit() {
188
+ if (this.id === null || this.id === undefined) {
189
+ throw new Error('Internal library error - id must be defined');
190
+ }
191
+ if (!this.images || this.images.length === 0) {
192
+ throw new Error('Internal library error - images array must be defined and with at least an element');
193
+ }
194
+ this.configService.setConfig(this.id, this.config);
195
+ const libConfig = this.configService.getConfig(this.id);
196
+ if (!libConfig) {
197
+ throw new Error('Internal library error - libConfig must be defined');
198
+ }
199
+ this.currentImage = this.images[0];
200
+ this.carouselDotsConfig = libConfig.carouselDotsConfig;
201
+ this.accessibilityConfig = libConfig.accessibilityConfig;
202
+ this.carouselSlideInfinite = libConfig.carouselSlideInfinite;
203
+ this.carouselConfig = libConfig.carouselConfig;
204
+ this.carouselImageConfig = libConfig.carouselImageConfig;
205
+ this.manageSlideConfig();
206
+ }
207
+ ngOnChanges(changes) {
208
+ if (this.id === null || this.id === undefined) {
209
+ throw new Error('Internal library error - id must be defined');
210
+ }
211
+ // this.configService.setConfig(this.id, this.config);
212
+ const libConfig = this.configService.getConfig(this.id);
213
+ if (!libConfig) {
214
+ throw new Error('Internal library error - libConfig must be defined');
215
+ }
216
+ const configChange = changes.config;
217
+ // handle changes of dotsConfig.visible
218
+ if (configChange &&
219
+ !configChange.firstChange &&
220
+ (configChange.previousValue.carouselDotsConfig?.visible !== configChange.currentValue.carouselDotsConfig?.visible || (!configChange.previousValue.carouselDotsConfig && !configChange.currentValue.carouselDotsConfig))) {
221
+ this.configService.setConfig(this.id, {
222
+ carouselDotsConfig: configChange.currentValue?.carouselDotsConfig
223
+ });
224
+ this.carouselDotsConfig = configChange.currentValue?.carouselDotsConfig;
225
+ this.ref.markForCheck();
226
+ }
227
+ // handle changes of carouselConfig.showArrows
228
+ if (configChange &&
229
+ !configChange.firstChange &&
230
+ (configChange.previousValue.carouselConfig?.showArrows !== configChange.currentValue.carouselConfig?.showArrows || (!configChange.previousValue.carouselConfig && !configChange.currentValue.carouselConfig))) {
231
+ this.configService.setConfig(this.id, {
232
+ carouselConfig: configChange.currentValue?.carouselConfig
233
+ });
234
+ this.carouselConfig = configChange.currentValue?.carouselConfig;
235
+ this.ref.markForCheck();
236
+ }
237
+ // handle changes of playConfig starting/stopping the carousel accordingly
238
+ if (configChange &&
239
+ !configChange.firstChange &&
240
+ (configChange.previousValue.carouselPlayConfig?.autoPlay !== configChange.currentValue.carouselPlayConfig?.autoPlay || (!configChange.previousValue.carouselPlayConfig && !configChange.currentValue.carouselPlayConfig))) {
241
+ this.configService.setConfig(this.id, {
242
+ carouselPlayConfig: configChange.currentValue?.carouselPlayConfig
243
+ });
244
+ // this.configPlay = playConfigChange.currentValue;
245
+ // if autoplay is enabled, and this is not the
246
+ // first change (to prevent multiple starts at the beginning)
247
+ if (configChange.currentValue.carouselPlayConfig?.autoPlay && !configChange.firstChange) {
248
+ this.start$.next();
249
+ }
250
+ else {
251
+ this.stopCarousel();
252
+ }
253
+ this.ref.markForCheck();
254
+ }
255
+ }
256
+ ngAfterContentInit() {
257
+ // interval doesn't play well with SSR and protractor,
258
+ // so we should run it in the browser and outside Angular
259
+ if (isPlatformBrowser(this.platformId)) {
260
+ if (this.id === null || this.id === undefined) {
261
+ throw new Error('Internal library error - id must be defined');
262
+ }
263
+ const libConfig = this.configService.getConfig(this.id);
264
+ if (!libConfig || !libConfig.carouselPlayConfig) {
265
+ throw new Error('Internal library error - libConfig and carouselPlayConfig must be defined');
266
+ }
267
+ this.ngZone.runOutsideAngular(() => {
268
+ this.start$
269
+ .pipe(map(() => libConfig?.carouselPlayConfig?.interval),
270
+ // tslint:disable-next-line:no-any
271
+ filter((interval) => interval > 0), switchMap(interval => timer(interval).pipe(takeUntil(this.stop$))))
272
+ .subscribe(() => this.ngZone.run(() => {
273
+ if (libConfig.carouselPlayConfig?.autoPlay) {
274
+ this.nextImage();
275
+ }
276
+ this.ref.markForCheck();
277
+ }));
278
+ this.start$.next();
279
+ });
280
+ }
281
+ }
282
+ /**
283
+ * Method called when a dot is clicked and used to update the current image.
284
+ * @param number index of the clicked dot
285
+ */
286
+ onClickDot(index) {
287
+ this.changeCurrentImage(this.images[index], Action.NORMAL);
288
+ }
289
+ /**
290
+ * Method called by events from both keyboard and mouse on a navigation arrow.
291
+ * @param string direction of the navigation that can be either 'next' or 'prev'
292
+ * @param KeyboardEvent | MouseEvent event payload
293
+ * @param Action action that triggered the event or `Action.NORMAL` if not provided
294
+ */
295
+ onNavigationEvent(direction, event, action = Action.NORMAL) {
296
+ const result = super.handleNavigationEvent(direction, event);
297
+ if (result === NEXT) {
298
+ this.nextImage(action);
299
+ }
300
+ else if (result === PREV) {
301
+ this.prevImage(action);
302
+ }
303
+ }
304
+ /**
305
+ * Method triggered when you click on the current image.
306
+ * Also, if modalGalleryEnable is true, you can open the modal-gallery.
307
+ */
308
+ onClickCurrentImage() {
309
+ if (this.id === null || this.id === undefined) {
310
+ throw new Error('Internal library error - id must be defined');
311
+ }
312
+ const libConfig = this.configService.getConfig(this.id);
313
+ if (!libConfig || !libConfig.carouselConfig || !this.currentImage) {
314
+ throw new Error('Internal library error - libConfig, carouselConfig and currentImage must be defined');
315
+ }
316
+ if (!libConfig.carouselConfig.modalGalleryEnable) {
317
+ return;
318
+ }
319
+ const index = getIndex(this.currentImage, this.images);
320
+ this.clickImage.emit(index);
321
+ }
322
+ /**
323
+ * Method to get the image description based on input params.
324
+ * If you provide a full description this will be the visible description, otherwise,
325
+ * it will be built using the `Description` object, concatenating its fields.
326
+ * @param Image image to get its description. If not provided it will be the current image
327
+ * @returns String description of the image (or the current image if not provided)
328
+ * @throws an Error if description isn't available
329
+ */
330
+ getDescriptionToDisplay(image = this.currentImage) {
331
+ if (this.id === null || this.id === undefined) {
332
+ throw new Error('Internal library error - id must be defined');
333
+ }
334
+ const libConfig = this.configService.getConfig(this.id);
335
+ if (!libConfig) {
336
+ throw new Error('Internal library error - libConfig must be defined');
337
+ }
338
+ const configCurrentImageCarousel = libConfig.carouselImageConfig;
339
+ if (!configCurrentImageCarousel || !configCurrentImageCarousel.description) {
340
+ throw new Error('Description input must be a valid object implementing the Description interface');
341
+ }
342
+ if (!image) {
343
+ throw new Error('Internal library error - image must be defined');
344
+ }
345
+ const imageWithoutDescription = !image || !image.modal || !image.modal.description || image.modal.description === '';
346
+ switch (configCurrentImageCarousel.description.strategy) {
347
+ case DescriptionStrategy.HIDE_IF_EMPTY:
348
+ return imageWithoutDescription ? '' : image.modal.description + '';
349
+ case DescriptionStrategy.ALWAYS_HIDDEN:
350
+ return '';
351
+ default:
352
+ // ----------- DescriptionStrategy.ALWAYS_VISIBLE -----------------
353
+ return this.buildTextDescription(image, imageWithoutDescription);
354
+ }
355
+ }
356
+ /**
357
+ * Method used by Hammerjs to support touch gestures (you can also invert the swipe direction with configCurrentImage.invertSwipe).
358
+ * @param action String that represent the direction of the swipe action. 'swiperight' by default.
359
+ */
360
+ swipe(action = this.SWIPE_ACTION.RIGHT) {
361
+ if (this.id === null || this.id === undefined) {
362
+ throw new Error('Internal library error - id must be defined');
363
+ }
364
+ const libConfig = this.configService.getConfig(this.id);
365
+ if (!libConfig || !libConfig.carouselImageConfig) {
366
+ throw new Error('Internal library error - libConfig and carouselImageConfig must be defined');
367
+ }
368
+ const configCurrentImageCarousel = libConfig.carouselImageConfig;
369
+ switch (action) {
370
+ case this.SWIPE_ACTION.RIGHT:
371
+ if (configCurrentImageCarousel.invertSwipe) {
372
+ this.prevImage(Action.SWIPE);
373
+ }
374
+ else {
375
+ this.nextImage(Action.SWIPE);
376
+ }
377
+ break;
378
+ case this.SWIPE_ACTION.LEFT:
379
+ if (configCurrentImageCarousel.invertSwipe) {
380
+ this.nextImage(Action.SWIPE);
381
+ }
382
+ else {
383
+ this.prevImage(Action.SWIPE);
384
+ }
385
+ break;
386
+ // case this.SWIPE_ACTION.UP:
387
+ // break;
388
+ // case this.SWIPE_ACTION.DOWN:
389
+ // break;
390
+ }
391
+ }
392
+ /**
393
+ * Method to go back to the previous image.
394
+ * @param action Enum of type `Action` that represents the source
395
+ * action that moved back to the previous image. `Action.NORMAL` by default.
396
+ */
397
+ prevImage(action = Action.NORMAL) {
398
+ // check if prevImage should be blocked
399
+ if (this.isPreventSliding(0)) {
400
+ return;
401
+ }
402
+ this.changeCurrentImage(this.getPrevImage(), action);
403
+ this.manageSlideConfig();
404
+ this.start$.next();
405
+ }
406
+ /**
407
+ * Method to go back to the previous image.
408
+ * @param action Enum of type `Action` that represents the source
409
+ * action that moved to the next image. `Action.NORMAL` by default.
410
+ */
411
+ nextImage(action = Action.NORMAL) {
412
+ // check if nextImage should be blocked
413
+ if (this.isPreventSliding(this.images.length - 1)) {
414
+ return;
415
+ }
416
+ this.changeCurrentImage(this.getNextImage(), action);
417
+ this.manageSlideConfig();
418
+ this.start$.next();
419
+ }
420
+ /**
421
+ * Method used in the template to track ids in ngFor.
422
+ * @param number index of the array
423
+ * @param Image item of the array
424
+ * @returns number the id of the item
425
+ */
426
+ trackById(index, item) {
427
+ return item.id;
428
+ }
429
+ /**
430
+ * Method called when an image preview is clicked and used to update the current image.
431
+ * @param event an ImageEvent object with the relative action and the index of the clicked preview.
432
+ */
433
+ onClickPreview(event) {
434
+ const imageFound = this.images[event.result];
435
+ if (!!imageFound) {
436
+ this.manageSlideConfig();
437
+ this.changeCurrentImage(imageFound, event.action);
438
+ }
439
+ }
440
+ /**
441
+ * Method to play carousel.
442
+ */
443
+ playCarousel() {
444
+ this.start$.next();
445
+ }
446
+ /**
447
+ * Stops the carousel from cycling through items.
448
+ */
449
+ stopCarousel() {
450
+ this.stop$.next();
451
+ }
452
+ // TODO remove this because duplicated
453
+ /**
454
+ * Method to get `alt attribute`.
455
+ * `alt` specifies an alternate text for an image, if the image cannot be displayed.
456
+ * @param Image image to get its alt description. If not provided it will be the current image
457
+ * @returns String alt description of the image (or the current image if not provided)
458
+ */
459
+ getAltDescriptionByImage(image = this.currentImage) {
460
+ if (!image) {
461
+ return '';
462
+ }
463
+ return image.modal && image.modal.description ? image.modal.description : `Image ${getIndex(image, this.images) + 1}`;
464
+ }
465
+ // TODO remove this because duplicated
466
+ /**
467
+ * Method to get the title attributes based on descriptions.
468
+ * This is useful to prevent accessibility issues, because if DescriptionStrategy is ALWAYS_HIDDEN,
469
+ * it prevents an empty string as title.
470
+ * @param Image image to get its description. If not provided it will be the current image
471
+ * @returns String title of the image based on descriptions
472
+ * @throws an Error if description isn't available
473
+ */
474
+ getTitleToDisplay(image = this.currentImage) {
475
+ if (this.id === null || this.id === undefined) {
476
+ throw new Error('Internal library error - id must be defined');
477
+ }
478
+ const libConfig = this.configService.getConfig(this.id);
479
+ if (!libConfig || !libConfig.carouselImageConfig) {
480
+ throw new Error('Internal library error - libConfig and carouselImageConfig must be defined');
481
+ }
482
+ const configCurrentImageCarousel = libConfig.carouselImageConfig;
483
+ if (!configCurrentImageCarousel || !configCurrentImageCarousel.description) {
484
+ throw new Error('Description input must be a valid object implementing the Description interface');
485
+ }
486
+ const imageWithoutDescription = !image || !image.modal || !image.modal.description || image.modal.description === '';
487
+ const description = this.buildTextDescription(image, imageWithoutDescription);
488
+ return description;
489
+ }
490
+ /**
491
+ * Method to reset carousel (force image with index 0 to be the current image and re-init also previews)
492
+ */
493
+ // temporary removed because never tested
494
+ // reset() {
495
+ // if (this.configPlay && this.configPlay.autoPlay) {
496
+ // this.stopCarousel();
497
+ // }
498
+ // this.currentImage = this.images[0];
499
+ // this.handleBoundaries(0);
500
+ // if (this.configPlay && this.configPlay.autoPlay) {
501
+ // this.playCarousel();
502
+ // }
503
+ // this.ref.markForCheck();
504
+ // }
505
+ /**
506
+ * Method to cleanup resources. In fact, this will stop the carousel.
507
+ * This is an Angular's lifecycle hook that is called when this component is destroyed.
508
+ */
509
+ ngOnDestroy() {
510
+ this.stopCarousel();
511
+ }
512
+ /**
513
+ * Method to change the current image, receiving the new image as input the relative action.
514
+ * @param image an Image object that represents the new image to set as current.
515
+ * @param action Enum of type `Action` that represents the source action that triggered the change.
516
+ */
517
+ changeCurrentImage(image, action) {
518
+ if (this.id === null || this.id === undefined) {
519
+ throw new Error('Internal library error - id must be defined');
520
+ }
521
+ this.currentImage = image;
522
+ const index = getIndex(image, this.images);
523
+ // emit first/last event based on newIndex value
524
+ this.emitBoundaryEvent(action, index);
525
+ // emit current visible image index
526
+ this.changeImage.emit(new ImageEvent(this.id, action, index + 1));
527
+ }
528
+ /**
529
+ * Private method to get the next index.
530
+ * This is necessary because at the end, when you call next again, you'll go to the first image.
531
+ * That happens because all modal images are shown like in a circle.
532
+ */
533
+ getNextImage() {
534
+ if (!this.currentImage) {
535
+ throw new Error('Internal library error - currentImage must be defined');
536
+ }
537
+ const currentIndex = getIndex(this.currentImage, this.images);
538
+ let newIndex = 0;
539
+ if (currentIndex >= 0 && currentIndex < this.images.length - 1) {
540
+ newIndex = currentIndex + 1;
541
+ }
542
+ else {
543
+ newIndex = 0; // start from the first index
544
+ }
545
+ return this.images[newIndex];
546
+ }
547
+ /**
548
+ * Private method to get the previous index.
549
+ * This is necessary because at index 0, when you call prev again, you'll go to the last image.
550
+ * That happens because all modal images are shown like in a circle.
551
+ */
552
+ getPrevImage() {
553
+ if (!this.currentImage) {
554
+ throw new Error('Internal library error - currentImage must be defined');
555
+ }
556
+ const currentIndex = getIndex(this.currentImage, this.images);
557
+ let newIndex = 0;
558
+ if (currentIndex > 0 && currentIndex <= this.images.length - 1) {
559
+ newIndex = currentIndex - 1;
560
+ }
561
+ else {
562
+ newIndex = this.images.length - 1; // start from the last index
563
+ }
564
+ return this.images[newIndex];
565
+ }
566
+ /**
567
+ * Private method to build a text description.
568
+ * This is used also to create titles.
569
+ * @param Image image to get its description. If not provided it will be the current image.
570
+ * @param boolean imageWithoutDescription is a boolean that it's true if the image hasn't a 'modal' description.
571
+ * @returns String description built concatenating image fields with a specific logic.
572
+ */
573
+ buildTextDescription(image, imageWithoutDescription) {
574
+ if (this.id === null || this.id === undefined) {
575
+ throw new Error('Internal library error - id must be defined');
576
+ }
577
+ const libConfig = this.configService.getConfig(this.id);
578
+ if (!libConfig || !libConfig.carouselImageConfig) {
579
+ throw new Error('Internal library error - libConfig and carouselImageConfig must be defined');
580
+ }
581
+ const configCurrentImageCarousel = libConfig.carouselImageConfig;
582
+ if (!configCurrentImageCarousel || !configCurrentImageCarousel.description) {
583
+ throw new Error('Description input must be a valid object implementing the Description interface');
584
+ }
585
+ if (!image) {
586
+ throw new Error('Internal library error - image must be defined');
587
+ }
588
+ // If customFullDescription use it, otherwise proceed to build a description
589
+ if (configCurrentImageCarousel.description.customFullDescription && configCurrentImageCarousel.description.customFullDescription !== '') {
590
+ return configCurrentImageCarousel.description.customFullDescription;
591
+ }
592
+ const currentIndex = getIndex(image, this.images);
593
+ // If the current image hasn't a description,
594
+ // prevent to write the ' - ' (or this.description.beforeTextDescription)
595
+ const prevDescription = configCurrentImageCarousel.description.imageText ? configCurrentImageCarousel.description.imageText : '';
596
+ const midSeparator = configCurrentImageCarousel.description.numberSeparator ? configCurrentImageCarousel.description.numberSeparator : '';
597
+ const middleDescription = currentIndex + 1 + midSeparator + this.images.length;
598
+ if (imageWithoutDescription) {
599
+ return prevDescription + middleDescription;
600
+ }
601
+ const currImgDescription = image.modal && image.modal.description ? image.modal.description : '';
602
+ const endDescription = configCurrentImageCarousel.description.beforeTextDescription + currImgDescription;
603
+ return prevDescription + middleDescription + endDescription;
604
+ }
605
+ /**
606
+ * Private method to update both `isFirstImage` and `isLastImage` based on
607
+ * the index of the current image.
608
+ * @param number currentIndex is the index of the current image
609
+ */
610
+ handleBoundaries(currentIndex) {
611
+ if (this.images.length === 1) {
612
+ this.isFirstImage = true;
613
+ this.isLastImage = true;
614
+ return;
615
+ }
616
+ switch (currentIndex) {
617
+ case 0:
618
+ // execute this only if infinite sliding is disabled
619
+ this.isFirstImage = true;
620
+ this.isLastImage = false;
621
+ break;
622
+ case this.images.length - 1:
623
+ // execute this only if infinite sliding is disabled
624
+ this.isFirstImage = false;
625
+ this.isLastImage = true;
626
+ break;
627
+ default:
628
+ this.isFirstImage = false;
629
+ this.isLastImage = false;
630
+ break;
631
+ }
632
+ }
633
+ /**
634
+ * Private method to manage boundary arrows and sliding.
635
+ * This is based on the slideConfig input to enable/disable 'infinite sliding'.
636
+ * @param number index of the visible image
637
+ */
638
+ manageSlideConfig() {
639
+ if (this.id === null || this.id === undefined) {
640
+ throw new Error('Internal library error - id must be defined');
641
+ }
642
+ const libConfig = this.configService.getConfig(this.id);
643
+ if (!libConfig) {
644
+ throw new Error('Internal library error - libConfig must be defined');
645
+ }
646
+ if (!this.currentImage) {
647
+ throw new Error('Internal library error - currentImage must be defined');
648
+ }
649
+ let index;
650
+ try {
651
+ index = getIndex(this.currentImage, this.images);
652
+ }
653
+ catch (err) {
654
+ console.error('Cannot get the current image index in current-image');
655
+ throw err;
656
+ }
657
+ if (libConfig.carouselSlideInfinite === true) {
658
+ // enable infinite sliding
659
+ this.isFirstImage = false;
660
+ this.isLastImage = false;
661
+ }
662
+ else {
663
+ this.handleBoundaries(index);
664
+ }
665
+ }
666
+ /**
667
+ * Private method to emit events when either the last or the first image are visible.
668
+ * @param action Enum of type Action that represents the source of the event that changed the
669
+ * current image to the first one or the last one.
670
+ * @param indexToCheck is the index number of the image (the first or the last one).
671
+ */
672
+ emitBoundaryEvent(action, indexToCheck) {
673
+ if (this.id === null || this.id === undefined) {
674
+ return;
675
+ }
676
+ // to emit first/last event
677
+ switch (indexToCheck) {
678
+ case 0:
679
+ this.firstImage.emit(new ImageEvent(this.id, action, true));
680
+ break;
681
+ case this.images.length - 1:
682
+ this.lastImage.emit(new ImageEvent(this.id, action, true));
683
+ break;
684
+ }
685
+ }
686
+ /**
687
+ * Private method to check if next/prev actions should be blocked.
688
+ * It checks if carouselSlideInfinite === false and if the image index is equals to the input parameter.
689
+ * If yes, it returns true to say that sliding should be blocked, otherwise not.
690
+ * @param number boundaryIndex that could be either the beginning index (0) or the last index
691
+ * of images (this.images.length - 1).
692
+ * @returns boolean true if carouselSlideInfinite === false and the current index is
693
+ * either the first or the last one.
694
+ */
695
+ isPreventSliding(boundaryIndex) {
696
+ if (this.id === null || this.id === undefined) {
697
+ throw new Error('Internal library error - id must be defined');
698
+ }
699
+ const libConfig = this.configService.getConfig(this.id);
700
+ if (!libConfig) {
701
+ throw new Error('Internal library error - libConfig must be defined');
702
+ }
703
+ if (!this.currentImage) {
704
+ throw new Error('Internal library error - currentImage must be defined');
705
+ }
706
+ return !libConfig.carouselSlideInfinite && getIndex(this.currentImage, this.images) === boundaryIndex;
707
+ }
708
+ }
709
+ CarouselComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: CarouselComponent, deps: [{ token: PLATFORM_ID }, { token: i0.NgZone }, { token: i1.ModalGalleryService }, { token: i2.ConfigService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
710
+ CarouselComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.0", type: CarouselComponent, selector: "ks-carousel", inputs: { id: "id", images: "images", config: "config" }, outputs: { clickImage: "clickImage", changeImage: "changeImage", firstImage: "firstImage", lastImage: "lastImage" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "keydown.arrowLeft": "onKeyDownLeft()", "keydown.arrowRight": "onKeyDownLRight()" }, properties: { "attr.aria-label": "this.ariaLabel" } }, providers: [ConfigService], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<main id=\"carousel-container\"\n [attr.aria-label]=\"accessibilityConfig?.carouselContainerAriaLabel\"\n [title]=\"accessibilityConfig?.carouselContainerTitle\"\n ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n maxHeight: ''}\">\n\n\n <!-- Workaround to support 2 ng-content in the same template in 2 ngIf (https://github.com/angular/angular/issues/22972) -->\n <ng-template #content><ng-content></ng-content></ng-template>\n\n <figure class=\"current-figure\" *ngIf=\"currentImage && currentImage.modal\"\n ksSize [sizeConfig]=\"{width: carouselConfig?.maxWidth,\n height: ''}\">\n\n <a class=\"nav-left\" *ngIf=\"carouselConfig?.showArrows\"\n [attr.aria-label]=\"accessibilityConfig?.carouselPrevImageAriaLabel\"\n [tabIndex]=\"isLastImage && !carouselSlideInfinite ? -1 : 0\" role=\"button\"\n (click)=\"onNavigationEvent('left', $event, clickAction)\" (keyup)=\"onNavigationEvent('left', $event, keyboardAction)\">\n <div class=\"inside {{(isFirstImage && !carouselSlideInfinite) || !carouselConfig.showArrows ? 'empty-arrow-image' : 'left-arrow-image'}}\"\n aria-hidden=\"true\"\n [title]=\"accessibilityConfig?.carouselPrevImageTitle\"></div>\n </a>\n\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n\n <img id=\"current-image\"\n [style.object-fit]=\"carouselConfig?.objectFit\"\n ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n maxHeight: carouselConfig?.maxHeight}\"\n [src]=\"currentImage.modal.img\"\n ksFallbackImage [fallbackImg]=\"currentImage.modal.fallbackImg\"\n [attr.aria-label]=\"currentImage.modal.ariaLabel\"\n [title]=\"(currentImage.modal.title || currentImage.modal.title === '') ? currentImage.modal.title : getTitleToDisplay()\"\n alt=\"{{currentImage.modal.alt ? currentImage.modal.alt : getAltDescriptionByImage()}}\"\n [tabIndex]=\"0\" role=\"img\"\n (click)=\"onClickCurrentImage()\"\n (swipeleft)=\"swipe($event.type)\"\n (swiperight)=\"swipe($event.type)\"/>\n\n <figcaption *ngIf=\"getDescriptionToDisplay() !== ''\"\n class=\"description\"\n ksDescription [description]=\"carouselImageConfig?.description\"\n [innerHTML]=\"getDescriptionToDisplay()\"></figcaption>\n\n <a class=\"nav-right\" *ngIf=\"carouselConfig?.showArrows\"\n [attr.aria-label]=\"accessibilityConfig?.carouselNextImageAriaLabel\"\n [tabIndex]=\"isLastImage && !carouselSlideInfinite ? -1 : 0\" role=\"button\"\n (click)=\"onNavigationEvent('right', $event, clickAction)\" (keyup)=\"onNavigationEvent('right', $event, keyboardAction)\">\n <div class=\"inside {{(isLastImage && !carouselSlideInfinite) || !carouselConfig.showArrows ? 'empty-arrow-image' : 'right-arrow-image'}}\"\n aria-hidden=\"true\"\n [title]=\"accessibilityConfig?.carouselNextImageTitle\"></div>\n </a>\n\n <div id=\"dots\">\n <ks-dots [id]=\"id\"\n [currentImage]=\"currentImage\"\n [images]=\"images\"\n [dotsConfig]=\"carouselDotsConfig\"\n (clickDot)=\"onClickDot($event)\"></ks-dots>\n </div>\n\n </figure>\n\n</main>\n\n<ks-carousel-previews [id]=\"id\"\n [images]=\"images\"\n [currentImage]=\"currentImage\"\n (clickPreview)=\"onClickPreview($event)\"></ks-carousel-previews>\n", styles: [":host{display:flex;flex-direction:column;justify-content:flex-start;align-items:center}#carousel-container{display:flex;flex-direction:row;align-items:center;justify-content:space-between;width:100%}#carousel-container>.current-figure{animation:fadein-visible .8s;text-align:center;margin:0;position:relative}#carousel-container>.current-figure .nav,#carousel-container>.current-figure>.nav-right,#carousel-container>.current-figure>.nav-left{animation:animatezoom 1s;cursor:pointer;transition:all .5s;top:50%;position:absolute}#carousel-container>.current-figure .nav:hover,#carousel-container>.current-figure>.nav-right:hover,#carousel-container>.current-figure>.nav-left:hover{transform:scale(1.1)}#carousel-container>.current-figure>.nav-left{left:5px}#carousel-container>.current-figure>.nav-right{right:5px}#carousel-container>.current-figure>#current-image{width:100%;height:auto;display:block}#carousel-container>.current-figure>figcaption{padding:10px;position:absolute;bottom:0;left:0;right:0}#carousel-container>.current-figure>figcaption .description{font-weight:bold;text-align:center}#carousel-container>.current-figure>#dots{position:absolute;bottom:20px;width:100%}\n", ".arrow-image,.right-arrow-image,.left-arrow-image,.empty-arrow-image{width:30px;height:30px;background-size:30px}.empty-arrow-image{background:black;opacity:0}.left-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.left-arrow-image:hover{transform:scale(1.2)}.right-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.right-arrow-image:hover{transform:scale(1.2)}\n"], components: [{ type: i3.DotsComponent, selector: "ks-dots", inputs: ["id", "currentImage", "images", "dotsConfig"], outputs: ["clickDot"] }, { type: i4.CarouselPreviewsComponent, selector: "ks-carousel-previews", inputs: ["id", "currentImage", "images"], outputs: ["clickPreview"] }], directives: [{ type: i5.MaxSizeDirective, selector: "[ksMaxSize]", inputs: ["maxSizeConfig"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i7.SizeDirective, selector: "[ksSize]", inputs: ["sizeConfig"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i8.FallbackImageDirective, selector: "[ksFallbackImage]", inputs: ["fallbackImg"], outputs: ["fallbackApplied"] }, { type: i9.DescriptionDirective, selector: "[ksDescription]", inputs: ["description"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
711
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: CarouselComponent, decorators: [{
712
+ type: Component,
713
+ args: [{ selector: 'ks-carousel', changeDetection: ChangeDetectionStrategy.OnPush, providers: [ConfigService], template: "<main id=\"carousel-container\"\n [attr.aria-label]=\"accessibilityConfig?.carouselContainerAriaLabel\"\n [title]=\"accessibilityConfig?.carouselContainerTitle\"\n ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n maxHeight: ''}\">\n\n\n <!-- Workaround to support 2 ng-content in the same template in 2 ngIf (https://github.com/angular/angular/issues/22972) -->\n <ng-template #content><ng-content></ng-content></ng-template>\n\n <figure class=\"current-figure\" *ngIf=\"currentImage && currentImage.modal\"\n ksSize [sizeConfig]=\"{width: carouselConfig?.maxWidth,\n height: ''}\">\n\n <a class=\"nav-left\" *ngIf=\"carouselConfig?.showArrows\"\n [attr.aria-label]=\"accessibilityConfig?.carouselPrevImageAriaLabel\"\n [tabIndex]=\"isLastImage && !carouselSlideInfinite ? -1 : 0\" role=\"button\"\n (click)=\"onNavigationEvent('left', $event, clickAction)\" (keyup)=\"onNavigationEvent('left', $event, keyboardAction)\">\n <div class=\"inside {{(isFirstImage && !carouselSlideInfinite) || !carouselConfig.showArrows ? 'empty-arrow-image' : 'left-arrow-image'}}\"\n aria-hidden=\"true\"\n [title]=\"accessibilityConfig?.carouselPrevImageTitle\"></div>\n </a>\n\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n\n <img id=\"current-image\"\n [style.object-fit]=\"carouselConfig?.objectFit\"\n ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n maxHeight: carouselConfig?.maxHeight}\"\n [src]=\"currentImage.modal.img\"\n ksFallbackImage [fallbackImg]=\"currentImage.modal.fallbackImg\"\n [attr.aria-label]=\"currentImage.modal.ariaLabel\"\n [title]=\"(currentImage.modal.title || currentImage.modal.title === '') ? currentImage.modal.title : getTitleToDisplay()\"\n alt=\"{{currentImage.modal.alt ? currentImage.modal.alt : getAltDescriptionByImage()}}\"\n [tabIndex]=\"0\" role=\"img\"\n (click)=\"onClickCurrentImage()\"\n (swipeleft)=\"swipe($event.type)\"\n (swiperight)=\"swipe($event.type)\"/>\n\n <figcaption *ngIf=\"getDescriptionToDisplay() !== ''\"\n class=\"description\"\n ksDescription [description]=\"carouselImageConfig?.description\"\n [innerHTML]=\"getDescriptionToDisplay()\"></figcaption>\n\n <a class=\"nav-right\" *ngIf=\"carouselConfig?.showArrows\"\n [attr.aria-label]=\"accessibilityConfig?.carouselNextImageAriaLabel\"\n [tabIndex]=\"isLastImage && !carouselSlideInfinite ? -1 : 0\" role=\"button\"\n (click)=\"onNavigationEvent('right', $event, clickAction)\" (keyup)=\"onNavigationEvent('right', $event, keyboardAction)\">\n <div class=\"inside {{(isLastImage && !carouselSlideInfinite) || !carouselConfig.showArrows ? 'empty-arrow-image' : 'right-arrow-image'}}\"\n aria-hidden=\"true\"\n [title]=\"accessibilityConfig?.carouselNextImageTitle\"></div>\n </a>\n\n <div id=\"dots\">\n <ks-dots [id]=\"id\"\n [currentImage]=\"currentImage\"\n [images]=\"images\"\n [dotsConfig]=\"carouselDotsConfig\"\n (clickDot)=\"onClickDot($event)\"></ks-dots>\n </div>\n\n </figure>\n\n</main>\n\n<ks-carousel-previews [id]=\"id\"\n [images]=\"images\"\n [currentImage]=\"currentImage\"\n (clickPreview)=\"onClickPreview($event)\"></ks-carousel-previews>\n", styles: [":host{display:flex;flex-direction:column;justify-content:flex-start;align-items:center}#carousel-container{display:flex;flex-direction:row;align-items:center;justify-content:space-between;width:100%}#carousel-container>.current-figure{animation:fadein-visible .8s;text-align:center;margin:0;position:relative}#carousel-container>.current-figure .nav,#carousel-container>.current-figure>.nav-right,#carousel-container>.current-figure>.nav-left{animation:animatezoom 1s;cursor:pointer;transition:all .5s;top:50%;position:absolute}#carousel-container>.current-figure .nav:hover,#carousel-container>.current-figure>.nav-right:hover,#carousel-container>.current-figure>.nav-left:hover{transform:scale(1.1)}#carousel-container>.current-figure>.nav-left{left:5px}#carousel-container>.current-figure>.nav-right{right:5px}#carousel-container>.current-figure>#current-image{width:100%;height:auto;display:block}#carousel-container>.current-figure>figcaption{padding:10px;position:absolute;bottom:0;left:0;right:0}#carousel-container>.current-figure>figcaption .description{font-weight:bold;text-align:center}#carousel-container>.current-figure>#dots{position:absolute;bottom:20px;width:100%}\n", ".arrow-image,.right-arrow-image,.left-arrow-image,.empty-arrow-image{width:30px;height:30px;background-size:30px}.empty-arrow-image{background:black;opacity:0}.left-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.left-arrow-image:hover{transform:scale(1.2)}.right-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.right-arrow-image:hover{transform:scale(1.2)}\n"] }]
714
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
715
+ type: Inject,
716
+ args: [PLATFORM_ID]
717
+ }] }, { type: i0.NgZone }, { type: i1.ModalGalleryService }, { type: i2.ConfigService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { ariaLabel: [{
718
+ type: HostBinding,
719
+ args: ['attr.aria-label']
720
+ }], id: [{
721
+ type: Input
722
+ }], images: [{
723
+ type: Input
724
+ }], config: [{
725
+ type: Input
726
+ }], clickImage: [{
727
+ type: Output
728
+ }], changeImage: [{
729
+ type: Output
730
+ }], firstImage: [{
731
+ type: Output
732
+ }], lastImage: [{
733
+ type: Output
734
+ }], onMouseEnter: [{
735
+ type: HostListener,
736
+ args: ['mouseenter']
737
+ }], onMouseLeave: [{
738
+ type: HostListener,
739
+ args: ['mouseleave']
740
+ }], onKeyDownLeft: [{
741
+ type: HostListener,
742
+ args: ['keydown.arrowLeft']
743
+ }], onKeyDownLRight: [{
744
+ type: HostListener,
745
+ args: ['keydown.arrowRight']
746
+ }] } });
747
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Fyb3VzZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva3M4OS9hbmd1bGFyLW1vZGFsLWdhbGxlcnkvc3JjL2xpYi9jb21wb25lbnRzL2Nhcm91c2VsL2Nhcm91c2VsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2tzODkvYW5ndWxhci1tb2RhbC1nYWxsZXJ5L3NyYy9saWIvY29tcG9uZW50cy9jYXJvdXNlbC9jYXJvdXNlbC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBRUgseUVBQXlFO0FBQ3pFLDRIQUE0SDtBQUU1SCxPQUFPLEVBRUwsdUJBQXVCLEVBRXZCLFNBQVMsRUFDVCxZQUFZLEVBQ1osV0FBVyxFQUNYLFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUtMLE1BQU0sRUFDTixXQUFXLEVBR1osTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFcEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRW5FLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRzlELE9BQU8sRUFBUyxVQUFVLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDakQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2xELE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDekQsT0FBTyxFQUFFLG1C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c0JBRFQsTUFBTTtnQkFNUCxXQUFXO3NCQURWLE1BQU07Z0JBTVAsVUFBVTtzQkFEVCxNQUFNO2dCQU1QLFNBQVM7c0JBRFIsTUFBTTtnQkE0RVAsWUFBWTtzQkFEWCxZQUFZO3VCQUFDLFlBQVk7Z0JBbUIxQixZQUFZO3NCQURYLFlBQVk7dUJBQUMsWUFBWTtnQkFtQjFCLGFBQWE7c0JBRFosWUFBWTt1QkFBQyxtQkFBbUI7Z0JBbUJqQyxlQUFlO3NCQURkLFlBQVk7dUJBQUMsb0JBQW9CIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiBUaGUgTUlUIExpY2Vuc2UgKE1JVClcblxuIENvcHlyaWdodCAoQykgMjAxNy0yMDIxIFN0ZWZhbm8gQ2FwcGEgKEtzODkpXG5cbiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4gb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4gY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcblxuIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbFxuIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG5cbiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4gRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTiBJTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFXG4gU09GVFdBUkUuXG4gKi9cblxuLy8gVGhlIGlkZWEgdG8gY3JlYXRlIGEgY2Fyb3VzZWwgd2l0aCB0d28gU3ViamVjdHMgY2FtZSBmcm9tIG5nLWJvb3RzdHJhcFxuLy8gU28gYSBiaWcgdGhhbmsgeW91IHRvIHRoZSBuZy1ib290c3RyYXAgdGVhbSBmb3IgdGhlIGludGVyZXN0aW5nIGltcGxlbWVudGF0aW9uIHRoYXQgSSB1c2VkIGhlcmUgd2l0aCBzb21lIGN1c3RvbWl6YXRpb25zLlxuXG5pbXBvcnQge1xuICBBZnRlckNvbnRlbnRJbml0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBIb3N0QmluZGluZyxcbiAgSG9zdExpc3RlbmVyLFxuICBJbmplY3QsXG4gIElucHV0LFxuICBOZ1pvbmUsXG4gIE9uQ2hhbmdlcyxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgUExBVEZPUk1fSUQsXG4gIFNpbXBsZUNoYW5nZSxcbiAgU2ltcGxlQ2hhbmdlc1xufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGlzUGxhdGZvcm1Ccm93c2VyIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcblxuaW1wb3J0IHsgU3ViamVjdCwgdGltZXIgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGZpbHRlciwgbWFwLCBzd2l0Y2hNYXAsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgQWNjZXNzaWJsZUNvbXBvbmVudCB9IGZyb20gJy4uL2FjY2Vzc2libGUuY29tcG9uZW50JztcblxuaW1wb3J0IHsgQWNjZXNzaWJpbGl0eUNvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVsL2FjY2Vzc2liaWxpdHkuaW50ZXJmYWNlJztcbmltcG9ydCB7IEltYWdlLCBJbWFnZUV2ZW50IH0gZnJvbSAnLi4vLi4vbW9kZWwvaW1hZ2UuY2xhc3MnO1xuaW1wb3J0IHsgQWN0aW9uIH0gZnJvbSAnLi4vLi4vbW9kZWwvYWN0aW9uLmVudW0nO1xuaW1wb3J0IHsgZ2V0SW5kZXggfSBmcm9tICcuLi8uLi91dGlscy9pbWFnZS51dGlsJztcbmltcG9ydCB7IE5FWFQsIFBSRVYgfSBmcm9tICcuLi8uLi91dGlscy91c2VyLWlucHV0LnV0aWwnO1xuaW1wb3J0IHsgRGVzY3JpcHRpb25TdHJhdGVneSB9IGZyb20gJy4uLy4uL21vZGVsL2Rlc2NyaXB0aW9uLmludGVyZmFjZSc7XG5pbXBvcnQgeyBEb3RzQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvZG90cy1jb25maWcuaW50ZXJmYWNlJztcbmltcG9ydCB7IENhcm91c2VsQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvY2Fyb3VzZWwtY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBDYXJvdXNlbEltYWdlQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWwvY2Fyb3VzZWwtaW1hZ2UtY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBDb25maWdTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvY29uZmlnLnNlcnZpY2UnO1xuaW1wb3J0IHsgTW9kYWxHYWxsZXJ5U2VydmljZSB9IGZyb20gJy4uL21vZGFsLWdhbGxlcnkvbW9kYWwtZ2FsbGVyeS5zZXJ2aWNlJztcbmltcG9ydCB7IENhcm91c2VsTGliQ29uZmlnLCBMaWJDb25maWcgfSBmcm9tICcuLi8uLi9tb2RlbC9saWItY29uZmlnLmludGVyZmFjZSc7XG5cbi8qKlxuICogQ29tcG9uZW50IHdpdGggY29uZmlndXJhYmxlIGlubGluZS9wbGFpbiBjYXJvdXNlbC5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAna3MtY2Fyb3VzZWwnLFxuICBzdHlsZVVybHM6IFsnY2Fyb3VzZWwuc2NzcycsICcuLi9pbWFnZS1hcnJvd3Muc2NzcyddLFxuICB0ZW1wbGF0ZVVybDogJ2Nhcm91c2VsLmh0bWwnLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgcHJvdmlkZXJzOiBbQ29uZmlnU2VydmljZV1cbn0pXG5leHBvcnQgY2xhc3MgQ2Fyb3VzZWxDb21wb25lbnQgZXh0ZW5kcyBBY2Nlc3NpYmxlQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBBZnRlckNvbnRlbnRJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XG4gIC8qKlxuICAgKiBBdHRyaWJ1dGUgdG8gc2V0IGFyaWFMYWJlbCBvZiB0aGUgaG9zdCBjb21wb25lbnRcbiAgICovXG4gIEBIb3N0QmluZGluZygnYXR0ci5hcmlhLWxhYmVsJylcbiAgYXJpYUxhYmVsID0gYENhcm91c2VsYDtcbiAgLyoqXG4gICAqIFVuaXF1ZSBpZCAoPj0wKSBvZiB0aGUgY3VycmVudCBpbnN0YW5jZSBvZiB0aGUgY2Fyb3VzZWwuIFRoaXMgaXMgdXNlZnVsIHdoZW4geW91IGFyZSB1c2luZ1xuICAgKiB0aGUgY2Fyb3VzZWwncyBmZWF0dXJlIHRvIG9wZW4gbW9kYWwgZ2FsbGVyeS5cbiAgICovXG4gIEBJbnB1dCgpXG4gIGlkOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBBcnJheSBvZiBgSW50ZXJuYWxMaWJJbWFnZWAgdGhhdCByZXByZXNlbnQgdGhlIG1vZGVsIG9mIHRoaXMgbGlicmFyeSB3aXRoIGFsbCBpbWFnZXMsXG4gICAqIHRodW1icyBhbmQgc28gb24uXG4gICAqL1xuICBASW5wdXQoKVxuICBpbWFnZXM6IEltYWdlW10gPSBbXTtcbiAgLyoqXG4gICAqIENhcm91c2VsTGliQ29uZmlnIG9iamVjdCB0byBjb25maWd1cmUgY2Fyb3VzZWwuXG4gICAqL1xuICBASW5wdXQoKVxuICBjb25maWc6IENhcm91c2VsTGliQ29uZmlnIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBPdXRwdXQgdG8gZW1pdCBhbiBldmVudCB3aGVuIGFuIGltYWdlIGlzIGNsaWNrZWQuXG4gICAqL1xuICBAT3V0cHV0KClcbiAgY2xpY2tJbWFnZTogRXZlbnRFbWl0dGVyPG51bWJlcj4gPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcbiAgLyoqXG4gICAqIE91dHB1dCB0byBlbWl0IGFuIGV2ZW50IHdoZW4gY3VycmVudCBpbWFnZSBpcyBjaGFuZ2VkLlxuICAgKi9cbiAgQE91dHB1dCgpXG4gIGNoYW5nZUltYWdlOiBFdmVudEVtaXR0ZXI8SW1hZ2VFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyPEltYWdlRXZlbnQ+KCk7XG4gIC8qKlxuICAgKiBPdXRwdXQgdG8gZW1pdCBhbiBldmVudCB3aGVuIHRoZSBjdXJyZW50IGltYWdlIGlzIHRoZSBmaXJzdCBvbmUuXG4gICAqL1xuICBAT3V0cHV0KClcbiAgZmlyc3RJbWFnZTogRXZlbnRFbWl0dGVyPEltYWdlRXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxJbWFnZUV2ZW50PigpO1xuICAvKipcbiAgICogT3V0cHV0IHRvIGVtaXQgYW4gZXZlbnQgd2hlbiB0aGUgY3VycmVudCBpbWFnZSBpcyB0aGUgbGFzdCBvbmUuXG4gICAqL1xuICBAT3V0cHV0KClcbiAgbGFzdEltYWdlOiBFdmVudEVtaXR0ZXI8SW1hZ2VFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyPEltYWdlRXZlbnQ+KCk7XG5cbiAgLyoqXG4gICAqIE9iamVjdCBvZiB0eXBlIGBDYXJvdXNlbENvbmZpZ2AgdG8gaW5pdCBDYXJvdXNlbENvbXBvbmVudCdzIGZlYXR1cmVzLlxuICAgKiBGb3IgaW5zdGFuY2UsIGl0IGNvbnRhaW5zIHBhcmFtZXRlcnMgdG8gY2hhbmdlIHRoZSBzdHlsZSwgaG93IGl0IG5hdmlnYXRlcyBhbmQgc28gb24uXG4gICAqL1xuICBjYXJvdXNlbENvbmZpZzogQ2Fyb3VzZWxDb25maWcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIE9iamVjdCBvZiB0eXBlIGBEb3RzQ29uZmlnYCB0byBpbml0IERvdHNDb21wb25lbnQncyBmZWF0dXJlcy5cbiAgICogRm9yIGluc3RhbmNlLCBpdCBjb250YWlucyBhIHBhcmFtIHRvIHNob3cvaGlkZSB0aGlzIGNvbXBvbmVudC5cbiAgICovXG4gIGNhcm91c2VsRG90c0NvbmZpZzogRG90c0NvbmZpZyB8IHVuZGVmaW5lZDtcbiAgLyoqXG4gICAqIE9iamVjdCBvZiB0eXBlIGBBY2Nlc3NpYmlsaXR5Q29uZmlnYCB0byBpbml0IGN1c3RvbSBhY2Nlc3NpYmlsaXR5IGZlYXR1cmVzLlxuICAgKiBGb3IgaW5zdGFuY2UsIGl0IGNvbnRhaW5zIHRpdGxlcywgYWx0IHRleHRzLCBhcmlhLWxhYmVscyBhbmQgc28gb24uXG4gICAqL1xuICBhY2Nlc3NpYmlsaXR5Q29uZmlnOiBBY2Nlc3NpYmlsaXR5Q29uZmlnIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogT2JqZWN0IG9mIHR5cGUgYENhcm91c2VsSW1hZ2VDb25maWdgIHRvIGNvbmZpZ3VyZSB0aGUgY3VycmVudCBpbWFnZSBvZiB0aGUgY2Fyb3VzZWwuXG4gICAqL1xuICBjYXJvdXNlbEltYWdlQ29uZmlnOiBDYXJvdXNlbEltYWdlQ29uZmlnIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogRW5hYmxlL2Rpc2FibGUgaW5maW5pdGUgc2xpZGluZy5cbiAgICovXG4gIGNhcm91c2VsU2xpZGVJbmZpbml0ZTogYm9vbGVhbiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogRW51bSBvZiB0eXBlIGBBY3Rpb25gIHRoYXQgcmVwcmVzZW50cyBhIG1vdXNlIGNsaWNrIG9uIGEgYnV0dG9uLlxuICAgKiBEZWNsYXJlZCBoZXJlIHRvIGJlIHVzZWQgaW5zaWRlIHRoZSB0ZW1wbGF0ZS5cbiAgICovXG4gIGNsaWNrQWN0aW9uOiBBY3Rpb24gPSBBY3Rpb24uQ0xJQ0s7XG4gIC8qKlxuICAgKiBFbnVtIG9mIHR5cGUgYEFjdGlvbmAgdGhhdCByZXByZXNlbnRzIGEga2V5Ym9hcmQgYWN0aW9uLlxuICAgKiBEZWNsYXJlZCBoZXJlIHRvIGJlIHVzZWQgaW5zaWRlIHRoZSB0ZW1wbGF0ZS5cbiAgICovXG4gIGtleWJvYXJkQWN0aW9uOiBBY3Rpb24gPSBBY3Rpb24uS0VZQk9BUkQ7XG4gIC8qKlxuICAgKiBgSW1hZ2VgIHRoYXQgaXMgdmlzaWJsZSByaWdodCBub3cuXG4gICAqL1xuICBjdXJyZW50SW1hZ2U6IEltYWdlIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogQm9vbGVhbiB0aGF0IGl0J3MgdHJ1ZSB3aGVuIHlvdSBhcmUgd2F0Y2hpbmcgdGhlIGZpcnN0IGltYWdlIChjdXJyZW50bHkgdmlzaWJsZSkuXG4gICAqIEZhbHNlIGJ5IGRlZmF1bHRcbiAgICovXG4gIGlzRmlyc3RJbWFnZSA9IGZhbHNlO1xuICAvKipcbiAgICogQm9vbGVhbiB0aGF0IGl0J3MgdHJ1ZSB3aGVuIHlvdSBhcmUgd2F0Y2hpbmcgdGhlIGxhc3QgaW1hZ2UgKGN1cnJlbnRseSB2aXNpYmxlKS5cbiAgICogRmFsc2UgYnkgZGVmYXVsdFxuICAgKi9cbiAgaXNMYXN0SW1hZ2UgPSBmYWxzZTtcblxuICAvKipcbiAgICogU3ViamVjdCB0byBwbGF5IHRoZSBjYXJvdXNlbC5cbiAgICovXG4gIHByaXZhdGUgc3RhcnQkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgLyoqXG4gICAqIFN1YmplY3QgdG8gc3RvcCB0aGUgY2Fyb3VzZWwuXG4gICAqL1xuICBwcml2YXRlIHN0b3AkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAvKipcbiAgICogUHJpdmF0ZSBvYmplY3Qgd2l0aG91dCB0eXBlIHRvIGRlZmluZSBhbGwgc3dpcGUgYWN0aW9ucyB1c2VkIGJ5IGhhbW1lcmpzLlxuICAgKi9cbiAgcHJpdmF0ZSBTV0lQRV9BQ1RJT04gPSB7XG4gICAgTEVGVDogJ3N3aXBlbGVmdCcsXG4gICAgUklHSFQ6ICdzd2lwZXJpZ2h0JyxcbiAgICBVUDogJ3N3aXBldXAnLFxuICAgIERPV046ICdzd2lwZWRvd24nXG4gIH07XG5cbiAgLyoqXG4gICAqIExpc3RlbmVyIHRvIHN0b3AgdGhlIGdhbGxlcnkgd2hlbiB0aGUgbW91c2UgcG9pbnRlciBpcyBvdmVyIHRoZSBjdXJyZW50IGltYWdlLlxuICAgKi9cbiAgQEhvc3RMaXN0ZW5lcignbW91c2VlbnRlcicpXG4gIG9uTW91c2VFbnRlcigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pZCA9PT0gbnVsbCB8fCB0aGlzLmlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGlkIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBjb25zdCBsaWJDb25maWc6IExpYkNvbmZpZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlnU2VydmljZS5nZXRDb25maWcodGhpcy5pZCk7XG4gICAgaWYgKCFsaWJDb25maWcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGxpYkNvbmZpZyBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgaWYgKCFsaWJDb25maWcuY2Fyb3VzZWxQbGF5Q29uZmlnIHx8ICFsaWJDb25maWcuY2Fyb3VzZWxQbGF5Q29uZmlnLnBhdXNlT25Ib3Zlcikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnN0b3BDYXJvdXNlbCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3RlbmVyIHRvIHBsYXkgdGhlIGdhbGxlcnkgd2hlbiB0aGUgbW91c2UgcG9pbnRlciBsZWF2ZSB0aGUgY3VycmVudCBpbWFnZS5cbiAgICovXG4gIEBIb3N0TGlzdGVuZXIoJ21vdXNlbGVhdmUnKVxuICBvbk1vdXNlTGVhdmUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaWQgPT09IG51bGwgfHwgdGhpcy5pZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBpZCBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgY29uc3QgbGliQ29uZmlnOiBMaWJDb25maWcgfCB1bmRlZmluZWQgPSB0aGlzLmNvbmZpZ1NlcnZpY2UuZ2V0Q29uZmlnKHRoaXMuaWQpO1xuICAgIGlmICghbGliQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBsaWJDb25maWcgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGlmICghbGliQ29uZmlnLmNhcm91c2VsUGxheUNvbmZpZyB8fCAhbGliQ29uZmlnLmNhcm91c2VsUGxheUNvbmZpZy5wYXVzZU9uSG92ZXIgfHwgIWxpYkNvbmZpZy5jYXJvdXNlbFBsYXlDb25maWcuYXV0b1BsYXkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5wbGF5Q2Fyb3VzZWwoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMaXN0ZW5lciB0byBuYXZpZ2F0ZSBjYXJvdXNlbCBpbWFnZXMgd2l0aCBrZXlib2FyZCAobGVmdCkuXG4gICAqL1xuICBASG9zdExpc3RlbmVyKCdrZXlkb3duLmFycm93TGVmdCcpXG4gIG9uS2V5RG93bkxlZnQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaWQgPT09IG51bGwgfHwgdGhpcy5pZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBpZCBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgY29uc3QgbGliQ29uZmlnOiBMaWJDb25maWcgfCB1bmRlZmluZWQgPSB0aGlzLmNvbmZpZ1NlcnZpY2UuZ2V0Q29uZmlnKHRoaXMuaWQpO1xuICAgIGlmICghbGliQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBsaWJDb25maWcgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGlmICghbGliQ29uZmlnLmNhcm91c2VsQ29uZmlnIHx8ICFsaWJDb25maWcuY2Fyb3VzZWxDb25maWcua2V5Ym9hcmRFbmFibGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5wcmV2SW1hZ2UoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMaXN0ZW5lciB0byBuYXZpZ2F0ZSBjYXJvdXNlbCBpbWFnZXMgd2l0aCBrZXlib2FyZCAocmlnaHQpLlxuICAgKi9cbiAgQEhvc3RMaXN0ZW5lcigna2V5ZG93bi5hcnJvd1JpZ2h0JylcbiAgb25LZXlEb3duTFJpZ2h0KCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlkID09PSBudWxsIHx8IHRoaXMuaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gaWQgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICBpZiAoIWxpYkNvbmZpZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gbGliQ29uZmlnIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBpZiAoIWxpYkNvbmZpZy5jYXJvdXNlbENvbmZpZyB8fCAhbGliQ29uZmlnLmNhcm91c2VsQ29uZmlnLmtleWJvYXJkRW5hYmxlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMubmV4dEltYWdlKCk7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJpdmF0ZSBwbGF0Zm9ybUlkOiBhbnksXG4gICAgcHJpdmF0ZSBuZ1pvbmU6IE5nWm9uZSxcbiAgICBwcml2YXRlIG1vZGFsR2FsbGVyeVNlcnZpY2U6IE1vZGFsR2FsbGVyeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBjb25maWdTZXJ2aWNlOiBDb25maWdTZXJ2aWNlLFxuICAgIHByaXZhdGUgcmVmOiBDaGFuZ2VEZXRlY3RvclJlZlxuICApIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaWQgPT09IG51bGwgfHwgdGhpcy5pZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBpZCBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmltYWdlcyB8fCB0aGlzLmltYWdlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGltYWdlcyBhcnJheSBtdXN0IGJlIGRlZmluZWQgYW5kIHdpdGggYXQgbGVhc3QgYW4gZWxlbWVudCcpO1xuICAgIH1cbiAgICB0aGlzLmNvbmZpZ1NlcnZpY2Uuc2V0Q29uZmlnKHRoaXMuaWQsIHRoaXMuY29uZmlnKTtcblxuICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICBpZiAoIWxpYkNvbmZpZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gbGliQ29uZmlnIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cblxuICAgIHRoaXMuY3VycmVudEltYWdlID0gdGhpcy5pbWFnZXNbMF07XG4gICAgdGhpcy5jYXJvdXNlbERvdHNDb25maWcgPSBsaWJDb25maWcuY2Fyb3VzZWxEb3RzQ29uZmlnO1xuICAgIHRoaXMuYWNjZXNzaWJpbGl0eUNvbmZpZyA9IGxpYkNvbmZpZy5hY2Nlc3NpYmlsaXR5Q29uZmlnO1xuICAgIHRoaXMuY2Fyb3VzZWxTbGlkZUluZmluaXRlID0gbGliQ29uZmlnLmNhcm91c2VsU2xpZGVJbmZpbml0ZTtcbiAgICB0aGlzLmNhcm91c2VsQ29uZmlnID0gbGliQ29uZmlnLmNhcm91c2VsQ29uZmlnO1xuICAgIHRoaXMuY2Fyb3VzZWxJbWFnZUNvbmZpZyA9IGxpYkNvbmZpZy5jYXJvdXNlbEltYWdlQ29uZmlnO1xuXG4gICAgdGhpcy5tYW5hZ2VTbGlkZUNvbmZpZygpO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlkID09PSBudWxsIHx8IHRoaXMuaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gaWQgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuXG4gICAgLy8gdGhpcy5jb25maWdTZXJ2aWNlLnNldENvbmZpZyh0aGlzLmlkLCB0aGlzLmNvbmZpZyk7XG4gICAgY29uc3QgbGliQ29uZmlnOiBMaWJDb25maWcgfCB1bmRlZmluZWQgPSB0aGlzLmNvbmZpZ1NlcnZpY2UuZ2V0Q29uZmlnKHRoaXMuaWQpO1xuICAgIGlmICghbGliQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBsaWJDb25maWcgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuXG4gICAgY29uc3QgY29uZmlnQ2hhbmdlOiBTaW1wbGVDaGFuZ2UgPSBjaGFuZ2VzLmNvbmZpZztcblxuICAgIC8vIGhhbmRsZSBjaGFuZ2VzIG9mIGRvdHNDb25maWcudmlzaWJsZVxuICAgIGlmIChjb25maWdDaGFuZ2UgJiZcbiAgICAgICFjb25maWdDaGFuZ2UuZmlyc3RDaGFuZ2UgJiZcbiAgICAgIChjb25maWdDaGFuZ2UucHJldmlvdXNWYWx1ZS5jYXJvdXNlbERvdHNDb25maWc/LnZpc2libGUgIT09IGNvbmZpZ0NoYW5nZS5jdXJyZW50VmFsdWUuY2Fyb3VzZWxEb3RzQ29uZmlnPy52aXNpYmxlIHx8ICghY29uZmlnQ2hhbmdlLnByZXZpb3VzVmFsdWUuY2Fyb3VzZWxEb3RzQ29uZmlnICYmICFjb25maWdDaGFuZ2UuY3VycmVudFZhbHVlLmNhcm91c2VsRG90c0NvbmZpZykpXG4gICAgKSB7XG4gICAgICB0aGlzLmNvbmZpZ1NlcnZpY2Uuc2V0Q29uZmlnKHRoaXMuaWQsIHtcbiAgICAgICAgY2Fyb3VzZWxEb3RzQ29uZmlnOiBjb25maWdDaGFuZ2UuY3VycmVudFZhbHVlPy5jYXJvdXNlbERvdHNDb25maWdcbiAgICAgIH0pO1xuICAgICAgdGhpcy5jYXJvdXNlbERvdHNDb25maWcgPSBjb25maWdDaGFuZ2UuY3VycmVudFZhbHVlPy5jYXJvdXNlbERvdHNDb25maWc7XG4gICAgICB0aGlzLnJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICB9XG4gICAgLy8gaGFuZGxlIGNoYW5nZXMgb2YgY2Fyb3VzZWxDb25maWcuc2hvd0Fycm93c1xuICAgIGlmIChjb25maWdDaGFuZ2UgJiZcbiAgICAgICFjb25maWdDaGFuZ2UuZmlyc3RDaGFuZ2UgJiZcbiAgICAgIChjb25maWdDaGFuZ2UucHJldmlvdXNWYWx1ZS5jYXJvdXNlbENvbmZpZz8uc2hvd0Fycm93cyAhPT0gY29uZmlnQ2hhbmdlLmN1cnJlbnRWYWx1ZS5jYXJvdXNlbENvbmZpZz8uc2hvd0Fycm93cyB8fCAoIWNvbmZpZ0NoYW5nZS5wcmV2aW91c1ZhbHVlLmNhcm91c2VsQ29uZmlnICYmICFjb25maWdDaGFuZ2UuY3VycmVudFZhbHVlLmNhcm91c2VsQ29uZmlnKSlcbiAgICApIHtcbiAgICAgIHRoaXMuY29uZmlnU2VydmljZS5zZXRDb25maWcodGhpcy5pZCwge1xuICAgICAgICBjYXJvdXNlbENvbmZpZzogY29uZmlnQ2hhbmdlLmN1cnJlbnRWYWx1ZT8uY2Fyb3VzZWxDb25maWdcbiAgICAgIH0pO1xuICAgICAgdGhpcy5jYXJvdXNlbENvbmZpZyA9IGNvbmZpZ0NoYW5nZS5jdXJyZW50VmFsdWU/LmNhcm91c2VsQ29uZmlnO1xuICAgICAgdGhpcy5yZWYubWFya0ZvckNoZWNrKCk7XG4gICAgfVxuICAgIC8vIGhhbmRsZSBjaGFuZ2VzIG9mIHBsYXlDb25maWcgc3RhcnRpbmcvc3RvcHBpbmcgdGhlIGNhcm91c2VsIGFjY29yZGluZ2x5XG4gICAgaWYgKGNvbmZpZ0NoYW5nZSAmJlxuICAgICAgIWNvbmZpZ0NoYW5nZS5maXJzdENoYW5nZSAmJlxuICAgICAgKGNvbmZpZ0NoYW5nZS5wcmV2aW91c1ZhbHVlLmNhcm91c2VsUGxheUNvbmZpZz8uYXV0b1BsYXkgIT09IGNvbmZpZ0NoYW5nZS5jdXJyZW50VmFsdWUuY2Fyb3VzZWxQbGF5Q29uZmlnPy5hdXRvUGxheSB8fCAoIWNvbmZpZ0NoYW5nZS5wcmV2aW91c1ZhbHVlLmNhcm91c2VsUGxheUNvbmZpZyAmJiAhY29uZmlnQ2hhbmdlLmN1cnJlbnRWYWx1ZS5jYXJvdXNlbFBsYXlDb25maWcpKVxuICAgICkge1xuICAgICAgdGhpcy5jb25maWdTZXJ2aWNlLnNldENvbmZpZyh0aGlzLmlkLCB7XG4gICAgICAgIGNhcm91c2VsUGxheUNvbmZpZzogY29uZmlnQ2hhbmdlLmN1cnJlbnRWYWx1ZT8uY2Fyb3VzZWxQbGF5Q29uZmlnXG4gICAgICB9KTtcbiAgICAgIC8vIHRoaXMuY29uZmlnUGxheSA9IHBsYXlDb25maWdDaGFuZ2UuY3VycmVudFZhbHVlO1xuICAgICAgLy8gaWYgYXV0b3BsYXkgaXMgZW5hYmxlZCwgYW5kIHRoaXMgaXMgbm90IHRoZVxuICAgICAgLy8gZmlyc3QgY2hhbmdlICh0byBwcmV2ZW50IG11bHRpcGxlIHN0YXJ0cyBhdCB0aGUgYmVnaW5uaW5nKVxuICAgICAgaWYgKGNvbmZpZ0NoYW5nZS5jdXJyZW50VmFsdWUuY2Fyb3VzZWxQbGF5Q29uZmlnPy5hdXRvUGxheSAmJiAhY29uZmlnQ2hhbmdlLmZpcnN0Q2hhbmdlKSB7XG4gICAgICAgIHRoaXMuc3RhcnQkLm5leHQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc3RvcENhcm91c2VsKCk7XG4gICAgICB9XG4gICAgICB0aGlzLnJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICB9XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudEluaXQoKTogdm9pZCB7XG4gICAgLy8gaW50ZXJ2YWwgZG9lc24ndCBwbGF5IHdlbGwgd2l0aCBTU1IgYW5kIHByb3RyYWN0b3IsXG4gICAgLy8gc28gd2Ugc2hvdWxkIHJ1biBpdCBpbiB0aGUgYnJvd3NlciBhbmQgb3V0c2lkZSBBbmd1bGFyXG4gICAgaWYgKGlzUGxhdGZvcm1Ccm93c2VyKHRoaXMucGxhdGZvcm1JZCkpIHtcbiAgICAgIGlmICh0aGlzLmlkID09PSBudWxsIHx8IHRoaXMuaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBpZCBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICAgIGlmICghbGliQ29uZmlnIHx8ICFsaWJDb25maWcuY2Fyb3VzZWxQbGF5Q29uZmlnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGxpYkNvbmZpZyBhbmQgY2Fyb3VzZWxQbGF5Q29uZmlnIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgICAgfVxuICAgICAgdGhpcy5uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuICAgICAgICB0aGlzLnN0YXJ0JFxuICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgbWFwKCgpID0+IGxpYkNvbmZpZz8uY2Fyb3VzZWxQbGF5Q29uZmlnPy5pbnRlcnZhbCksXG4gICAgICAgICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gICAgICAgICAgICBmaWx0ZXIoKGludGVydmFsOiBhbnkpID0+IGludGVydmFsID4gMCksXG4gICAgICAgICAgICBzd2l0Y2hNYXAoaW50ZXJ2YWwgPT4gdGltZXIoaW50ZXJ2YWwpLnBpcGUodGFrZVVudGlsKHRoaXMuc3RvcCQpKSlcbiAgICAgICAgICApXG4gICAgICAgICAgLnN1YnNjcmliZSgoKSA9PlxuICAgICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgICAgaWYgKGxpYkNvbmZpZy5jYXJvdXNlbFBsYXlDb25maWc/LmF1dG9QbGF5KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5uZXh0SW1hZ2UoKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB0aGlzLnJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnN0YXJ0JC5uZXh0KCk7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCB3aGVuIGEgZG90IGlzIGNsaWNrZWQgYW5kIHVzZWQgdG8gdXBkYXRlIHRoZSBjdXJyZW50IGltYWdlLlxuICAgKiBAcGFyYW0gbnVtYmVyIGluZGV4IG9mIHRoZSBjbGlja2VkIGRvdFxuICAgKi9cbiAgb25DbGlja0RvdChpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5jaGFuZ2VDdXJyZW50SW1hZ2UodGhpcy5pbWFnZXNbaW5kZXhdLCBBY3Rpb24uTk9STUFMKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgY2FsbGVkIGJ5IGV2ZW50cyBmcm9tIGJvdGgga2V5Ym9hcmQgYW5kIG1vdXNlIG9uIGEgbmF2aWdhdGlvbiBhcnJvdy5cbiAgICogQHBhcmFtIHN0cmluZyBkaXJlY3Rpb24gb2YgdGhlIG5hdmlnYXRpb24gdGhhdCBjYW4gYmUgZWl0aGVyICduZXh0JyBvciAncHJldidcbiAgICogQHBhcmFtIEtleWJvYXJkRXZlbnQgfCBNb3VzZUV2ZW50IGV2ZW50IHBheWxvYWRcbiAgICogQHBhcmFtIEFjdGlvbiBhY3Rpb24gdGhhdCB0cmlnZ2VyZWQgdGhlIGV2ZW50IG9yIGBBY3Rpb24uTk9STUFMYCBpZiBub3QgcHJvdmlkZWRcbiAgICovXG4gIG9uTmF2aWdhdGlvbkV2ZW50KGRpcmVjdGlvbjogc3RyaW5nLCBldmVudDogS2V5Ym9hcmRFdmVudCB8IE1vdXNlRXZlbnQsIGFjdGlvbjogQWN0aW9uID0gQWN0aW9uLk5PUk1BTCk6IHZvaWQge1xuICAgIGNvbnN0IHJlc3VsdDogbnVtYmVyID0gc3VwZXIuaGFuZGxlTmF2aWdhdGlvbkV2ZW50KGRpcmVjdGlvbiwgZXZlbnQpO1xuICAgIGlmIChyZXN1bHQgPT09IE5FWFQpIHtcbiAgICAgIHRoaXMubmV4dEltYWdlKGFjdGlvbik7XG4gICAgfSBlbHNlIGlmIChyZXN1bHQgPT09IFBSRVYpIHtcbiAgICAgIHRoaXMucHJldkltYWdlKGFjdGlvbik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0cmlnZ2VyZWQgd2hlbiB5b3UgY2xpY2sgb24gdGhlIGN1cnJlbnQgaW1hZ2UuXG4gICAqIEFsc28sIGlmIG1vZGFsR2FsbGVyeUVuYWJsZSBpcyB0cnVlLCB5b3UgY2FuIG9wZW4gdGhlIG1vZGFsLWdhbGxlcnkuXG4gICAqL1xuICBvbkNsaWNrQ3VycmVudEltYWdlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlkID09PSBudWxsIHx8IHRoaXMuaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gaWQgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICBpZiAoIWxpYkNvbmZpZyB8fCAhbGliQ29uZmlnLmNhcm91c2VsQ29uZmlnIHx8ICF0aGlzLmN1cnJlbnRJbWFnZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gbGliQ29uZmlnLCBjYXJvdXNlbENvbmZpZyBhbmQgY3VycmVudEltYWdlIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBpZiAoIWxpYkNvbmZpZy5jYXJvdXNlbENvbmZpZy5tb2RhbEdhbGxlcnlFbmFibGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgaW5kZXggPSBnZXRJbmRleCh0aGlzLmN1cnJlbnRJbWFnZSwgdGhpcy5pbWFnZXMpO1xuICAgIHRoaXMuY2xpY2tJbWFnZS5lbWl0KGluZGV4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gZ2V0IHRoZSBpbWFnZSBkZXNjcmlwdGlvbiBiYXNlZCBvbiBpbnB1dCBwYXJhbXMuXG4gICAqIElmIHlvdSBwcm92aWRlIGEgZnVsbCBkZXNjcmlwdGlvbiB0aGlzIHdpbGwgYmUgdGhlIHZpc2libGUgZGVzY3JpcHRpb24sIG90aGVyd2lzZSxcbiAgICogaXQgd2lsbCBiZSBidWlsdCB1c2luZyB0aGUgYERlc2NyaXB0aW9uYCBvYmplY3QsIGNvbmNhdGVuYXRpbmcgaXRzIGZpZWxkcy5cbiAgICogQHBhcmFtIEltYWdlIGltYWdlIHRvIGdldCBpdHMgZGVzY3JpcHRpb24uIElmIG5vdCBwcm92aWRlZCBpdCB3aWxsIGJlIHRoZSBjdXJyZW50IGltYWdlXG4gICAqIEByZXR1cm5zIFN0cmluZyBkZXNjcmlwdGlvbiBvZiB0aGUgaW1hZ2UgKG9yIHRoZSBjdXJyZW50IGltYWdlIGlmIG5vdCBwcm92aWRlZClcbiAgICogQHRocm93cyBhbiBFcnJvciBpZiBkZXNjcmlwdGlvbiBpc24ndCBhdmFpbGFibGVcbiAgICovXG4gIGdldERlc2NyaXB0aW9uVG9EaXNwbGF5KGltYWdlOiBJbWFnZSB8IHVuZGVmaW5lZCA9IHRoaXMuY3VycmVudEltYWdlKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5pZCA9PT0gbnVsbCB8fCB0aGlzLmlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGlkIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBjb25zdCBsaWJDb25maWc6IExpYkNvbmZpZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlnU2VydmljZS5nZXRDb25maWcodGhpcy5pZCk7XG4gICAgaWYgKCFsaWJDb25maWcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGxpYkNvbmZpZyBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgY29uc3QgY29uZmlnQ3VycmVudEltYWdlQ2Fyb3VzZWw6IENhcm91c2VsSW1hZ2VDb25maWcgfCB1bmRlZmluZWQgPSBsaWJDb25maWcuY2Fyb3VzZWxJbWFnZUNvbmZpZztcbiAgICBpZiAoIWNvbmZpZ0N1cnJlbnRJbWFnZUNhcm91c2VsIHx8ICFjb25maWdDdXJyZW50SW1hZ2VDYXJvdXNlbC5kZXNjcmlwdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdEZXNjcmlwdGlvbiBpbnB1dCBtdXN0IGJlIGEgdmFsaWQgb2JqZWN0IGltcGxlbWVudGluZyB0aGUgRGVzY3JpcHRpb24gaW50ZXJmYWNlJyk7XG4gICAgfVxuICAgIGlmICghaW1hZ2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGltYWdlIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBjb25zdCBpbWFnZVdpdGhvdXREZXNjcmlwdGlvbjogYm9vbGVhbiA9ICFpbWFnZSB8fCAhaW1hZ2UubW9kYWwgfHwgIWltYWdlLm1vZGFsLmRlc2NyaXB0aW9uIHx8IGltYWdlLm1vZGFsLmRlc2NyaXB0aW9uID09PSAnJztcblxuICAgIHN3aXRjaCAoY29uZmlnQ3VycmVudEltYWdlQ2Fyb3VzZWwuZGVzY3JpcHRpb24uc3RyYXRlZ3kpIHtcbiAgICAgIGNhc2UgRGVzY3JpcHRpb25TdHJhdGVneS5ISURFX0lGX0VNUFRZOlxuICAgICAgICByZXR1cm4gaW1hZ2VXaXRob3V0RGVzY3JpcHRpb24gPyAnJyA6IGltYWdlLm1vZGFsLmRlc2NyaXB0aW9uICsgJyc7XG4gICAgICBjYXNlIERlc2NyaXB0aW9uU3RyYXRlZ3kuQUxXQVlTX0hJRERFTjpcbiAgICAgICAgcmV0dXJuICcnO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgLy8gLS0tLS0tLS0tLS0gRGVzY3JpcHRpb25TdHJhdGVneS5BTFdBWVNfVklTSUJMRSAtLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICByZXR1cm4gdGhpcy5idWlsZFRleHREZXNjcmlwdGlvbihpbWFnZSwgaW1hZ2VXaXRob3V0RGVzY3JpcHRpb24pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdXNlZCBieSBIYW1tZXJqcyB0byBzdXBwb3J0IHRvdWNoIGdlc3R1cmVzICh5b3UgY2FuIGFsc28gaW52ZXJ0IHRoZSBzd2lwZSBkaXJlY3Rpb24gd2l0aCBjb25maWdDdXJyZW50SW1hZ2UuaW52ZXJ0U3dpcGUpLlxuICAgKiBAcGFyYW0gYWN0aW9uIFN0cmluZyB0aGF0IHJlcHJlc2VudCB0aGUgZGlyZWN0aW9uIG9mIHRoZSBzd2lwZSBhY3Rpb24uICdzd2lwZXJpZ2h0JyBieSBkZWZhdWx0LlxuICAgKi9cbiAgc3dpcGUoYWN0aW9uID0gdGhpcy5TV0lQRV9BQ1RJT04uUklHSFQpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pZCA9PT0gbnVsbCB8fCB0aGlzLmlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGlkIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBjb25zdCBsaWJDb25maWc6IExpYkNvbmZpZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlnU2VydmljZS5nZXRDb25maWcodGhpcy5pZCk7XG4gICAgaWYgKCFsaWJDb25maWcgfHwgIWxpYkNvbmZpZy5jYXJvdXNlbEltYWdlQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBsaWJDb25maWcgYW5kIGNhcm91c2VsSW1hZ2VDb25maWcgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGNvbmZpZ0N1cnJlbnRJbWFnZUNhcm91c2VsOiBDYXJvdXNlbEltYWdlQ29uZmlnID0gbGliQ29uZmlnLmNhcm91c2VsSW1hZ2VDb25maWc7XG4gICAgc3dpdGNoIChhY3Rpb24pIHtcbiAgICAgIGNhc2UgdGhpcy5TV0lQRV9BQ1RJT04uUklHSFQ6XG4gICAgICAgIGlmIChjb25maWdDdXJyZW50SW1hZ2VDYXJvdXNlbC5pbnZlcnRTd2lwZSkge1xuICAgICAgICAgIHRoaXMucHJldkltYWdlKEFjdGlvbi5TV0lQRSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5uZXh0SW1hZ2UoQWN0aW9uLlNXSVBFKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdGhpcy5TV0lQRV9BQ1RJT04uTEVGVDpcbiAgICAgICAgaWYgKGNvbmZpZ0N1cnJlbnRJbWFnZUNhcm91c2VsLmludmVydFN3aXBlKSB7XG4gICAgICAgICAgdGhpcy5uZXh0SW1hZ2UoQWN0aW9uLlNXSVBFKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnByZXZJbWFnZShBY3Rpb24uU1dJUEUpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgLy8gY2FzZSB0aGlzLlNXSVBFX0FDVElPTi5VUDpcbiAgICAgIC8vICAgYnJlYWs7XG4gICAgICAvLyBjYXNlIHRoaXMuU1dJUEVfQUNUSU9OLkRPV046XG4gICAgICAvLyAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gZ28gYmFjayB0byB0aGUgcHJldmlvdXMgaW1hZ2UuXG4gICAqIEBwYXJhbSBhY3Rpb24gRW51bSBvZiB0eXBlIGBBY3Rpb25gIHRoYXQgcmVwcmVzZW50cyB0aGUgc291cmNlXG4gICAqICBhY3Rpb24gdGhhdCBtb3ZlZCBiYWNrIHRvIHRoZSBwcmV2aW91cyBpbWFnZS4gYEFjdGlvbi5OT1JNQUxgIGJ5IGRlZmF1bHQuXG4gICAqL1xuICBwcmV2SW1hZ2UoYWN0aW9uOiBBY3Rpb24gPSBBY3Rpb24uTk9STUFMKTogdm9pZCB7XG4gICAgLy8gY2hlY2sgaWYgcHJldkltYWdlIHNob3VsZCBiZSBibG9ja2VkXG4gICAgaWYgKHRoaXMuaXNQcmV2ZW50U2xpZGluZygwKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmNoYW5nZUN1cnJlbnRJbWFnZSh0aGlzLmdldFByZXZJbWFnZSgpLCBhY3Rpb24pO1xuXG4gICAgdGhpcy5tYW5hZ2VTbGlkZUNvbmZpZygpO1xuXG4gICAgdGhpcy5zdGFydCQubmV4dCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0byBnbyBiYWNrIHRvIHRoZSBwcmV2aW91cyBpbWFnZS5cbiAgICogQHBhcmFtIGFjdGlvbiBFbnVtIG9mIHR5cGUgYEFjdGlvbmAgdGhhdCByZXByZXNlbnRzIHRoZSBzb3VyY2VcbiAgICogIGFjdGlvbiB0aGF0IG1vdmVkIHRvIHRoZSBuZXh0IGltYWdlLiBgQWN0aW9uLk5PUk1BTGAgYnkgZGVmYXVsdC5cbiAgICovXG4gIG5leHRJbWFnZShhY3Rpb246IEFjdGlvbiA9IEFjdGlvbi5OT1JNQUwpOiB2b2lkIHtcbiAgICAvLyBjaGVjayBpZiBuZXh0SW1hZ2Ugc2hvdWxkIGJlIGJsb2NrZWRcbiAgICBpZiAodGhpcy5pc1ByZXZlbnRTbGlkaW5nKHRoaXMuaW1hZ2VzLmxlbmd0aCAtIDEpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuY2hhbmdlQ3VycmVudEltYWdlKHRoaXMuZ2V0TmV4dEltYWdlKCksIGFjdGlvbik7XG5cbiAgICB0aGlzLm1hbmFnZVNsaWRlQ29uZmlnKCk7XG5cbiAgICB0aGlzLnN0YXJ0JC5uZXh0KCk7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIHVzZWQgaW4gdGhlIHRlbXBsYXRlIHRvIHRyYWNrIGlkcyBpbiBuZ0Zvci5cbiAgICogQHBhcmFtIG51bWJlciBpbmRleCBvZiB0aGUgYXJyYXlcbiAgICogQHBhcmFtIEltYWdlIGl0ZW0gb2YgdGhlIGFycmF5XG4gICAqIEByZXR1cm5zIG51bWJlciB0aGUgaWQgb2YgdGhlIGl0ZW1cbiAgICovXG4gIHRyYWNrQnlJZChpbmRleDogbnVtYmVyLCBpdGVtOiBJbWFnZSk6IG51bWJlciB7XG4gICAgcmV0dXJuIGl0ZW0uaWQ7XG4gIH1cblxuICAvKipcbiAgICogTWV0aG9kIGNhbGxlZCB3aGVuIGFuIGltYWdlIHByZXZpZXcgaXMgY2xpY2tlZCBhbmQgdXNlZCB0byB1cGRhdGUgdGhlIGN1cnJlbnQgaW1hZ2UuXG4gICAqIEBwYXJhbSBldmVudCBhbiBJbWFnZUV2ZW50IG9iamVjdCB3aXRoIHRoZSByZWxhdGl2ZSBhY3Rpb24gYW5kIHRoZSBpbmRleCBvZiB0aGUgY2xpY2tlZCBwcmV2aWV3LlxuICAgKi9cbiAgb25DbGlja1ByZXZpZXcoZXZlbnQ6IEltYWdlRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBpbWFnZUZvdW5kOiBJbWFnZSA9IHRoaXMuaW1hZ2VzW2V2ZW50LnJlc3VsdCBhcyBudW1iZXJdO1xuICAgIGlmICghIWltYWdlRm91bmQpIHtcbiAgICAgIHRoaXMubWFuYWdlU2xpZGVDb25maWcoKTtcbiAgICAgIHRoaXMuY2hhbmdlQ3VycmVudEltYWdlKGltYWdlRm91bmQsIGV2ZW50LmFjdGlvbik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0byBwbGF5IGNhcm91c2VsLlxuICAgKi9cbiAgcGxheUNhcm91c2VsKCk6IHZvaWQge1xuICAgIHRoaXMuc3RhcnQkLm5leHQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyB0aGUgY2Fyb3VzZWwgZnJvbSBjeWNsaW5nIHRocm91Z2ggaXRlbXMuXG4gICAqL1xuICBzdG9wQ2Fyb3VzZWwoKTogdm9pZCB7XG4gICAgdGhpcy5zdG9wJC5uZXh0KCk7XG4gIH1cblxuICAvLyBUT0RPIHJlbW92ZSB0aGlzIGJlY2F1c2UgZHVwbGljYXRlZFxuICAvKipcbiAgICogTWV0aG9kIHRvIGdldCBgYWx0IGF0dHJpYnV0ZWAuXG4gICAqIGBhbHRgIHNwZWNpZmllcyBhbiBhbHRlcm5hdGUgdGV4dCBmb3IgYW4gaW1hZ2UsIGlmIHRoZSBpbWFnZSBjYW5ub3QgYmUgZGlzcGxheWVkLlxuICAgKiBAcGFyYW0gSW1hZ2UgaW1hZ2UgdG8gZ2V0IGl0cyBhbHQgZGVzY3JpcHRpb24uIElmIG5vdCBwcm92aWRlZCBpdCB3aWxsIGJlIHRoZSBjdXJyZW50IGltYWdlXG4gICAqIEByZXR1cm5zIFN0cmluZyBhbHQgZGVzY3JpcHRpb24gb2YgdGhlIGltYWdlIChvciB0aGUgY3VycmVudCBpbWFnZSBpZiBub3QgcHJvdmlkZWQpXG4gICAqL1xuICBnZXRBbHREZXNjcmlwdGlvbkJ5SW1hZ2UoaW1hZ2U6IEltYWdlIHwgdW5kZWZpbmVkID0gdGhpcy5jdXJyZW50SW1hZ2UpOiBzdHJpbmcge1xuICAgIGlmICghaW1hZ2UpIHtcbiAgICAgIHJldHVybiAnJztcbiAgICB9XG4gICAgcmV0dXJuIGltYWdlLm1vZGFsICYmIGltYWdlLm1vZGFsLmRlc2NyaXB0aW9uID8gaW1hZ2UubW9kYWwuZGVzY3JpcHRpb24gOiBgSW1hZ2UgJHtnZXRJbmRleChpbWFnZSwgdGhpcy5pbWFnZXMpICsgMX1gO1xuICB9XG5cbiAgLy8gVE9ETyByZW1vdmUgdGhpcyBiZWNhdXNlIGR1cGxpY2F0ZWRcbiAgLyoqXG4gICAqIE1ldGhvZCB0byBnZXQgdGhlIHRpdGxlIGF0dHJpYnV0ZXMgYmFzZWQgb24gZGVzY3JpcHRpb25zLlxuICAgKiBUaGlzIGlzIHVzZWZ1bCB0byBwcmV2ZW50IGFjY2Vzc2liaWxpdHkgaXNzdWVzLCBiZWNhdXNlIGlmIERlc2NyaXB0aW9uU3RyYXRlZ3kgaXMgQUxXQVlTX0hJRERFTixcbiAgICogaXQgcHJldmVudHMgYW4gZW1wdHkgc3RyaW5nIGFzIHRpdGxlLlxuICAgKiBAcGFyYW0gSW1hZ2UgaW1hZ2UgdG8gZ2V0IGl0cyBkZXNjcmlwdGlvbi4gSWYgbm90IHByb3ZpZGVkIGl0IHdpbGwgYmUgdGhlIGN1cnJlbnQgaW1hZ2VcbiAgICogQHJldHVybnMgU3RyaW5nIHRpdGxlIG9mIHRoZSBpbWFnZSBiYXNlZCBvbiBkZXNjcmlwdGlvbnNcbiAgICogQHRocm93cyBhbiBFcnJvciBpZiBkZXNjcmlwdGlvbiBpc24ndCBhdmFpbGFibGVcbiAgICovXG4gIGdldFRpdGxlVG9EaXNwbGF5KGltYWdlOiBJbWFnZSB8IHVuZGVmaW5lZCA9IHRoaXMuY3VycmVudEltYWdlKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5pZCA9PT0gbnVsbCB8fCB0aGlzLmlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGlkIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBjb25zdCBsaWJDb25maWc6IExpYkNvbmZpZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlnU2VydmljZS5nZXRDb25maWcodGhpcy5pZCk7XG4gICAgaWYgKCFsaWJDb25maWcgfHwgIWxpYkNvbmZpZy5jYXJvdXNlbEltYWdlQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBsaWJDb25maWcgYW5kIGNhcm91c2VsSW1hZ2VDb25maWcgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGNvbmZpZ0N1cnJlbnRJbWFnZUNhcm91c2VsOiBDYXJvdXNlbEltYWdlQ29uZmlnID0gbGliQ29uZmlnLmNhcm91c2VsSW1hZ2VDb25maWc7XG4gICAgaWYgKCFjb25maWdDdXJyZW50SW1hZ2VDYXJvdXNlbCB8fCAhY29uZmlnQ3VycmVudEltYWdlQ2Fyb3VzZWwuZGVzY3JpcHRpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRGVzY3JpcHRpb24gaW5wdXQgbXVzdCBiZSBhIHZhbGlkIG9iamVjdCBpbXBsZW1lbnRpbmcgdGhlIERlc2NyaXB0aW9uIGludGVyZmFjZScpO1xuICAgIH1cbiAgICBjb25zdCBpbWFnZVdpdGhvdXREZXNjcmlwdGlvbjogYm9vbGVhbiA9ICFpbWFnZSB8fCAhaW1hZ2UubW9kYWwgfHwgIWltYWdlLm1vZGFsLmRlc2NyaXB0aW9uIHx8IGltYWdlLm1vZGFsLmRlc2NyaXB0aW9uID09PSAnJztcbiAgICBjb25zdCBkZXNjcmlwdGlvbjogc3RyaW5nID0gdGhpcy5idWlsZFRleHREZXNjcmlwdGlvbihpbWFnZSwgaW1hZ2VXaXRob3V0RGVzY3JpcHRpb24pO1xuICAgIHJldHVybiBkZXNjcmlwdGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gcmVzZXQgY2Fyb3VzZWwgKGZvcmNlIGltYWdlIHdpdGggaW5kZXggMCB0byBiZSB0aGUgY3VycmVudCBpbWFnZSBhbmQgcmUtaW5pdCBhbHNvIHByZXZpZXdzKVxuICAgKi9cbiAgLy8gdGVtcG9yYXJ5IHJlbW92ZWQgYmVjYXVzZSBuZXZlciB0ZXN0ZWRcbiAgLy8gcmVzZXQoKSB7XG4gIC8vICAgaWYgKHRoaXMuY29uZmlnUGxheSAmJiB0aGlzLmNvbmZpZ1BsYXkuYXV0b1BsYXkpIHtcbiAgLy8gICAgIHRoaXMuc3RvcENhcm91c2VsKCk7XG4gIC8vICAgfVxuICAvLyAgIHRoaXMuY3VycmVudEltYWdlID0gdGhpcy5pbWFnZXNbMF07XG4gIC8vICAgdGhpcy5oYW5kbGVCb3VuZGFyaWVzKDApO1xuICAvLyAgIGlmICh0aGlzLmNvbmZpZ1BsYXkgJiYgdGhpcy5jb25maWdQbGF5LmF1dG9QbGF5KSB7XG4gIC8vICAgICB0aGlzLnBsYXlDYXJvdXNlbCgpO1xuICAvLyAgIH1cbiAgLy8gICB0aGlzLnJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgLy8gfVxuXG4gIC8qKlxuICAgKiBNZXRob2QgdG8gY2xlYW51cCByZXNvdXJjZXMuIEluIGZhY3QsIHRoaXMgd2lsbCBzdG9wIHRoZSBjYXJvdXNlbC5cbiAgICogVGhpcyBpcyBhbiBBbmd1bGFyJ3MgbGlmZWN5Y2xlIGhvb2sgdGhhdCBpcyBjYWxsZWQgd2hlbiB0aGlzIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQuXG4gICAqL1xuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnN0b3BDYXJvdXNlbCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldGhvZCB0byBjaGFuZ2UgdGhlIGN1cnJlbnQgaW1hZ2UsIHJlY2VpdmluZyB0aGUgbmV3IGltYWdlIGFzIGlucHV0IHRoZSByZWxhdGl2ZSBhY3Rpb24uXG4gICAqIEBwYXJhbSBpbWFnZSBhbiBJbWFnZSBvYmplY3QgdGhhdCByZXByZXNlbnRzIHRoZSBuZXcgaW1hZ2UgdG8gc2V0IGFzIGN1cnJlbnQuXG4gICAqIEBwYXJhbSBhY3Rpb24gRW51bSBvZiB0eXBlIGBBY3Rpb25gIHRoYXQgcmVwcmVzZW50cyB0aGUgc291cmNlIGFjdGlvbiB0aGF0IHRyaWdnZXJlZCB0aGUgY2hhbmdlLlxuICAgKi9cbiAgcHJpdmF0ZSBjaGFuZ2VDdXJyZW50SW1hZ2UoaW1hZ2U6IEltYWdlLCBhY3Rpb246IEFjdGlvbik6IHZvaWQge1xuICAgIGlmICh0aGlzLmlkID09PSBudWxsIHx8IHRoaXMuaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gaWQgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIHRoaXMuY3VycmVudEltYWdlID0gaW1hZ2U7XG4gICAgY29uc3QgaW5kZXg6IG51bWJlciA9IGdldEluZGV4KGltYWdlLCB0aGlzLmltYWdlcyk7XG5cbiAgICAvLyBlbWl0IGZpcnN0L2xhc3QgZXZlbnQgYmFzZWQgb24gbmV3SW5kZXggdmFsdWVcbiAgICB0aGlzLmVtaXRCb3VuZGFyeUV2ZW50KGFjdGlvbiwgaW5kZXgpO1xuXG4gICAgLy8gZW1pdCBjdXJyZW50IHZpc2libGUgaW1hZ2UgaW5kZXhcbiAgICB0aGlzLmNoYW5nZUltYWdlLmVtaXQobmV3IEltYWdlRXZlbnQodGhpcy5pZCwgYWN0aW9uLCBpbmRleCArIDEpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcml2YXRlIG1ldGhvZCB0byBnZXQgdGhlIG5leHQgaW5kZXguXG4gICAqIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2UgYXQgdGhlIGVuZCwgd2hlbiB5b3UgY2FsbCBuZXh0IGFnYWluLCB5b3UnbGwgZ28gdG8gdGhlIGZpcnN0IGltYWdlLlxuICAgKiBUaGF0IGhhcHBlbnMgYmVjYXVzZSBhbGwgbW9kYWwgaW1hZ2VzIGFyZSBzaG93biBsaWtlIGluIGEgY2lyY2xlLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXROZXh0SW1hZ2UoKTogSW1hZ2Uge1xuICAgIGlmICghdGhpcy5jdXJyZW50SW1hZ2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGN1cnJlbnRJbWFnZSBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgY29uc3QgY3VycmVudEluZGV4OiBudW1iZXIgPSBnZXRJbmRleCh0aGlzLmN1cnJlbnRJbWFnZSwgdGhpcy5pbWFnZXMpO1xuICAgIGxldCBuZXdJbmRleCA9IDA7XG4gICAgaWYgKGN1cnJlbnRJbmRleCA+PSAwICYmIGN1cnJlbnRJbmRleCA8IHRoaXMuaW1hZ2VzLmxlbmd0aCAtIDEpIHtcbiAgICAgIG5ld0luZGV4ID0gY3VycmVudEluZGV4ICsgMTtcbiAgICB9IGVsc2Uge1xuICAgICAgbmV3SW5kZXggPSAwOyAvLyBzdGFydCBmcm9tIHRoZSBmaXJzdCBpbmRleFxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5pbWFnZXNbbmV3SW5kZXhdO1xuICB9XG5cbiAgLyoqXG4gICAqIFByaXZhdGUgbWV0aG9kIHRvIGdldCB0aGUgcHJldmlvdXMgaW5kZXguXG4gICAqIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2UgYXQgaW5kZXggMCwgd2hlbiB5b3UgY2FsbCBwcmV2IGFnYWluLCB5b3UnbGwgZ28gdG8gdGhlIGxhc3QgaW1hZ2UuXG4gICAqIFRoYXQgaGFwcGVucyBiZWNhdXNlIGFsbCBtb2RhbCBpbWFnZXMgYXJlIHNob3duIGxpa2UgaW4gYSBjaXJjbGUuXG4gICAqL1xuICBwcml2YXRlIGdldFByZXZJbWFnZSgpOiBJbWFnZSB7XG4gICAgaWYgKCF0aGlzLmN1cnJlbnRJbWFnZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gY3VycmVudEltYWdlIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBjb25zdCBjdXJyZW50SW5kZXg6IG51bWJlciA9IGdldEluZGV4KHRoaXMuY3VycmVudEltYWdlLCB0aGlzLmltYWdlcyk7XG4gICAgbGV0IG5ld0luZGV4ID0gMDtcbiAgICBpZiAoY3VycmVudEluZGV4ID4gMCAmJiBjdXJyZW50SW5kZXggPD0gdGhpcy5pbWFnZXMubGVuZ3RoIC0gMSkge1xuICAgICAgbmV3SW5kZXggPSBjdXJyZW50SW5kZXggLSAxO1xuICAgIH0gZWxzZSB7XG4gICAgICBuZXdJbmRleCA9IHRoaXMuaW1hZ2VzLmxlbmd0aCAtIDE7IC8vIHN0YXJ0IGZyb20gdGhlIGxhc3QgaW5kZXhcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaW1hZ2VzW25ld0luZGV4XTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcml2YXRlIG1ldGhvZCB0byBidWlsZCBhIHRleHQgZGVzY3JpcHRpb24uXG4gICAqIFRoaXMgaXMgdXNlZCBhbHNvIHRvIGNyZWF0ZSB0aXRsZXMuXG4gICAqIEBwYXJhbSBJbWFnZSBpbWFnZSB0byBnZXQgaXRzIGRlc2NyaXB0aW9uLiBJZiBub3QgcHJvdmlkZWQgaXQgd2lsbCBiZSB0aGUgY3VycmVudCBpbWFnZS5cbiAgICogQHBhcmFtIGJvb2xlYW4gaW1hZ2VXaXRob3V0RGVzY3JpcHRpb24gaXMgYSBib29sZWFuIHRoYXQgaXQncyB0cnVlIGlmIHRoZSBpbWFnZSBoYXNuJ3QgYSAnbW9kYWwnIGRlc2NyaXB0aW9uLlxuICAgKiBAcmV0dXJucyBTdHJpbmcgZGVzY3JpcHRpb24gYnVpbHQgY29uY2F0ZW5hdGluZyBpbWFnZSBmaWVsZHMgd2l0aCBhIHNwZWNpZmljIGxvZ2ljLlxuICAgKi9cbiAgcHJpdmF0ZSBidWlsZFRleHREZXNjcmlwdGlvbihpbWFnZTogSW1hZ2UgfCB1bmRlZmluZWQsIGltYWdlV2l0aG91dERlc2NyaXB0aW9uOiBib29sZWFuKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5pZCA9PT0gbnVsbCB8fCB0aGlzLmlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGlkIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBjb25zdCBsaWJDb25maWc6IExpYkNvbmZpZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlnU2VydmljZS5nZXRDb25maWcodGhpcy5pZCk7XG4gICAgaWYgKCFsaWJDb25maWcgfHwgIWxpYkNvbmZpZy5jYXJvdXNlbEltYWdlQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBsaWJDb25maWcgYW5kIGNhcm91c2VsSW1hZ2VDb25maWcgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGNvbmZpZ0N1cnJlbnRJbWFnZUNhcm91c2VsOiBDYXJvdXNlbEltYWdlQ29uZmlnIHwgdW5kZWZpbmVkID0gbGliQ29uZmlnLmNhcm91c2VsSW1hZ2VDb25maWc7XG4gICAgaWYgKCFjb25maWdDdXJyZW50SW1hZ2VDYXJvdXNlbCB8fCAhY29uZmlnQ3VycmVudEltYWdlQ2Fyb3VzZWwuZGVzY3JpcHRpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRGVzY3JpcHRpb24gaW5wdXQgbXVzdCBiZSBhIHZhbGlkIG9iamVjdCBpbXBsZW1lbnRpbmcgdGhlIERlc2NyaXB0aW9uIGludGVyZmFjZScpO1xuICAgIH1cbiAgICBpZiAoIWltYWdlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBpbWFnZSBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG5cbiAgICAvLyBJZiBjdXN0b21GdWxsRGVzY3JpcHRpb24gdXNlIGl0LCBvdGhlcndpc2UgcHJvY2VlZCB0byBidWlsZCBhIGRlc2NyaXB0aW9uXG4gICAgaWYgKGNvbmZpZ0N1cnJlbnRJbWFnZUNhcm91c2VsLmRlc2NyaXB0aW9uLmN1c3RvbUZ1bGxEZXNjcmlwdGlvbiAmJiBjb25maWdDdXJyZW50SW1hZ2VDYXJvdXNlbC5kZXNjcmlwdGlvbi5jdXN0b21GdWxsRGVzY3JpcHRpb24gIT09ICcnKSB7XG4gICAgICByZXR1cm4gY29uZmlnQ3VycmVudEltYWdlQ2Fyb3VzZWwuZGVzY3JpcHRpb24uY3VzdG9tRnVsbERlc2NyaXB0aW9uO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnJlbnRJbmRleDogbnVtYmVyID0gZ2V0SW5kZXgoaW1hZ2UsIHRoaXMuaW1hZ2VzKTtcbiAgICAvLyBJZiB0aGUgY3VycmVudCBpbWFnZSBoYXNuJ3QgYSBkZXNjcmlwdGlvbixcbiAgICAvLyBwcmV2ZW50IHRvIHdyaXRlIHRoZSAnIC0gJyAob3IgdGhpcy5kZXNjcmlwdGlvbi5iZWZvcmVUZXh0RGVzY3JpcHRpb24pXG5cbiAgICBjb25zdCBwcmV2RGVzY3JpcHRpb246IHN0cmluZyA9IGNvbmZpZ0N1cnJlbnRJbWFnZUNhcm91c2VsLmRlc2NyaXB0aW9uLmltYWdlVGV4dCA/IGNvbmZpZ0N1cnJlbnRJbWFnZUNhcm91c2VsLmRlc2NyaXB0aW9uLmltYWdlVGV4dCA6ICcnO1xuICAgIGNvbnN0IG1pZFNlcGFyYXRvcjogc3RyaW5nID0gY29uZmlnQ3VycmVudEltYWdlQ2Fyb3VzZWwuZGVzY3JpcHRpb24ubnVtYmVyU2VwYXJhdG9yID8gY29uZmlnQ3VycmVudEltYWdlQ2Fyb3VzZWwuZGVzY3JpcHRpb24ubnVtYmVyU2VwYXJhdG9yIDogJyc7XG4gICAgY29uc3QgbWlkZGxlRGVzY3JpcHRpb246IHN0cmluZyA9IGN1cnJlbnRJbmRleCArIDEgKyBtaWRTZXBhcmF0b3IgKyB0aGlzLmltYWdlcy5sZW5ndGg7XG5cbiAgICBpZiAoaW1hZ2VXaXRob3V0RGVzY3JpcHRpb24pIHtcbiAgICAgIHJldHVybiBwcmV2RGVzY3JpcHRpb24gKyBtaWRkbGVEZXNjcmlwdGlvbjtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJySW1nRGVzY3JpcHRpb246IHN0cmluZyA9IGltYWdlLm1vZGFsICYmIGltYWdlLm1vZGFsLmRlc2NyaXB0aW9uID8gaW1hZ2UubW9kYWwuZGVzY3JpcHRpb24gOiAnJztcbiAgICBjb25zdCBlbmREZXNjcmlwdGlvbjogc3RyaW5nID0gY29uZmlnQ3VycmVudEltYWdlQ2Fyb3VzZWwuZGVzY3JpcHRpb24uYmVmb3JlVGV4dERlc2NyaXB0aW9uICsgY3VyckltZ0Rlc2NyaXB0aW9uO1xuICAgIHJldHVybiBwcmV2RGVzY3JpcHRpb24gKyBtaWRkbGVEZXNjcmlwdGlvbiArIGVuZERlc2NyaXB0aW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIFByaXZhdGUgbWV0aG9kIHRvIHVwZGF0ZSBib3RoIGBpc0ZpcnN0SW1hZ2VgIGFuZCBgaXNMYXN0SW1hZ2VgIGJhc2VkIG9uXG4gICAqIHRoZSBpbmRleCBvZiB0aGUgY3VycmVudCBpbWFnZS5cbiAgICogQHBhcmFtIG51bWJlciBjdXJyZW50SW5kZXggaXMgdGhlIGluZGV4IG9mIHRoZSBjdXJyZW50IGltYWdlXG4gICAqL1xuICBwcml2YXRlIGhhbmRsZUJvdW5kYXJpZXMoY3VycmVudEluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pbWFnZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICB0aGlzLmlzRmlyc3RJbWFnZSA9IHRydWU7XG4gICAgICB0aGlzLmlzTGFzdEltYWdlID0gdHJ1ZTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgc3dpdGNoIChjdXJyZW50SW5kZXgpIHtcbiAgICAgIGNhc2UgMDpcbiAgICAgICAgLy8gZXhlY3V0ZSB0aGlzIG9ubHkgaWYgaW5maW5pdGUgc2xpZGluZyBpcyBkaXNhYmxlZFxuICAgICAgICB0aGlzLmlzRmlyc3RJbWFnZSA9IHRydWU7XG4gICAgICAgIHRoaXMuaXNMYXN0SW1hZ2UgPSBmYWxzZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIHRoaXMuaW1hZ2VzLmxlbmd0aCAtIDE6XG4gICAgICAgIC8vIGV4ZWN1dGUgdGhpcyBvbmx5IGlmIGluZmluaXRlIHNsaWRpbmcgaXMgZGlzYWJsZWRcbiAgICAgICAgdGhpcy5pc0ZpcnN0SW1hZ2UgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc0xhc3RJbWFnZSA9IHRydWU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhpcy5pc0ZpcnN0SW1hZ2UgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc0xhc3RJbWFnZSA9IGZhbHNlO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUHJpdmF0ZSBtZXRob2QgdG8gbWFuYWdlIGJvdW5kYXJ5IGFycm93cyBhbmQgc2xpZGluZy5cbiAgICogVGhpcyBpcyBiYXNlZCBvbiB0aGUgc2xpZGVDb25maWcgaW5wdXQgdG8gZW5hYmxlL2Rpc2FibGUgJ2luZmluaXRlIHNsaWRpbmcnLlxuICAgKiBAcGFyYW0gbnVtYmVyIGluZGV4IG9mIHRoZSB2aXNpYmxlIGltYWdlXG4gICAqL1xuICBwcml2YXRlIG1hbmFnZVNsaWRlQ29uZmlnKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlkID09PSBudWxsIHx8IHRoaXMuaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gaWQgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGxpYkNvbmZpZzogTGliQ29uZmlnIHwgdW5kZWZpbmVkID0gdGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZyh0aGlzLmlkKTtcbiAgICBpZiAoIWxpYkNvbmZpZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnRlcm5hbCBsaWJyYXJ5IGVycm9yIC0gbGliQ29uZmlnIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuY3VycmVudEltYWdlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBjdXJyZW50SW1hZ2UgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGxldCBpbmRleDogbnVtYmVyO1xuICAgIHRyeSB7XG4gICAgICBpbmRleCA9IGdldEluZGV4KHRoaXMuY3VycmVudEltYWdlLCB0aGlzLmltYWdlcyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdDYW5ub3QgZ2V0IHRoZSBjdXJyZW50IGltYWdlIGluZGV4IGluIGN1cnJlbnQtaW1hZ2UnKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG5cbiAgICBpZiAobGliQ29uZmlnLmNhcm91c2VsU2xpZGVJbmZpbml0ZSA9PT0gdHJ1ZSkge1xuICAgICAgLy8gZW5hYmxlIGluZmluaXRlIHNsaWRpbmdcbiAgICAgIHRoaXMuaXNGaXJzdEltYWdlID0gZmFsc2U7XG4gICAgICB0aGlzLmlzTGFzdEltYWdlID0gZmFsc2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaGFuZGxlQm91bmRhcmllcyhpbmRleCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFByaXZhdGUgbWV0aG9kIHRvIGVtaXQgZXZlbnRzIHdoZW4gZWl0aGVyIHRoZSBsYXN0IG9yIHRoZSBmaXJzdCBpbWFnZSBhcmUgdmlzaWJsZS5cbiAgICogQHBhcmFtIGFjdGlvbiBFbnVtIG9mIHR5cGUgQWN0aW9uIHRoYXQgcmVwcmVzZW50cyB0aGUgc291cmNlIG9mIHRoZSBldmVudCB0aGF0IGNoYW5nZWQgdGhlXG4gICAqICBjdXJyZW50IGltYWdlIHRvIHRoZSBmaXJzdCBvbmUgb3IgdGhlIGxhc3Qgb25lLlxuICAgKiBAcGFyYW0gaW5kZXhUb0NoZWNrIGlzIHRoZSBpbmRleCBudW1iZXIgb2YgdGhlIGltYWdlICh0aGUgZmlyc3Qgb3IgdGhlIGxhc3Qgb25lKS5cbiAgICovXG4gIHByaXZhdGUgZW1pdEJvdW5kYXJ5RXZlbnQoYWN0aW9uOiBBY3Rpb24sIGluZGV4VG9DaGVjazogbnVtYmVyKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaWQgPT09IG51bGwgfHwgdGhpcy5pZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIHRvIGVtaXQgZmlyc3QvbGFzdCBldmVudFxuICAgIHN3aXRjaCAoaW5kZXhUb0NoZWNrKSB7XG4gICAgICBjYXNlIDA6XG4gICAgICAgIHRoaXMuZmlyc3RJbWFnZS5lbWl0KG5ldyBJbWFnZUV2ZW50KHRoaXMuaWQsIGFjdGlvbiwgdHJ1ZSkpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdGhpcy5pbWFnZXMubGVuZ3RoIC0gMTpcbiAgICAgICAgdGhpcy5sYXN0SW1hZ2UuZW1pdChuZXcgSW1hZ2VFdmVudCh0aGlzLmlkLCBhY3Rpb24sIHRydWUpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFByaXZhdGUgbWV0aG9kIHRvIGNoZWNrIGlmIG5leHQvcHJldiBhY3Rpb25zIHNob3VsZCBiZSBibG9ja2VkLlxuICAgKiBJdCBjaGVja3MgaWYgY2Fyb3VzZWxTbGlkZUluZmluaXRlID09PSBmYWxzZSBhbmQgaWYgdGhlIGltYWdlIGluZGV4IGlzIGVxdWFscyB0byB0aGUgaW5wdXQgcGFyYW1ldGVyLlxuICAgKiBJZiB5ZXMsIGl0IHJldHVybnMgdHJ1ZSB0byBzYXkgdGhhdCBzbGlkaW5nIHNob3VsZCBiZSBibG9ja2VkLCBvdGhlcndpc2Ugbm90LlxuICAgKiBAcGFyYW0gbnVtYmVyIGJvdW5kYXJ5SW5kZXggdGhhdCBjb3VsZCBiZSBlaXRoZXIgdGhlIGJlZ2lubmluZyBpbmRleCAoMCkgb3IgdGhlIGxhc3QgaW5kZXhcbiAgICogIG9mIGltYWdlcyAodGhpcy5pbWFnZXMubGVuZ3RoIC0gMSkuXG4gICAqIEByZXR1cm5zIGJvb2xlYW4gdHJ1ZSBpZiBjYXJvdXNlbFNsaWRlSW5maW5pdGUgPT09IGZhbHNlIGFuZCB0aGUgY3VycmVudCBpbmRleCBpc1xuICAgKiAgZWl0aGVyIHRoZSBmaXJzdCBvciB0aGUgbGFzdCBvbmUuXG4gICAqL1xuICBwcml2YXRlIGlzUHJldmVudFNsaWRpbmcoYm91bmRhcnlJbmRleDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuaWQgPT09IG51bGwgfHwgdGhpcy5pZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBpZCBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgY29uc3QgbGliQ29uZmlnOiBMaWJDb25maWcgfCB1bmRlZmluZWQgPSB0aGlzLmNvbmZpZ1NlcnZpY2UuZ2V0Q29uZmlnKHRoaXMuaWQpO1xuICAgIGlmICghbGliQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVybmFsIGxpYnJhcnkgZXJyb3IgLSBsaWJDb25maWcgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuICAgIGlmICghdGhpcy5jdXJyZW50SW1hZ2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW50ZXJuYWwgbGlicmFyeSBlcnJvciAtIGN1cnJlbnRJbWFnZSBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG4gICAgcmV0dXJuICFsaWJDb25maWcuY2Fyb3VzZWxTbGlkZUluZmluaXRlICYmIGdldEluZGV4KHRoaXMuY3VycmVudEltYWdlLCB0aGlzLmltYWdlcykgPT09IGJvdW5kYXJ5SW5kZXg7XG4gIH1cbn1cbiIsIjxtYWluIGlkPVwiY2Fyb3VzZWwtY29udGFpbmVyXCJcbiAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYWNjZXNzaWJpbGl0eUNvbmZpZz8uY2Fyb3VzZWxDb250YWluZXJBcmlhTGFiZWxcIlxuICAgICAgW3RpdGxlXT1cImFjY2Vzc2liaWxpdHlDb25maWc/LmNhcm91c2VsQ29udGFpbmVyVGl0bGVcIlxuICAgICAga3NNYXhTaXplIFttYXhTaXplQ29uZmlnXT1cInttYXhXaWR0aDogY2Fyb3VzZWxDb25maWc/Lm1heFdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heEhlaWdodDogJyd9XCI+XG5cblxuICA8IS0tIFdvcmthcm91bmQgdG8gc3VwcG9ydCAyIG5nLWNvbnRlbnQgaW4gdGhlIHNhbWUgdGVtcGxhdGUgaW4gMiBuZ0lmIChodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2lzc3Vlcy8yMjk3MikgLS0+XG4gIDxuZy10ZW1wbGF0ZSAjY29udGVudD48bmctY29udGVudD48L25nLWNvbnRlbnQ+PC9uZy10ZW1wbGF0ZT5cblxuICA8ZmlndXJlIGNsYXNzPVwiY3VycmVudC1maWd1cmVcIiAqbmdJZj1cImN1cnJlbnRJbWFnZSAmJiBjdXJyZW50SW1hZ2UubW9kYWxcIlxuICAgICAgICAgIGtzU2l6ZSBbc2l6ZUNvbmZpZ109XCJ7d2lkdGg6IGNhcm91c2VsQ29uZmlnPy5tYXhXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiAnJ31cIj5cblxuICAgIDxhIGNsYXNzPVwibmF2LWxlZnRcIiAqbmdJZj1cImNhcm91c2VsQ29uZmlnPy5zaG93QXJyb3dzXCJcbiAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImFjY2Vzc2liaWxpdHlDb25maWc/LmNhcm91c2VsUHJldkltYWdlQXJpYUxhYmVsXCJcbiAgICAgICBbdGFiSW5kZXhdPVwiaXNMYXN0SW1hZ2UgJiYgIWNhcm91c2VsU2xpZGVJbmZpbml0ZSA/IC0xIDogMFwiIHJvbGU9XCJidXR0b25cIlxuICAgICAgIChjbGljayk9XCJvbk5hdmlnYXRpb25FdmVudCgnbGVmdCcsICRldmVudCwgY2xpY2tBY3Rpb24pXCIgKGtleXVwKT1cIm9uTmF2aWdhdGlvbkV2ZW50KCdsZWZ0JywgJGV2ZW50LCBrZXlib2FyZEFjdGlvbilcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJpbnNpZGUge3soaXNGaXJzdEltYWdlICYmICFjYXJvdXNlbFNsaWRlSW5maW5pdGUpIHx8ICFjYXJvdXNlbENvbmZpZy5zaG93QXJyb3dzID8gJ2VtcHR5LWFycm93LWltYWdlJyA6ICdsZWZ0LWFycm93LWltYWdlJ319XCJcbiAgICAgICAgICAgYXJpYS1oaWRkZW49XCJ0cnVlXCJcbiAgICAgICAgICAgW3RpdGxlXT1cImFjY2Vzc2liaWxpdHlDb25maWc/LmNhcm91c2VsUHJldkltYWdlVGl0bGVcIj48L2Rpdj5cbiAgICA8L2E+XG5cbiAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiY29udGVudFwiPjwvbmctY29udGFpbmVyPlxuXG4gICAgPGltZyBpZD1cImN1cnJlbnQtaW1hZ2VcIlxuICAgICAgICAgW3N0eWxlLm9iamVjdC1maXRdPVwiY2Fyb3VzZWxDb25maWc/Lm9iamVjdEZpdFwiXG4gICAgICAgICBrc01heFNpemUgW21heFNpemVDb25maWddPVwie21heFdpZHRoOiBjYXJvdXNlbENvbmZpZz8ubWF4V2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4SGVpZ2h0OiBjYXJvdXNlbENvbmZpZz8ubWF4SGVpZ2h0fVwiXG4gICAgICAgICBbc3JjXT1cImN1cnJlbnRJbWFnZS5tb2RhbC5pbWdcIlxuICAgICAgICAga3NGYWxsYmFja0ltYWdlIFtmYWxsYmFja0ltZ109XCJjdXJyZW50SW1hZ2UubW9kYWwuZmFsbGJhY2tJbWdcIlxuICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJjdXJyZW50SW1hZ2UubW9kYWwuYXJpYUxhYmVsXCJcbiAgICAgICAgIFt0aXRsZV09XCIoY3VycmVudEltYWdlLm1vZGFsLnRpdGxlIHx8IGN1cnJlbnRJbWFnZS5tb2RhbC50aXRsZSA9PT0gJycpID8gY3VycmVudEltYWdlLm1vZGFsLnRpdGxlIDogZ2V0VGl0bGVUb0Rpc3BsYXkoKVwiXG4gICAgICAgICBhbHQ9XCJ7e2N1cnJlbnRJbWFnZS5tb2RhbC5hbHQgPyBjdXJyZW50SW1hZ2UubW9kYWwuYWx0IDogZ2V0QWx0RGVzY3JpcHRpb25CeUltYWdlKCl9fVwiXG4gICAgICAgICBbdGFiSW5kZXhdPVwiMFwiIHJvbGU9XCJpbWdcIlxuICAgICAgICAgKGNsaWNrKT1cIm9uQ2xpY2tDdXJyZW50SW1hZ2UoKVwiXG4gICAgICAgICAoc3dpcGVsZWZ0KT1cInN3aXBlKCRldmVudC50eXBlKVwiXG4gICAgICAgICAoc3dpcGVyaWdodCk9XCJzd2lwZSgkZXZlbnQudHlwZSlcIi8+XG5cbiAgICA8ZmlnY2FwdGlvbiAqbmdJZj1cImdldERlc2NyaXB0aW9uVG9EaXNwbGF5KCkgIT09ICcnXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImRlc2NyaXB0aW9uXCJcbiAgICAgICAgICAgICAgICBrc0Rlc2NyaXB0aW9uIFtkZXNjcmlwdGlvbl09XCJjYXJvdXNlbEltYWdlQ29uZmlnPy5kZXNjcmlwdGlvblwiXG4gICAgICAgICAgICAgICAgW2lubmVySFRNTF09XCJnZXREZXNjcmlwdGlvblRvRGlzcGxheSgpXCI+PC9maWdjYXB0aW9uPlxuXG4gICAgPGEgY2xhc3M9XCJuYXYtcmlnaHRcIiAqbmdJZj1cImNhcm91c2VsQ29uZmlnPy5zaG93QXJyb3dzXCJcbiAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImFjY2Vzc2liaWxpdHlDb25maWc/LmNhcm91c2VsTmV4dEltYWdlQXJpYUxhYmVsXCJcbiAgICAgICBbdGFiSW5kZXhdPVwiaXNMYXN0SW1hZ2UgJiYgIWNhcm91c2VsU2xpZGVJbmZpbml0ZSA/IC0xIDogMFwiIHJvbGU9XCJidXR0b25cIlxuICAgICAgIChjbGljayk9XCJvbk5hdmlnYXRpb25FdmVudCgncmlnaHQnLCAkZXZlbnQsIGNsaWNrQWN0aW9uKVwiIChrZXl1cCk9XCJvbk5hdmlnYXRpb25FdmVudCgncmlnaHQnLCAkZXZlbnQsIGtleWJvYXJkQWN0aW9uKVwiPlxuICAgICAgPGRpdiBjbGFzcz1cImluc2lkZSB7eyhpc0xhc3RJbWFnZSAmJiAhY2Fyb3VzZWxTbGlkZUluZmluaXRlKSB8fCAhY2Fyb3VzZWxDb25maWcuc2hvd0Fycm93cyA/ICdlbXB0eS1hcnJvdy1pbWFnZScgOiAncmlnaHQtYXJyb3ctaW1hZ2UnfX1cIlxuICAgICAgICAgICBhcmlhLWhpZGRlbj1cInRydWVcIlxuICAgICAgICAgICBbdGl0bGVdPVwiYWNjZXNzaWJpbGl0eUNvbmZpZz8uY2Fyb3VzZWxOZXh0SW1hZ2VUaXRsZVwiPjwvZGl2PlxuICAgIDwvYT5cblxuICAgIDxkaXYgaWQ9XCJkb3RzXCI+XG4gICAgICA8a3MtZG90cyBbaWRdPVwiaWRcIlxuICAgICAgICAgICAgICAgW2N1cnJlbnRJbWFnZV09XCJjdXJyZW50SW1hZ2VcIlxuICAgICAgICAgICAgICAgW2ltYWdlc109XCJpbWFnZXNcIlxuICAgICAgICAgICAgICAgW2RvdHNDb25maWddPVwiY2Fyb3VzZWxEb3RzQ29uZmlnXCJcbiAgICAgICAgICAgICAgIChjbGlja0RvdCk9XCJvbkNsaWNrRG90KCRldmVudClcIj48L2tzLWRvdHM+XG4gICAgPC9kaXY+XG5cbiAgPC9maWd1cmU+XG5cbjwvbWFpbj5cblxuPGtzLWNhcm91c2VsLXByZXZpZXdzIFtpZF09XCJpZFwiXG4gICAgICAgICAgICAgICAgICAgICAgW2ltYWdlc109XCJpbWFnZXNcIlxuICAgICAgICAgICAgICAgICAgICAgIFtjdXJyZW50SW1hZ2VdPVwiY3VycmVudEltYWdlXCJcbiAgICAgICAgICAgICAgICAgICAgICAoY2xpY2tQcmV2aWV3KT1cIm9uQ2xpY2tQcmV2aWV3KCRldmVudClcIj48L2tzLWNhcm91c2VsLXByZXZpZXdzPlxuIl19