stream-chat-angular 6.0.0-beta.5 → 6.0.0-rc.2

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 (202) hide show
  1. package/README.md +2 -2
  2. package/assets/i18n/en.d.ts +0 -1
  3. package/assets/version.d.ts +1 -1
  4. package/{esm2022 → esm2020}/assets/i18n/en.mjs +1 -2
  5. package/{esm2022 → esm2020}/assets/version.mjs +2 -2
  6. package/esm2020/lib/attachment-configuration.service.mjs +182 -0
  7. package/esm2020/lib/attachment-list/attachment-list.component.mjs +232 -0
  8. package/esm2020/lib/attachment-preview-list/attachment-preview-list.component.mjs +55 -0
  9. package/esm2020/lib/attachment.service.mjs +481 -0
  10. package/esm2020/lib/avatar/avatar.component.mjs +160 -0
  11. package/esm2020/lib/avatar-placeholder/avatar-placeholder.component.mjs +66 -0
  12. package/esm2020/lib/channel/channel.component.mjs +45 -0
  13. package/esm2020/lib/channel-header/channel-header.component.mjs +72 -0
  14. package/esm2020/lib/channel-list/channel-list.component.mjs +47 -0
  15. package/esm2020/lib/channel-preview/channel-preview.component.mjs +155 -0
  16. package/esm2020/lib/channel-query.mjs +77 -0
  17. package/esm2020/lib/channel.service.mjs +1561 -0
  18. package/esm2020/lib/chat-client.service.mjs +233 -0
  19. package/esm2020/lib/custom-templates.service.mjs +244 -0
  20. package/{esm2022 → esm2020}/lib/date-parser.service.mjs +5 -5
  21. package/esm2020/lib/file-utils.mjs +35 -0
  22. package/{esm2022 → esm2020}/lib/get-channel-display-text.mjs +1 -1
  23. package/esm2020/lib/get-message-translation.mjs +12 -0
  24. package/esm2020/lib/icon/icon-placeholder/icon-placeholder.component.mjs +28 -0
  25. package/{esm2022 → esm2020}/lib/icon/icon.component.mjs +5 -5
  26. package/{esm2022 → esm2020}/lib/icon/icon.module.mjs +11 -11
  27. package/{esm2022 → esm2020}/lib/icon/loading-indicator/loading-indicator.component.mjs +5 -5
  28. package/esm2020/lib/icon/loading-indicator-placeholder/loading-indicator-placeholder.component.mjs +20 -0
  29. package/{esm2022 → esm2020}/lib/list-users.mjs +1 -1
  30. package/esm2020/lib/message/message.component.mjs +486 -0
  31. package/esm2020/lib/message-actions-box/message-actions-box.component.mjs +123 -0
  32. package/esm2020/lib/message-actions.service.mjs +187 -0
  33. package/esm2020/lib/message-bounce-prompt/message-bounce-prompt.component.mjs +71 -0
  34. package/esm2020/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.mjs +333 -0
  35. package/{esm2022 → esm2020}/lib/message-input/emoji-input.service.mjs +7 -7
  36. package/esm2020/lib/message-input/message-input-config.service.mjs +50 -0
  37. package/esm2020/lib/message-input/message-input.component.mjs +507 -0
  38. package/{esm2022 → esm2020}/lib/message-input/textarea/textarea.component.mjs +6 -6
  39. package/{esm2022 → esm2020}/lib/message-input/textarea.directive.mjs +5 -5
  40. package/{esm2022 → esm2020}/lib/message-input/voice-recorder.service.mjs +5 -5
  41. package/{esm2022 → esm2020}/lib/message-list/group-styles.mjs +1 -1
  42. package/esm2020/lib/message-list/message-list.component.mjs +717 -0
  43. package/esm2020/lib/message-preview.mjs +21 -0
  44. package/esm2020/lib/message-reactions/message-reactions.component.mjs +168 -0
  45. package/esm2020/lib/message-reactions-selector/message-reactions-selector.component.mjs +61 -0
  46. package/{esm2022 → esm2020}/lib/message-reactions.service.mjs +6 -6
  47. package/esm2020/lib/message-text/message-text.component.mjs +143 -0
  48. package/esm2020/lib/message.service.mjs +43 -0
  49. package/{esm2022 → esm2020}/lib/modal/modal.component.mjs +6 -6
  50. package/esm2020/lib/notification/notification.component.mjs +20 -0
  51. package/esm2020/lib/notification-list/notification-list.component.mjs +36 -0
  52. package/{esm2022 → esm2020}/lib/notification.service.mjs +6 -6
  53. package/esm2020/lib/paginated-list/paginated-list.component.mjs +94 -0
  54. package/{esm2022 → esm2020}/lib/parse-date.mjs +1 -1
  55. package/esm2020/lib/read-by.mjs +12 -0
  56. package/esm2020/lib/stream-autocomplete-textarea.module.mjs +33 -0
  57. package/{esm2022 → esm2020}/lib/stream-avatar.module.mjs +5 -5
  58. package/{esm2022 → esm2020}/lib/stream-chat.module.mjs +59 -59
  59. package/{esm2022 → esm2020}/lib/stream-i18n.service.mjs +6 -6
  60. package/esm2020/lib/stream-textarea.module.mjs +31 -0
  61. package/{esm2022 → esm2020}/lib/theme.service.mjs +6 -6
  62. package/esm2020/lib/thread/thread.component.mjs +51 -0
  63. package/{esm2022 → esm2020}/lib/transliteration.service.mjs +5 -5
  64. package/esm2020/lib/types-custom.mjs +2 -0
  65. package/esm2020/lib/types.mjs +2 -0
  66. package/esm2020/lib/user-list/user-list.component.mjs +47 -0
  67. package/esm2020/lib/virtualized-list.service.mjs +271 -0
  68. package/{esm2022 → esm2020}/lib/virtualized-message-list.service.mjs +1 -1
  69. package/{esm2022 → esm2020}/lib/voice-recorder/amplitude-recorder.service.mjs +5 -5
  70. package/{esm2022 → esm2020}/lib/voice-recorder/audio-recorder.service.mjs +5 -5
  71. package/{esm2022 → esm2020}/lib/voice-recorder/media-recorder.mjs +1 -1
  72. package/esm2020/lib/voice-recorder/mp3-transcoder.mjs +61 -0
  73. package/esm2020/lib/voice-recorder/transcoder.service.mjs +121 -0
  74. package/esm2020/lib/voice-recorder/voice-recorder-wavebar/voice-recorder-wavebar.component.mjs +35 -0
  75. package/esm2020/lib/voice-recorder/voice-recorder.component.mjs +80 -0
  76. package/{esm2022 → esm2020}/lib/voice-recorder/voice-recorder.module.mjs +9 -9
  77. package/esm2020/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.mjs +112 -0
  78. package/esm2020/lib/voice-recording/voice-recording.component.mjs +91 -0
  79. package/{esm2022 → esm2020}/lib/voice-recording/voice-recording.module.mjs +5 -5
  80. package/{esm2022 → esm2020}/lib/wave-form-sampler.mjs +1 -1
  81. package/esm2020/public-api.mjs +86 -0
  82. package/esm2020/stream-chat.mjs +2 -0
  83. package/fesm2015/stream-chat-angular.mjs +9171 -0
  84. package/fesm2015/stream-chat-angular.mjs.map +1 -0
  85. package/{fesm2022 → fesm2020}/stream-chat-angular.mjs +1251 -961
  86. package/fesm2020/stream-chat-angular.mjs.map +1 -0
  87. package/lib/attachment-configuration.service.d.ts +12 -12
  88. package/lib/attachment-list/attachment-list.component.d.ts +15 -10
  89. package/lib/attachment-preview-list/attachment-preview-list.component.d.ts +1 -1
  90. package/lib/attachment.service.d.ts +12 -10
  91. package/lib/avatar/avatar.component.d.ts +7 -7
  92. package/lib/avatar-placeholder/avatar-placeholder.component.d.ts +5 -5
  93. package/lib/channel/channel.component.d.ts +1 -1
  94. package/lib/channel-header/channel-header.component.d.ts +2 -2
  95. package/lib/channel-list/channel-list.component.d.ts +3 -4
  96. package/lib/channel-preview/channel-preview.component.d.ts +6 -6
  97. package/lib/channel-query.d.ts +26 -0
  98. package/lib/channel.service.d.ts +146 -154
  99. package/lib/chat-client.service.d.ts +17 -15
  100. package/lib/custom-templates.service.d.ts +50 -50
  101. package/lib/get-channel-display-text.d.ts +1 -2
  102. package/lib/get-message-translation.d.ts +3 -3
  103. package/lib/icon/icon-placeholder/icon-placeholder.component.d.ts +2 -2
  104. package/lib/icon/icon.component.d.ts +2 -2
  105. package/lib/icon/loading-indicator-placeholder/loading-indicator-placeholder.component.d.ts +1 -1
  106. package/lib/message/message.component.d.ts +6 -6
  107. package/lib/message-actions-box/message-actions-box.component.d.ts +5 -4
  108. package/lib/message-actions.service.d.ts +10 -10
  109. package/lib/message-bounce-prompt/message-bounce-prompt.component.d.ts +1 -1
  110. package/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.d.ts +5 -5
  111. package/lib/message-input/emoji-input.service.d.ts +2 -2
  112. package/lib/message-input/message-input-config.service.d.ts +3 -3
  113. package/lib/message-input/message-input.component.d.ts +10 -33
  114. package/lib/message-input/textarea/textarea.component.d.ts +3 -3
  115. package/lib/message-input/textarea.directive.d.ts +1 -1
  116. package/lib/message-list/group-styles.d.ts +1 -1
  117. package/lib/message-list/message-list.component.d.ts +3 -2
  118. package/lib/message-preview.d.ts +2 -3
  119. package/lib/message-reactions/message-reactions.component.d.ts +9 -8
  120. package/lib/message-reactions-selector/message-reactions-selector.component.d.ts +6 -5
  121. package/lib/message-reactions.service.d.ts +4 -4
  122. package/lib/message-text/message-text.component.d.ts +5 -5
  123. package/lib/message.service.d.ts +6 -7
  124. package/lib/modal/modal.component.d.ts +1 -1
  125. package/lib/notification/notification.component.d.ts +2 -2
  126. package/lib/notification-list/notification-list.component.d.ts +1 -0
  127. package/lib/notification.service.d.ts +1 -1
  128. package/lib/paginated-list/paginated-list.component.d.ts +2 -5
  129. package/lib/read-by.d.ts +1 -2
  130. package/lib/stream-i18n.service.d.ts +1 -1
  131. package/lib/theme.service.d.ts +1 -1
  132. package/lib/thread/thread.component.d.ts +3 -3
  133. package/lib/types-custom.d.ts +15 -0
  134. package/lib/types.d.ts +116 -155
  135. package/lib/user-list/user-list.component.d.ts +2 -3
  136. package/lib/virtualized-message-list.service.d.ts +1 -1
  137. package/lib/voice-recorder/amplitude-recorder.service.d.ts +2 -2
  138. package/lib/voice-recorder/media-recorder.d.ts +2 -2
  139. package/lib/voice-recorder/transcoder.service.d.ts +4 -4
  140. package/lib/voice-recorder/voice-recorder-wavebar/voice-recorder-wavebar.component.d.ts +1 -0
  141. package/lib/voice-recorder/voice-recorder.component.d.ts +2 -2
  142. package/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.d.ts +3 -3
  143. package/lib/voice-recording/voice-recording.component.d.ts +2 -3
  144. package/package.json +21 -15
  145. package/public-api.d.ts +3 -0
  146. package/src/assets/i18n/en.ts +0 -1
  147. package/src/assets/version.ts +1 -1
  148. package/esm2022/lib/attachment-configuration.service.mjs +0 -185
  149. package/esm2022/lib/attachment-list/attachment-list.component.mjs +0 -212
  150. package/esm2022/lib/attachment-preview-list/attachment-preview-list.component.mjs +0 -55
  151. package/esm2022/lib/attachment.service.mjs +0 -479
  152. package/esm2022/lib/avatar/avatar.component.mjs +0 -157
  153. package/esm2022/lib/avatar-placeholder/avatar-placeholder.component.mjs +0 -66
  154. package/esm2022/lib/channel/channel.component.mjs +0 -45
  155. package/esm2022/lib/channel-header/channel-header.component.mjs +0 -72
  156. package/esm2022/lib/channel-list/channel-list.component.mjs +0 -50
  157. package/esm2022/lib/channel-preview/channel-preview.component.mjs +0 -150
  158. package/esm2022/lib/channel.service.mjs +0 -1393
  159. package/esm2022/lib/chat-client.service.mjs +0 -227
  160. package/esm2022/lib/custom-templates.service.mjs +0 -244
  161. package/esm2022/lib/file-utils.mjs +0 -35
  162. package/esm2022/lib/get-message-translation.mjs +0 -12
  163. package/esm2022/lib/icon/icon-placeholder/icon-placeholder.component.mjs +0 -28
  164. package/esm2022/lib/icon/loading-indicator-placeholder/loading-indicator-placeholder.component.mjs +0 -20
  165. package/esm2022/lib/message/message.component.mjs +0 -486
  166. package/esm2022/lib/message-actions-box/message-actions-box.component.mjs +0 -120
  167. package/esm2022/lib/message-actions.service.mjs +0 -187
  168. package/esm2022/lib/message-bounce-prompt/message-bounce-prompt.component.mjs +0 -71
  169. package/esm2022/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.mjs +0 -333
  170. package/esm2022/lib/message-input/message-input-config.service.mjs +0 -50
  171. package/esm2022/lib/message-input/message-input.component.mjs +0 -507
  172. package/esm2022/lib/message-list/message-list.component.mjs +0 -715
  173. package/esm2022/lib/message-preview.mjs +0 -21
  174. package/esm2022/lib/message-reactions/message-reactions.component.mjs +0 -165
  175. package/esm2022/lib/message-reactions-selector/message-reactions-selector.component.mjs +0 -57
  176. package/esm2022/lib/message-text/message-text.component.mjs +0 -143
  177. package/esm2022/lib/message.service.mjs +0 -43
  178. package/esm2022/lib/notification/notification.component.mjs +0 -20
  179. package/esm2022/lib/notification-list/notification-list.component.mjs +0 -33
  180. package/esm2022/lib/paginated-list/paginated-list.component.mjs +0 -94
  181. package/esm2022/lib/read-by.mjs +0 -12
  182. package/esm2022/lib/stream-autocomplete-textarea.module.mjs +0 -33
  183. package/esm2022/lib/stream-textarea.module.mjs +0 -31
  184. package/esm2022/lib/thread/thread.component.mjs +0 -51
  185. package/esm2022/lib/types.mjs +0 -2
  186. package/esm2022/lib/user-list/user-list.component.mjs +0 -47
  187. package/esm2022/lib/virtualized-list.service.mjs +0 -273
  188. package/esm2022/lib/voice-recorder/mp3-transcoder.mjs +0 -61
  189. package/esm2022/lib/voice-recorder/transcoder.service.mjs +0 -121
  190. package/esm2022/lib/voice-recorder/voice-recorder-wavebar/voice-recorder-wavebar.component.mjs +0 -32
  191. package/esm2022/lib/voice-recorder/voice-recorder.component.mjs +0 -80
  192. package/esm2022/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.mjs +0 -112
  193. package/esm2022/lib/voice-recording/voice-recording.component.mjs +0 -91
  194. package/esm2022/public-api.mjs +0 -82
  195. package/fesm2022/stream-chat-angular.mjs.map +0 -1
  196. /package/{esm2022 → esm2020}/lib/format-duration.mjs +0 -0
  197. /package/{esm2022 → esm2020}/lib/injection-tokens.mjs +0 -0
  198. /package/{esm2022 → esm2020}/lib/is-image-attachment.mjs +0 -0
  199. /package/{esm2022 → esm2020}/lib/is-on-separate-date.mjs +0 -0
  200. /package/{esm2022 → esm2020}/lib/is-safari.mjs +0 -0
  201. /package/{esm2022 → esm2020}/lib/message-input/textarea.interface.mjs +0 -0
  202. /package/{esm2022 → esm2020}/stream-chat-angular.mjs +0 -0
@@ -0,0 +1,481 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { createUriFromBlob, isImageFile } from './file-utils';
3
+ import { BehaviorSubject, combineLatest, map, shareReplay, take, } from 'rxjs';
4
+ import { isImageAttachment } from './is-image-attachment';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "./channel.service";
7
+ import * as i2 from "./notification.service";
8
+ import * as i3 from "./chat-client.service";
9
+ import * as i4 from "./message.service";
10
+ /**
11
+ * The `AttachmentService` manages the uploads of a message input.
12
+ *
13
+ * You can read more about [uploads](/chat/docs/javascript/file_uploads/) in the Stream API documentation. You can use Stream's API or the dashboard to customize the [file](/chat/docs/javascript/app_setting_overview/#file-uploads) and [image upload](/chat/docs/javascript/app_setting_overview/#image-uploads) configuration.
14
+ */
15
+ export class AttachmentService {
16
+ constructor(channelService, notificationService, chatClientService, messageService) {
17
+ this.channelService = channelService;
18
+ this.notificationService = notificationService;
19
+ this.chatClientService = chatClientService;
20
+ this.messageService = messageService;
21
+ /**
22
+ * Emits the number of uploads in progress.
23
+ *
24
+ * You can increment and decrement this counter if you're using custom attachments and want to disable message sending until all attachments are uploaded.
25
+ *
26
+ * The SDK will handle updating this counter for built-in attachments, but for custom attachments you should take care of this.
27
+ */
28
+ this.attachmentUploadInProgressCounter$ = new BehaviorSubject(0);
29
+ /**
30
+ * You can get and set the list if uploaded custom attachments
31
+ *
32
+ * By default the SDK components won't display these, but you can provide your own `customAttachmentPreviewListTemplate$` and `customAttachmentListTemplate$` for the [`CustomTemplatesService`](/chat/docs/sdk/angular/v6-rc/services/CustomTemplatesService/).
33
+ */
34
+ this.customAttachments$ = new BehaviorSubject([]);
35
+ /**
36
+ * The maximum number of attachments allowed for a message.
37
+ *
38
+ * The maximum is 30, you can set it to lower, but not higher.
39
+ */
40
+ this.maxNumberOfAttachments = 30;
41
+ this.attachmentUploadsSubject = new BehaviorSubject([]);
42
+ this.attachmentUploads$ = this.attachmentUploadsSubject.asObservable();
43
+ this.chatClientService.appSettings$.subscribe((appSettings) => (this.appSettings = appSettings));
44
+ this.attachmentsCounter$ = combineLatest([
45
+ this.attachmentUploads$,
46
+ this.customAttachments$,
47
+ ]).pipe(map(([attchmentUploads, customAttachments]) => {
48
+ return (attchmentUploads.filter((u) => u.state === 'success').length +
49
+ customAttachments.length);
50
+ }), shareReplay(1));
51
+ this.attachmentsCounter$.subscribe((count) => {
52
+ if (count > this.maxNumberOfAttachments) {
53
+ this.attachmentLimitNotificationHide =
54
+ this.notificationService.addPermanentNotification('streamChat.You currently have {{count}} attachments, the maximum is {{max}}', 'error', { count, max: this.maxNumberOfAttachments });
55
+ }
56
+ else {
57
+ this.attachmentLimitNotificationHide?.();
58
+ }
59
+ });
60
+ }
61
+ /**
62
+ * Resets the attachments uploads (for example after the message with the attachments sent successfully)
63
+ */
64
+ resetAttachmentUploads() {
65
+ this.attachmentUploadsSubject.next([]);
66
+ this.customAttachments$.next([]);
67
+ this.attachmentLimitNotificationHide?.();
68
+ }
69
+ /**
70
+ * Upload a voice recording
71
+ * @param audioRecording
72
+ * @returns A promise with true or false. If false is returned the upload was canceled because of a client side error. The error is emitted via the `NotificationService`.
73
+ */
74
+ async uploadVoiceRecording(audioRecording) {
75
+ if (!this.isWithinLimit(1)) {
76
+ return false;
77
+ }
78
+ if (!(await this.areAttachmentsHaveValidExtension([audioRecording.recording]))) {
79
+ return false;
80
+ }
81
+ if (!(await this.areAttachmentsHaveValidSize([audioRecording.recording]))) {
82
+ return false;
83
+ }
84
+ const upload = {
85
+ file: audioRecording.recording,
86
+ previewUri: audioRecording.asset_url,
87
+ extraData: {
88
+ duration: audioRecording.duration,
89
+ waveform_data: audioRecording.waveform_data,
90
+ },
91
+ state: 'uploading',
92
+ type: 'voiceRecording',
93
+ };
94
+ this.attachmentUploadsSubject.next([
95
+ ...this.attachmentUploadsSubject.getValue(),
96
+ upload,
97
+ ]);
98
+ await this.uploadAttachments([upload]);
99
+ return true;
100
+ }
101
+ /**
102
+ * Uploads the selected files, and creates preview for image files. The result is propagated throught the `attachmentUploads$` stream.
103
+ * @param fileList The files selected by the user, if you have Blobs instead of Files, you can convert them with this method: https://developer.mozilla.org/en-US/docs/Web/API/File/File
104
+ * @returns A promise with true or false. If false is returned the upload was canceled because of a client side error. The error is emitted via the `NotificationService`.
105
+ */
106
+ async filesSelected(fileList) {
107
+ if (!fileList) {
108
+ return;
109
+ }
110
+ const files = Array.from(fileList);
111
+ if (!this.isWithinLimit(files.length)) {
112
+ return false;
113
+ }
114
+ if (!(await this.areAttachmentsHaveValidExtension(files))) {
115
+ return false;
116
+ }
117
+ if (!(await this.areAttachmentsHaveValidSize(files))) {
118
+ return false;
119
+ }
120
+ const imageFiles = [];
121
+ const dataFiles = [];
122
+ const videoFiles = [];
123
+ files.forEach((file) => {
124
+ if (isImageFile(file)) {
125
+ imageFiles.push(file);
126
+ }
127
+ else if (file.type.startsWith('video/')) {
128
+ videoFiles.push(file);
129
+ }
130
+ else {
131
+ dataFiles.push(file);
132
+ }
133
+ });
134
+ imageFiles.forEach((f) => void this.createPreview(f));
135
+ const newUploads = [
136
+ ...imageFiles.map((file) => ({
137
+ file,
138
+ state: 'uploading',
139
+ type: 'image',
140
+ })),
141
+ ...videoFiles.map((file) => ({
142
+ file,
143
+ state: 'uploading',
144
+ type: 'video',
145
+ })),
146
+ ...dataFiles.map((file) => ({
147
+ file,
148
+ state: 'uploading',
149
+ type: 'file',
150
+ })),
151
+ ];
152
+ this.attachmentUploadsSubject.next([
153
+ ...this.attachmentUploadsSubject.getValue(),
154
+ ...newUploads,
155
+ ]);
156
+ await this.uploadAttachments(newUploads);
157
+ return true;
158
+ }
159
+ /**
160
+ * You can add custom `image`, `video` and `file` attachments using this method.
161
+ *
162
+ * Note: If you just want to use your own CDN for file uploads, you don't necessary need this method, you can just specify you own upload function in the [`ChannelService`](/chat/docs/sdk/angular/v6-rc/services/ChannelService/)
163
+ * @param attachment
164
+ *
165
+ * Will set `isCustomAttachment` to `true` on the attachment. This is a non-standard field, other SDKs will ignore this property.
166
+ */
167
+ addAttachment(attachment) {
168
+ attachment.isCustomAttachment = true;
169
+ this.createFromAttachments([attachment]);
170
+ }
171
+ /**
172
+ * Retries to upload an attachment.
173
+ * @param file
174
+ * @returns A promise with the result
175
+ */
176
+ async retryAttachmentUpload(file) {
177
+ const attachmentUploads = this.attachmentUploadsSubject.getValue();
178
+ const upload = attachmentUploads.find((u) => u.file === file);
179
+ if (!upload) {
180
+ return;
181
+ }
182
+ upload.state = 'uploading';
183
+ this.attachmentUploadsSubject.next([...attachmentUploads]);
184
+ await this.uploadAttachments([upload]);
185
+ }
186
+ /**
187
+ * Deletes an attachment, the attachment can have any state (`error`, `uploading` or `success`).
188
+ * @param upload
189
+ */
190
+ async deleteAttachment(upload) {
191
+ const attachmentUploads = this.attachmentUploadsSubject.getValue();
192
+ let result;
193
+ if (upload.state === 'success' &&
194
+ !upload.fromAttachment?.isCustomAttachment) {
195
+ try {
196
+ await this.channelService.deleteAttachment(upload);
197
+ result = [...attachmentUploads];
198
+ const index = attachmentUploads.indexOf(upload);
199
+ result.splice(index, 1);
200
+ }
201
+ catch (error) {
202
+ result = attachmentUploads;
203
+ this.notificationService.addTemporaryNotification('streamChat.Error deleting attachment');
204
+ }
205
+ }
206
+ else {
207
+ result = [...attachmentUploads];
208
+ const index = attachmentUploads.indexOf(upload);
209
+ result.splice(index, 1);
210
+ }
211
+ this.attachmentUploadsSubject.next([...result]);
212
+ }
213
+ /**
214
+ * Maps the current uploads to a format that can be sent along with the message to the Stream API.
215
+ * @returns the attachments
216
+ */
217
+ mapToAttachments() {
218
+ const attachmentUploads = this.attachmentUploadsSubject.getValue();
219
+ const builtInAttachments = attachmentUploads
220
+ .filter((r) => r.state === 'success')
221
+ .map((r) => {
222
+ let attachment = {
223
+ type: r.type,
224
+ };
225
+ if (r.fromAttachment) {
226
+ return r.fromAttachment;
227
+ }
228
+ else {
229
+ attachment.mime_type = r.file?.type;
230
+ if (r.type === 'image') {
231
+ attachment.fallback = r.file?.name;
232
+ attachment.image_url = r.url;
233
+ }
234
+ else {
235
+ attachment.asset_url = r.url;
236
+ attachment.title = r.file?.name;
237
+ attachment.file_size = r.file?.size;
238
+ attachment.thumb_url = r.thumb_url;
239
+ }
240
+ if (r.extraData) {
241
+ attachment = { ...attachment, ...r.extraData };
242
+ }
243
+ }
244
+ return attachment;
245
+ });
246
+ return [...builtInAttachments, ...this.customAttachments$.value];
247
+ }
248
+ /**
249
+ * Maps attachments received from the Stream API to uploads. This is useful when editing a message.
250
+ * @param attachments Attachemnts received with the message
251
+ */
252
+ createFromAttachments(attachments) {
253
+ const attachmentUploads = [];
254
+ const builtInAttachments = [];
255
+ const customAttachments = [];
256
+ attachments.forEach((attachment) => {
257
+ if (this.messageService.isCustomAttachment(attachment)) {
258
+ customAttachments.push(attachment);
259
+ }
260
+ else {
261
+ builtInAttachments.push(attachment);
262
+ }
263
+ });
264
+ builtInAttachments.forEach((attachment) => {
265
+ if (isImageAttachment(attachment)) {
266
+ attachmentUploads.push({
267
+ url: (attachment.img_url ||
268
+ attachment.thumb_url ||
269
+ attachment.image_url),
270
+ state: 'success',
271
+ type: 'image',
272
+ file: {
273
+ name: attachment.fallback,
274
+ type: attachment.mime_type,
275
+ },
276
+ fromAttachment: attachment,
277
+ });
278
+ }
279
+ else if (attachment.type === 'file' || attachment.type === 'video') {
280
+ attachmentUploads.push({
281
+ url: attachment.asset_url,
282
+ state: 'success',
283
+ file: {
284
+ name: attachment.title,
285
+ size: attachment.file_size,
286
+ type: attachment.mime_type,
287
+ },
288
+ type: attachment.type,
289
+ thumb_url: attachment.thumb_url,
290
+ fromAttachment: attachment,
291
+ });
292
+ }
293
+ else if (attachment.type === 'voiceRecording') {
294
+ attachmentUploads.push({
295
+ url: attachment.asset_url,
296
+ state: 'success',
297
+ file: {
298
+ name: attachment.title,
299
+ size: attachment.file_size,
300
+ type: attachment.mime_type,
301
+ },
302
+ type: 'voiceRecording',
303
+ extraData: {
304
+ duration: attachment.duration,
305
+ waveform_data: attachment.waveform_data,
306
+ },
307
+ });
308
+ }
309
+ });
310
+ if (attachmentUploads.length > 0) {
311
+ this.attachmentUploadsSubject.next([
312
+ ...this.attachmentUploadsSubject.getValue(),
313
+ ...attachmentUploads,
314
+ ]);
315
+ }
316
+ if (customAttachments.length > 0) {
317
+ this.customAttachments$.next(customAttachments);
318
+ }
319
+ }
320
+ async createPreview(file) {
321
+ try {
322
+ const uri = await createUriFromBlob(file);
323
+ const attachmentUploads = this.attachmentUploadsSubject.getValue();
324
+ const upload = attachmentUploads.find((upload) => upload.file === file);
325
+ if (!upload) {
326
+ return;
327
+ }
328
+ upload.previewUri = uri;
329
+ this.attachmentUploadsSubject.next([...attachmentUploads]);
330
+ }
331
+ catch (e) {
332
+ this.chatClientService?.chatClient?.logger('error', e instanceof Error ? e.message : `Can't create image preview`, { error: e, tag: ['AttachmentService'] });
333
+ }
334
+ }
335
+ async uploadAttachments(uploads) {
336
+ this.attachmentUploadInProgressCounter$.next(this.attachmentUploadInProgressCounter$.value + 1);
337
+ const result = await this.channelService.uploadAttachments(uploads);
338
+ const attachmentUploads = this.attachmentUploadsSubject.getValue();
339
+ result.forEach((r) => {
340
+ const upload = attachmentUploads.find((upload) => upload.file === r.file);
341
+ if (!upload) {
342
+ if (r.url) {
343
+ void this.channelService.deleteAttachment(r);
344
+ }
345
+ return;
346
+ }
347
+ upload.state = r.state;
348
+ upload.url = r.url;
349
+ upload.thumb_url = r.thumb_url;
350
+ if (upload.state === 'error') {
351
+ upload.errorReason = r.errorReason;
352
+ upload.errorExtraInfo = r.errorExtraInfo;
353
+ let errorKey;
354
+ const translateParams = { name: upload.file.name };
355
+ switch (upload.errorReason) {
356
+ case 'file-extension':
357
+ errorKey =
358
+ 'streamChat.Error uploading file, extension not supported';
359
+ translateParams.ext = upload.errorExtraInfo?.[0]?.param;
360
+ break;
361
+ case 'file-size':
362
+ errorKey =
363
+ 'streamChat.Error uploading file, maximum file size exceeded';
364
+ translateParams.limit = upload.errorExtraInfo?.[0]?.param;
365
+ break;
366
+ default:
367
+ errorKey = 'streamChat.Error uploading file';
368
+ }
369
+ this.notificationService.addTemporaryNotification(errorKey, 'error', undefined, translateParams);
370
+ }
371
+ });
372
+ this.attachmentUploadInProgressCounter$.next(this.attachmentUploadInProgressCounter$.value - 1);
373
+ this.attachmentUploadsSubject.next([...attachmentUploads]);
374
+ }
375
+ async areAttachmentsHaveValidExtension(files) {
376
+ if (!this.appSettings) {
377
+ try {
378
+ await this.chatClientService.getAppSettings();
379
+ }
380
+ catch (error) {
381
+ return true;
382
+ }
383
+ }
384
+ let isValid = true;
385
+ files.forEach((f) => {
386
+ let hasBlockedExtension;
387
+ let hasBlockedMimeType;
388
+ let hasNotAllowedExtension;
389
+ let hasNotAllowedMimeType;
390
+ if (isImageFile(f)) {
391
+ hasBlockedExtension =
392
+ !!this.appSettings?.image_upload_config?.blocked_file_extensions?.find((ext) => f.name.endsWith(ext));
393
+ hasBlockedMimeType =
394
+ !!this.appSettings?.image_upload_config?.blocked_mime_types?.find((type) => f.type === type);
395
+ hasNotAllowedExtension =
396
+ !!this.appSettings?.image_upload_config?.allowed_file_extensions
397
+ ?.length &&
398
+ !this.appSettings?.image_upload_config?.allowed_file_extensions?.find((ext) => f.name.endsWith(ext));
399
+ hasNotAllowedMimeType =
400
+ !!this.appSettings?.image_upload_config?.allowed_mime_types?.length &&
401
+ !this.appSettings?.image_upload_config?.allowed_mime_types?.find((type) => f.type === type);
402
+ }
403
+ else {
404
+ hasBlockedExtension =
405
+ !!this.appSettings?.file_upload_config?.blocked_file_extensions?.find((ext) => f.name.endsWith(ext));
406
+ hasBlockedMimeType =
407
+ !!this.appSettings?.file_upload_config?.blocked_mime_types?.find((type) => f.type === type);
408
+ hasNotAllowedExtension =
409
+ !!this.appSettings?.file_upload_config?.allowed_file_extensions
410
+ ?.length &&
411
+ !this.appSettings?.file_upload_config?.allowed_file_extensions?.find((ext) => f.name.endsWith(ext));
412
+ hasNotAllowedMimeType =
413
+ !!this.appSettings?.file_upload_config?.allowed_mime_types?.length &&
414
+ !this.appSettings?.file_upload_config?.allowed_mime_types?.find((type) => f.type === type);
415
+ }
416
+ if (hasBlockedExtension ||
417
+ hasBlockedMimeType ||
418
+ hasNotAllowedExtension ||
419
+ hasNotAllowedMimeType) {
420
+ this.notificationService.addTemporaryNotification('streamChat.Error uploading file, extension not supported', undefined, undefined, { name: f.name, ext: f.type });
421
+ isValid = false;
422
+ }
423
+ });
424
+ return isValid;
425
+ }
426
+ async areAttachmentsHaveValidSize(files) {
427
+ if (!this.appSettings) {
428
+ try {
429
+ await this.chatClientService.getAppSettings();
430
+ }
431
+ catch (error) {
432
+ return true;
433
+ }
434
+ }
435
+ const imageSizeLimitInBytes = this.appSettings?.image_upload_config?.size_limit || 0;
436
+ const imageSizeLimiString = `${imageSizeLimitInBytes / (1024 * 1024)}MB`;
437
+ const fileSizeLimitInBytes = this.appSettings?.file_upload_config?.size_limit || 0;
438
+ const fileSizeLimitInString = `${fileSizeLimitInBytes / (1024 * 1024)}MB`;
439
+ let isValid = true;
440
+ files.forEach((f) => {
441
+ let isOverSized = false;
442
+ let limit = '';
443
+ if (isImageFile(f) && imageSizeLimitInBytes > 0) {
444
+ isOverSized = f.size > imageSizeLimitInBytes;
445
+ limit = imageSizeLimiString;
446
+ }
447
+ else if (fileSizeLimitInBytes > 0) {
448
+ isOverSized = f.size > fileSizeLimitInBytes;
449
+ limit = fileSizeLimitInString;
450
+ }
451
+ if (isOverSized) {
452
+ this.notificationService.addTemporaryNotification('streamChat.Error uploading file, maximum file size exceeded', undefined, undefined, { name: f.name, limit: limit });
453
+ isValid = false;
454
+ }
455
+ });
456
+ return isValid;
457
+ }
458
+ isWithinLimit(numberOfNewAttachments) {
459
+ let currentNumberOfAttachments = 0;
460
+ this.attachmentsCounter$
461
+ .pipe(take(1))
462
+ .subscribe((counter) => (currentNumberOfAttachments = counter));
463
+ if (currentNumberOfAttachments + numberOfNewAttachments >
464
+ this.maxNumberOfAttachments) {
465
+ this.notificationService.addTemporaryNotification(`streamChat.You can't uplod more than {{max}} attachments`, 'error', undefined, { max: this.maxNumberOfAttachments });
466
+ return false;
467
+ }
468
+ else {
469
+ return true;
470
+ }
471
+ }
472
+ }
473
+ AttachmentService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: AttachmentService, deps: [{ token: i1.ChannelService }, { token: i2.NotificationService }, { token: i3.ChatClientService }, { token: i4.MessageService }], target: i0.ɵɵFactoryTarget.Injectable });
474
+ AttachmentService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: AttachmentService, providedIn: 'root' });
475
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: AttachmentService, decorators: [{
476
+ type: Injectable,
477
+ args: [{
478
+ providedIn: 'root',
479
+ }]
480
+ }], ctorParameters: function () { return [{ type: i1.ChannelService }, { type: i2.NotificationService }, { type: i3.ChatClientService }, { type: i4.MessageService }]; } });
481
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0YWNobWVudC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvc3RyZWFtLWNoYXQtYW5ndWxhci9zcmMvbGliL2F0dGFjaG1lbnQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxXQUFXLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDOUQsT0FBTyxFQUNMLGVBQWUsRUFDZixhQUFhLEVBQ2IsR0FBRyxFQUVILFdBQVcsRUFDWCxJQUFJLEdBQ0wsTUFBTSxNQUFNLENBQUM7QUFHZCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQzs7Ozs7O0FBTTFEOzs7O0dBSUc7QUFJSCxNQUFNLE9BQU8saUJBQWlCO0lBbUM1QixZQUNVLGNBQThCLEVBQzlCLG1CQUF3QyxFQUN4QyxpQkFBb0MsRUFDcEMsY0FBOEI7UUFIOUIsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLHdCQUFtQixHQUFuQixtQkFBbUIsQ0FBcUI7UUFDeEMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQUNwQyxtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUF0Q3hDOzs7Ozs7V0FNRztRQUNILHVDQUFrQyxHQUFHLElBQUksZUFBZSxDQUFTLENBQUMsQ0FBQyxDQUFDO1FBS3BFOzs7O1dBSUc7UUFDSCx1QkFBa0IsR0FBRyxJQUFJLGVBQWUsQ0FBZSxFQUFFLENBQUMsQ0FBQztRQUszRDs7OztXQUlHO1FBQ0gsMkJBQXNCLEdBQUcsRUFBRSxDQUFDO1FBQ3BCLDZCQUF3QixHQUFHLElBQUksZUFBZSxDQUNwRCxFQUFFLENBQ0gsQ0FBQztRQVVBLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDdkUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFlBQVksQ0FBQyxTQUFTLENBQzNDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDLENBQ2xELENBQUM7UUFDRixJQUFJLENBQUMsbUJBQW1CLEdBQUcsYUFBYSxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxrQkFBa0I7WUFDdkIsSUFBSSxDQUFDLGtCQUFrQjtTQUN4QixDQUFDLENBQUMsSUFBSSxDQUNMLEdBQUcsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLEVBQUUsaUJBQWlCLENBQUMsRUFBRSxFQUFFO1lBQzVDLE9BQU8sQ0FDTCxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUMsTUFBTTtnQkFDNUQsaUJBQWlCLENBQUMsTUFBTSxDQUN6QixDQUFDO1FBQ0osQ0FBQyxDQUFDLEVBQ0YsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUNmLENBQUM7UUFDRixJQUFJLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDM0MsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixFQUFFO2dCQUN2QyxJQUFJLENBQUMsK0JBQStCO29CQUNsQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsd0JBQXdCLENBQy9DLDZFQUE2RSxFQUM3RSxPQUFPLEVBQ1AsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUM1QyxDQUFDO2FBQ0w7aUJBQU07Z0JBQ0wsSUFBSSxDQUFDLCtCQUErQixFQUFFLEVBQUUsQ0FBQzthQUMxQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsc0JBQXNCO1FBQ3BCLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsK0JBQStCLEVBQUUsRUFBRSxDQUFDO0lBQzNDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLG9CQUFvQixDQUFDLGNBQThCO1FBQ3ZELElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFFO1lBQzFCLE9BQU8sS0FBSyxDQUFDO1NBQ2Q7UUFDRCxJQUNFLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQzFFO1lBQ0EsT0FBTyxLQUFLLENBQUM7U0FDZDtRQUNELElBQUksQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLDJCQUEyQixDQUFDLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUN6RSxPQUFPLEtBQUssQ0FBQztTQUNkO1FBRUQsTUFBTSxNQUFNLEdBQUc7WUFDYixJQUFJLEVBQUUsY0FBYyxDQUFDLFNBQVM7WUFDOUIsVUFBVSxFQUFFLGNBQWMsQ0FBQyxTQUFTO1lBQ3BDLFNBQVMsRUFBRTtnQkFDVCxRQUFRLEVBQUUsY0FBYyxDQUFDLFFBQVE7Z0JBQ2pDLGFBQWEsRUFBRSxjQUFjLENBQUMsYUFBYTthQUM1QztZQUNELEtBQUssRUFBRSxXQUFvQjtZQUMzQixJQUFJLEVBQUUsZ0JBQXlCO1NBQ2hDLENBQUM7UUFDRixJQUFJLENBQUMsd0JBQXdCLENBQUMsSUFBSSxDQUFDO1lBQ2pDLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFFBQVEsRUFBRTtZQUMzQyxNQUFNO1NBQ1AsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQWtDO1FBQ3BELElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDYixPQUFPO1NBQ1I7UUFFRCxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRW5DLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUNyQyxPQUFPLEtBQUssQ0FBQztTQUNkO1FBRUQsSUFBSSxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsZ0NBQWdDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUN6RCxPQUFPLEtBQUssQ0FBQztTQUNkO1FBQ0QsSUFBSSxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsMkJBQTJCLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUNwRCxPQUFPLEtBQUssQ0FBQztTQUNkO1FBQ0QsTUFBTSxVQUFVLEdBQVcsRUFBRSxDQUFDO1FBQzlCLE1BQU0sU0FBUyxHQUFXLEVBQUUsQ0FBQztRQUM3QixNQUFNLFVBQVUsR0FBVyxFQUFFLENBQUM7UUFFOUIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQ3JCLElBQUksV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFO2dCQUNyQixVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2FBQ3ZCO2lCQUFNLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUU7Z0JBQ3pDLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDdkI7aUJBQU07Z0JBQ0wsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQzthQUN0QjtRQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0gsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdEQsTUFBTSxVQUFVLEdBQUc7WUFDakIsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUMzQixJQUFJO2dCQUNKLEtBQUssRUFBRSxXQUFvQjtnQkFDM0IsSUFBSSxFQUFFLE9BQWdCO2FBQ3ZCLENBQUMsQ0FBQztZQUNILEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDM0IsSUFBSTtnQkFDSixLQUFLLEVBQUUsV0FBb0I7Z0JBQzNCLElBQUksRUFBRSxPQUFnQjthQUN2QixDQUFDLENBQUM7WUFDSCxHQUFHLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQzFCLElBQUk7Z0JBQ0osS0FBSyxFQUFFLFdBQW9CO2dCQUMzQixJQUFJLEVBQUUsTUFBZTthQUN0QixDQUFDLENBQUM7U0FDSixDQUFDO1FBQ0YsSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQztZQUNqQyxHQUFHLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLEVBQUU7WUFDM0MsR0FBRyxVQUFVO1NBQ2QsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDekMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILGFBQWEsQ0FBQyxVQUFzQjtRQUNsQyxVQUFVLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMscUJBQXFCLENBQUMsSUFBVTtRQUNwQyxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNuRSxNQUFNLE1BQU0sR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUM7UUFDOUQsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNYLE9BQU87U0FDUjtRQUNELE1BQU0sQ0FBQyxLQUFLLEdBQUcsV0FBVyxDQUFDO1FBQzNCLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLGlCQUFpQixDQUFDLENBQUMsQ0FBQztRQUMzRCxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxNQUF3QjtRQUM3QyxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNuRSxJQUFJLE1BQTJCLENBQUM7UUFDaEMsSUFDRSxNQUFNLENBQUMsS0FBSyxLQUFLLFNBQVM7WUFDMUIsQ0FBQyxNQUFNLENBQUMsY0FBYyxFQUFFLGtCQUFrQixFQUMxQztZQUNBLElBQUk7Z0JBQ0YsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUNuRCxNQUFNLEdBQUcsQ0FBQyxHQUFHLGlCQUFpQixDQUFDLENBQUM7Z0JBQ2hDLE1BQU0sS0FBSyxHQUFHLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDaEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7YUFDekI7WUFBQyxPQUFPLEtBQUssRUFBRTtnQkFDZCxNQUFNLEdBQUcsaUJBQWlCLENBQUM7Z0JBQzNCLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyx3QkFBd0IsQ0FDL0Msc0NBQXNDLENBQ3ZDLENBQUM7YUFDSDtTQUNGO2FBQU07WUFDTCxNQUFNLEdBQUcsQ0FBQyxHQUFHLGlCQUFpQixDQUFDLENBQUM7WUFDaEMsTUFBTSxLQUFLLEdBQUcsaUJBQWlCLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2hELE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQ3pCO1FBQ0QsSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZ0JBQWdCO1FBQ2QsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbkUsTUFBTSxrQkFBa0IsR0FBRyxpQkFBaUI7YUFDekMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQzthQUNwQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtZQUNULElBQUksVUFBVSxHQUFlO2dCQUMzQixJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUk7YUFDYixDQUFDO1lBQ0YsSUFBSSxDQUFDLENBQUMsY0FBYyxFQUFFO2dCQUNwQixPQUFPLENBQUMsQ0FBQyxjQUFjLENBQUM7YUFDekI7aUJBQU07Z0JBQ0wsVUFBVSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQztnQkFDcEMsSUFBSSxDQUFDLENBQUMsSUFBSSxLQUFLLE9BQU8sRUFBRTtvQkFDdEIsVUFBVSxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQztvQkFDbkMsVUFBVSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDO2lCQUM5QjtxQkFBTTtvQkFDTCxVQUFVLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUM7b0JBQzdCLFVBQVUsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUM7b0JBQ2hDLFVBQVUsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUM7b0JBQ3BDLFVBQVUsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLFNBQVMsQ0FBQztpQkFDcEM7Z0JBQ0QsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFO29CQUNmLFVBQVUsR0FBRyxFQUFFLEdBQUcsVUFBVSxFQUFFLEdBQUcsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDO2lCQUNoRDthQUNGO1lBRUQsT0FBTyxVQUFVLENBQUM7UUFDcEIsQ0FBQyxDQUFDLENBQUM7UUFDTCxPQUFPLENBQUMsR0FBRyxrQkFBa0IsRUFBRSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gscUJBQXFCLENBQUMsV0FBeUI7UUFDN0MsTUFBTSxpQkFBaUIsR0FBdUIsRUFBRSxDQUFDO1FBQ2pELE1BQU0sa0JBQWtCLEdBQWlCLEVBQUUsQ0FBQztRQUM1QyxNQUFNLGlCQUFpQixHQUFpQixFQUFFLENBQUM7UUFDM0MsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLFVBQVUsRUFBRSxFQUFFO1lBQ2pDLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsRUFBRTtnQkFDdEQsaUJBQWlCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2FBQ3BDO2lCQUFNO2dCQUNMLGtCQUFrQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQzthQUNyQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0gsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUMsVUFBVSxFQUFFLEVBQUU7WUFDeEMsSUFBSSxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsRUFBRTtnQkFDakMsaUJBQWlCLENBQUMsSUFBSSxDQUFDO29CQUNyQixHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTzt3QkFDdEIsVUFBVSxDQUFDLFNBQVM7d0JBQ3BCLFVBQVUsQ0FBQyxTQUFTLENBQVc7b0JBQ2pDLEtBQUssRUFBRSxTQUFTO29CQUNoQixJQUFJLEVBQUUsT0FBTztvQkFDYixJQUFJLEVBQUU7d0JBQ0osSUFBSSxFQUFFLFVBQVUsQ0FBQyxRQUFRO3dCQUN6QixJQUFJLEVBQUUsVUFBVSxDQUFDLFNBQVM7cUJBQ25CO29CQUNULGNBQWMsRUFBRSxVQUFVO2lCQUMzQixDQUFDLENBQUM7YUFDSjtpQkFBTSxJQUFJLFVBQVUsQ0FBQyxJQUFJLEtBQUssTUFBTSxJQUFJLFVBQVUsQ0FBQyxJQUFJLEtBQUssT0FBTyxFQUFFO2dCQUNwRSxpQkFBaUIsQ0FBQyxJQUFJLENBQUM7b0JBQ3JCLEdBQUcsRUFBRSxVQUFVLENBQUMsU0FBUztvQkFDekIsS0FBSyxFQUFFLFNBQVM7b0JBQ2hCLElBQUksRUFBRTt3QkFDSixJQUFJLEVBQUUsVUFBVSxDQUFDLEtBQUs7d0JBQ3RCLElBQUksRUFBRSxVQUFVLENBQUMsU0FBUzt3QkFDMUIsSUFBSSxFQUFFLFVBQVUsQ0FBQyxTQUFTO3FCQUNuQjtvQkFDVCxJQUFJLEVBQUUsVUFBVSxDQUFDLElBQUk7b0JBQ3JCLFNBQVMsRUFBRSxVQUFVLENBQUMsU0FBUztvQkFDL0IsY0FBYyxFQUFFLFVBQVU7aUJBQzNCLENBQUMsQ0FBQzthQUNKO2lCQUFNLElBQUksVUFBVSxDQUFDLElBQUksS0FBSyxnQkFBZ0IsRUFBRTtnQkFDL0MsaUJBQWlCLENBQUMsSUFBSSxDQUFDO29CQUNyQixHQUFHLEVBQUUsVUFBVSxDQUFDLFNBQVM7b0JBQ3pCLEtBQUssRUFBRSxTQUFTO29CQUNoQixJQUFJLEVBQUU7d0JBQ0osSUFBSSxFQUFFLFVBQVUsQ0FBQyxLQUFLO3dCQUN0QixJQUFJLEVBQUUsVUFBVSxDQUFDLFNBQVM7d0JBQzFCLElBQUksRUFBRSxVQUFVLENBQUMsU0FBUztxQkFDbkI7b0JBQ1QsSUFBSSxFQUFFLGdCQUFnQjtvQkFDdEIsU0FBUyxFQUFFO3dCQUNULFFBQVEsRUFBRSxVQUFVLENBQUMsUUFBUTt3QkFDN0IsYUFBYSxFQUFFLFVBQVUsQ0FBQyxhQUFhO3FCQUN4QztpQkFDRixDQUFDLENBQUM7YUFDSjtRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxpQkFBaUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ2hDLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLENBQUM7Z0JBQ2pDLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFFBQVEsRUFBRTtnQkFDM0MsR0FBRyxpQkFBaUI7YUFDckIsQ0FBQyxDQUFDO1NBQ0o7UUFFRCxJQUFJLGlCQUFpQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDaEMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1NBQ2pEO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBaUI7UUFDM0MsSUFBSTtZQUNGLE1BQU0sR0FBRyxHQUFHLE1BQU0saUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDMUMsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbkUsTUFBTSxNQUFNLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDO1lBQ3hFLElBQUksQ0FBQyxNQUFNLEVBQUU7Z0JBQ1gsT0FBTzthQUNSO1lBQ0QsTUFBTSxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUM7WUFDeEIsSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsaUJBQWlCLENBQUMsQ0FBQyxDQUFDO1NBQzVEO1FBQUMsT0FBTyxDQUFVLEVBQUU7WUFDbkIsSUFBSSxDQUFDLGlCQUFpQixFQUFFLFVBQVUsRUFBRSxNQUFNLENBQ3hDLE9BQU8sRUFDUCxDQUFDLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyw0QkFBNEIsRUFDN0QsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsQ0FDekMsQ0FBQztTQUNIO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxPQUEyQjtRQUN6RCxJQUFJLENBQUMsa0NBQWtDLENBQUMsSUFBSSxDQUMxQyxJQUFJLENBQUMsa0NBQWtDLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FDbEQsQ0FBQztRQUNGLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNwRSxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNuRSxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDbkIsTUFBTSxNQUFNLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMxRSxJQUFJLENBQUMsTUFBTSxFQUFFO2dCQUNYLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRTtvQkFDVCxLQUFLLElBQUksQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUM7aUJBQzlDO2dCQUNELE9BQU87YUFDUjtZQUNELE1BQU0sQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQztZQUN2QixNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFDbkIsTUFBTSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDO1lBQy9CLElBQUksTUFBTSxDQUFDLEtBQUssS0FBSyxPQUFPLEVBQUU7Z0JBQzVCLE1BQU0sQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDLFdBQVcsQ0FBQztnQkFDbkMsTUFBTSxDQUFDLGNBQWMsR0FBRyxDQUFDLENBQUMsY0FBYyxDQUFDO2dCQUN6QyxJQUFJLFFBQVEsQ0FBQztnQkFDYixNQUFNLGVBQWUsR0FDbkIsRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDN0IsUUFBUSxNQUFNLENBQUMsV0FBVyxFQUFFO29CQUMxQixLQUFLLGdCQUFnQjt3QkFDbkIsUUFBUTs0QkFDTiwwREFBMEQsQ0FBQzt3QkFDN0QsZUFBZSxDQUFDLEdBQUcsR0FBRyxNQUFNLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDO3dCQUN4RCxNQUFNO29CQUNSLEtBQUssV0FBVzt3QkFDZCxRQUFROzRCQUNOLDZEQUE2RCxDQUFDO3dCQUNoRSxlQUFlLENBQUMsS0FBSyxHQUFHLE1BQU0sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUM7d0JBQzFELE1BQU07b0JBQ1I7d0JBQ0UsUUFBUSxHQUFHLGlDQUFpQyxDQUFDO2lCQUNoRDtnQkFDRCxJQUFJLENBQUMsbUJBQW1CLENBQUMsd0JBQXdCLENBQy9DLFFBQVEsRUFDUixPQUFPLEVBQ1AsU0FBUyxFQUNULGVBQWUsQ0FDaEIsQ0FBQzthQUNIO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsa0NBQWtDLENBQUMsSUFBSSxDQUMxQyxJQUFJLENBQUMsa0NBQWtDLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FDbEQsQ0FBQztRQUNGLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLGlCQUFpQixDQUFDLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRU8sS0FBSyxDQUFDLGdDQUFnQyxDQUFDLEtBQWE7UUFDMUQsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDckIsSUFBSTtnQkFDRixNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxjQUFjLEVBQUUsQ0FBQzthQUMvQztZQUFDLE9BQU8sS0FBSyxFQUFFO2dCQUNkLE9BQU8sSUFBSSxDQUFDO2FBQ2I7U0FDRjtRQUNELElBQUksT0FBTyxHQUFHLElBQUksQ0FBQztRQUNuQixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDbEIsSUFBSSxtQkFBNEIsQ0FBQztZQUNqQyxJQUFJLGtCQUEyQixDQUFDO1lBQ2hDLElBQUksc0JBQStCLENBQUM7WUFDcEMsSUFBSSxxQkFBOEIsQ0FBQztZQUNuQyxJQUFJLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDbEIsbUJBQW1CO29CQUNqQixDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxtQkFBbUIsRUFBRSx1QkFBdUIsRUFBRSxJQUFJLENBQ3BFLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FDOUIsQ0FBQztnQkFDSixrQkFBa0I7b0JBQ2hCLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLG1CQUFtQixFQUFFLGtCQUFrQixFQUFFLElBQUksQ0FDL0QsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUMxQixDQUFDO2dCQUNKLHNCQUFzQjtvQkFDcEIsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsbUJBQW1CLEVBQUUsdUJBQXVCO3dCQUM5RCxFQUFFLE1BQU07d0JBQ1YsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLG1CQUFtQixFQUFFLHVCQUF1QixFQUFFLElBQUksQ0FDbkUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUM5QixDQUFDO2dCQUNKLHFCQUFxQjtvQkFDbkIsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsbUJBQW1CLEVBQUUsa0JBQWtCLEVBQUUsTUFBTTt3QkFDbkUsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLG1CQUFtQixFQUFFLGtCQUFrQixFQUFFLElBQUksQ0FDOUQsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUMxQixDQUFDO2FBQ0w7aUJBQU07Z0JBQ0wsbUJBQW1CO29CQUNqQixDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxrQkFBa0IsRUFBRSx1QkFBdUIsRUFBRSxJQUFJLENBQ25FLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FDOUIsQ0FBQztnQkFDSixrQkFBa0I7b0JBQ2hCLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLGtCQUFrQixFQUFFLGtCQUFrQixFQUFFLElBQUksQ0FDOUQsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUMxQixDQUFDO2dCQUNKLHNCQUFzQjtvQkFDcEIsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsa0JBQWtCLEVBQUUsdUJBQXVCO3dCQUM3RCxFQUFFLE1BQU07d0JBQ1YsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLGtCQUFrQixFQUFFLHVCQUF1QixFQUFFLElBQUksQ0FDbEUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUM5QixDQUFDO2dCQUNKLHFCQUFxQjtvQkFDbkIsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsTUFBTTt3QkFDbEUsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLGtCQUFrQixFQUFFLGtCQUFrQixFQUFFLElBQUksQ0FDN0QsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUMxQixDQUFDO2FBQ0w7WUFDRCxJQUNFLG1CQUFtQjtnQkFDbkIsa0JBQWtCO2dCQUNsQixzQkFBc0I7Z0JBQ3RCLHFCQUFxQixFQUNyQjtnQkFDQSxJQUFJLENBQUMsbUJBQW1CLENBQUMsd0JBQXdCLENBQy9DLDBEQUEwRCxFQUMxRCxTQUFTLEVBQ1QsU0FBUyxFQUNULEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FDOUIsQ0FBQztnQkFDRixPQUFPLEdBQUcsS0FBSyxDQUFDO2FBQ2pCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRU8sS0FBSyxDQUFDLDJCQUEyQixDQUFDLEtBQWE7UUFDckQsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDckIsSUFBSTtnQkFDRixNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxjQUFjLEVBQUUsQ0FBQzthQUMvQztZQUFDLE9BQU8sS0FBSyxFQUFFO2dCQUNkLE9BQU8sSUFBSSxDQUFDO2FBQ2I7U0FDRjtRQUNELE1BQU0scUJBQXFCLEdBQ3pCLElBQUksQ0FBQyxXQUFXLEVBQUUsbUJBQW1CLEVBQUUsVUFBVSxJQUFJLENBQUMsQ0FBQztRQUN6RCxNQUFNLG1CQUFtQixHQUFHLEdBQUcscUJBQXFCLEdBQUcsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN6RSxNQUFNLG9CQUFvQixHQUN4QixJQUFJLENBQUMsV0FBVyxFQUFFLGtCQUFrQixFQUFFLFVBQVUsSUFBSSxDQUFDLENBQUM7UUFDeEQsTUFBTSxxQkFBcUIsR0FBRyxHQUFHLG9CQUFvQixHQUFHLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDMUUsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ25CLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtZQUNsQixJQUFJLFdBQVcsR0FBRyxLQUFLLENBQUM7WUFDeEIsSUFBSSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ2YsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLElBQUkscUJBQXFCLEdBQUcsQ0FBQyxFQUFFO2dCQUMvQyxXQUFXLEdBQUcsQ0FBQyxDQUFDLElBQUksR0FBRyxxQkFBcUIsQ0FBQztnQkFDN0MsS0FBSyxHQUFHLG1CQUFtQixDQUFDO2FBQzdCO2lCQUFNLElBQUksb0JBQW9CLEdBQUcsQ0FBQyxFQUFFO2dCQUNuQyxXQUFXLEdBQUcsQ0FBQyxDQUFDLElBQUksR0FBRyxvQkFBb0IsQ0FBQztnQkFDNUMsS0FBSyxHQUFHLHFCQUFxQixDQUFDO2FBQy9CO1lBQ0QsSUFBSSxXQUFXLEVBQUU7Z0JBQ2YsSUFBSSxDQUFDLG1CQUFtQixDQUFDLHdCQUF3QixDQUMvQyw2REFBNkQsRUFDN0QsU0FBUyxFQUNULFNBQVMsRUFDVCxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsQ0FDL0IsQ0FBQztnQkFDRixPQUFPLEdBQUcsS0FBSyxDQUFDO2FBQ2pCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRU8sYUFBYSxDQUFDLHNCQUE4QjtRQUNsRCxJQUFJLDBCQUEwQixHQUFXLENBQUMsQ0FBQztRQUMzQyxJQUFJLENBQUMsbUJBQW1CO2FBQ3JCLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDYixTQUFTLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsMEJBQTBCLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUNsRSxJQUNFLDBCQUEwQixHQUFHLHNCQUFzQjtZQUNuRCxJQUFJLENBQUMsc0JBQXNCLEVBQzNCO1lBQ0EsSUFBSSxDQUFDLG1CQUFtQixDQUFDLHdCQUF3QixDQUMvQywwREFBMEQsRUFDMUQsT0FBTyxFQUNQLFNBQVMsRUFDVCxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FDckMsQ0FBQztZQUNGLE9BQU8sS0FBSyxDQUFDO1NBQ2Q7YUFBTTtZQUNMLE9BQU8sSUFBSSxDQUFDO1NBQ2I7SUFDSCxDQUFDOzs4R0EvaEJVLGlCQUFpQjtrSEFBakIsaUJBQWlCLGNBRmhCLE1BQU07MkZBRVAsaUJBQWlCO2tCQUg3QixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGNyZWF0ZVVyaUZyb21CbG9iLCBpc0ltYWdlRmlsZSB9IGZyb20gJy4vZmlsZS11dGlscyc7XG5pbXBvcnQge1xuICBCZWhhdmlvclN1YmplY3QsXG4gIGNvbWJpbmVMYXRlc3QsXG4gIG1hcCxcbiAgT2JzZXJ2YWJsZSxcbiAgc2hhcmVSZXBsYXksXG4gIHRha2UsXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQXBwU2V0dGluZ3MsIEF0dGFjaG1lbnQgfSBmcm9tICdzdHJlYW0tY2hhdCc7XG5pbXBvcnQgeyBDaGFubmVsU2VydmljZSB9IGZyb20gJy4vY2hhbm5lbC5zZXJ2aWNlJztcbmltcG9ydCB7IGlzSW1hZ2VBdHRhY2htZW50IH0gZnJvbSAnLi9pcy1pbWFnZS1hdHRhY2htZW50JztcbmltcG9ydCB7IE5vdGlmaWNhdGlvblNlcnZpY2UgfSBmcm9tICcuL25vdGlmaWNhdGlvbi5zZXJ2aWNlJztcbmltcG9ydCB7IEF0dGFjaG1lbnRVcGxvYWQsIEF1ZGlvUmVjb3JkaW5nIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBDaGF0Q2xpZW50U2VydmljZSB9IGZyb20gJy4vY2hhdC1jbGllbnQuc2VydmljZSc7XG5pbXBvcnQgeyBNZXNzYWdlU2VydmljZSB9IGZyb20gJy4vbWVzc2FnZS5zZXJ2aWNlJztcblxuLyoqXG4gKiBUaGUgYEF0dGFjaG1lbnRTZXJ2aWNlYCBtYW5hZ2VzIHRoZSB1cGxvYWRzIG9mIGEgbWVzc2FnZSBpbnB1dC5cbiAqXG4gKiBZb3UgY2FuIHJlYWQgbW9yZSBhYm91dCBbdXBsb2Fkc10oL2NoYXQvZG9jcy9qYXZhc2NyaXB0L2ZpbGVfdXBsb2Fkcy8pIGluIHRoZSBTdHJlYW0gQVBJIGRvY3VtZW50YXRpb24uIFlvdSBjYW4gdXNlIFN0cmVhbSdzIEFQSSBvciB0aGUgZGFzaGJvYXJkIHRvIGN1c3RvbWl6ZSB0aGUgW2ZpbGVdKC9jaGF0L2RvY3MvamF2YXNjcmlwdC9hcHBfc2V0dGluZ19vdmVydmlldy8jZmlsZS11cGxvYWRzKSBhbmQgW2ltYWdlIHVwbG9hZF0oL2NoYXQvZG9jcy9qYXZhc2NyaXB0L2FwcF9zZXR0aW5nX292ZXJ2aWV3LyNpbWFnZS11cGxvYWRzKSBjb25maWd1cmF0aW9uLlxuICovXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290Jyxcbn0pXG5leHBvcnQgY2xhc3MgQXR0YWNobWVudFNlcnZpY2Uge1xuICAvKipcbiAgICogRW1pdHMgdGhlIG51bWJlciBvZiB1cGxvYWRzIGluIHByb2dyZXNzLlxuICAgKlxuICAgKiBZb3UgY2FuIGluY3JlbWVudCBhbmQgZGVjcmVtZW50IHRoaXMgY291bnRlciBpZiB5b3UncmUgdXNpbmcgY3VzdG9tIGF0dGFjaG1lbnRzIGFuZCB3YW50IHRvIGRpc2FibGUgbWVzc2FnZSBzZW5kaW5nIHVudGlsIGFsbCBhdHRhY2htZW50cyBhcmUgdXBsb2FkZWQuXG4gICAqXG4gICAqIFRoZSBTREsgd2lsbCBoYW5kbGUgdXBkYXRpbmcgdGhpcyBjb3VudGVyIGZvciBidWlsdC1pbiBhdHRhY2htZW50cywgYnV0IGZvciBjdXN0b20gYXR0YWNobWVudHMgeW91IHNob3VsZCB0YWtlIGNhcmUgb2YgdGhpcy5cbiAgICovXG4gIGF0dGFjaG1lbnRVcGxvYWRJblByb2dyZXNzQ291bnRlciQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PG51bWJlcj4oMCk7XG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgc3RhdGUgb2YgdGhlIHVwbG9hZHMgKFtgQXR0YWNobWVudFVwbG9hZFtdYF0oaHR0cHM6Ly9naXRodWIuY29tL0dldFN0cmVhbS9zdHJlYW0tY2hhdC1hbmd1bGFyL2Jsb2IvbWFzdGVyL3Byb2plY3RzL3N0cmVhbS1jaGF0LWFuZ3VsYXIvc3JjL2xpYi90eXBlcy50cykpLCBpdCBhZGRzIGEgc3RhdGUgKGBzdWNjZXNzYCwgYGVycm9yYCBvciBgdXBsb2FkaW5nYCkgdG8gZWFjaCBmaWxlIHRoZSB1c2VyIHNlbGVjdHMgZm9yIHVwbG9hZC4gSXQgaXMgdXNlZCBieSB0aGUgW2BBdHRhY2htZW50UHJldmlld0xpc3RgXSgvY2hhdC9kb2NzL3Nkay9hbmd1bGFyL3Y2LXJjL2NvbXBvbmVudHMvQXR0YWNobWVudFByZXZpZXdMaXN0Q29tcG9uZW50LykgdG8gZGlzcGxheSB0aGUgYXR0YWNobWVudCBwcmV2aWV3cy5cbiAgICovXG4gIGF0dGFjaG1lbnRVcGxvYWRzJDogT2JzZXJ2YWJsZTxBdHRhY2htZW50VXBsb2FkW10+O1xuICAvKipcbiAgICogWW91IGNhbiBnZXQgYW5kIHNldCB0aGUgbGlzdCBpZiB1cGxvYWRlZCBjdXN0b20gYXR0YWNobWVudHNcbiAgICpcbiAgICogQnkgZGVmYXVsdCB0aGUgU0RLIGNvbXBvbmVudHMgd29uJ3QgZGlzcGxheSB0aGVzZSwgYnV0IHlvdSBjYW4gcHJvdmlkZSB5b3VyIG93biBgY3VzdG9tQXR0YWNobWVudFByZXZpZXdMaXN0VGVtcGxhdGUkYCBhbmQgYGN1c3RvbUF0dGFjaG1lbnRMaXN0VGVtcGxhdGUkYCBmb3IgdGhlIFtgQ3VzdG9tVGVtcGxhdGVzU2VydmljZWBdKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvdjYtcmMvc2VydmljZXMvQ3VzdG9tVGVtcGxhdGVzU2VydmljZS8pLlxuICAgKi9cbiAgY3VzdG9tQXR0YWNobWVudHMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxBdHRhY2htZW50W10+KFtdKTtcbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IG51bWJlciBvZiBhdHRhY2htZW50c1xuICAgKi9cbiAgYXR0YWNobWVudHNDb3VudGVyJDogT2JzZXJ2YWJsZTxudW1iZXI+O1xuICAvKipcbiAgICogVGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGFjaG1lbnRzIGFsbG93ZWQgZm9yIGEgbWVzc2FnZS5cbiAgICpcbiAgICogVGhlIG1heGltdW0gaXMgMzAsIHlvdSBjYW4gc2V0IGl0IHRvIGxvd2VyLCBidXQgbm90IGhpZ2hlci5cbiAgICovXG4gIG1heE51bWJlck9mQXR0YWNobWVudHMgPSAzMDtcbiAgcHJpdmF0ZSBhdHRhY2htZW50VXBsb2Fkc1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PEF0dGFjaG1lbnRVcGxvYWRbXT4oXG4gICAgW11cbiAgKTtcbiAgcHJpdmF0ZSBhcHBTZXR0aW5nczogQXBwU2V0dGluZ3MgfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgYXR0YWNobWVudExpbWl0Tm90aWZpY2F0aW9uSGlkZT86ICgpID0+IHZvaWQ7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjaGFubmVsU2VydmljZTogQ2hhbm5lbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBub3RpZmljYXRpb25TZXJ2aWNlOiBOb3RpZmljYXRpb25TZXJ2aWNlLFxuICAgIHByaXZhdGUgY2hhdENsaWVudFNlcnZpY2U6IENoYXRDbGllbnRTZXJ2aWNlLFxuICAgIHByaXZhdGUgbWVzc2FnZVNlcnZpY2U6IE1lc3NhZ2VTZXJ2aWNlXG4gICkge1xuICAgIHRoaXMuYXR0YWNobWVudFVwbG9hZHMkID0gdGhpcy5hdHRhY2htZW50VXBsb2Fkc1N1YmplY3QuYXNPYnNlcnZhYmxlKCk7XG4gICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5hcHBTZXR0aW5ncyQuc3Vic2NyaWJlKFxuICAgICAgKGFwcFNldHRpbmdzKSA9PiAodGhpcy5hcHBTZXR0aW5ncyA9IGFwcFNldHRpbmdzKVxuICAgICk7XG4gICAgdGhpcy5hdHRhY2htZW50c0NvdW50ZXIkID0gY29tYmluZUxhdGVzdChbXG4gICAgICB0aGlzLmF0dGFjaG1lbnRVcGxvYWRzJCxcbiAgICAgIHRoaXMuY3VzdG9tQXR0YWNobWVudHMkLFxuICAgIF0pLnBpcGUoXG4gICAgICBtYXAoKFthdHRjaG1lbnRVcGxvYWRzLCBjdXN0b21BdHRhY2htZW50c10pID0+IHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICBhdHRjaG1lbnRVcGxvYWRzLmZpbHRlcigodSkgPT4gdS5zdGF0ZSA9PT0gJ3N1Y2Nlc3MnKS5sZW5ndGggK1xuICAgICAgICAgIGN1c3RvbUF0dGFjaG1lbnRzLmxlbmd0aFxuICAgICAgICApO1xuICAgICAgfSksXG4gICAgICBzaGFyZVJlcGxheSgxKVxuICAgICk7XG4gICAgdGhpcy5hdHRhY2htZW50c0NvdW50ZXIkLnN1YnNjcmliZSgoY291bnQpID0+IHtcbiAgICAgIGlmIChjb3VudCA+IHRoaXMubWF4TnVtYmVyT2ZBdHRhY2htZW50cykge1xuICAgICAgICB0aGlzLmF0dGFjaG1lbnRMaW1pdE5vdGlmaWNhdGlvbkhpZGUgPVxuICAgICAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRQZXJtYW5lbnROb3RpZmljYXRpb24oXG4gICAgICAgICAgICAnc3RyZWFtQ2hhdC5Zb3UgY3VycmVudGx5IGhhdmUge3tjb3VudH19IGF0dGFjaG1lbnRzLCB0aGUgbWF4aW11bSBpcyB7e21heH19JyxcbiAgICAgICAgICAgICdlcnJvcicsXG4gICAgICAgICAgICB7IGNvdW50LCBtYXg6IHRoaXMubWF4TnVtYmVyT2ZBdHRhY2htZW50cyB9XG4gICAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYXR0YWNobWVudExpbWl0Tm90aWZpY2F0aW9uSGlkZT8uKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVzZXRzIHRoZSBhdHRhY2htZW50cyB1cGxvYWRzIChmb3IgZXhhbXBsZSBhZnRlciB0aGUgbWVzc2FnZSB3aXRoIHRoZSBhdHRhY2htZW50cyBzZW50IHN1Y2Nlc3NmdWxseSlcbiAgICovXG4gIHJlc2V0QXR0YWNobWVudFVwbG9hZHMoKSB7XG4gICAgdGhpcy5hdHRhY2htZW50VXBsb2Fkc1N1YmplY3QubmV4dChbXSk7XG4gICAgdGhpcy5jdXN0b21BdHRhY2htZW50cyQubmV4dChbXSk7XG4gICAgdGhpcy5hdHRhY2htZW50TGltaXROb3RpZmljYXRpb25IaWRlPy4oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGxvYWQgYSB2b2ljZSByZWNvcmRpbmdcbiAgICogQHBhcmFtIGF1ZGlvUmVjb3JkaW5nXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB3aXRoIHRydWUgb3IgZmFsc2UuIElmIGZhbHNlIGlzIHJldHVybmVkIHRoZSB1cGxvYWQgd2FzIGNhbmNlbGVkIGJlY2F1c2Ugb2YgYSBjbGllbnQgc2lkZSBlcnJvci4gVGhlIGVycm9yIGlzIGVtaXR0ZWQgdmlhIHRoZSBgTm90aWZpY2F0aW9uU2VydmljZWAuXG4gICAqL1xuICBhc3luYyB1cGxvYWRWb2ljZVJlY29yZGluZyhhdWRpb1JlY29yZGluZzogQXVkaW9SZWNvcmRpbmcpIHtcbiAgICBpZiAoIXRoaXMuaXNXaXRoaW5MaW1pdCgxKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoXG4gICAgICAhKGF3YWl0IHRoaXMuYXJlQXR0YWNobWVudHNIYXZlVmFsaWRFeHRlbnNpb24oW2F1ZGlvUmVjb3JkaW5nLnJlY29yZGluZ10pKVxuICAgICkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoIShhd2FpdCB0aGlzLmFyZUF0dGFjaG1lbnRzSGF2ZVZhbGlkU2l6ZShbYXVkaW9SZWNvcmRpbmcucmVjb3JkaW5nXSkpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgY29uc3QgdXBsb2FkID0ge1xuICAgICAgZmlsZTogYXVkaW9SZWNvcmRpbmcucmVjb3JkaW5nLFxuICAgICAgcHJldmlld1VyaTogYXVkaW9SZWNvcmRpbmcuYXNzZXRfdXJsLFxuICAgICAgZXh0cmFEYXRhOiB7XG4gICAgICAgIGR1cmF0aW9uOiBhdWRpb1JlY29yZGluZy5kdXJhdGlvbixcbiAgICAgICAgd2F2ZWZvcm1fZGF0YTogYXVkaW9SZWNvcmRpbmcud2F2ZWZvcm1fZGF0YSxcbiAgICAgIH0sXG4gICAgICBzdGF0ZTogJ3VwbG9hZGluZycgYXMgY29uc3QsXG4gICAgICB0eXBlOiAndm9pY2VSZWNvcmRpbmcnIGFzIGNvbnN0LFxuICAgIH07XG4gICAgdGhpcy5hdHRhY2htZW50VXBsb2Fkc1N1YmplY3QubmV4dChbXG4gICAgICAuLi50aGlzLmF0dGFjaG1lbnRVcGxvYWRzU3ViamVjdC5nZXRWYWx1ZSgpLFxuICAgICAgdXBsb2FkLFxuICAgIF0pO1xuICAgIGF3YWl0IHRoaXMudXBsb2FkQXR0YWNobWVudHMoW3VwbG9hZF0pO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwbG9hZHMgdGhlIHNlbGVjdGVkIGZpbGVzLCBhbmQgY3JlYXRlcyBwcmV2aWV3IGZvciBpbWFnZSBmaWxlcy4gVGhlIHJlc3VsdCBpcyBwcm9wYWdhdGVkIHRocm91Z2h0IHRoZSBgYXR0YWNobWVudFVwbG9hZHMkYCBzdHJlYW0uXG4gICAqIEBwYXJhbSBmaWxlTGlzdCBUaGUgZmlsZXMgc2VsZWN0ZWQgYnkgdGhlIHVzZXIsIGlmIHlvdSBoYXZlIEJsb2JzIGluc3RlYWQgb2YgRmlsZXMsIHlvdSBjYW4gY29udmVydCB0aGVtIHdpdGggdGhpcyBtZXRob2Q6IGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9GaWxlL0ZpbGVcbiAgICogQHJldHVybnMgQSBwcm9taXNlIHdpdGggdHJ1ZSBvciBmYWxzZS4gSWYgZmFsc2UgaXMgcmV0dXJuZWQgdGhlIHVwbG9hZCB3YXMgY2FuY2VsZWQgYmVjYXVzZSBvZiBhIGNsaWVudCBzaWRlIGVycm9yLiBUaGUgZXJyb3IgaXMgZW1pdHRlZCB2aWEgdGhlIGBOb3RpZmljYXRpb25TZXJ2aWNlYC5cbiAgICovXG4gIGFzeW5jIGZpbGVzU2VsZWN0ZWQoZmlsZUxpc3Q6IEZpbGVMaXN0IHwgRmlsZVtdIHwgbnVsbCkge1xuICAgIGlmICghZmlsZUxpc3QpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBmaWxlcyA9IEFycmF5LmZyb20oZmlsZUxpc3QpO1xuXG4gICAgaWYgKCF0aGlzLmlzV2l0aGluTGltaXQoZmlsZXMubGVuZ3RoKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmICghKGF3YWl0IHRoaXMuYXJlQXR0YWNobWVudHNIYXZlVmFsaWRFeHRlbnNpb24oZmlsZXMpKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoIShhd2FpdCB0aGlzLmFyZUF0dGFjaG1lbnRzSGF2ZVZhbGlkU2l6ZShmaWxlcykpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IGltYWdlRmlsZXM6IEZpbGVbXSA9IFtdO1xuICAgIGNvbnN0IGRhdGFGaWxlczogRmlsZVtdID0gW107XG4gICAgY29uc3QgdmlkZW9GaWxlczogRmlsZVtdID0gW107XG5cbiAgICBmaWxlcy5mb3JFYWNoKChmaWxlKSA9PiB7XG4gICAgICBpZiAoaXNJbWFnZUZpbGUoZmlsZSkpIHtcbiAgICAgICAgaW1hZ2VGaWxlcy5wdXNoKGZpbGUpO1xuICAgICAgfSBlbHNlIGlmIChmaWxlLnR5cGUuc3RhcnRzV2l0aCgndmlkZW8vJykpIHtcbiAgICAgICAgdmlkZW9GaWxlcy5wdXNoKGZpbGUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGF0YUZpbGVzLnB1c2goZmlsZSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaW1hZ2VGaWxlcy5mb3JFYWNoKChmKSA9PiB2b2lkIHRoaXMuY3JlYXRlUHJldmlldyhmKSk7XG4gICAgY29uc3QgbmV3VXBsb2FkcyA9IFtcbiAgICAgIC4uLmltYWdlRmlsZXMubWFwKChmaWxlKSA9PiAoe1xuICAgICAgICBmaWxlLFxuICAgICAgICBzdGF0ZTogJ3VwbG9hZGluZycgYXMgY29uc3QsXG4gICAgICAgIHR5cGU6ICdpbWFnZScgYXMgY29uc3QsXG4gICAgICB9KSksXG4gICAgICAuLi52aWRlb0ZpbGVzLm1hcCgoZmlsZSkgPT4gKHtcbiAgICAgICAgZmlsZSxcbiAgICAgICAgc3RhdGU6ICd1cGxvYWRpbmcnIGFzIGNvbnN0LFxuICAgICAgICB0eXBlOiAndmlkZW8nIGFzIGNvbnN0LFxuICAgICAgfSkpLFxuICAgICAgLi4uZGF0YUZpbGVzLm1hcCgoZmlsZSkgPT4gKHtcbiAgICAgICAgZmlsZSxcbiAgICAgICAgc3RhdGU6ICd1cGxvYWRpbmcnIGFzIGNvbnN0LFxuICAgICAgICB0eXBlOiAnZmlsZScgYXMgY29uc3QsXG4gICAgICB9KSksXG4gICAgXTtcbiAgICB0aGlzLmF0dGFjaG1lbnRVcGxvYWRzU3ViamVjdC5uZXh0KFtcbiAgICAgIC4uLnRoaXMuYXR0YWNobWVudFVwbG9hZHNTdWJqZWN0LmdldFZhbHVlKCksXG4gICAgICAuLi5uZXdVcGxvYWRzLFxuICAgIF0pO1xuICAgIGF3YWl0IHRoaXMudXBsb2FkQXR0YWNobWVudHMobmV3VXBsb2Fkcyk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogWW91IGNhbiBhZGQgY3VzdG9tIGBpbWFnZWAsIGB2aWRlb2AgYW5kIGBmaWxlYCBhdHRhY2htZW50cyB1c2luZyB0aGlzIG1ldGhvZC5cbiAgICpcbiAgICogTm90ZTogSWYgeW91IGp1c3Qgd2FudCB0byB1c2UgeW91ciBvd24gQ0ROIGZvciBmaWxlIHVwbG9hZHMsIHlvdSBkb24ndCBuZWNlc3NhcnkgbmVlZCB0aGlzIG1ldGhvZCwgeW91IGNhbiBqdXN0IHNwZWNpZnkgeW91IG93biB1cGxvYWQgZnVuY3Rpb24gaW4gdGhlIFtgQ2hhbm5lbFNlcnZpY2VgXSgvY2hhdC9kb2NzL3Nkay9hbmd1bGFyL3Y2LXJjL3NlcnZpY2VzL0NoYW5uZWxTZXJ2aWNlLylcbiAgICogQHBhcmFtIGF0dGFjaG1lbnRcbiAgICpcbiAgICogV2lsbCBzZXQgYGlzQ3VzdG9tQXR0YWNobWVudGAgdG8gYHRydWVgIG9uIHRoZSBhdHRhY2htZW50LiBUaGlzIGlzIGEgbm9uLXN0YW5kYXJkIGZpZWxkLCBvdGhlciBTREtzIHdpbGwgaWdub3JlIHRoaXMgcHJvcGVydHkuXG4gICAqL1xuICBhZGRBdHRhY2htZW50KGF0dGFjaG1lbnQ6IEF0dGFjaG1lbnQpIHtcbiAgICBhdHRhY2htZW50LmlzQ3VzdG9tQXR0YWNobWVudCA9IHRydWU7XG4gICAgdGhpcy5jcmVhdGVGcm9tQXR0YWNobWVudHMoW2F0dGFjaG1lbnRdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWVzIHRvIHVwbG9hZCBhbiBhdHRhY2htZW50LlxuICAgKiBAcGFyYW0gZmlsZVxuICAgKiBAcmV0dXJucyBBIHByb21pc2Ugd2l0aCB0aGUgcmVzdWx0XG4gICAqL1xuICBhc3luYyByZXRyeUF0dGFjaG1lbnRVcGxvYWQoZmlsZTogRmlsZSkge1xuICAgIGNvbnN0IGF0dGFjaG1lbnRVcGxvYWRzID0gdGhpcy5hdHRhY2htZW50VXBsb2Fkc1N1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBjb25zdCB1cGxvYWQgPSBhdHRhY2htZW50VXBsb2Fkcy5maW5kKCh1KSA9PiB1LmZpbGUgPT09IGZpbGUpO1xuICAgIGlmICghdXBsb2FkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHVwbG9hZC5zdGF0ZSA9ICd1cGxvYWRpbmcnO1xuICAgIHRoaXMuYXR0YWNobWVudFVwbG9hZHNTdWJqZWN0Lm5leHQoWy4uLmF0dGFjaG1lbnRVcGxvYWRzXSk7XG4gICAgYXdhaXQgdGhpcy51cGxvYWRBdHRhY2htZW50cyhbdXBsb2FkXSk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyBhbiBhdHRhY2htZW50LCB0aGUgYXR0YWNobWVudCBjYW4gaGF2ZSBhbnkgc3RhdGUgKGBlcnJvcmAsIGB1cGxvYWRpbmdgIG9yIGBzdWNjZXNzYCkuXG4gICAqIEBwYXJhbSB1cGxvYWRcbiAgICovXG4gIGFzeW5jIGRlbGV0ZUF0dGFjaG1lbnQodXBsb2FkOiBBdHRhY2htZW50VXBsb2FkKSB7XG4gICAgY29uc3QgYXR0YWNobWVudFVwbG9hZHMgPSB0aGlzLmF0dGFjaG1lbnRVcGxvYWRzU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGxldCByZXN1bHQhOiBBdHRhY2htZW50VXBsb2FkW107XG4gICAgaWYgKFxuICAgICAgdXBsb2FkLnN0YXRlID09PSAnc3VjY2VzcycgJiZcbiAgICAgICF1cGxvYWQuZnJvbUF0dGFjaG1lbnQ/LmlzQ3VzdG9tQXR0YWNobWVudFxuICAgICkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5jaGFubmVsU2VydmljZS5kZWxldGVBdHRhY2htZW50KHVwbG9hZCk7XG4gICAgICAgIHJlc3VsdCA9IFsuLi5hdHRhY2htZW50VXBsb2Fkc107XG4gICAgICAgIGNvbnN0IGluZGV4ID0gYXR0YWNobWVudFVwbG9hZHMuaW5kZXhPZih1cGxvYWQpO1xuICAgICAgICByZXN1bHQuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHJlc3VsdCA9IGF0dGFjaG1lbnRVcGxvYWRzO1xuICAgICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2UuYWRkVGVtcG9yYXJ5Tm90aWZpY2F0aW9uKFxuICAgICAgICAgICdzdHJlYW1DaGF0LkVycm9yIGRlbGV0aW5nIGF0dGFjaG1lbnQnXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlc3VsdCA9IFsuLi5hdHRhY2htZW50VXBsb2Fkc107XG4gICAgICBjb25zdCBpbmRleCA9IGF0dGFjaG1lbnRVcGxvYWRzLmluZGV4T2YodXBsb2FkKTtcbiAgICAgIHJlc3VsdC5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIH1cbiAgICB0aGlzLmF0dGFjaG1lbnRVcGxvYWRzU3ViamVjdC5uZXh0KFsuLi5yZXN1bHRdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNYXBzIHRoZSBjdXJyZW50IHVwbG9hZHMgdG8gYSBmb3JtYXQgdGhhdCBjYW4gYmUgc2VudCBhbG9uZyB3aXRoIHRoZSBtZXNzYWdlIHRvIHRoZSBTdHJlYW0gQVBJLlxuICAgKiBAcmV0dXJucyB0aGUgYXR0YWNobWVudHNcbiAgICovXG4gIG1hcFRvQXR0YWNobWVudHMoKSB7XG4gICAgY29uc3QgYXR0YWNobWVudFVwbG9hZHMgPSB0aGlzLmF0dGFjaG1lbnRVcGxvYWRzU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGNvbnN0IGJ1aWx0SW5BdHRhY2htZW50cyA9IGF0dGFjaG1lbnRVcGxvYWRzXG4gICAgICAuZmlsdGVyKChyKSA9PiByLnN0YXRlID09PSAnc3VjY2VzcycpXG4gICAgICAubWFwKChyKSA9PiB7XG4gICAgICAgIGxldCBhdHRhY2htZW50OiBBdHRhY2htZW50ID0ge1xuICAgICAgICAgIHR5cGU6IHIudHlwZSxcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKHIuZnJvbUF0dGFjaG1lbnQpIHtcbiAgICAgICAgICByZXR1cm4gci5mcm9tQXR0YWNobWVudDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhdHRhY2htZW50Lm1pbWVfdHlwZSA9IHIuZmlsZT8udHlwZTtcbiAgICAgICAgICBpZiAoci50eXBlID09PSAnaW1hZ2UnKSB7XG4gICAgICAgICAgICBhdHRhY2htZW50LmZhbGxiYWNrID0gci5maWxlPy5uYW1lO1xuICAgICAgICAgICAgYXR0YWNobWVudC5pbWFnZV91cmwgPSByLnVybDtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYXR0YWNobWVudC5hc3NldF91cmwgPSByLnVybDtcbiAgICAgICAgICAgIGF0dGFjaG1lbnQudGl0bGUgPSByLmZpbGU/Lm5hbWU7XG4gICAgICAgICAgICBhdHRhY2htZW50LmZpbGVfc2l6ZSA9IHIuZmlsZT8uc2l6ZTtcbiAgICAgICAgICAgIGF0dGFjaG1lbnQudGh1bWJfdXJsID0gci50aHVtYl91cmw7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChyLmV4dHJhRGF0YSkge1xuICAgICAgICAgICAgYXR0YWNobWVudCA9IHsgLi4uYXR0YWNobWVudCwgLi4uci5leHRyYURhdGEgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYXR0YWNobWVudDtcbiAgICAgIH0pO1xuICAgIHJldHVybiBbLi4uYnVpbHRJbkF0dGFjaG1lbnRzLCAuLi50aGlzLmN1c3RvbUF0dGFjaG1lbnRzJC52YWx1ZV07XG4gIH1cblxuICAvKipcbiAgICogTWFwcyBhdHRhY2htZW50cyByZWNlaXZlZCBmcm9tIHRoZSBTdHJlYW0gQVBJIHRvIHVwbG9hZHMuIFRoaXMgaXMgdXNlZnVsIHdoZW4gZWRpdGluZyBhIG1lc3NhZ2UuXG4gICAqIEBwYXJhbSBhdHRhY2htZW50cyBBdHRhY2hlbW50cyByZWNlaXZlZCB3aXRoIHRoZSBtZXNzYWdlXG4gICAqL1xuICBjcmVhdGVGcm9tQXR0YWNobWVudHMoYXR0YWNobWVudHM6IEF0dGFjaG1lbnRbXSkge1xuICAgIGNvbnN0IGF0dGFjaG1lbnRVcGxvYWRzOiBBdHRhY2htZW50VXBsb2FkW10gPSBbXTtcbiAgICBjb25zdCBidWlsdEluQXR0YWNobWVudHM6IEF0dGFjaG1lbnRbXSA9IFtdO1xuICAgIGNvbnN0IGN1c3RvbUF0dGFjaG1lbnRzOiBBdHRhY2htZW50W10gPSBbXTtcbiAgICBhdHRhY2htZW50cy5mb3JFYWNoKChhdHRhY2htZW50KSA9PiB7XG4gICAgICBpZiAodGhpcy5tZXNzYWdlU2VydmljZS5pc0N1c3RvbUF0dGFjaG1lbnQoYXR0YWNobWVudCkpIHtcbiAgICAgICAgY3VzdG9tQXR0YWNobWVudHMucHVzaChhdHRhY2htZW50KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGJ1aWx0SW5BdHRhY2htZW50cy5wdXNoKGF0dGFjaG1lbnQpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGJ1aWx0SW5BdHRhY2htZW50cy5mb3JFYWNoKChhdHRhY2htZW50KSA9PiB7XG4gICAgICBpZiAoaXNJbWFnZUF0dGFjaG1lbnQoYXR0YWNobWVudCkpIHtcbiAgICAgICAgYXR0YWNobWVudFVwbG9hZHMucHVzaCh7XG4gICAgICAgICAgdXJsOiAoYXR0YWNobWVudC5pbWdfdXJsIHx8XG4gICAgICAgICAgICBhdHRhY2htZW50LnRodW1iX3VybCB8fFxuICAgICAgICAgICAgYXR0YWNobWVudC5pbWFnZV91cmwpIGFzIHN0cmluZyxcbiAgICAgICAgICBzdGF0ZTogJ3N1Y2Nlc3MnLFxuICAgICAgICAgIHR5cGU6ICdpbWFnZScsXG4gICAgICAgICAgZmlsZToge1xuICAgICAgICAgICAgbmFtZTogYXR0YWNobWVudC5mYWxsYmFjayxcbiAgICAgICAgICAgIHR5cGU6IGF0dGFjaG1lbnQubWltZV90eXBlLFxuICAgICAgICAgIH0gYXMgRmlsZSxcbiAgICAgICAgICBmcm9tQXR0YWNobWVudDogYXR0YWNobWVudCxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGF0dGFjaG1lbnQudHlwZSA9PT0gJ2ZpbGUnIHx8IGF0dGFjaG1lbnQudHlwZSA9PT0gJ3ZpZGVvJykge1xuICAgICAgICBhdHRhY2htZW50VXBsb2Fkcy5wdXNoKHtcbiAgICAgICAgICB1cmw6IGF0dGFjaG1lbnQuYXNzZXRfdXJsLFxuICAgICAgICAgIHN0YXRlOiAnc3VjY2VzcycsXG4gICAgICAgICAgZmlsZToge1xuICAgICAgICAgICAgbmFtZTogYXR0YWNobWVudC50aXRsZSxcbiAgICAgICAgICAgIHNpemU6IGF0dGFjaG1lbnQuZmlsZV9zaXplLFxuICAgICAgICAgICAgdHlwZTogYXR0YWNobWVudC5taW1lX3R5cGUsXG4gICAgICAgICAgfSBhcyBGaWxlLFxuICAgICAgICAgIHR5cGU6IGF0dGFjaG1lbnQudHlwZSxcbiAgICAgICAgICB0aHVtYl91cmw6IGF0dGFjaG1lbnQudGh1bWJfdXJsLFxuICAgICAgICAgIGZyb21BdHRhY2htZW50OiBhdHRhY2htZW50LFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoYXR0YWNobWVudC50eXBlID09PSAndm9pY2VSZWNvcmRpbmcnKSB7XG4gICAgICAgIGF0dGFjaG1lbnRVcGxvYWRzLnB1c2goe1xuICAgICAgICAgIHVybDogYXR0YWNobWVudC5hc3NldF91cmwsXG4gICAgICAgICAgc3RhdGU6ICdzdWNjZXNzJyxcbiAgICAgICAgICBmaWxlOiB7XG4gICAgICAgICAgICBuYW1lOiBhdHRhY2htZW50LnRpdGxlLFxuICAgICAgICAgICAgc2l6ZTogYXR0YWNobWVudC5maWxlX3NpemUsXG4gICAgICAgICAgICB0eXBlOiBhdHRhY2htZW50Lm1pbWVfdHlwZSxcbiAgICAgICAgICB9IGFzIEZpbGUsXG4gICAgICAgICAgdHlwZTogJ3ZvaWNlUmVjb3JkaW5nJyxcbiAgICAgICAgICBleHRyYURhdGE6IHtcbiAgICAgICAgICAgIGR1cmF0aW9uOiBhdHRhY2htZW50LmR1cmF0aW9uLFxuICAgICAgICAgICAgd2F2ZWZvcm1fZGF0YTogYXR0YWNobWVudC53YXZlZm9ybV9kYXRhLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaWYgKGF0dGFjaG1lbnRVcGxvYWRzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuYXR0YWNobWVudFVwbG9hZHNTdWJqZWN0Lm5leHQoW1xuICAgICAgICAuLi50aGlzLmF0dGFjaG1lbnRVcGxvYWRzU3ViamVjdC5nZXRWYWx1ZSgpLFxuICAgICAgICAuLi5hdHRhY2htZW50VXBsb2FkcyxcbiAgICAgIF0pO1xuICAgIH1cblxuICAgIGlmIChjdXN0b21BdHRhY2htZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLmN1c3RvbUF0dGFjaG1lbnRzJC5uZXh0KGN1c3RvbUF0dGFjaG1lbnRzKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNyZWF0ZVByZXZpZXcoZmlsZTogRmlsZSB8IEJsb2IpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdXJpID0gYXdhaXQgY3JlYXRlVXJpRnJvbUJsb2IoZmlsZSk7XG4gICAgICBjb25zdCBhdHRhY2htZW50VXBsb2FkcyA9IHRoaXMuYXR0YWNobWVudFVwbG9hZHNTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgICBjb25zdCB1cGxvYWQgPSBhdHRhY2htZW50VXBsb2Fkcy5maW5kKCh1cGxvYWQpID0+IHVwbG9hZC5maWxlID09PSBmaWxlKTtcbiAgICAgIGlmICghdXBsb2FkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHVwbG9hZC5wcmV2aWV3VXJpID0gdXJpO1xuICAgICAgdGhpcy5hdHRhY2htZW50VXBsb2Fkc1N1YmplY3QubmV4dChbLi4uYXR0YWNobWVudFVwbG9hZHNdKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlPy5jaGF0Q2xpZW50Py5sb2dnZXIoXG4gICAgICAgICdlcnJvcicsXG4gICAgICAgIGUgaW5zdGFuY2VvZiBFcnJvciA/IGUubWVzc2FnZSA6IGBDYW4ndCBjcmVhdGUgaW1hZ2UgcHJldmlld2AsXG4gICAgICAgIHsgZXJyb3I6IGUsIHRhZzogWydBdHRhY2htZW50U2VydmljZSddIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB1cGxvYWRBdHRhY2htZW50cyh1cGxvYWRzOiBBdHRhY2htZW50VXBsb2FkW10pIHtcbiAgICB0aGlzLmF0dGFjaG1lbnRVcGxvYWRJblByb2dyZXNzQ291bnRlciQubmV4dChcbiAgICAgIHRoaXMuYXR0YWNobWVudFVwbG9hZEluUHJvZ3Jlc3NDb3VudGVyJC52YWx1ZSArIDFcbiAgICApO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuY2hhbm5lbFNlcnZpY2UudXBsb2FkQXR0YWNobWVudHModXBsb2Fkcyk7XG4gICAgY29uc3QgYXR0YWNobWVudFVwbG9hZHMgPSB0aGlzLmF0dGFjaG1lbnRVcGxvYWRzU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIHJlc3VsdC5mb3JFYWNoKChyKSA9PiB7XG4gICAgICBjb25zdCB1cGxvYWQgPSBhdHRhY2htZW50VXBsb2Fkcy5maW5kKCh1cGxvYWQpID0+IHVwbG9hZC5maWxlID09PSByLmZpbGUpO1xuICAgICAgaWYgKCF1cGxvYWQpIHtcbiAgICAgICAgaWYgKHIudXJsKSB7XG4gICAgICAgICAgdm9pZCB0aGlzLmNoYW5uZWxTZXJ2aWNlLmRlbGV0ZUF0dGFjaG1lbnQocik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdXBsb2FkLnN0YXRlID0gci5zdGF0ZTtcbiAgICAgIHVwbG9hZC51cmwgPSByLnVybDtcbiAgICAgIHVwbG9hZC50aHVtYl91cmwgPSByLnRodW1iX3VybDtcbiAgICAgIGlmICh1cGxvYWQuc3RhdGUgPT09ICdlcnJvcicpIHtcbiAgICAgICAgdXBsb2FkLmVycm9yUmVhc29uID0gci5lcnJvclJlYXNvbjtcbiAgICAgICAgdXBsb2FkLmVycm9yRXh0cmFJbmZvID0gci5lcnJvckV4dHJhSW5mbztcbiAgICAgICAgbGV0IGVycm9yS2V5O1xuICAgICAgICBjb25zdCB0cmFuc2xhdGVQYXJhbXM6IHsgbmFtZTogc3RyaW5nOyBleHQ/OiBzdHJpbmc7IGxpbWl0Pzogc3RyaW5nIH0gPVxuICAgICAgICAgIHsgbmFtZTogdXBsb2FkLmZpbGUubmFtZSB9O1xuICAgICAgICBzd2l0Y2ggKHVwbG9hZC5lcnJvclJlYXNvbikge1xuICAgICAgICAgIGNhc2UgJ2ZpbGUtZXh0ZW5zaW9uJzpcbiAgICAgICAgICAgIGVycm9yS2V5ID1cbiAgICAgICAgICAgICAgJ3N0cmVhbUNoYXQuRXJyb3IgdXBsb2FkaW5nIGZpbGUsIGV4dGVuc2lvbiBub3Qgc3VwcG9ydGVkJztcbiAgICAgICAgICAgIHRyYW5zbGF0ZVBhcmFtcy5leHQgPSB1cGxvYWQuZXJyb3JFeHRyYUluZm8/LlswXT8ucGFyYW07XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlICdmaWxlLXNpemUnOlxuICAgICAgICAgICAgZXJyb3JLZXkgPVxuICAgICAgICAgICAgICAnc3RyZWFtQ2hhdC5FcnJvciB1cGxvYWRpbmcgZmlsZSwgbWF4aW11bSBmaWxlIHNpemUgZXhjZWVkZWQnO1xuICAgICAgICAgICAgdHJhbnNsYXRlUGFyYW1zLmxpbWl0ID0gdXBsb2FkLmVycm9yRXh0cmFJbmZvPy5bMF0/LnBhcmFtO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIGVycm9yS2V5ID0gJ3N0cmVhbUNoYXQuRXJyb3IgdXBsb2FkaW5nIGZpbGUnO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICAgZXJyb3JLZXksXG4gICAgICAgICAgJ2Vycm9yJyxcbiAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgdHJhbnNsYXRlUGFyYW1zXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5hdHRhY2htZW50VXBsb2FkSW5Qcm9ncmVzc0NvdW50ZXIkLm5leHQoXG4gICAgICB0aGlzLmF0dGFjaG1lbnRVcGxvYWRJblByb2dyZXNzQ291bnRlciQudmFsdWUgLSAxXG4gICAgKTtcbiAgICB0aGlzLmF0dGFjaG1lbnRVcGxvYWRzU3ViamVjdC5uZXh0KFsuLi5hdHRhY2htZW50VXBsb2Fkc10pO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBhcmVBdHRhY2htZW50c0hhdmVWYWxpZEV4dGVuc2lvbihmaWxlczogRmlsZVtdKSB7XG4gICAgaWYgKCF0aGlzLmFwcFNldHRpbmdzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmdldEFwcFNldHRpbmdzKCk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgbGV0IGlzVmFsaWQgPSB0cnVlO1xuICAgIGZpbGVzLmZvckVhY2goKGYpID0+IHtcbiAgICAgIGxldCBoYXNCbG9ja2VkRXh0ZW5zaW9uOiBib29sZWFuO1xuICAgICAgbGV0IGhhc0Jsb2NrZWRNaW1lVHlwZTogYm9vbGVhbjtcbiAgICAgIGxldCBoYXNOb3RBbGxvd2VkRXh0ZW5zaW9uOiBib29sZWFuO1xuICAgICAgbGV0IGhhc05vdEFsbG93ZWRNaW1lVHlwZTogYm9vbGVhbjtcbiAgICAgIGlmIChpc0ltYWdlRmlsZShmKSkge1xuICAgICAgICBoYXNCbG9ja2VkRXh0ZW5zaW9uID1cbiAgICAgICAgICAhIXRoaXMuYXBwU2V0dGluZ3M/LmltYWdlX3VwbG9hZF9jb25maWc/LmJsb2NrZWRfZmlsZV9leHRlbnNpb25zPy5maW5kKFxuICAgICAgICAgICAgKGV4dCkgPT4gZi5uYW1lLmVuZHNXaXRoKGV4dClcbiAgICAgICAgICApO1xuICAgICAgICBoYXNCbG9ja2VkTWltZVR5cGUgPVxuICAgICAgICAgICEhdGhpcy5hcHBTZXR0aW5ncz8uaW1hZ2VfdXBsb2FkX2NvbmZpZz8uYmxvY2tlZF9taW1lX3R5cGVzPy5maW5kKFxuICAgICAgICAgICAgKHR5cGUpID0+IGYudHlwZSA9PT0gdHlwZVxuICAgICAgICAgICk7XG4gICAgICAgIGhhc05vdEFsbG93ZWRFeHRlbnNpb24gPVxuICAgICAgICAgICEhdGhpcy5hcHBTZXR0aW5ncz8uaW1hZ2VfdXBsb2FkX2NvbmZpZz8uYWxsb3dlZF9maWxlX2V4dGVuc2lvbnNcbiAgICAgICAgICAgID8ubGVuZ3RoICYmXG4gICAgICAgICAgIXRoaXMuYXBwU2V0dGluZ3M/LmltYWdlX3VwbG9hZF9jb25maWc/LmFsbG93ZWRfZmlsZV9leHRlbnNpb25zPy5maW5kKFxuICAgICAgICAgICAgKGV4dCkgPT4gZi5uYW1lLmVuZHNXaXRoKGV4dClcbiAgICAgICAgICApO1xuICAgICAgICBoYXNOb3RBbGxvd2VkTWltZVR5cGUgPVxuICAgICAgICAgICEhdGhpcy5hcHBTZXR0aW5ncz8uaW1hZ2VfdXBsb2FkX2NvbmZpZz8uYWxsb3dlZF9taW1lX3R5cGVzPy5sZW5ndGggJiZcbiAgICAgICAgICAhdGhpcy5hcHBTZXR0aW5ncz8uaW1hZ2VfdXBsb2FkX2NvbmZpZz8uYWxsb3dlZF9taW1lX3R5cGVzPy5maW5kKFxuICAgICAgICAgICAgKHR5cGUpID0+IGYudHlwZSA9PT0gdHlwZVxuICAgICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoYXNCbG9ja2VkRXh0ZW5zaW9uID1cbiAgICAgICAgICAhIXRoaXMuYXBwU2V0dGluZ3M/LmZpbGVfdXBsb2FkX2NvbmZpZz8uYmxvY2tlZF9maWxlX2V4dGVuc2lvbnM/LmZpbmQoXG4gICAgICAgICAgICAoZXh0KSA9PiBmLm5hbWUuZW5kc1dpdGgoZXh0KVxuICAgICAgICAgICk7XG4gICAgICAgIGhhc0Jsb2NrZWRNaW1lVHlwZSA9XG4gICAgICAgICAgISF0aGlzLmFwcFNldHRpbmdzPy5maWxlX3VwbG9hZF9jb25maWc/LmJsb2NrZWRfbWltZV90eXBlcz8uZmluZChcbiAgICAgICAgICAgICh0eXBlKSA9PiBmLnR5cGUgPT09IHR5cGVcbiAgICAgICAgICApO1xuICAgICAgICBoYXNOb3RBbGxvd2VkRXh0ZW5zaW9uID1cbiAgICAgICAgICAhIXRoaXMuYXBwU2V0dGluZ3M/LmZpbGVfdXBsb2FkX2NvbmZpZz8uYWxsb3dlZF9maWxlX2V4dGVuc2lvbnNcbiAgICAgICAgICAgID8ubGVuZ3RoICYmXG4gICAgICAgICAgIXRoaXMuYXBwU2V0dGluZ3M/LmZpbGVfdXBsb2FkX2NvbmZpZz8uYWxsb3dlZF9maWxlX2V4dGVuc2lvbnM/LmZpbmQoXG4gICAgICAgICAgICAoZXh0KSA9PiBmLm5hbWUuZW5kc1dpdGgoZXh0KVxuICAgICAgICAgICk7XG4gICAgICAgIGhhc05vdEFsbG93ZWRNaW1lVHlwZSA9XG4gICAgICAgICAgISF0aGlzLmFwcFNldHRpbmdzPy5maWxlX3VwbG9hZF9jb25maWc/LmFsbG93ZWRfbWltZV90eXBlcz8ubGVuZ3RoICYmXG4gICAgICAgICAgIXRoaXMuYXBwU2V0dGluZ3M/LmZpbGVfdXBsb2FkX2NvbmZpZz8uYWxsb3dlZF9taW1lX3R5cGVzPy5maW5kKFxuICAgICAgICAgICAgKHR5cGUpID0+IGYudHlwZSA9PT0gdHlwZVxuICAgICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAoXG4gICAgICAgIGhhc0Jsb2NrZWRFeHRlbnNpb24gfHxcbiAgICAgICAgaGFzQmxvY2tlZE1pbWVUeXBlIHx8XG4gICAgICAgIGhhc05vdEFsbG93ZWRFeHRlbnNpb24gfHxcbiAgICAgICAgaGFzTm90QWxsb3dlZE1pbWVUeXBlXG4gICAgICApIHtcbiAgICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLmFkZFRlbXBvcmFyeU5vdGlmaWNhdGlvbihcbiAgICAgICAgICAnc3RyZWFtQ2hhdC5FcnJvciB1cGxvYWRpbmcgZmlsZSwgZXh0ZW5zaW9uIG5vdCBzdXBwb3J0ZWQnLFxuICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgeyBuYW1lOiBmLm5hbWUsIGV4dDogZi50eXBlIH1cbiAgICAgICAgKTtcbiAgICAgICAgaXNWYWxpZCA9IGZhbHNlO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBpc1ZhbGlkO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBhcmVBdHRhY2htZW50c0hhdmVWYWxpZFNpemUoZmlsZXM6IEZpbGVbXSkge1xuICAgIGlmICghdGhpcy5hcHBTZXR0aW5ncykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5nZXRBcHBTZXR0aW5ncygpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGltYWdlU2l6ZUxpbWl0SW5CeXRlcyA9XG4gICAgICB0aGlzLmFwcFNldHRpbmdzPy5pbWFnZV91cGxvYWRfY29uZmlnPy5zaXplX2xpbWl0IHx8IDA7XG4gICAgY29uc3QgaW1hZ2VTaXplTGltaVN0cmluZyA9IGAke2ltYWdlU2l6ZUxpbWl0SW5CeXRlcyAvICgxMDI0ICogMTAyNCl9TUJgO1xuICAgIGNvbnN0IGZpbGVTaXplTGltaXRJbkJ5dGVzID1cbiAgICAgIHRoaXMuYXBwU2V0dGluZ3M/LmZpbGVfdXBsb2FkX2NvbmZpZz8uc2l6ZV9saW1pdCB8fCAwO1xuICAgIGNvbnN0IGZpbGVTaXplTGltaXRJblN0cmluZyA9IGAke2ZpbGVTaXplTGltaXRJbkJ5dGVzIC8gKDEwMjQgKiAxMDI0KX1NQmA7XG4gICAgbGV0IGlzVmFsaWQgPSB0cnVlO1xuICAgIGZpbGVzLmZvckVhY2goKGYpID0+IHtcbiAgICAgIGxldCBpc092ZXJTaXplZCA9IGZhbHNlO1xuICAgICAgbGV0IGxpbWl0ID0gJyc7XG4gICAgICBpZiAoaXNJbWFnZUZpbGUoZikgJiYgaW1hZ2VTaXplTGltaXRJbkJ5dGVzID4gMCkge1xuICAgICAgICBpc092ZXJTaXplZCA9IGYuc2l6ZSA+IGltYWdlU2l6ZUxpbWl0SW5CeXRlcztcbiAgICAgICAgbGltaXQgPSBpbWFnZVNpemVMaW1pU3RyaW5nO1xuICAgICAgfSBlbHNlIGlmIChmaWxlU2l6ZUxpbWl0SW5CeXRlcyA+IDApIHtcbiAgICAgICAgaXNPdmVyU2l6ZWQgPSBmLnNpemUgPiBmaWxlU2l6ZUxpbWl0SW5CeXRlcztcbiAgICAgICAgbGltaXQgPSBmaWxlU2l6ZUxpbWl0SW5TdHJpbmc7XG4gICAgICB9XG4gICAgICBpZiAoaXNPdmVyU2l6ZWQpIHtcbiAgICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLmFkZFRlbXBvcmFyeU5vdGlmaWNhdGlvbihcbiAgICAgICAgICAnc3RyZWFtQ2hhdC5FcnJvciB1cGxvYWRpbmcgZmlsZSwgbWF4aW11bSBmaWxlIHNpemUgZXhjZWVkZWQnLFxuICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgeyBuYW1lOiBmLm5hbWUsIGxpbWl0OiBsaW1pdCB9XG4gICAgICAgICk7XG4gICAgICAgIGlzVmFsaWQgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gaXNWYWxpZDtcbiAgfVxuXG4gIHByaXZhdGUgaXNXaXRoaW5MaW1pdChudW1iZXJPZk5ld0F0dGFjaG1lbnRzOiBudW1iZXIpIHtcbiAgICBsZXQgY3VycmVudE51bWJlck9mQXR0YWNobWVudHM6IG51bWJlciA9IDA7XG4gICAgdGhpcy5hdHRhY2htZW50c0NvdW50ZXIkXG4gICAgICAucGlwZSh0YWtlKDEpKVxuICAgICAgLnN1YnNjcmliZSgoY291bnRlcikgPT4gKGN1cnJlbnROdW1iZXJPZkF0dGFjaG1lbnRzID0gY291bnRlcikpO1xuICAgIGlmIChcbiAgICAgIGN1cnJlbnROdW1iZXJPZkF0dGFjaG1lbnRzICsgbnVtYmVyT2ZOZXdBdHRhY2htZW50cyA+XG4gICAgICB0aGlzLm1heE51bWJlck9mQXR0YWNobWVudHNcbiAgICApIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgIGBzdHJlYW1DaGF0LllvdSBjYW4ndCB1cGxvZCBtb3JlIHRoYW4ge3ttYXh9fSBhdHRhY2htZW50c2AsXG4gICAgICAgICdlcnJvcicsXG4gICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgeyBtYXg6IHRoaXMubWF4TnVtYmVyT2ZBdHRhY2htZW50cyB9XG4gICAgICApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==