stream-chat-angular 4.66.2 → 5.0.0-v5.10

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 (315) hide show
  1. package/assets/version.d.ts +1 -1
  2. package/{esm2015/assets/version.js → esm2020/assets/version.mjs} +2 -2
  3. package/esm2020/lib/attachment-configuration.service.mjs +185 -0
  4. package/esm2020/lib/attachment-list/attachment-list.component.mjs +203 -0
  5. package/esm2020/lib/attachment-preview-list/attachment-preview-list.component.mjs +42 -0
  6. package/esm2020/lib/attachment.service.mjs +262 -0
  7. package/esm2020/lib/avatar/avatar.component.mjs +163 -0
  8. package/esm2020/lib/avatar-placeholder/avatar-placeholder.component.mjs +74 -0
  9. package/esm2020/lib/channel/channel.component.mjs +46 -0
  10. package/esm2020/lib/channel-header/channel-header.component.mjs +72 -0
  11. package/esm2020/lib/channel-list/channel-list.component.mjs +51 -0
  12. package/esm2020/lib/channel-preview/channel-preview.component.mjs +155 -0
  13. package/esm2020/lib/channel.service.mjs +1454 -0
  14. package/esm2020/lib/chat-client.service.mjs +206 -0
  15. package/{esm2015/lib/custom-templates.service.js → esm2020/lib/custom-templates.service.mjs} +3 -3
  16. package/{esm2015/lib/date-parser.service.js → esm2020/lib/date-parser.service.mjs} +3 -3
  17. package/esm2020/lib/edit-message-form/edit-message-form.component.mjs +83 -0
  18. package/esm2020/lib/get-channel-display-text.mjs +14 -0
  19. package/esm2020/lib/get-message-translation.mjs +12 -0
  20. package/esm2020/lib/icon/icon.component.mjs +21 -0
  21. package/esm2020/lib/icon-placeholder/icon-placeholder.component.mjs +31 -0
  22. package/esm2020/lib/loading-indicator/loading-indicator.component.mjs +31 -0
  23. package/esm2020/lib/loading-indicator-placeholder/loading-indicator-placeholder.component.mjs +38 -0
  24. package/esm2020/lib/message/message.component.mjs +402 -0
  25. package/esm2020/lib/message-actions-box/message-actions-box.component.mjs +98 -0
  26. package/esm2020/lib/message-actions.service.mjs +119 -0
  27. package/esm2020/lib/message-bounce-prompt/message-bounce-prompt.component.mjs +71 -0
  28. package/esm2020/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.mjs +259 -0
  29. package/{esm2015/lib/message-input/emoji-input.service.js → esm2020/lib/message-input/emoji-input.service.mjs} +3 -3
  30. package/{esm2015/lib/message-input/message-input-config.service.js → esm2020/lib/message-input/message-input-config.service.mjs} +3 -3
  31. package/esm2020/lib/message-input/message-input.component.mjs +441 -0
  32. package/{esm2015/lib/message-input/textarea/textarea.component.js → esm2020/lib/message-input/textarea/textarea.component.mjs} +7 -13
  33. package/esm2020/lib/message-input/textarea.directive.mjs +89 -0
  34. package/esm2020/lib/message-list/group-styles.mjs +52 -0
  35. package/esm2020/lib/message-list/message-list.component.mjs +679 -0
  36. package/esm2020/lib/message-preview.mjs +21 -0
  37. package/esm2020/lib/message-reactions/message-reactions.component.mjs +247 -0
  38. package/esm2020/lib/message-reactions.service.mjs +44 -0
  39. package/{esm2015/lib/message.service.js → esm2020/lib/message.service.mjs} +4 -4
  40. package/esm2020/lib/modal/modal.component.mjs +69 -0
  41. package/esm2020/lib/notification/notification.component.mjs +20 -0
  42. package/esm2020/lib/notification-list/notification-list.component.mjs +36 -0
  43. package/esm2020/lib/notification.service.mjs +79 -0
  44. package/esm2020/lib/read-by.mjs +12 -0
  45. package/{esm2015/lib/stream-autocomplete-textarea.module.js → esm2020/lib/stream-autocomplete-textarea.module.mjs} +6 -6
  46. package/{esm2015/lib/stream-avatar.module.js → esm2020/lib/stream-avatar.module.mjs} +5 -5
  47. package/{esm2015/lib/stream-chat.module.js → esm2020/lib/stream-chat.module.mjs} +14 -16
  48. package/{esm2015/lib/stream-i18n.service.js → esm2020/lib/stream-i18n.service.mjs} +5 -5
  49. package/{esm2015/lib/stream-textarea.module.js → esm2020/lib/stream-textarea.module.mjs} +6 -6
  50. package/esm2020/lib/theme.service.mjs +23 -0
  51. package/esm2020/lib/thread/thread.component.mjs +51 -0
  52. package/{esm2015/lib/transliteration.service.js → esm2020/lib/transliteration.service.mjs} +3 -3
  53. package/esm2020/lib/types.mjs +2 -0
  54. package/esm2020/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.mjs +183 -0
  55. package/esm2020/lib/voice-recording/voice-recording.component.mjs +102 -0
  56. package/esm2020/public-api.mjs +64 -0
  57. package/fesm2015/{stream-chat-angular.js → stream-chat-angular.mjs} +354 -754
  58. package/fesm2015/stream-chat-angular.mjs.map +1 -0
  59. package/fesm2020/stream-chat-angular.mjs +6835 -0
  60. package/fesm2020/stream-chat-angular.mjs.map +1 -0
  61. package/lib/attachment-list/attachment-list.component.d.ts +4 -6
  62. package/lib/attachment-preview-list/attachment-preview-list.component.d.ts +2 -4
  63. package/lib/attachment.service.d.ts +0 -1
  64. package/lib/avatar/avatar.component.d.ts +1 -1
  65. package/lib/avatar-placeholder/avatar-placeholder.component.d.ts +1 -1
  66. package/lib/channel/channel.component.d.ts +1 -1
  67. package/lib/channel-header/channel-header.component.d.ts +2 -5
  68. package/lib/channel-list/channel-list.component.d.ts +4 -9
  69. package/lib/channel-preview/channel-preview.component.d.ts +1 -1
  70. package/lib/channel.service.d.ts +7 -14
  71. package/lib/chat-client.service.d.ts +1 -1
  72. package/lib/edit-message-form/edit-message-form.component.d.ts +1 -1
  73. package/lib/get-message-translation.d.ts +1 -1
  74. package/lib/icon/icon.component.d.ts +1 -1
  75. package/lib/icon-placeholder/icon-placeholder.component.d.ts +1 -1
  76. package/lib/loading-indicator/loading-indicator.component.d.ts +1 -1
  77. package/lib/loading-indicator-placeholder/loading-indicator-placeholder.component.d.ts +1 -1
  78. package/lib/message/message.component.d.ts +6 -19
  79. package/lib/message-actions-box/message-actions-box.component.d.ts +4 -32
  80. package/lib/message-actions.service.d.ts +0 -1
  81. package/lib/message-bounce-prompt/message-bounce-prompt.component.d.ts +1 -1
  82. package/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.d.ts +1 -2
  83. package/lib/message-input/message-input.component.d.ts +3 -5
  84. package/lib/message-input/textarea/textarea.component.d.ts +1 -1
  85. package/lib/message-input/textarea.directive.d.ts +1 -1
  86. package/lib/message-list/group-styles.d.ts +1 -1
  87. package/lib/message-list/message-list.component.d.ts +4 -12
  88. package/lib/message-reactions/message-reactions.component.d.ts +2 -7
  89. package/lib/message.service.d.ts +0 -1
  90. package/lib/modal/modal.component.d.ts +1 -1
  91. package/lib/notification/notification.component.d.ts +1 -1
  92. package/lib/notification-list/notification-list.component.d.ts +2 -3
  93. package/lib/notification.service.d.ts +2 -5
  94. package/lib/stream-chat.module.d.ts +3 -3
  95. package/lib/theme.service.d.ts +1 -44
  96. package/lib/thread/thread.component.d.ts +1 -1
  97. package/lib/types.d.ts +16 -33
  98. package/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.d.ts +2 -2
  99. package/lib/voice-recording/voice-recording.component.d.ts +1 -1
  100. package/package.json +31 -17
  101. package/public-api.d.ts +0 -2
  102. package/src/assets/styles/css/index.css +3 -1
  103. package/src/assets/styles/css/index.layout.css +3 -0
  104. package/src/assets/styles/{v2/scss → scss}/AttachmentList/AttachmentList-layout.scss +1 -1
  105. package/src/assets/styles/{v2/scss → scss}/Message/Message-layout.scss +2 -2
  106. package/src/assets/styles/scss/_base.scss +7 -198
  107. package/src/assets/styles/scss/index.scss +35 -48
  108. package/src/assets/version.ts +1 -1
  109. package/bundles/stream-chat-angular.umd.js +0 -8445
  110. package/bundles/stream-chat-angular.umd.js.map +0 -1
  111. package/esm2015/lib/attachment-configuration.service.js +0 -186
  112. package/esm2015/lib/attachment-list/attachment-list.component.js +0 -209
  113. package/esm2015/lib/attachment-preview-list/attachment-preview-list.component.js +0 -49
  114. package/esm2015/lib/attachment.service.js +0 -276
  115. package/esm2015/lib/avatar/avatar.component.js +0 -172
  116. package/esm2015/lib/avatar-placeholder/avatar-placeholder.component.js +0 -78
  117. package/esm2015/lib/channel/channel.component.js +0 -50
  118. package/esm2015/lib/channel-header/channel-header.component.js +0 -86
  119. package/esm2015/lib/channel-list/channel-list-toggle.service.js +0 -73
  120. package/esm2015/lib/channel-list/channel-list.component.js +0 -67
  121. package/esm2015/lib/channel-preview/channel-preview.component.js +0 -167
  122. package/esm2015/lib/channel.service.js +0 -1487
  123. package/esm2015/lib/chat-client.service.js +0 -211
  124. package/esm2015/lib/edit-message-form/edit-message-form.component.js +0 -87
  125. package/esm2015/lib/get-channel-display-text.js +0 -15
  126. package/esm2015/lib/get-message-translation.js +0 -13
  127. package/esm2015/lib/icon/icon.component.js +0 -25
  128. package/esm2015/lib/icon-placeholder/icon-placeholder.component.js +0 -35
  129. package/esm2015/lib/loading-indicator/loading-indicator.component.js +0 -35
  130. package/esm2015/lib/loading-indicator-placeholder/loading-indicator-placeholder.component.js +0 -42
  131. package/esm2015/lib/message/message.component.js +0 -436
  132. package/esm2015/lib/message-actions-box/message-actions-box.component.js +0 -137
  133. package/esm2015/lib/message-actions.service.js +0 -114
  134. package/esm2015/lib/message-bounce-prompt/message-bounce-prompt.component.js +0 -80
  135. package/esm2015/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.js +0 -262
  136. package/esm2015/lib/message-input/message-input.component.js +0 -455
  137. package/esm2015/lib/message-input/textarea.directive.js +0 -90
  138. package/esm2015/lib/message-list/group-styles.js +0 -53
  139. package/esm2015/lib/message-list/image-load.service.js +0 -24
  140. package/esm2015/lib/message-list/message-list.component.js +0 -726
  141. package/esm2015/lib/message-preview.js +0 -7
  142. package/esm2015/lib/message-reactions/message-reactions.component.js +0 -266
  143. package/esm2015/lib/message-reactions.service.js +0 -45
  144. package/esm2015/lib/modal/modal.component.js +0 -74
  145. package/esm2015/lib/notification/notification.component.js +0 -24
  146. package/esm2015/lib/notification-list/notification-list.component.js +0 -38
  147. package/esm2015/lib/notification.service.js +0 -79
  148. package/esm2015/lib/read-by.js +0 -13
  149. package/esm2015/lib/theme.service.js +0 -122
  150. package/esm2015/lib/thread/thread.component.js +0 -55
  151. package/esm2015/lib/types.js +0 -2
  152. package/esm2015/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.js +0 -192
  153. package/esm2015/lib/voice-recording/voice-recording.component.js +0 -115
  154. package/esm2015/public-api.js +0 -66
  155. package/fesm2015/stream-chat-angular.js.map +0 -1
  156. package/lib/channel-list/channel-list-toggle.service.d.ts +0 -40
  157. package/lib/message-list/image-load.service.d.ts +0 -15
  158. package/src/assets/EmojiOneColor.woff2 +0 -0
  159. package/src/assets/NotoColorEmoji-flags.woff2 +0 -0
  160. package/src/assets/Poweredby_100px-White_VertText.png +0 -0
  161. package/src/assets/str-chat__alert.svg +0 -1
  162. package/src/assets/str-chat__file-file.svg +0 -20
  163. package/src/assets/str-chat__icon-chevron-down.svg +0 -1
  164. package/src/assets/str-chat__icon-search.svg +0 -1
  165. package/src/assets/str-chat__icon-send.svg +0 -1
  166. package/src/assets/str-chat__icon-sprite.png +0 -0
  167. package/src/assets/str-chat__icon-sprite@1x.png +0 -0
  168. package/src/assets/str-chat__icon-sprite@2x.png +0 -0
  169. package/src/assets/str-chat__icon-sprite@3x.png +0 -0
  170. package/src/assets/str-chat__loading-indicator.svg +0 -23
  171. package/src/assets/str-chat__reaction-list-sprite@1x.png +0 -0
  172. package/src/assets/str-chat__reaction-list-sprite@2x.png +0 -0
  173. package/src/assets/str-chat__reaction-list-sprite@3x.png +0 -0
  174. package/src/assets/str-chat__reactions-sprite@1x.png +0 -0
  175. package/src/assets/str-chat__reactions-sprite@2x.png +0 -0
  176. package/src/assets/str-chat__reactions-sprite@3x.png +0 -0
  177. package/src/assets/styles/assets/EmojiOneColor.woff2 +0 -0
  178. package/src/assets/styles/assets/NotoColorEmoji-flags.woff2 +0 -0
  179. package/src/assets/styles/assets/Poweredby_100px-White_VertText.png +0 -0
  180. package/src/assets/styles/assets/str-chat__reaction-list-sprite@1x.png +0 -0
  181. package/src/assets/styles/assets/str-chat__reaction-list-sprite@2x.png +0 -0
  182. package/src/assets/styles/assets/str-chat__reaction-list-sprite@3x.png +0 -0
  183. package/src/assets/styles/scss/ActionsBox.scss +0 -56
  184. package/src/assets/styles/scss/Attachment.scss +0 -329
  185. package/src/assets/styles/scss/AttachmentActions.scss +0 -44
  186. package/src/assets/styles/scss/Audio.scss +0 -113
  187. package/src/assets/styles/scss/Avatar.scss +0 -79
  188. package/src/assets/styles/scss/Card.scss +0 -125
  189. package/src/assets/styles/scss/ChannelHeader.scss +0 -284
  190. package/src/assets/styles/scss/ChannelList.scss +0 -141
  191. package/src/assets/styles/scss/ChannelListMessenger.scss +0 -9
  192. package/src/assets/styles/scss/ChannelPreview.scss +0 -133
  193. package/src/assets/styles/scss/ChannelSearch.scss +0 -124
  194. package/src/assets/styles/scss/ChatDown.scss +0 -15
  195. package/src/assets/styles/scss/DateSeparator.scss +0 -51
  196. package/src/assets/styles/scss/EditMessageForm.scss +0 -112
  197. package/src/assets/styles/scss/EventComponent.scss +0 -48
  198. package/src/assets/styles/scss/Gallery.scss +0 -121
  199. package/src/assets/styles/scss/ImageCarousel.scss +0 -45
  200. package/src/assets/styles/scss/InfiniteScrollPaginator.scss +0 -6
  201. package/src/assets/styles/scss/LoadMoreButton.scss +0 -44
  202. package/src/assets/styles/scss/LoadingChannels.scss +0 -70
  203. package/src/assets/styles/scss/LoadingIndicator.scss +0 -38
  204. package/src/assets/styles/scss/Message.scss +0 -1283
  205. package/src/assets/styles/scss/MessageActions.scss +0 -137
  206. package/src/assets/styles/scss/MessageCommerce.scss +0 -608
  207. package/src/assets/styles/scss/MessageInput.scss +0 -398
  208. package/src/assets/styles/scss/MessageInputFlat.scss +0 -323
  209. package/src/assets/styles/scss/MessageList.scss +0 -244
  210. package/src/assets/styles/scss/MessageLivestream.scss +0 -338
  211. package/src/assets/styles/scss/MessageNotification.scss +0 -43
  212. package/src/assets/styles/scss/MessageRepliesCountButton.scss +0 -33
  213. package/src/assets/styles/scss/MessageTeam.scss +0 -644
  214. package/src/assets/styles/scss/Modal.scss +0 -78
  215. package/src/assets/styles/scss/ReactionList.scss +0 -197
  216. package/src/assets/styles/scss/ReactionSelector.scss +0 -218
  217. package/src/assets/styles/scss/SendButton.scss +0 -20
  218. package/src/assets/styles/scss/SimpleReactionsList.scss +0 -76
  219. package/src/assets/styles/scss/SmallMessageInput.scss +0 -171
  220. package/src/assets/styles/scss/Thread.scss +0 -381
  221. package/src/assets/styles/scss/Tooltip.scss +0 -41
  222. package/src/assets/styles/scss/TypingIndicator.scss +0 -80
  223. package/src/assets/styles/scss/VirtualMessage.scss +0 -288
  224. package/src/assets/styles/scss/_variables.scss +0 -161
  225. package/src/assets/styles/v2/css/index.css +0 -3
  226. package/src/assets/styles/v2/css/index.layout.css +0 -3
  227. package/src/assets/styles/v2/scss/_base.scss +0 -28
  228. package/src/assets/styles/v2/scss/index.scss +0 -37
  229. package/src/assets/styles/vendor/emoji-mart.scss +0 -514
  230. package/src/assets/styles/vendor/mml-react.scss +0 -2246
  231. package/src/assets/styles/vendor/react-file-utils.scss +0 -441
  232. package/src/assets/styles/vendor/react-image-gallery.scss +0 -237
  233. /package/{esm2015/assets/i18n/en.js → esm2020/assets/i18n/en.mjs} +0 -0
  234. /package/{esm2015/lib/injection-tokens.js → esm2020/lib/injection-tokens.mjs} +0 -0
  235. /package/{esm2015/lib/is-image-attachment.js → esm2020/lib/is-image-attachment.mjs} +0 -0
  236. /package/{esm2015/lib/is-image-file.js → esm2020/lib/is-image-file.mjs} +0 -0
  237. /package/{esm2015/lib/is-on-separate-date.js → esm2020/lib/is-on-separate-date.mjs} +0 -0
  238. /package/{esm2015/lib/list-users.js → esm2020/lib/list-users.mjs} +0 -0
  239. /package/{esm2015/lib/message-input/textarea.interface.js → esm2020/lib/message-input/textarea.interface.mjs} +0 -0
  240. /package/{esm2015/lib/parse-date.js → esm2020/lib/parse-date.mjs} +0 -0
  241. /package/{esm2015/stream-chat-angular.js → esm2020/stream-chat-angular.mjs} +0 -0
  242. /package/{stream-chat-angular.d.ts → index.d.ts} +0 -0
  243. /package/src/assets/styles/{v2/css → css}/emoji-mart.css +0 -0
  244. /package/src/assets/styles/{v2/css → css}/emoji-replacement.css +0 -0
  245. /package/src/assets/styles/{v2/scss → scss}/AttachmentList/AttachmentList-theme.scss +0 -0
  246. /package/src/assets/styles/{v2/scss → scss}/AttachmentPreviewList/AttachmentPreviewList-layout.scss +0 -0
  247. /package/src/assets/styles/{v2/scss → scss}/AttachmentPreviewList/AttachmentPreviewList-theme.scss +0 -0
  248. /package/src/assets/styles/{v2/scss → scss}/Autocomplete/Autocomplete-layout.scss +0 -0
  249. /package/src/assets/styles/{v2/scss → scss}/Autocomplete/Autocomplete-theme.scss +0 -0
  250. /package/src/assets/styles/{v2/scss → scss}/Avatar/Avatar-layout.scss +0 -0
  251. /package/src/assets/styles/{v2/scss → scss}/Avatar/Avatar-theme.scss +0 -0
  252. /package/src/assets/styles/{v2/scss → scss}/BaseImage/BaseImage-layout.scss +0 -0
  253. /package/src/assets/styles/{v2/scss → scss}/BaseImage/BaseImage-theme.scss +0 -0
  254. /package/src/assets/styles/{v2/scss → scss}/BaseImage/index.scss +0 -0
  255. /package/src/assets/styles/{v2/scss → scss}/Channel/Channel-layout.scss +0 -0
  256. /package/src/assets/styles/{v2/scss → scss}/Channel/Channel-theme.scss +0 -0
  257. /package/src/assets/styles/{v2/scss → scss}/ChannelHeader/ChannelHeader-layout.scss +0 -0
  258. /package/src/assets/styles/{v2/scss → scss}/ChannelHeader/ChannelHeader-theme.scss +0 -0
  259. /package/src/assets/styles/{v2/scss → scss}/ChannelList/ChannelList-layout.scss +0 -0
  260. /package/src/assets/styles/{v2/scss → scss}/ChannelList/ChannelList-theme.scss +0 -0
  261. /package/src/assets/styles/{v2/scss → scss}/ChannelPreview/ChannelPreview-layout.scss +0 -0
  262. /package/src/assets/styles/{v2/scss → scss}/ChannelPreview/ChannelPreview-theme.scss +0 -0
  263. /package/src/assets/styles/{v2/scss → scss}/ChannelSearch/ChannelSearch-layout.scss +0 -0
  264. /package/src/assets/styles/{v2/scss → scss}/ChannelSearch/ChannelSearch-theme.scss +0 -0
  265. /package/src/assets/styles/{v2/scss → scss}/EditMessageForm/EditMessageForm-layout.scss +0 -0
  266. /package/src/assets/styles/{v2/scss → scss}/EditMessageForm/EditMessageForm-theme.scss +0 -0
  267. /package/src/assets/styles/{v2/scss → scss}/ImageCarousel/ImageCarousel-layout.scss +0 -0
  268. /package/src/assets/styles/{v2/scss → scss}/ImageCarousel/ImageCarousel-theme.scss +0 -0
  269. /package/src/assets/styles/{v2/scss → scss}/LinkPreview/LinkPreview-layout.scss +0 -0
  270. /package/src/assets/styles/{v2/scss → scss}/LinkPreview/LinkPreview-theme.scss +0 -0
  271. /package/src/assets/styles/{v2/scss → scss}/LinkPreview/index.scss +0 -0
  272. /package/src/assets/styles/{v2/scss → scss}/LoadingIndicator/LoadingIndicator-layout.scss +0 -0
  273. /package/src/assets/styles/{v2/scss → scss}/LoadingIndicator/LoadingIndicator-theme.scss +0 -0
  274. /package/src/assets/styles/{v2/scss → scss}/Message/Message-theme.scss +0 -0
  275. /package/src/assets/styles/{v2/scss → scss}/MessageActionsBox/MessageActionsBox-layout.scss +0 -0
  276. /package/src/assets/styles/{v2/scss → scss}/MessageActionsBox/MessageActionsBox-theme.scss +0 -0
  277. /package/src/assets/styles/{v2/scss → scss}/MessageBouncePrompt/MessageBouncePrompt-layout.scss +0 -0
  278. /package/src/assets/styles/{v2/scss → scss}/MessageBouncePrompt/MessageBouncePrompt-theme.scss +0 -0
  279. /package/src/assets/styles/{v2/scss → scss}/MessageInput/MessageInput-layout.scss +0 -0
  280. /package/src/assets/styles/{v2/scss → scss}/MessageInput/MessageInput-theme.scss +0 -0
  281. /package/src/assets/styles/{v2/scss → scss}/MessageList/MessageList-layout.scss +0 -0
  282. /package/src/assets/styles/{v2/scss → scss}/MessageList/MessageList-theme.scss +0 -0
  283. /package/src/assets/styles/{v2/scss → scss}/MessageList/VirtualizedMessageList-layout.scss +0 -0
  284. /package/src/assets/styles/{v2/scss → scss}/MessageList/VirtualizedMessageList-theme.scss +0 -0
  285. /package/src/assets/styles/{v2/scss → scss}/MessageReactions/MessageReactions-layout.scss +0 -0
  286. /package/src/assets/styles/{v2/scss → scss}/MessageReactions/MessageReactions-theme.scss +0 -0
  287. /package/src/assets/styles/{v2/scss → scss}/MessageReactions/MessageReactionsSelector-layout.scss +0 -0
  288. /package/src/assets/styles/{v2/scss → scss}/MessageReactions/MessageReactionsSelector-theme.scss +0 -0
  289. /package/src/assets/styles/{v2/scss → scss}/Modal/Modal-layout.scss +0 -0
  290. /package/src/assets/styles/{v2/scss → scss}/Modal/Modal-theme.scss +0 -0
  291. /package/src/assets/styles/{v2/scss → scss}/Notification/MessageNotification-layout.scss +0 -0
  292. /package/src/assets/styles/{v2/scss → scss}/Notification/MessageNotification-theme.scss +0 -0
  293. /package/src/assets/styles/{v2/scss → scss}/Notification/Notification-layout.scss +0 -0
  294. /package/src/assets/styles/{v2/scss → scss}/Notification/Notification-theme.scss +0 -0
  295. /package/src/assets/styles/{v2/scss → scss}/Notification/NotificationList-layout.scss +0 -0
  296. /package/src/assets/styles/{v2/scss → scss}/Notification/NotificationList-theme.scss +0 -0
  297. /package/src/assets/styles/{v2/scss → scss}/Thread/Thread-layout.scss +0 -0
  298. /package/src/assets/styles/{v2/scss → scss}/Thread/Thread-theme.scss +0 -0
  299. /package/src/assets/styles/{v2/scss → scss}/Tooltip/Tooltip-layout.scss +0 -0
  300. /package/src/assets/styles/{v2/scss → scss}/Tooltip/Tooltip-theme.scss +0 -0
  301. /package/src/assets/styles/{v2/scss → scss}/TypingIndicator/TypingIndicator-layout.scss +0 -0
  302. /package/src/assets/styles/{v2/scss → scss}/TypingIndicator/TypingIndicator-theme.scss +0 -0
  303. /package/src/assets/styles/{v2/scss → scss}/_emoji-replacement.scss +0 -0
  304. /package/src/assets/styles/{v2/scss → scss}/_global-layout-variables.scss +0 -0
  305. /package/src/assets/styles/{v2/scss → scss}/_global-theme-variables.scss +0 -0
  306. /package/src/assets/styles/{v2/scss → scss}/_icons.scss +0 -0
  307. /package/src/assets/styles/{v2/scss → scss}/_palette-variables.scss +0 -0
  308. /package/src/assets/styles/{v2/scss → scss}/_utils.scss +0 -0
  309. /package/src/assets/styles/{v2/scss → scss}/common/CTAButton/CTAButton-layout.scss +0 -0
  310. /package/src/assets/styles/{v2/scss → scss}/common/CTAButton/CTAButton-theme.scss +0 -0
  311. /package/src/assets/styles/{v2/scss → scss}/common/CircleFAButton/CircleFAButton-layout.scss +0 -0
  312. /package/src/assets/styles/{v2/scss → scss}/common/CircleFAButton/CircleFAButton-theme.scss +0 -0
  313. /package/src/assets/styles/{v2/scss → scss}/index.layout.scss +0 -0
  314. /package/src/assets/styles/{v2/scss → scss}/vendor/emoji-mart.scss +0 -0
  315. /package/src/assets/styles/{v2/scss → scss}/vendor/react-image-gallery.scss +0 -0
@@ -0,0 +1,679 @@
1
+ import { ChangeDetectionStrategy, Component, HostBinding, Input, ViewChild, } from '@angular/core';
2
+ import { filter, map, tap } from 'rxjs/operators';
3
+ import { getGroupStyles } from './group-styles';
4
+ import { listUsers } from '../list-users';
5
+ import { isOnSeparateDate } from '../is-on-separate-date';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "../channel.service";
8
+ import * as i2 from "../chat-client.service";
9
+ import * as i3 from "../custom-templates.service";
10
+ import * as i4 from "../date-parser.service";
11
+ import * as i5 from "@angular/common";
12
+ import * as i6 from "../message/message.component";
13
+ import * as i7 from "../loading-indicator/loading-indicator.component";
14
+ import * as i8 from "../icon/icon.component";
15
+ import * as i9 from "../icon-placeholder/icon-placeholder.component";
16
+ import * as i10 from "@ngx-translate/core";
17
+ /**
18
+ * The `MessageList` component renders a scrollable list of messages.
19
+ */
20
+ export class MessageListComponent {
21
+ constructor(channelService, chatClientService, customTemplatesService, dateParser, ngZone, cdRef) {
22
+ this.channelService = channelService;
23
+ this.chatClientService = chatClientService;
24
+ this.customTemplatesService = customTemplatesService;
25
+ this.dateParser = dateParser;
26
+ this.ngZone = ngZone;
27
+ this.cdRef = cdRef;
28
+ /**
29
+ * Determines if the message list should display channel messages or [thread messages](https://getstream.io/chat/docs/javascript/threads/?language=javascript).
30
+ */
31
+ this.mode = 'main';
32
+ /**
33
+ * The direction of the messages in the list, `bottom-to-top` means newest message is at the bottom of the message list and users scroll upwards to load older messages
34
+ */
35
+ this.direction = 'bottom-to-top';
36
+ /**
37
+ * Determines what triggers the appearance of the message options: by default you can hover (click on mobile) anywhere in the row of the message (`message-row` option), or you can set `message-bubble`, in that case only a hover (click on mobile) in the message bubble will trigger the options to appear.
38
+ */
39
+ this.messageOptionsTrigger = 'message-row';
40
+ /**
41
+ * You can hide the "jump to latest" button while scrolling. A potential use-case for this input would be to [workaround a known issue on iOS Safar webview](https://github.com/GetStream/stream-chat-angular/issues/418)
42
+ *
43
+ */
44
+ this.hideJumpToLatestButtonDuringScroll = false;
45
+ /**
46
+ * If `true` date separators will be displayed
47
+ */
48
+ this.displayDateSeparator = true;
49
+ /**
50
+ * If `true` unread indicator will be displayed
51
+ */
52
+ this.displayUnreadSeparator = true;
53
+ /**
54
+ * If date separators are displayed, you can set the horizontal position of the date text.
55
+ */
56
+ this.dateSeparatorTextPos = 'center';
57
+ /**
58
+ * `last-message` option will open the message list at the last message, `last-read-message` will open the list at the last unread message. This option only works if mode is `main`.
59
+ */
60
+ this.openMessageListAt = 'last-message';
61
+ /**
62
+ * If the user has unread messages when they open the channel the UI shows the unread indicator / notification which features the unread count by default. This count will be increased every time a user receives a new message. If you don't want to show the unread count, you can turn that off.
63
+ *
64
+ * This is only applicable for `main` mode, as threads doesn't have read infromation.
65
+ */
66
+ this.hideUnreadCountForNotificationAndIndicator = false;
67
+ /**
68
+ * You can turn on and off the loading indicator that signals to users that more messages are being loaded to the message list
69
+ */
70
+ this.displayLoadingIndicator = true;
71
+ this.emptyMainMessageListTemplate = null;
72
+ this.emptyThreadMessageListTemplate = null;
73
+ this.enabledMessageActions = [];
74
+ this.isEmpty = true;
75
+ this.newMessageCountWhileBeingScrolled = 0;
76
+ this.groupStyles = [];
77
+ this.isNextMessageOnSeparateDate = [];
78
+ this.isLoading = false;
79
+ this.isUnreadNotificationVisible = true;
80
+ this.isJumpingToLatestUnreadMessage = false;
81
+ this.isJumpToLatestButtonVisible = true;
82
+ this.subscriptions = [];
83
+ this.isLatestMessageInList = true;
84
+ this.parsedDates = new Map();
85
+ this.isViewInited = false;
86
+ this.messageNotificationJumpClicked = () => {
87
+ this.jumpToFirstUnreadMessage();
88
+ this.isUnreadNotificationVisible = false;
89
+ };
90
+ this.messageNotificationDismissClicked = () => {
91
+ this.isUnreadNotificationVisible = false;
92
+ };
93
+ this.usersTypingInChannel$ = this.channelService.usersTypingInChannel$;
94
+ this.usersTypingInThread$ = this.channelService.usersTypingInThread$;
95
+ }
96
+ get class() {
97
+ return `str-chat-angular__main-panel-inner str-chat-angular__message-list-host str-chat__main-panel-inner ${this.isEmpty ? 'str-chat-angular__message-list-host--empty' : ''}`;
98
+ }
99
+ ngOnInit() {
100
+ this.subscriptions.push(this.channelService.activeChannel$.subscribe((channel) => {
101
+ this.chatClientService.chatClient?.logger?.('info', `${channel?.cid || 'undefined'} selected`, { tags: `message list ${this.mode}` });
102
+ let isNewChannel = false;
103
+ if (this.channelId !== channel?.id) {
104
+ isNewChannel = true;
105
+ if (this.checkIfUnreadNotificationIsVisibleTimeout) {
106
+ clearTimeout(this.checkIfUnreadNotificationIsVisibleTimeout);
107
+ }
108
+ this.isUnreadNotificationVisible = false;
109
+ this.chatClientService?.chatClient?.logger?.('info', `new channel is different from prev channel, reseting scroll state`, { tags: `message list ${this.mode}` });
110
+ this.parsedDates = new Map();
111
+ this.resetScrollState();
112
+ this.channelId = channel?.id;
113
+ if (this.isViewInited) {
114
+ this.cdRef.detectChanges();
115
+ }
116
+ }
117
+ if (this.mode === 'main') {
118
+ const lastReadMessageId = this.channelService.activeChannelLastReadMessageId;
119
+ const unreadCount = this.channelService.activeChannelUnreadCount;
120
+ if (lastReadMessageId !== this.lastReadMessageId ||
121
+ unreadCount !== this.unreadCount) {
122
+ this.lastReadMessageId = lastReadMessageId;
123
+ this.unreadCount = unreadCount || 0;
124
+ if (isNewChannel && this.lastReadMessageId) {
125
+ if (this.openMessageListAt === 'last-read-message') {
126
+ this.jumpToFirstUnreadMessage();
127
+ }
128
+ else {
129
+ // Wait till messages and the unread banner is rendered
130
+ // If unread banner isn't visible on the screen, we display the unread notificaion
131
+ setTimeout(() => {
132
+ const bannerElement = document.getElementById('stream-chat-new-message-indicator');
133
+ if (!bannerElement ||
134
+ bannerElement?.offsetTop <
135
+ this.scrollContainer?.nativeElement?.scrollHeight -
136
+ this.scrollContainer?.nativeElement?.clientHeight) {
137
+ this.isUnreadNotificationVisible = true;
138
+ if (this.isViewInited) {
139
+ this.cdRef.detectChanges();
140
+ }
141
+ }
142
+ }, 100);
143
+ }
144
+ }
145
+ if (this.isViewInited) {
146
+ this.cdRef.detectChanges();
147
+ }
148
+ }
149
+ }
150
+ else if (this.lastReadMessageId) {
151
+ this.lastReadMessageId = undefined;
152
+ this.unreadCount = 0;
153
+ if (this.isViewInited) {
154
+ this.cdRef.detectChanges();
155
+ }
156
+ }
157
+ const capabilites = channel?.data?.own_capabilities;
158
+ const capabilitesString = [...(capabilites || [])].sort().join('');
159
+ const enabledActionsString = [...(this.enabledMessageActions || [])]
160
+ .sort()
161
+ .join('');
162
+ if (capabilitesString !== enabledActionsString) {
163
+ this.enabledMessageActions = capabilites || [];
164
+ if (this.isViewInited) {
165
+ this.cdRef.detectChanges();
166
+ }
167
+ }
168
+ this.newMessageSubscription?.unsubscribe();
169
+ if (channel) {
170
+ this.newMessageSubscription = channel.on('message.new', (event) => {
171
+ // If we display main channel messages and we're switched to an older message set -> use message.new event to update unread count and detect new messages sent by current user
172
+ if (!event.message ||
173
+ channel.state.messages === channel.state.latestMessages ||
174
+ this.mode === 'thread') {
175
+ return;
176
+ }
177
+ this.newMessageReceived({
178
+ id: event.message.id,
179
+ user: event.message.user,
180
+ created_at: new Date(event.message.created_at || ''),
181
+ });
182
+ });
183
+ }
184
+ }));
185
+ this.subscriptions.push(this.channelService.activeParentMessage$.subscribe((message) => {
186
+ if (message &&
187
+ this.parentMessage &&
188
+ message.id !== this.parentMessage.id &&
189
+ this.mode === 'thread') {
190
+ this.resetScrollState();
191
+ }
192
+ if (this.parentMessage === message) {
193
+ return;
194
+ }
195
+ this.parentMessage = message;
196
+ if (this.isViewInited) {
197
+ this.cdRef.detectChanges();
198
+ }
199
+ }));
200
+ this.subscriptions.push(this.customTemplatesService.messageTemplate$.subscribe((template) => {
201
+ if (this.messageTemplate === template) {
202
+ return;
203
+ }
204
+ this.messageTemplate = template;
205
+ if (this.isViewInited) {
206
+ this.cdRef.detectChanges();
207
+ }
208
+ }));
209
+ this.subscriptions.push(this.customTemplatesService.dateSeparatorTemplate$.subscribe((template) => {
210
+ if (this.customDateSeparatorTemplate === template) {
211
+ return;
212
+ }
213
+ this.customDateSeparatorTemplate = template;
214
+ if (this.isViewInited) {
215
+ this.cdRef.detectChanges();
216
+ }
217
+ }));
218
+ this.subscriptions.push(this.customTemplatesService.newMessagesIndicatorTemplate$.subscribe((template) => {
219
+ if (this.customnewMessagesIndicatorTemplate === template) {
220
+ return;
221
+ }
222
+ this.customnewMessagesIndicatorTemplate = template;
223
+ if (this.isViewInited) {
224
+ this.cdRef.detectChanges();
225
+ }
226
+ }));
227
+ this.subscriptions.push(this.customTemplatesService.newMessagesNotificationTemplate$.subscribe((template) => {
228
+ if (this.customnewMessagesNotificationTemplate === template) {
229
+ return;
230
+ }
231
+ this.customnewMessagesNotificationTemplate = template;
232
+ if (this.isViewInited) {
233
+ this.cdRef.detectChanges();
234
+ }
235
+ }));
236
+ this.subscriptions.push(this.customTemplatesService.typingIndicatorTemplate$.subscribe((template) => {
237
+ if (this.typingIndicatorTemplate === template) {
238
+ return;
239
+ }
240
+ this.typingIndicatorTemplate = template;
241
+ if (this.isViewInited) {
242
+ this.cdRef.detectChanges();
243
+ }
244
+ }));
245
+ this.subscriptions.push(this.channelService.jumpToMessage$
246
+ .pipe(filter((config) => !!config.id))
247
+ .subscribe((config) => {
248
+ let messageId = undefined;
249
+ if (this.mode === 'main') {
250
+ messageId = config.parentId || config.id;
251
+ }
252
+ else if (config.parentId) {
253
+ messageId = config.id;
254
+ }
255
+ this.chatClientService.chatClient?.logger?.('info', `Jumping to ${messageId || ''}`, { tags: `message list ${this.mode}` });
256
+ if (messageId) {
257
+ if (messageId === 'latest') {
258
+ this.scrollToLatestMessage();
259
+ if (this.isViewInited) {
260
+ this.cdRef.detectChanges();
261
+ }
262
+ }
263
+ else {
264
+ if (this.isJumpingToLatestUnreadMessage) {
265
+ this.scrollMessageIntoView(this.firstUnreadMessageId || messageId);
266
+ this.highlightedMessageId =
267
+ this.firstUnreadMessageId || messageId;
268
+ }
269
+ else {
270
+ this.scrollMessageIntoView(messageId);
271
+ this.highlightedMessageId = messageId;
272
+ }
273
+ }
274
+ }
275
+ }));
276
+ this.subscriptions.push(this.customTemplatesService.emptyMainMessageListPlaceholder$.subscribe((template) => {
277
+ const isChanged = this.emptyMainMessageListTemplate !== template;
278
+ this.emptyMainMessageListTemplate = template || null;
279
+ if (isChanged && this.isViewInited) {
280
+ this.cdRef.detectChanges();
281
+ }
282
+ }));
283
+ this.subscriptions.push(this.customTemplatesService.emptyThreadMessageListPlaceholder$.subscribe((template) => {
284
+ const isChanged = this.emptyThreadMessageListTemplate !== template;
285
+ this.emptyThreadMessageListTemplate = template || null;
286
+ if (isChanged && this.isViewInited) {
287
+ this.cdRef.detectChanges();
288
+ }
289
+ }));
290
+ this.setMessages$();
291
+ }
292
+ ngOnChanges(changes) {
293
+ if (changes.mode || changes.direction) {
294
+ this.setMessages$();
295
+ }
296
+ if (changes.direction) {
297
+ if (this.scrollContainer?.nativeElement) {
298
+ this.jumpToLatestMessage();
299
+ }
300
+ }
301
+ }
302
+ ngAfterViewInit() {
303
+ this.isViewInited = true;
304
+ this.ngZone.runOutsideAngular(() => {
305
+ this.scrollContainer.nativeElement.addEventListener('scroll', () => this.scrolled());
306
+ });
307
+ }
308
+ ngAfterViewChecked() {
309
+ if (this.highlightedMessageId) {
310
+ // Turn off programatic scroll adjustments while jump to message is in progress
311
+ this.hasNewMessages = false;
312
+ this.olderMassagesLoaded = false;
313
+ }
314
+ if (this.direction === 'top-to-bottom') {
315
+ if (this.hasNewMessages &&
316
+ (this.isNewMessageSentByUser || !this.isUserScrolled)) {
317
+ this.isLatestMessageInList
318
+ ? this.scrollToTop()
319
+ : this.jumpToLatestMessage();
320
+ this.hasNewMessages = false;
321
+ this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
322
+ }
323
+ }
324
+ else {
325
+ if (this.hasNewMessages) {
326
+ if (!this.isUserScrolled || this.isNewMessageSentByUser) {
327
+ this.chatClientService.chatClient?.logger?.('info', `User has new messages, and not scrolled or sent new messages, therefore we ${this.isLatestMessageInList ? 'scroll' : 'jump'} to latest message`, { tags: `message list ${this.mode}` });
328
+ this.isLatestMessageInList
329
+ ? this.scrollToBottom()
330
+ : this.jumpToLatestMessage();
331
+ }
332
+ this.hasNewMessages = false;
333
+ this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
334
+ }
335
+ else if (this.olderMassagesLoaded) {
336
+ this.chatClientService.chatClient?.logger?.('info', `Older messages are loaded, we preserve the scroll position`, { tags: `message list ${this.mode}` });
337
+ this.preserveScrollbarPosition();
338
+ this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
339
+ this.olderMassagesLoaded = false;
340
+ }
341
+ else if (this.getScrollPosition() !== 'bottom' &&
342
+ !this.isUserScrolled &&
343
+ !this.highlightedMessageId) {
344
+ this.chatClientService.chatClient?.logger?.('info', `Container grew and user didn't scroll therefore we ${this.isLatestMessageInList ? 'scroll' : 'jump'} to latest message`, { tags: `message list ${this.mode}` });
345
+ this.isLatestMessageInList
346
+ ? this.scrollToBottom()
347
+ : this.jumpToLatestMessage();
348
+ this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
349
+ }
350
+ }
351
+ }
352
+ ngOnDestroy() {
353
+ this.subscriptions.forEach((s) => s.unsubscribe());
354
+ this.newMessageSubscription?.unsubscribe();
355
+ if (this.scrollEndTimeout) {
356
+ clearTimeout(this.scrollEndTimeout);
357
+ }
358
+ if (this.checkIfUnreadNotificationIsVisibleTimeout) {
359
+ clearTimeout(this.checkIfUnreadNotificationIsVisibleTimeout);
360
+ }
361
+ if (this.jumpToLatestButtonVisibilityTimeout) {
362
+ clearTimeout(this.jumpToLatestButtonVisibilityTimeout);
363
+ }
364
+ }
365
+ trackByMessageId(index, item) {
366
+ return item.id;
367
+ }
368
+ trackByUserId(index, user) {
369
+ return user.id;
370
+ }
371
+ jumpToLatestMessage() {
372
+ void this.channelService.jumpToMessage('latest', this.mode === 'thread' ? this.parentMessage?.id : undefined);
373
+ }
374
+ scrollToBottom() {
375
+ this.scrollContainer.nativeElement.scrollTop =
376
+ this.scrollContainer.nativeElement.scrollHeight + 0.1;
377
+ this.forceRepaint();
378
+ }
379
+ scrollToTop() {
380
+ this.scrollContainer.nativeElement.scrollTop = 0;
381
+ }
382
+ scrolled() {
383
+ if (this.scrollContainer.nativeElement.scrollHeight ===
384
+ this.scrollContainer.nativeElement.clientHeight) {
385
+ return;
386
+ }
387
+ const scrollPosition = this.getScrollPosition();
388
+ this.chatClientService.chatClient?.logger?.('info', `Scrolled - scroll position: ${scrollPosition}, container height: ${this.scrollContainer.nativeElement.scrollHeight}`, { tags: `message list ${this.mode}` });
389
+ const isUserScrolled = (this.direction === 'bottom-to-top'
390
+ ? scrollPosition !== 'bottom'
391
+ : scrollPosition !== 'top') || !this.isLatestMessageInList;
392
+ if (this.isUserScrolled !== isUserScrolled) {
393
+ this.ngZone.run(() => {
394
+ this.isUserScrolled = isUserScrolled;
395
+ if (!this.isUserScrolled) {
396
+ this.newMessageCountWhileBeingScrolled = 0;
397
+ }
398
+ this.cdRef.detectChanges();
399
+ });
400
+ }
401
+ if (this.hideJumpToLatestButtonDuringScroll) {
402
+ if (this.isJumpToLatestButtonVisible) {
403
+ this.isJumpToLatestButtonVisible = false;
404
+ this.cdRef.detectChanges();
405
+ }
406
+ if (this.jumpToLatestButtonVisibilityTimeout) {
407
+ clearTimeout(this.jumpToLatestButtonVisibilityTimeout);
408
+ }
409
+ this.jumpToLatestButtonVisibilityTimeout = setTimeout(() => {
410
+ if (this.isUserScrolled) {
411
+ this.isJumpToLatestButtonVisible = true;
412
+ this.jumpToLatestButtonVisibilityTimeout = undefined;
413
+ this.cdRef.detectChanges();
414
+ }
415
+ }, 100);
416
+ }
417
+ if (this.shouldLoadMoreMessages(scrollPosition)) {
418
+ this.ngZone.run(() => {
419
+ this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
420
+ let direction;
421
+ if (this.direction === 'top-to-bottom') {
422
+ direction = scrollPosition === 'top' ? 'newer' : 'older';
423
+ }
424
+ else {
425
+ direction = scrollPosition === 'top' ? 'older' : 'newer';
426
+ }
427
+ const result = this.mode === 'main'
428
+ ? this.channelService.loadMoreMessages(direction)
429
+ : this.channelService.loadMoreThreadReplies(direction);
430
+ if (result) {
431
+ this.chatClientService.chatClient?.logger?.('info', `Displaying loading indicator`, { tags: `message list ${this.mode}` });
432
+ this.isLoading = true;
433
+ }
434
+ this.cdRef.detectChanges();
435
+ });
436
+ }
437
+ this.prevScrollTop = this.scrollContainer.nativeElement.scrollTop;
438
+ }
439
+ jumpToFirstUnreadMessage() {
440
+ if (!this.lastReadMessageId) {
441
+ return;
442
+ }
443
+ this.isJumpingToLatestUnreadMessage = true;
444
+ void this.channelService.jumpToMessage(this.lastReadMessageId);
445
+ }
446
+ getTypingIndicatorContext() {
447
+ return {
448
+ usersTyping$: this.usersTyping$,
449
+ };
450
+ }
451
+ getTypingIndicatorText(users) {
452
+ const text = listUsers(users);
453
+ return text;
454
+ }
455
+ isSentByCurrentUser(message) {
456
+ if (!message) {
457
+ return false;
458
+ }
459
+ return message.user?.id === this.chatClientService.chatClient.user?.id;
460
+ }
461
+ parseDate(date) {
462
+ if (this.parsedDates.has(date)) {
463
+ return this.parsedDates.get(date);
464
+ }
465
+ const parsedDate = this.dateParser.parseDate(date);
466
+ this.parsedDates.set(date, parsedDate);
467
+ return parsedDate;
468
+ }
469
+ get replyCountParam() {
470
+ return { replyCount: this.parentMessage?.reply_count };
471
+ }
472
+ get emptyListTemplate() {
473
+ return this.mode === 'main'
474
+ ? this.emptyMainMessageListTemplate
475
+ : this.emptyThreadMessageListTemplate;
476
+ }
477
+ preserveScrollbarPosition() {
478
+ this.scrollContainer.nativeElement.scrollTop =
479
+ (this.prevScrollTop || 0) +
480
+ (this.scrollContainer.nativeElement.scrollHeight - this.containerHeight);
481
+ }
482
+ forceRepaint() {
483
+ // Solves the issue of empty screen on Safari when scrolling
484
+ this.scrollContainer.nativeElement.style.display = 'none';
485
+ this.scrollContainer.nativeElement.offsetHeight; // no need to store this anywhere, the reference is enough
486
+ this.scrollContainer.nativeElement.style.display = '';
487
+ }
488
+ getScrollPosition() {
489
+ let position = 'middle';
490
+ if (Math.floor(this.scrollContainer.nativeElement.scrollTop) <=
491
+ (this.parentMessageElement?.nativeElement.clientHeight || 0) &&
492
+ (this.prevScrollTop === undefined ||
493
+ this.prevScrollTop >
494
+ (this.parentMessageElement?.nativeElement.clientHeight || 0))) {
495
+ position = 'top';
496
+ }
497
+ else if (Math.ceil(this.scrollContainer.nativeElement.scrollTop) +
498
+ this.scrollContainer.nativeElement.clientHeight >=
499
+ this.scrollContainer.nativeElement.scrollHeight) {
500
+ position = 'bottom';
501
+ }
502
+ return position;
503
+ }
504
+ shouldLoadMoreMessages(scrollPosition) {
505
+ return scrollPosition !== 'middle' && !this.highlightedMessageId;
506
+ }
507
+ setMessages$() {
508
+ this.messages$ = (this.mode === 'main'
509
+ ? this.channelService.activeChannelMessages$
510
+ : this.channelService.activeThreadMessages$).pipe(tap((messages) => {
511
+ this.isLoading = false;
512
+ if (messages.length === 0) {
513
+ this.chatClientService.chatClient?.logger?.('info', `Empty messages array, reseting scroll state`, {
514
+ tags: `message list ${this.mode}`,
515
+ });
516
+ this.resetScrollState();
517
+ return;
518
+ }
519
+ if (this.isEmpty) {
520
+ // cdRef.detectChanges() isn't enough here, test will fail
521
+ setTimeout(() => (this.isEmpty = false), 0);
522
+ }
523
+ this.chatClientService.chatClient?.logger?.('info', `Received one or more messages`, {
524
+ tags: `message list ${this.mode}`,
525
+ });
526
+ const currentLatestMessageInState = messages[messages.length - 1];
527
+ this.newMessageReceived(currentLatestMessageInState);
528
+ const currentOldestMessage = messages[0];
529
+ if (!this.oldestMessage ||
530
+ !messages.find((m) => m.id === this.oldestMessage.id)) {
531
+ this.oldestMessage = currentOldestMessage;
532
+ }
533
+ else if (this.oldestMessage.created_at.getTime() >
534
+ currentOldestMessage.created_at.getTime()) {
535
+ this.oldestMessage = currentOldestMessage;
536
+ this.olderMassagesLoaded = true;
537
+ }
538
+ }), tap((messages) => {
539
+ if (this.isJumpingToLatestUnreadMessage &&
540
+ !this.firstUnreadMessageId &&
541
+ this.lastReadMessageId) {
542
+ const lastReadIndex = messages.findIndex((m) => m.id === this.lastReadMessageId);
543
+ this.firstUnreadMessageId =
544
+ messages[lastReadIndex + 1]?.id || this.lastReadMessageId;
545
+ }
546
+ }), tap((messages) => (this.lastSentMessageId = [...messages]
547
+ .reverse()
548
+ .find((m) => m.user?.id === this.chatClientService.chatClient?.user?.id &&
549
+ m.status !== 'sending')?.id)), tap((messages) => {
550
+ this.isLatestMessageInList =
551
+ !this.latestMessage ||
552
+ messages.length === 0 ||
553
+ messages[messages.length - 1].id === this.latestMessage.id ||
554
+ this.mode === 'thread';
555
+ if (!this.isLatestMessageInList) {
556
+ this.isUserScrolled = true;
557
+ }
558
+ }), map((messages) => this.direction === 'bottom-to-top' ? messages : [...messages].reverse()), tap((messages) => {
559
+ this.groupStyles = messages.map((m, i) => getGroupStyles(m, messages[i - 1], messages[i + 1], {
560
+ lastReadMessageId: this.lastReadMessageId,
561
+ }));
562
+ this.isNextMessageOnSeparateDate = messages.map((m, i) => this.checkIfOnSeparateDates(m, messages[i + 1]));
563
+ }));
564
+ }
565
+ resetScrollState() {
566
+ this.isEmpty = true;
567
+ this.latestMessage = undefined;
568
+ this.hasNewMessages = true;
569
+ this.isUserScrolled = false;
570
+ this.containerHeight = undefined;
571
+ this.olderMassagesLoaded = false;
572
+ this.oldestMessage = undefined;
573
+ this.newMessageCountWhileBeingScrolled = 0;
574
+ this.prevScrollTop = undefined;
575
+ this.isNewMessageSentByUser = undefined;
576
+ this.isLatestMessageInList = true;
577
+ }
578
+ get usersTyping$() {
579
+ return this.mode === 'thread'
580
+ ? this.usersTypingInThread$
581
+ : this.usersTypingInChannel$;
582
+ }
583
+ scrollMessageIntoView(messageId, withRetry = true) {
584
+ const element = document.getElementById(messageId);
585
+ if (!element && withRetry) {
586
+ // If the message was newly inserted into activeChannelMessages$, the message will be rendered after the current change detection cycle -> wait for this cycle to complete
587
+ setTimeout(() => this.scrollMessageIntoView(messageId, false));
588
+ }
589
+ else if (element) {
590
+ element.scrollIntoView({
591
+ block: 'center',
592
+ });
593
+ setTimeout(() => {
594
+ this.highlightedMessageId = undefined;
595
+ this.firstUnreadMessageId = undefined;
596
+ this.isJumpingToLatestUnreadMessage = false;
597
+ this.cdRef.detectChanges();
598
+ }, 1000);
599
+ }
600
+ }
601
+ scrollToLatestMessage(withRetry = true) {
602
+ if (document.getElementById(this.latestMessage.id)) {
603
+ this.direction === 'bottom-to-top'
604
+ ? this.scrollToBottom()
605
+ : this.scrollToTop();
606
+ }
607
+ else if (withRetry) {
608
+ // If the message was newly inserted into activeChannelMessages$, the message will be rendered after the current change detection cycle -> wait for this cycle to complete
609
+ setTimeout(() => this.scrollToLatestMessage(false), 0);
610
+ }
611
+ }
612
+ newMessageReceived(message) {
613
+ const latestMessages = this.channelService.activeChannel?.state?.latestMessages;
614
+ if (!this.latestMessage ||
615
+ this.latestMessage.created_at?.getTime() < message.created_at.getTime() ||
616
+ (this.mode === 'main' &&
617
+ latestMessages &&
618
+ this.latestMessage &&
619
+ latestMessages[latestMessages.length - 1]?.id !== this.latestMessage.id)) {
620
+ this.chatClientService.chatClient?.logger?.('info', `Received new message`, { tags: `message list ${this.mode}` });
621
+ const isNewChannel = !this.latestMessage;
622
+ this.latestMessage = message;
623
+ this.hasNewMessages = true;
624
+ this.isNewMessageSentByUser =
625
+ message.user?.id === this.chatClientService.chatClient?.user?.id;
626
+ if (this.isUserScrolled) {
627
+ this.newMessageCountWhileBeingScrolled++;
628
+ }
629
+ if (!this.isNewMessageSentByUser &&
630
+ this.unreadCount !== undefined &&
631
+ !isNewChannel) {
632
+ this.unreadCount++;
633
+ }
634
+ this.cdRef.detectChanges();
635
+ }
636
+ }
637
+ checkIfOnSeparateDates(message, nextMessage) {
638
+ if (!message || !nextMessage) {
639
+ return false;
640
+ }
641
+ return isOnSeparateDate(message.created_at, nextMessage.created_at);
642
+ }
643
+ }
644
+ MessageListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MessageListComponent, deps: [{ token: i1.ChannelService }, { token: i2.ChatClientService }, { token: i3.CustomTemplatesService }, { token: i4.DateParserService }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
645
+ MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: MessageListComponent, selector: "stream-message-list", inputs: { mode: "mode", direction: "direction", messageOptionsTrigger: "messageOptionsTrigger", hideJumpToLatestButtonDuringScroll: "hideJumpToLatestButtonDuringScroll", displayDateSeparator: "displayDateSeparator", displayUnreadSeparator: "displayUnreadSeparator", dateSeparatorTextPos: "dateSeparatorTextPos", openMessageListAt: "openMessageListAt", hideUnreadCountForNotificationAndIndicator: "hideUnreadCountForNotificationAndIndicator", displayLoadingIndicator: "displayLoadingIndicator" }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }, { propertyName: "parentMessageElement", first: true, predicate: ["parentMessageElement"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container\n *ngIf=\"\n lastReadMessageId &&\n isUnreadNotificationVisible &&\n openMessageListAt === 'last-message' &&\n displayUnreadSeparator\n \"\n>\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesNotificationTemplate ||\n defaultUnreadMessagesNotification;\n context: {\n unreadCount: unreadCount,\n onDismiss: messageNotificationDismissClicked,\n onJump: messageNotificationJumpClicked\n }\n \"\n ></ng-container>\n</ng-container>\n<ng-template\n #defaultUnreadMessagesNotification\n let-unreadCount=\"unreadCount\"\n let-onDismiss=\"onDismiss\"\n let-onJump=\"onJump\"\n>\n <div\n class=\"str-chat__unread-messages-notification\"\n data-testid=\"unread-messages-notification\"\n >\n <button\n data-testid=\"unread-messages-notification-jump-to-message\"\n (click)=\"onJump()\"\n >\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </button>\n <button\n data-testid=\"unread-messages-notification-dismiss\"\n (click)=\"onDismiss()\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n<div #scrollContainer data-testid=\"scroll-container\" class=\"str-chat__list\">\n <ng-container *ngIf=\"mode === 'main' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <div class=\"str-chat__reverse-infinite-scroll str-chat__message-list-scroll\">\n <ul\n class=\"str-chat__ul\"\n [class.str-chat__message-options-in-bubble]=\"\n messageOptionsTrigger === 'message-bubble'\n \"\n >\n <li\n *ngIf=\"mode === 'thread' && parentMessage\"\n #parentMessageElement\n data-testid=\"parent-message\"\n class=\"str-chat__parent-message-li\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage, index: 'parent' }\n \"\n ></ng-container>\n <div data-testid=\"reply-count\" class=\"str-chat__thread-start\">\n {{parentMessage.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </div>\n </li>\n <ng-container *ngIf=\"mode === 'thread' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <stream-loading-indicator\n *ngIf=\"\n isLoading && direction === 'bottom-to-top' && displayLoadingIndicator\n \"\n data-testid=\"top-loading-indicator\"\n ></stream-loading-indicator>\n <ng-container *ngIf=\"messages$ | async as messages\">\n <ng-container\n *ngFor=\"\n let message of messages;\n let i = index;\n let isFirst = first;\n let isLast = last;\n trackBy: trackByMessageId\n \"\n >\n <ng-container *ngIf=\"isFirst\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: message.created_at,\n parsedDate: parseDate(message.created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n <li\n tabindex=\"0\"\n data-testclass=\"message\"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n id=\"{{ message.id }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message, index: i }\n \"\n ></ng-container>\n </li>\n <ng-container\n *ngIf=\"\n (lastReadMessageId === message?.id &&\n direction === 'bottom-to-top') ||\n (direction === 'top-to-bottom' &&\n lastReadMessageId === messages[i + 1]?.id)\n \"\n >\n <li\n *ngIf=\"displayUnreadSeparator\"\n id=\"stream-chat-new-message-indicator\"\n data-testid=\"new-messages-indicator\"\n class=\"str-chat__li str-chat__unread-messages-separator-wrapper\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesIndicatorTemplate ||\n defaultNewMessagesIndicator;\n context: { unreadCount: unreadCount }\n \"\n ></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"isNextMessageOnSeparateDate[i]\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: messages[i + 1].created_at,\n parsedDate: parseDate(messages[i + 1].created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ng-container>\n <stream-loading-indicator\n *ngIf=\"\n isLoading && direction === 'top-to-bottom' && displayLoadingIndicator\n \"\n data-testid=\"bottom-loading-indicator\"\n ></stream-loading-indicator>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <!-- eslint-disable-next-line @angular-eslint/template/no-any -->\n <ng-container *ngIf=\"$any(usersTyping$ | async) as users\">\n <div\n *ngIf=\"users.length > 0\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <div class=\"str-chat__typing-indicator__dots\">\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n </div>\n <div\n data-testid=\"typing-users\"\n class=\"str-chat__typing-indicator__users\"\n >\n {{\n users.length === 1\n ? (\"streamChat.user is typing\"\n | translate: { user: getTypingIndicatorText(users) })\n : (\"streamChat.users are typing\"\n | translate: { users: getTypingIndicatorText(users) })\n }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate || defaultTypingIndicator;\n context: getTypingIndicatorContext()\n \"\n ></ng-container>\n </div>\n</div>\n<div class=\"str-chat__jump-to-latest-message\">\n <button\n *ngIf=\"isUserScrolled && isJumpToLatestButtonVisible\"\n data-testid=\"scroll-to-latest\"\n class=\"\n str-chat__message-notification-scroll-to-latest\n str-chat__message-notification-scroll-to-latest-right\n str-chat__circle-fab\n \"\n (keyup.enter)=\"jumpToLatestMessage()\"\n (click)=\"jumpToLatestMessage()\"\n >\n <stream-icon\n class=\"str-chat__jump-to-latest-icon str-chat__circle-fab-icon\"\n [icon]=\"direction === 'bottom-to-top' ? 'arrow-down' : 'arrow-up'\"\n ></stream-icon>\n <div\n *ngIf=\"newMessageCountWhileBeingScrolled > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-to-latest-unread-count\n str-chat__jump-to-latest-unread-count\n \"\n >\n {{ newMessageCountWhileBeingScrolled }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\" let-index=\"index\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n let-isHighlighted=\"isHighlighted\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n [isHighlighted]=\"isHighlighted\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: {\n message: message,\n isLastSentMessage: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n enabledMessageActions: enabledMessageActions,\n mode: mode,\n isHighlighted: message?.id === highlightedMessageId\n }\n \"\n ></ng-container>\n</ng-template>\n\n<ng-template #dateSeparator let-date=\"date\" let-parsedDate=\"parsedDate\">\n <ng-container *ngIf=\"displayDateSeparator\">\n <ng-container\n *ngTemplateOutlet=\"\n customDateSeparatorTemplate || defaultDateSeparator;\n context: {\n date: date,\n parsedDate: parsedDate\n }\n \"\n ></ng-container>\n </ng-container>\n\n <ng-template\n #defaultDateSeparator\n let-date=\"date\"\n let-parsedDate=\"parsedDate\"\n >\n <div data-testid=\"date-separator\" class=\"str-chat__date-separator\">\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'right' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n <div class=\"str-chat__date-separator-date\">\n {{ parsedDate }}\n </div>\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'left' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n </div>\n </ng-template>\n</ng-template>\n\n<ng-template #defaultNewMessagesIndicator let-unreadCount=\"unreadCount\">\n <div class=\"str-chat__unread-messages-separator\">\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i6.MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "isLastSentMessage", "mode", "isHighlighted"] }, { kind: "component", type: i7.LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }, { kind: "component", type: i8.IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { kind: "component", type: i9.IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i10.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
646
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MessageListComponent, decorators: [{
647
+ type: Component,
648
+ args: [{ selector: 'stream-message-list', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container\n *ngIf=\"\n lastReadMessageId &&\n isUnreadNotificationVisible &&\n openMessageListAt === 'last-message' &&\n displayUnreadSeparator\n \"\n>\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesNotificationTemplate ||\n defaultUnreadMessagesNotification;\n context: {\n unreadCount: unreadCount,\n onDismiss: messageNotificationDismissClicked,\n onJump: messageNotificationJumpClicked\n }\n \"\n ></ng-container>\n</ng-container>\n<ng-template\n #defaultUnreadMessagesNotification\n let-unreadCount=\"unreadCount\"\n let-onDismiss=\"onDismiss\"\n let-onJump=\"onJump\"\n>\n <div\n class=\"str-chat__unread-messages-notification\"\n data-testid=\"unread-messages-notification\"\n >\n <button\n data-testid=\"unread-messages-notification-jump-to-message\"\n (click)=\"onJump()\"\n >\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </button>\n <button\n data-testid=\"unread-messages-notification-dismiss\"\n (click)=\"onDismiss()\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n<div #scrollContainer data-testid=\"scroll-container\" class=\"str-chat__list\">\n <ng-container *ngIf=\"mode === 'main' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <div class=\"str-chat__reverse-infinite-scroll str-chat__message-list-scroll\">\n <ul\n class=\"str-chat__ul\"\n [class.str-chat__message-options-in-bubble]=\"\n messageOptionsTrigger === 'message-bubble'\n \"\n >\n <li\n *ngIf=\"mode === 'thread' && parentMessage\"\n #parentMessageElement\n data-testid=\"parent-message\"\n class=\"str-chat__parent-message-li\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage, index: 'parent' }\n \"\n ></ng-container>\n <div data-testid=\"reply-count\" class=\"str-chat__thread-start\">\n {{parentMessage.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </div>\n </li>\n <ng-container *ngIf=\"mode === 'thread' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <stream-loading-indicator\n *ngIf=\"\n isLoading && direction === 'bottom-to-top' && displayLoadingIndicator\n \"\n data-testid=\"top-loading-indicator\"\n ></stream-loading-indicator>\n <ng-container *ngIf=\"messages$ | async as messages\">\n <ng-container\n *ngFor=\"\n let message of messages;\n let i = index;\n let isFirst = first;\n let isLast = last;\n trackBy: trackByMessageId\n \"\n >\n <ng-container *ngIf=\"isFirst\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: message.created_at,\n parsedDate: parseDate(message.created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n <li\n tabindex=\"0\"\n data-testclass=\"message\"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n id=\"{{ message.id }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message, index: i }\n \"\n ></ng-container>\n </li>\n <ng-container\n *ngIf=\"\n (lastReadMessageId === message?.id &&\n direction === 'bottom-to-top') ||\n (direction === 'top-to-bottom' &&\n lastReadMessageId === messages[i + 1]?.id)\n \"\n >\n <li\n *ngIf=\"displayUnreadSeparator\"\n id=\"stream-chat-new-message-indicator\"\n data-testid=\"new-messages-indicator\"\n class=\"str-chat__li str-chat__unread-messages-separator-wrapper\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesIndicatorTemplate ||\n defaultNewMessagesIndicator;\n context: { unreadCount: unreadCount }\n \"\n ></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"isNextMessageOnSeparateDate[i]\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: messages[i + 1].created_at,\n parsedDate: parseDate(messages[i + 1].created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ng-container>\n <stream-loading-indicator\n *ngIf=\"\n isLoading && direction === 'top-to-bottom' && displayLoadingIndicator\n \"\n data-testid=\"bottom-loading-indicator\"\n ></stream-loading-indicator>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <!-- eslint-disable-next-line @angular-eslint/template/no-any -->\n <ng-container *ngIf=\"$any(usersTyping$ | async) as users\">\n <div\n *ngIf=\"users.length > 0\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <div class=\"str-chat__typing-indicator__dots\">\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n </div>\n <div\n data-testid=\"typing-users\"\n class=\"str-chat__typing-indicator__users\"\n >\n {{\n users.length === 1\n ? (\"streamChat.user is typing\"\n | translate: { user: getTypingIndicatorText(users) })\n : (\"streamChat.users are typing\"\n | translate: { users: getTypingIndicatorText(users) })\n }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate || defaultTypingIndicator;\n context: getTypingIndicatorContext()\n \"\n ></ng-container>\n </div>\n</div>\n<div class=\"str-chat__jump-to-latest-message\">\n <button\n *ngIf=\"isUserScrolled && isJumpToLatestButtonVisible\"\n data-testid=\"scroll-to-latest\"\n class=\"\n str-chat__message-notification-scroll-to-latest\n str-chat__message-notification-scroll-to-latest-right\n str-chat__circle-fab\n \"\n (keyup.enter)=\"jumpToLatestMessage()\"\n (click)=\"jumpToLatestMessage()\"\n >\n <stream-icon\n class=\"str-chat__jump-to-latest-icon str-chat__circle-fab-icon\"\n [icon]=\"direction === 'bottom-to-top' ? 'arrow-down' : 'arrow-up'\"\n ></stream-icon>\n <div\n *ngIf=\"newMessageCountWhileBeingScrolled > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-to-latest-unread-count\n str-chat__jump-to-latest-unread-count\n \"\n >\n {{ newMessageCountWhileBeingScrolled }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\" let-index=\"index\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n let-isHighlighted=\"isHighlighted\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n [isHighlighted]=\"isHighlighted\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: {\n message: message,\n isLastSentMessage: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n enabledMessageActions: enabledMessageActions,\n mode: mode,\n isHighlighted: message?.id === highlightedMessageId\n }\n \"\n ></ng-container>\n</ng-template>\n\n<ng-template #dateSeparator let-date=\"date\" let-parsedDate=\"parsedDate\">\n <ng-container *ngIf=\"displayDateSeparator\">\n <ng-container\n *ngTemplateOutlet=\"\n customDateSeparatorTemplate || defaultDateSeparator;\n context: {\n date: date,\n parsedDate: parsedDate\n }\n \"\n ></ng-container>\n </ng-container>\n\n <ng-template\n #defaultDateSeparator\n let-date=\"date\"\n let-parsedDate=\"parsedDate\"\n >\n <div data-testid=\"date-separator\" class=\"str-chat__date-separator\">\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'right' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n <div class=\"str-chat__date-separator-date\">\n {{ parsedDate }}\n </div>\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'left' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n </div>\n </ng-template>\n</ng-template>\n\n<ng-template #defaultNewMessagesIndicator let-unreadCount=\"unreadCount\">\n <div class=\"str-chat__unread-messages-separator\">\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </div>\n</ng-template>\n" }]
649
+ }], ctorParameters: function () { return [{ type: i1.ChannelService }, { type: i2.ChatClientService }, { type: i3.CustomTemplatesService }, { type: i4.DateParserService }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { mode: [{
650
+ type: Input
651
+ }], direction: [{
652
+ type: Input
653
+ }], messageOptionsTrigger: [{
654
+ type: Input
655
+ }], hideJumpToLatestButtonDuringScroll: [{
656
+ type: Input
657
+ }], displayDateSeparator: [{
658
+ type: Input
659
+ }], displayUnreadSeparator: [{
660
+ type: Input
661
+ }], dateSeparatorTextPos: [{
662
+ type: Input
663
+ }], openMessageListAt: [{
664
+ type: Input
665
+ }], hideUnreadCountForNotificationAndIndicator: [{
666
+ type: Input
667
+ }], displayLoadingIndicator: [{
668
+ type: Input
669
+ }], scrollContainer: [{
670
+ type: ViewChild,
671
+ args: ['scrollContainer']
672
+ }], parentMessageElement: [{
673
+ type: ViewChild,
674
+ args: ['parentMessageElement']
675
+ }], class: [{
676
+ type: HostBinding,
677
+ args: ['class']
678
+ }] } });
679
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZS1saXN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3N0cmVhbS1jaGF0LWFuZ3VsYXIvc3JjL2xpYi9tZXNzYWdlLWxpc3QvbWVzc2FnZS1saXN0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3N0cmVhbS1jaGF0LWFuZ3VsYXIvc3JjL2xpYi9tZXNzYWdlLWxpc3QvbWVzc2FnZS1saXN0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFHTCx1QkFBdUIsRUFFdkIsU0FBUyxFQUVULFdBQVcsRUFDWCxLQUFLLEVBT0wsU0FBUyxHQUNWLE1BQU0sZUFBZSxDQUFDO0FBR3ZCLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBV2xELE9BQU8sRUFBRSxjQUFjLEVBQWMsTUFBTSxnQkFBZ0IsQ0FBQztBQUc1RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTFDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDOzs7Ozs7Ozs7Ozs7QUFFMUQ7O0dBRUc7QUFPSCxNQUFNLE9BQU8sb0JBQW9CO0lBZ0gvQixZQUNVLGNBQThCLEVBQzlCLGlCQUFvQyxFQUNwQyxzQkFBOEMsRUFDOUMsVUFBNkIsRUFDN0IsTUFBYyxFQUNkLEtBQXdCO1FBTHhCLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQUM5QixzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQ3BDLDJCQUFzQixHQUF0QixzQkFBc0IsQ0FBd0I7UUFDOUMsZUFBVSxHQUFWLFVBQVUsQ0FBbUI7UUFDN0IsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUNkLFVBQUssR0FBTCxLQUFLLENBQW1CO1FBbkhsQzs7V0FFRztRQUNNLFNBQUksR0FBc0IsTUFBTSxDQUFDO1FBQzFD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QUFJLENBQUMsT0FBTyxJQUFJLENBQUMsV0FBVyxFQUFFO1lBQzVCLE9BQU8sS0FBSyxDQUFDO1NBQ2Q7UUFDRCxPQUFPLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7O2lIQS8wQlUsb0JBQW9CO3FHQUFwQixvQkFBb0IsbzFCQzlDakMsMnlWQXlVQTsyRkQzUmEsb0JBQW9CO2tCQU5oQyxTQUFTOytCQUNFLHFCQUFxQixtQkFHZCx1QkFBdUIsQ0FBQyxNQUFNOytQQVF0QyxJQUFJO3NCQUFaLEtBQUs7Z0JBSUcsU0FBUztzQkFBakIsS0FBSztnQkFJRyxxQkFBcUI7c0JBQTdCLEtBQUs7Z0JBTUcsa0NBQWtDO3NCQUExQyxLQUFLO2dCQUlHLG9CQUFvQjtzQkFBNUIsS0FBSztnQkFJRyxzQkFBc0I7c0JBQTlCLEtBQUs7Z0JBSUcsb0JBQW9CO3NCQUE1QixLQUFLO2dCQUlHLGlCQUFpQjtzQkFBekIsS0FBSztnQkFPRywwQ0FBMEM7c0JBQWxELEtBQUs7Z0JBSUcsdUJBQXVCO3NCQUEvQixLQUFLO2dCQStCRSxlQUFlO3NCQUR0QixTQUFTO3VCQUFDLGlCQUFpQjtnQkFHcEIsb0JBQW9CO3NCQUQzQixTQUFTO3VCQUFDLHNCQUFzQjtnQkEyQnJCLEtBQUs7c0JBRGhCLFdBQVc7dUJBQUMsT0FBTyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyVmlld0NoZWNrZWQsXG4gIEFmdGVyVmlld0luaXQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBIb3N0QmluZGluZyxcbiAgSW5wdXQsXG4gIE5nWm9uZSxcbiAgT25DaGFuZ2VzLFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVGVtcGxhdGVSZWYsXG4gIFZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDaGFubmVsU2VydmljZSB9IGZyb20gJy4uL2NoYW5uZWwuc2VydmljZSc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGZpbHRlciwgbWFwLCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge1xuICBNZXNzYWdlQ29udGV4dCxcbiAgRGVmYXVsdFN0cmVhbUNoYXRHZW5lcmljcyxcbiAgU3RyZWFtTWVzc2FnZSxcbiAgVHlwaW5nSW5kaWNhdG9yQ29udGV4dCxcbiAgRGF0ZVNlcGFyYXRvckNvbnRleHQsXG4gIFVucmVhZE1lc3NhZ2VzTm90aWZpY2F0aW9uQ29udGV4dCxcbiAgVW5yZWFkTWVzc2FnZXNJbmRpY2F0b3JDb250ZXh0LFxufSBmcm9tICcuLi90eXBlcyc7XG5pbXBvcnQgeyBDaGF0Q2xpZW50U2VydmljZSB9IGZyb20gJy4uL2NoYXQtY2xpZW50LnNlcnZpY2UnO1xuaW1wb3J0IHsgZ2V0R3JvdXBTdHlsZXMsIEdyb3VwU3R5bGUgfSBmcm9tICcuL2dyb3VwLXN0eWxlcyc7XG5pbXBvcnQgeyBVc2VyUmVzcG9uc2UgfSBmcm9tICdzdHJlYW0tY2hhdCc7XG5pbXBvcnQgeyBDdXN0b21UZW1wbGF0ZXNTZXJ2aWNlIH0gZnJvbSAnLi4vY3VzdG9tLXRlbXBsYXRlcy5zZXJ2aWNlJztcbmltcG9ydCB7IGxpc3RVc2VycyB9IGZyb20gJy4uL2xpc3QtdXNlcnMnO1xuaW1wb3J0IHsgRGF0ZVBhcnNlclNlcnZpY2UgfSBmcm9tICcuLi9kYXRlLXBhcnNlci5zZXJ2aWNlJztcbmltcG9ydCB7IGlzT25TZXBhcmF0ZURhdGUgfSBmcm9tICcuLi9pcy1vbi1zZXBhcmF0ZS1kYXRlJztcblxuLyoqXG4gKiBUaGUgYE1lc3NhZ2VMaXN0YCBjb21wb25lbnQgcmVuZGVycyBhIHNjcm9sbGFibGUgbGlzdCBvZiBtZXNzYWdlcy5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnc3RyZWFtLW1lc3NhZ2UtbGlzdCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9tZXNzYWdlLWxpc3QuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZXM6IFtdLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgTWVzc2FnZUxpc3RDb21wb25lbnRcbiAgaW1wbGVtZW50cyBBZnRlclZpZXdDaGVja2VkLCBPbkNoYW5nZXMsIE9uSW5pdCwgT25EZXN0cm95LCBBZnRlclZpZXdJbml0XG57XG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIHRoZSBtZXNzYWdlIGxpc3Qgc2hvdWxkIGRpc3BsYXkgY2hhbm5lbCBtZXNzYWdlcyBvciBbdGhyZWFkIG1lc3NhZ2VzXShodHRwczovL2dldHN0cmVhbS5pby9jaGF0L2RvY3MvamF2YXNjcmlwdC90aHJlYWRzLz9sYW5ndWFnZT1qYXZhc2NyaXB0KS5cbiAgICovXG4gIEBJbnB1dCgpIG1vZGU6ICdtYWluJyB8ICd0aHJlYWQnID0gJ21haW4nO1xuICAvKipcbiAgICogVGhlIGRpcmVjdGlvbiBvZiB0aGUgbWVzc2FnZXMgaW4gdGhlIGxpc3QsIGBib3R0b20tdG8tdG9wYCBtZWFucyBuZXdlc3QgbWVzc2FnZSBpcyBhdCB0aGUgYm90dG9tIG9mIHRoZSBtZXNzYWdlIGxpc3QgYW5kIHVzZXJzIHNjcm9sbCB1cHdhcmRzIHRvIGxvYWQgb2xkZXIgbWVzc2FnZXNcbiAgICovXG4gIEBJbnB1dCgpIGRpcmVjdGlvbjogJ2JvdHRvbS10by10b3AnIHwgJ3RvcC10by1ib3R0b20nID0gJ2JvdHRvbS10by10b3AnO1xuICAvKipcbiAgICogRGV0ZXJtaW5lcyB3aGF0IHRyaWdnZXJzIHRoZSBhcHBlYXJhbmNlIG9mIHRoZSBtZXNzYWdlIG9wdGlvbnM6IGJ5IGRlZmF1bHQgeW91IGNhbiBob3ZlciAoY2xpY2sgb24gbW9iaWxlKSBhbnl3aGVyZSBpbiB0aGUgcm93IG9mIHRoZSBtZXNzYWdlIChgbWVzc2FnZS1yb3dgIG9wdGlvbiksIG9yIHlvdSBjYW4gc2V0IGBtZXNzYWdlLWJ1YmJsZWAsIGluIHRoYXQgY2FzZSBvbmx5IGEgaG92ZXIgKGNsaWNrIG9uIG1vYmlsZSkgaW4gdGhlIG1lc3NhZ2UgYnViYmxlIHdpbGwgdHJpZ2dlciB0aGUgb3B0aW9ucyB0byBhcHBlYXIuXG4gICAqL1xuICBASW5wdXQoKSBtZXNzYWdlT3B0aW9uc1RyaWdnZXI6ICdtZXNzYWdlLXJvdycgfCAnbWVzc2FnZS1idWJibGUnID1cbiAgICAnbWVzc2FnZS1yb3cnO1xuICAvKipcbiAgICogWW91IGNhbiBoaWRlIHRoZSBcImp1bXAgdG8gbGF0ZXN0XCIgYnV0dG9uIHdoaWxlIHNjcm9sbGluZy4gQSBwb3RlbnRpYWwgdXNlLWNhc2UgZm9yIHRoaXMgaW5wdXQgd291bGQgYmUgdG8gW3dvcmthcm91bmQgYSBrbm93biBpc3N1ZSBvbiBpT1MgU2FmYXIgd2Vidmlld10oaHR0cHM6Ly9naXRodWIuY29tL0dldFN0cmVhbS9zdHJlYW0tY2hhdC1hbmd1bGFyL2lzc3Vlcy80MTgpXG4gICAqXG4gICAqL1xuICBASW5wdXQoKSBoaWRlSnVtcFRvTGF0ZXN0QnV0dG9uRHVyaW5nU2Nyb2xsID0gZmFsc2U7XG4gIC8qKlxuICAgKiBJZiBgdHJ1ZWAgZGF0ZSBzZXBhcmF0b3JzIHdpbGwgYmUgZGlzcGxheWVkXG4gICAqL1xuICBASW5wdXQoKSBkaXNwbGF5RGF0ZVNlcGFyYXRvciA9IHRydWU7XG4gIC8qKlxuICAgKiBJZiBgdHJ1ZWAgdW5yZWFkIGluZGljYXRvciB3aWxsIGJlIGRpc3BsYXllZFxuICAgKi9cbiAgQElucHV0KCkgZGlzcGxheVVucmVhZFNlcGFyYXRvciA9IHRydWU7XG4gIC8qKlxuICAgKiBJZiBkYXRlIHNlcGFyYXRvcnMgYXJlIGRpc3BsYXllZCwgeW91IGNhbiBzZXQgdGhlIGhvcml6b250YWwgcG9zaXRpb24gb2YgdGhlIGRhdGUgdGV4dC5cbiAgICovXG4gIEBJbnB1dCgpIGRhdGVTZXBhcmF0b3JUZXh0UG9zOiAnY2VudGVyJyB8ICdyaWdodCcgfCAnbGVmdCcgPSAnY2VudGVyJztcbiAgLyoqXG4gICAqIGBsYXN0LW1lc3NhZ2VgIG9wdGlvbiB3aWxsIG9wZW4gdGhlIG1lc3NhZ2UgbGlzdCBhdCB0aGUgbGFzdCBtZXNzYWdlLCBgbGFzdC1yZWFkLW1lc3NhZ2VgIHdpbGwgb3BlbiB0aGUgbGlzdCBhdCB0aGUgbGFzdCB1bnJlYWQgbWVzc2FnZS4gVGhpcyBvcHRpb24gb25seSB3b3JrcyBpZiBtb2RlIGlzIGBtYWluYC5cbiAgICovXG4gIEBJbnB1dCgpIG9wZW5NZXNzYWdlTGlzdEF0OiAnbGFzdC1tZXNzYWdlJyB8ICdsYXN0LXJlYWQtbWVzc2FnZScgPVxuICAgICdsYXN0LW1lc3NhZ2UnO1xuICAvKipcbiAgICogSWYgdGhlIHVzZXIgaGFzIHVucmVhZCBtZXNzYWdlcyB3aGVuIHRoZXkgb3BlbiB0aGUgY2hhbm5lbCB0aGUgVUkgc2hvd3MgdGhlIHVucmVhZCBpbmRpY2F0b3IgLyBub3RpZmljYXRpb24gd2hpY2ggZmVhdHVyZXMgdGhlIHVucmVhZCBjb3VudCBieSBkZWZhdWx0LiBUaGlzIGNvdW50IHdpbGwgYmUgaW5jcmVhc2VkIGV2ZXJ5IHRpbWUgYSB1c2VyIHJlY2VpdmVzIGEgbmV3IG1lc3NhZ2UuIElmIHlvdSBkb24ndCB3YW50IHRvIHNob3cgdGhlIHVucmVhZCBjb3VudCwgeW91IGNhbiB0dXJuIHRoYXQgb2ZmLlxuICAgKlxuICAgKiBUaGlzIGlzIG9ubHkgYXBwbGljYWJsZSBmb3IgYG1haW5gIG1vZGUsIGFzIHRocmVhZHMgZG9lc24ndCBoYXZlIHJlYWQgaW5mcm9tYXRpb24uXG4gICAqL1xuICBASW5wdXQoKSBoaWRlVW5yZWFkQ291bnRGb3JOb3RpZmljYXRpb25BbmRJbmRpY2F0b3IgPSBmYWxzZTtcbiAgLyoqXG4gICAqIFlvdSBjYW4gdHVybiBvbiBhbmQgb2ZmIHRoZSBsb2FkaW5nIGluZGljYXRvciB0aGF0IHNpZ25hbHMgdG8gdXNlcnMgdGhhdCBtb3JlIG1lc3NhZ2VzIGFyZSBiZWluZyBsb2FkZWQgdG8gdGhlIG1lc3NhZ2UgbGlzdFxuICAgKi9cbiAgQElucHV0KCkgZGlzcGxheUxvYWRpbmdJbmRpY2F0b3IgPSB0cnVlO1xuICB0eXBpbmdJbmRpY2F0b3JUZW1wbGF0ZTogVGVtcGxhdGVSZWY8VHlwaW5nSW5kaWNhdG9yQ29udGV4dD4gfCB1bmRlZmluZWQ7XG4gIG1lc3NhZ2VUZW1wbGF0ZTogVGVtcGxhdGVSZWY8TWVzc2FnZUNvbnRleHQ+IHwgdW5kZWZpbmVkO1xuICBjdXN0b21EYXRlU2VwYXJhdG9yVGVtcGxhdGU6IFRlbXBsYXRlUmVmPERhdGVTZXBhcmF0b3JDb250ZXh0PiB8IHVuZGVmaW5lZDtcbiAgY3VzdG9tbmV3TWVzc2FnZXNJbmRpY2F0b3JUZW1wbGF0ZTpcbiAgICB8IFRlbXBsYXRlUmVmPFVucmVhZE1lc3NhZ2VzSW5kaWNhdG9yQ29udGV4dD5cbiAgICB8IHVuZGVmaW5lZDtcbiAgY3VzdG9tbmV3TWVzc2FnZXNOb3RpZmljYXRpb25UZW1wbGF0ZTpcbiAgICB8IFRlbXBsYXRlUmVmPFVucmVhZE1lc3NhZ2VzTm90aWZpY2F0aW9uQ29udGV4dD5cbiAgICB8IHVuZGVmaW5lZDtcbiAgZW1wdHlNYWluTWVzc2FnZUxpc3RUZW1wbGF0ZTogVGVtcGxhdGVSZWY8dm9pZD4gfCBudWxsID0gbnVsbDtcbiAgZW1wdHlUaHJlYWRNZXNzYWdlTGlzdFRlbXBsYXRlOiBUZW1wbGF0ZVJlZjx2b2lkPiB8IG51bGwgPSBudWxsO1xuICBtZXNzYWdlcyQhOiBPYnNlcnZhYmxlPFN0cmVhbU1lc3NhZ2VbXT47XG4gIGVuYWJsZWRNZXNzYWdlQWN0aW9uczogc3RyaW5nW10gPSBbXTtcbiAgaXNFbXB0eSA9IHRydWU7XG4gIG5ld01lc3NhZ2VDb3VudFdoaWxlQmVpbmdTY3JvbGxlZCA9IDA7XG4gIGlzVXNlclNjcm9sbGVkOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuICBncm91cFN0eWxlczogR3JvdXBTdHlsZVtdID0gW107XG4gIGlzTmV4dE1lc3NhZ2VPblNlcGFyYXRlRGF0ZTogYm9vbGVhbltdID0gW107XG4gIGxhc3RTZW50TWVzc2FnZUlkOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIHBhcmVudE1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2UgfCB1bmRlZmluZWQ7XG4gIGhpZ2hsaWdodGVkTWVzc2FnZUlkOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGlzTG9hZGluZyA9IGZhbHNlO1xuICBzY3JvbGxFbmRUaW1lb3V0PzogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG4gIGxhc3RSZWFkTWVzc2FnZUlkPzogc3RyaW5nO1xuICBpc1VucmVhZE5vdGlmaWNhdGlvblZpc2libGUgPSB0cnVlO1xuICBmaXJzdFVucmVhZE1lc3NhZ2VJZD86IHN0cmluZztcbiAgdW5yZWFkQ291bnQ/OiBudW1iZXI7XG4gIGlzSnVtcGluZ1RvTGF0ZXN0VW5yZWFkTWVzc2FnZSA9IGZhbHNlO1xuICBpc0p1bXBUb0xhdGVzdEJ1dHRvblZpc2libGUgPSB0cnVlO1xuICBAVmlld0NoaWxkKCdzY3JvbGxDb250YWluZXInKVxuICBwcml2YXRlIHNjcm9sbENvbnRhaW5lciE6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+O1xuICBAVmlld0NoaWxkKCdwYXJlbnRNZXNzYWdlRWxlbWVudCcpXG4gIHByaXZhdGUgcGFyZW50TWVzc2FnZUVsZW1lbnQhOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcbiAgcHJpdmF0ZSBsYXRlc3RNZXNzYWdlOiB7IGlkOiBzdHJpbmc7IGNyZWF0ZWRfYXQ6IERhdGUgfSB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBoYXNOZXdNZXNzYWdlczogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBjb250YWluZXJIZWlnaHQ6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBvbGRlc3RNZXNzYWdlOiB7IGlkOiBzdHJpbmc7IGNyZWF0ZWRfYXQ6IERhdGUgfSB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBvbGRlck1hc3NhZ2VzTG9hZGVkOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIGlzTmV3TWVzc2FnZVNlbnRCeVVzZXI6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW10gPSBbXTtcbiAgcHJpdmF0ZSBuZXdNZXNzYWdlU3Vic2NyaXB0aW9uOiB7IHVuc3Vic2NyaWJlOiAoKSA9PiB2b2lkIH0gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgcHJldlNjcm9sbFRvcDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHVzZXJzVHlwaW5nSW5DaGFubmVsJCE6IE9ic2VydmFibGU8XG4gICAgVXNlclJlc3BvbnNlPERlZmF1bHRTdHJlYW1DaGF0R2VuZXJpY3M+W11cbiAgPjtcbiAgcHJpdmF0ZSB1c2Vyc1R5cGluZ0luVGhyZWFkJCE6IE9ic2VydmFibGU8XG4gICAgVXNlclJlc3BvbnNlPERlZmF1bHRTdHJlYW1DaGF0R2VuZXJpY3M+W11cbiAgPjtcbiAgcHJpdmF0ZSBpc0xhdGVzdE1lc3NhZ2VJbkxpc3QgPSB0cnVlO1xuICBwcml2YXRlIGNoYW5uZWxJZD86IHN0cmluZztcbiAgcHJpdmF0ZSBwYXJzZWREYXRlcyA9IG5ldyBNYXA8RGF0ZSwgc3RyaW5nPigpO1xuICBwcml2YXRlIGlzVmlld0luaXRlZCA9IGZhbHNlO1xuICBwcml2YXRlIGNoZWNrSWZVbnJlYWROb3RpZmljYXRpb25Jc1Zpc2libGVUaW1lb3V0PzogUmV0dXJuVHlwZTxcbiAgICB0eXBlb2Ygc2V0VGltZW91dFxuICA+O1xuICBwcml2YXRlIGp1bXBUb0xhdGVzdEJ1dHRvblZpc2liaWxpdHlUaW1lb3V0PzogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG5cbiAgQEhvc3RCaW5kaW5nKCdjbGFzcycpXG4gIHByaXZhdGUgZ2V0IGNsYXNzKCkge1xuICAgIHJldHVybiBgc3RyLWNoYXQtYW5ndWxhcl9fbWFpbi1wYW5lbC1pbm5lciBzdHItY2hhdC1hbmd1bGFyX19tZXNzYWdlLWxpc3QtaG9zdCBzdHItY2hhdF9fbWFpbi1wYW5lbC1pbm5lciAke1xuICAgICAgdGhpcy5pc0VtcHR5ID8gJ3N0ci1jaGF0LWFuZ3VsYXJfX21lc3NhZ2UtbGlzdC1ob3N0LS1lbXB0eScgOiAnJ1xuICAgIH1gO1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjaGFubmVsU2VydmljZTogQ2hhbm5lbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBjaGF0Q2xpZW50U2VydmljZTogQ2hhdENsaWVudFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBjdXN0b21UZW1wbGF0ZXNTZXJ2aWNlOiBDdXN0b21UZW1wbGF0ZXNTZXJ2aWNlLFxuICAgIHByaXZhdGUgZGF0ZVBhcnNlcjogRGF0ZVBhcnNlclNlcnZpY2UsXG4gICAgcHJpdmF0ZSBuZ1pvbmU6IE5nWm9uZSxcbiAgICBwcml2YXRlIGNkUmVmOiBDaGFuZ2VEZXRlY3RvclJlZlxuICApIHtcbiAgICB0aGlzLnVzZXJzVHlwaW5nSW5DaGFubmVsJCA9IHRoaXMuY2hhbm5lbFNlcnZpY2UudXNlcnNUeXBpbmdJbkNoYW5uZWwkO1xuICAgIHRoaXMudXNlcnNUeXBpbmdJblRocmVhZCQgPSB0aGlzLmNoYW5uZWxTZXJ2aWNlLnVzZXJzVHlwaW5nSW5UaHJlYWQkO1xuICB9XG5cbiAgbWVzc2FnZU5vdGlmaWNhdGlvbkp1bXBDbGlja2VkID0gKCkgPT4ge1xuICAgIHRoaXMuanVtcFRvRmlyc3RVbnJlYWRNZXNzYWdlKCk7XG4gICAgdGhpcy5pc1VucmVhZE5vdGlmaWNhdGlvblZpc2libGUgPSBmYWxzZTtcbiAgfTtcblxuICBtZXNzYWdlTm90aWZpY2F0aW9uRGlzbWlzc0NsaWNrZWQgPSAoKSA9PiB7XG4gICAgdGhpcy5pc1VucmVhZE5vdGlmaWNhdGlvblZpc2libGUgPSBmYWxzZTtcbiAgfTtcblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIHRoaXMuY2hhbm5lbFNlcnZpY2UuYWN0aXZlQ2hhbm5lbCQuc3Vic2NyaWJlKChjaGFubmVsKSA9PiB7XG4gICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudD8ubG9nZ2VyPy4oXG4gICAgICAgICAgJ2luZm8nLFxuICAgICAgICAgIGAke2NoYW5uZWw/LmNpZCB8fCAndW5kZWZpbmVkJ30gc2VsZWN0ZWRgLFxuICAgICAgICAgIHsgdGFnczogYG1lc3NhZ2UgbGlzdCAke3RoaXMubW9kZX1gIH1cbiAgICAgICAgKTtcbiAgICAgICAgbGV0IGlzTmV3Q2hhbm5lbCA9IGZhbHNlO1xuICAgICAgICBpZiAodGhpcy5jaGFubmVsSWQgIT09IGNoYW5uZWw/LmlkKSB7XG4gICAgICAgICAgaXNOZXdDaGFubmVsID0gdHJ1ZTtcbiAgICAgICAgICBpZiAodGhpcy5jaGVja0lmVW5yZWFkTm90aWZpY2F0aW9uSXNWaXNpYmxlVGltZW91dCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuY2hlY2tJZlVucmVhZE5vdGlmaWNhdGlvbklzVmlzaWJsZVRpbWVvdXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmlzVW5yZWFkTm90aWZpY2F0aW9uVmlzaWJsZSA9IGZhbHNlO1xuICAgICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2U/LmNoYXRDbGllbnQ/LmxvZ2dlcj8uKFxuICAgICAgICAgICAgJ2luZm8nLFxuICAgICAgICAgICAgYG5ldyBjaGFubmVsIGlzIGRpZmZlcmVudCBmcm9tIHByZXYgY2hhbm5lbCwgcmVzZXRpbmcgc2Nyb2xsIHN0YXRlYCxcbiAgICAgICAgICAgIHsgdGFnczogYG1lc3NhZ2UgbGlzdCAke3RoaXMubW9kZX1gIH1cbiAgICAgICAgICApO1xuICAgICAgICAgIHRoaXMucGFyc2VkRGF0ZXMgPSBuZXcgTWFwKCk7XG4gICAgICAgICAgdGhpcy5yZXNldFNjcm9sbFN0YXRlKCk7XG4gICAgICAgICAgdGhpcy5jaGFubmVsSWQgPSBjaGFubmVsPy5pZDtcbiAgICAgICAgICBpZiAodGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY2RSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5tb2RlID09PSAnbWFpbicpIHtcbiAgICAgICAgICBjb25zdCBsYXN0UmVhZE1lc3NhZ2VJZCA9XG4gICAgICAgICAgICB0aGlzLmNoYW5uZWxTZXJ2aWNlLmFjdGl2ZUNoYW5uZWxMYXN0UmVhZE1lc3NhZ2VJZDtcbiAgICAgICAgICBjb25zdCB1bnJlYWRDb3VudCA9IHRoaXMuY2hhbm5lbFNlcnZpY2UuYWN0aXZlQ2hhbm5lbFVucmVhZENvdW50O1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIGxhc3RSZWFkTWVzc2FnZUlkICE9PSB0aGlzLmxhc3RSZWFkTWVzc2FnZUlkIHx8XG4gICAgICAgICAgICB1bnJlYWRDb3VudCAhPT0gdGhpcy51bnJlYWRDb3VudFxuICAgICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy5sYXN0UmVhZE1lc3NhZ2VJZCA9IGxhc3RSZWFkTWVzc2FnZUlkO1xuICAgICAgICAgICAgdGhpcy51bnJlYWRDb3VudCA9IHVucmVhZENvdW50IHx8IDA7XG4gICAgICAgICAgICBpZiAoaXNOZXdDaGFubmVsICYmIHRoaXMubGFzdFJlYWRNZXNzYWdlSWQpIHtcbiAgICAgICAgICAgICAgaWYgKHRoaXMub3Blbk1lc3NhZ2VMaXN0QXQgPT09ICdsYXN0LXJlYWQtbWVzc2FnZScpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmp1bXBUb0ZpcnN0VW5yZWFkTWVzc2FnZSgpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIFdhaXQgdGlsbCBtZXNzYWdlcyBhbmQgdGhlIHVucmVhZCBiYW5uZXIgaXMgcmVuZGVyZWRcbiAgICAgICAgICAgICAgICAvLyBJZiB1bnJlYWQgYmFubmVyIGlzbid0IHZpc2libGUgb24gdGhlIHNjcmVlbiwgd2UgZGlzcGxheSB0aGUgdW5yZWFkIG5vdGlmaWNhaW9uXG4gICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBiYW5uZXJFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXG4gICAgICAgICAgICAgICAgICAgICdzdHJlYW0tY2hhdC1uZXctbWVzc2FnZS1pbmRpY2F0b3InXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAhYmFubmVyRWxlbWVudCB8fFxuICAgICAgICAgICAgICAgICAgICBiYW5uZXJFbGVtZW50Py5vZmZzZXRUb3AgPFxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2Nyb2xsQ29udGFpbmVyPy5uYXRpdmVFbGVtZW50Py5zY3JvbGxIZWlnaHQgLVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zY3JvbGxDb250YWluZXI/Lm5hdGl2ZUVsZW1lbnQ/LmNsaWVudEhlaWdodFxuICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaXNVbnJlYWROb3RpZmljYXRpb25WaXNpYmxlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNWaWV3SW5pdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LCAxMDApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMubGFzdFJlYWRNZXNzYWdlSWQpIHtcbiAgICAgICAgICB0aGlzLmxhc3RSZWFkTWVzc2FnZUlkID0gdW5kZWZpbmVkO1xuICAgICAgICAgIHRoaXMudW5yZWFkQ291bnQgPSAwO1xuICAgICAgICAgIGlmICh0aGlzLmlzVmlld0luaXRlZCkge1xuICAgICAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNhcGFiaWxpdGVzID0gY2hhbm5lbD8uZGF0YT8ub3duX2NhcGFiaWxpdGllcyBhcyBzdHJpbmdbXTtcbiAgICAgICAgY29uc3QgY2FwYWJpbGl0ZXNTdHJpbmcgPSBbLi4uKGNhcGFiaWxpdGVzIHx8IFtdKV0uc29ydCgpLmpvaW4oJycpO1xuICAgICAgICBjb25zdCBlbmFibGVkQWN0aW9uc1N0cmluZyA9IFsuLi4odGhpcy5lbmFibGVkTWVzc2FnZUFjdGlvbnMgfHwgW10pXVxuICAgICAgICAgIC5zb3J0KClcbiAgICAgICAgICAuam9pbignJyk7XG4gICAgICAgIGlmIChjYXBhYmlsaXRlc1N0cmluZyAhPT0gZW5hYmxlZEFjdGlvbnNTdHJpbmcpIHtcbiAgICAgICAgICB0aGlzLmVuYWJsZWRNZXNzYWdlQWN0aW9ucyA9IGNhcGFiaWxpdGVzIHx8IFtdO1xuICAgICAgICAgIGlmICh0aGlzLmlzVmlld0luaXRlZCkge1xuICAgICAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMubmV3TWVzc2FnZVN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgaWYgKGNoYW5uZWwpIHtcbiAgICAgICAgICB0aGlzLm5ld01lc3NhZ2VTdWJzY3JpcHRpb24gPSBjaGFubmVsLm9uKCdtZXNzYWdlLm5ldycsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgLy8gSWYgd2UgZGlzcGxheSBtYWluIGNoYW5uZWwgbWVzc2FnZXMgYW5kIHdlJ3JlIHN3aXRjaGVkIHRvIGFuIG9sZGVyIG1lc3NhZ2Ugc2V0IC0+IHVzZSBtZXNzYWdlLm5ldyBldmVudCB0byB1cGRhdGUgdW5yZWFkIGNvdW50IGFuZCBkZXRlY3QgbmV3IG1lc3NhZ2VzIHNlbnQgYnkgY3VycmVudCB1c2VyXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICFldmVudC5tZXNzYWdlIHx8XG4gICAgICAgICAgICAgIGNoYW5uZWwuc3RhdGUubWVzc2FnZXMgPT09IGNoYW5uZWwuc3RhdGUubGF0ZXN0TWVzc2FnZXMgfHxcbiAgICAgICAgICAgICAgdGhpcy5tb2RlID09PSAndGhyZWFkJ1xuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMubmV3TWVzc2FnZVJlY2VpdmVkKHtcbiAgICAgICAgICAgICAgaWQ6IGV2ZW50Lm1lc3NhZ2UuaWQsXG4gICAgICAgICAgICAgIHVzZXI6IGV2ZW50Lm1lc3NhZ2UudXNlcixcbiAgICAgICAgICAgICAgY3JlYXRlZF9hdDogbmV3IERhdGUoZXZlbnQubWVzc2FnZS5jcmVhdGVkX2F0IHx8ICcnKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICk7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICB0aGlzLmNoYW5uZWxTZXJ2aWNlLmFjdGl2ZVBhcmVudE1lc3NhZ2UkLnN1YnNjcmliZSgobWVzc2FnZSkgPT4ge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgbWVzc2FnZSAmJlxuICAgICAgICAgIHRoaXMucGFyZW50TWVzc2FnZSAmJlxuICAgICAgICAgIG1lc3NhZ2UuaWQgIT09IHRoaXMucGFyZW50TWVzc2FnZS5pZCAmJlxuICAgICAgICAgIHRoaXMubW9kZSA9PT0gJ3RocmVhZCdcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGhpcy5yZXNldFNjcm9sbFN0YXRlKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMucGFyZW50TWVzc2FnZSA9PT0gbWVzc2FnZSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnBhcmVudE1lc3NhZ2UgPSBtZXNzYWdlO1xuICAgICAgICBpZiAodGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICB0aGlzLmNkUmVmLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICApO1xuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgdGhpcy5jdXN0b21UZW1wbGF0ZXNTZXJ2aWNlLm1lc3NhZ2VUZW1wbGF0ZSQuc3Vic2NyaWJlKCh0ZW1wbGF0ZSkgPT4ge1xuICAgICAgICBpZiAodGhpcy5tZXNzYWdlVGVtcGxhdGUgPT09IHRlbXBsYXRlKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubWVzc2FnZVRlbXBsYXRlID0gdGVtcGxhdGU7XG4gICAgICAgIGlmICh0aGlzLmlzVmlld0luaXRlZCkge1xuICAgICAgICAgIHRoaXMuY2RSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICk7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICB0aGlzLmN1c3RvbVRlbXBsYXRlc1NlcnZpY2UuZGF0ZVNlcGFyYXRvclRlbXBsYXRlJC5zdWJzY3JpYmUoXG4gICAgICAgICh0ZW1wbGF0ZSkgPT4ge1xuICAgICAgICAgIGlmICh0aGlzLmN1c3RvbURhdGVTZXBhcmF0b3JUZW1wbGF0ZSA9PT0gdGVtcGxhdGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5jdXN0b21EYXRlU2VwYXJhdG9yVGVtcGxhdGUgPSB0ZW1wbGF0ZTtcbiAgICAgICAgICBpZiAodGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY2RSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKVxuICAgICk7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICB0aGlzLmN1c3RvbVRlbXBsYXRlc1NlcnZpY2UubmV3TWVzc2FnZXNJbmRpY2F0b3JUZW1wbGF0ZSQuc3Vic2NyaWJlKFxuICAgICAgICAodGVtcGxhdGUpID0+IHtcbiAgICAgICAgICBpZiAodGhpcy5jdXN0b21uZXdNZXNzYWdlc0luZGljYXRvclRlbXBsYXRlID09PSB0ZW1wbGF0ZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmN1c3RvbW5ld01lc3NhZ2VzSW5kaWNhdG9yVGVtcGxhdGUgPSB0ZW1wbGF0ZTtcbiAgICAgICAgICBpZiAodGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY2RSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKVxuICAgICk7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICB0aGlzLmN1c3RvbVRlbXBsYXRlc1NlcnZpY2UubmV3TWVzc2FnZXNOb3RpZmljYXRpb25UZW1wbGF0ZSQuc3Vic2NyaWJlKFxuICAgICAgICAodGVtcGxhdGUpID0+IHtcbiAgICAgICAgICBpZiAodGhpcy5jdXN0b21uZXdNZXNzYWdlc05vdGlmaWNhdGlvblRlbXBsYXRlID09PSB0ZW1wbGF0ZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmN1c3RvbW5ld01lc3NhZ2VzTm90aWZpY2F0aW9uVGVtcGxhdGUgPSB0ZW1wbGF0ZTtcbiAgICAgICAgICBpZiAodGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY2RSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKVxuICAgICk7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICB0aGlzLmN1c3RvbVRlbXBsYXRlc1NlcnZpY2UudHlwaW5nSW5kaWNhdG9yVGVtcGxhdGUkLnN1YnNjcmliZShcbiAgICAgICAgKHRlbXBsYXRlKSA9PiB7XG4gICAgICAgICAgaWYgKHRoaXMudHlwaW5nSW5kaWNhdG9yVGVtcGxhdGUgPT09IHRlbXBsYXRlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIHRoaXMudHlwaW5nSW5kaWNhdG9yVGVtcGxhdGUgPSB0ZW1wbGF0ZTtcbiAgICAgICAgICBpZiAodGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY2RSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKVxuICAgICk7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICB0aGlzLmNoYW5uZWxTZXJ2aWNlLmp1bXBUb01lc3NhZ2UkXG4gICAgICAgIC5waXBlKGZpbHRlcigoY29uZmlnKSA9PiAhIWNvbmZpZy5pZCkpXG4gICAgICAgIC5zdWJzY3JpYmUoKGNvbmZpZykgPT4ge1xuICAgICAgICAgIGxldCBtZXNzYWdlSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICBpZiAodGhpcy5tb2RlID09PSAnbWFpbicpIHtcbiAgICAgICAgICAgIG1lc3NhZ2VJZCA9IGNvbmZpZy5wYXJlbnRJZCB8fCBjb25maWcuaWQ7XG4gICAgICAgICAgfSBlbHNlIGlmIChjb25maWcucGFyZW50SWQpIHtcbiAgICAgICAgICAgIG1lc3NhZ2VJZCA9IGNvbmZpZy5pZDtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50Py5sb2dnZXI/LihcbiAgICAgICAgICAgICdpbmZvJyxcbiAgICAgICAgICAgIGBKdW1waW5nIHRvICR7bWVzc2FnZUlkIHx8ICcnfWAsXG4gICAgICAgICAgICB7IHRhZ3M6IGBtZXNzYWdlIGxpc3QgJHt0aGlzLm1vZGV9YCB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAobWVzc2FnZUlkKSB7XG4gICAgICAgICAgICBpZiAobWVzc2FnZUlkID09PSAnbGF0ZXN0Jykge1xuICAgICAgICAgICAgICB0aGlzLnNjcm9sbFRvTGF0ZXN0TWVzc2FnZSgpO1xuICAgICAgICAgICAgICBpZiAodGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNkUmVmLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaWYgKHRoaXMuaXNKdW1waW5nVG9MYXRlc3RVbnJlYWRNZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zY3JvbGxNZXNzYWdlSW50b1ZpZXcoXG4gICAgICAgICAgICAgICAgICB0aGlzLmZpcnN0VW5yZWFkTWVzc2FnZUlkIHx8IG1lc3NhZ2VJZFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdGhpcy5oaWdobGlnaHRlZE1lc3NhZ2VJZCA9XG4gICAgICAgICAgICAgICAgICB0aGlzLmZpcnN0VW5yZWFkTWVzc2FnZUlkIHx8IG1lc3NhZ2VJZDtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNjcm9sbE1lc3NhZ2VJbnRvVmlldyhtZXNzYWdlSWQpO1xuICAgICAgICAgICAgICAgIHRoaXMuaGlnaGxpZ2h0ZWRNZXNzYWdlSWQgPSBtZXNzYWdlSWQ7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgKTtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIHRoaXMuY3VzdG9tVGVtcGxhdGVzU2VydmljZS5lbXB0eU1haW5NZXNzYWdlTGlzdFBsYWNlaG9sZGVyJC5zdWJzY3JpYmUoXG4gICAgICAgICh0ZW1wbGF0ZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGlzQ2hhbmdlZCA9IHRoaXMuZW1wdHlNYWluTWVzc2FnZUxpc3RUZW1wbGF0ZSAhPT0gdGVtcGxhdGU7XG4gICAgICAgICAgdGhpcy5lbXB0eU1haW5NZXNzYWdlTGlzdFRlbXBsYXRlID0gdGVtcGxhdGUgfHwgbnVsbDtcbiAgICAgICAgICBpZiAoaXNDaGFuZ2VkICYmIHRoaXMuaXNWaWV3SW5pdGVkKSB7XG4gICAgICAgICAgICB0aGlzLmNkUmVmLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIClcbiAgICApO1xuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgdGhpcy5jdXN0b21UZW1wbGF0ZXNTZXJ2aWNlLmVtcHR5VGhyZWFkTWVzc2FnZUxpc3RQbGFjZWhvbGRlciQuc3Vic2NyaWJlKFxuICAgICAgICAodGVtcGxhdGUpID0+IHtcbiAgICAgICAgICBjb25zdCBpc0NoYW5nZWQgPSB0aGlzLmVtcHR5VGhyZWFkTWVzc2FnZUxpc3RUZW1wbGF0ZSAhPT0gdGVtcGxhdGU7XG4gICAgICAgICAgdGhpcy5lbXB0eVRocmVhZE1lc3NhZ2VMaXN0VGVtcGxhdGUgPSB0ZW1wbGF0ZSB8fCBudWxsO1xuICAgICAgICAgIGlmIChpc0NoYW5nZWQgJiYgdGhpcy5pc1ZpZXdJbml0ZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY2RSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKVxuICAgICk7XG4gICAgdGhpcy5zZXRNZXNzYWdlcyQoKTtcbiAgfVxuXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICBpZiAoY2hhbmdlcy5tb2RlIHx8IGNoYW5nZXMuZGlyZWN0aW9uKSB7XG4gICAgICB0aGlzLnNldE1lc3NhZ2VzJCgpO1xuICAgIH1cbiAgICBpZiAoY2hhbmdlcy5kaXJlY3Rpb24pIHtcbiAgICAgIGlmICh0aGlzLnNjcm9sbENvbnRhaW5lcj8ubmF0aXZlRWxlbWVudCkge1xuICAgICAgICB0aGlzLmp1bXBUb0xhdGVzdE1lc3NhZ2UoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5pc1ZpZXdJbml0ZWQgPSB0cnVlO1xuICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgIHRoaXMuc2Nyb2xsQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgKCkgPT5cbiAgICAgICAgdGhpcy5zY3JvbGxlZCgpXG4gICAgICApO1xuICAgIH0pO1xuICB9XG5cbiAgbmdBZnRlclZpZXdDaGVja2VkKCkge1xuICAgIGlmICh0aGlzLmhpZ2hsaWdodGVkTWVzc2FnZUlkKSB7XG4gICAgICAvLyBUdXJuIG9mZiBwcm9ncmFtYXRpYyBzY3JvbGwgYWRqdXN0bWVudHMgd2hpbGUganVtcCB0byBtZXNzYWdlIGlzIGluIHByb2dyZXNzXG4gICAgICB0aGlzLmhhc05ld01lc3NhZ2VzID0gZmFsc2U7XG4gICAgICB0aGlzLm9sZGVyTWFzc2FnZXNMb2FkZWQgPSBmYWxzZTtcbiAgICB9XG4gICAgaWYgKHRoaXMuZGlyZWN0aW9uID09PSAndG9wLXRvLWJvdHRvbScpIHtcbiAgICAgIGlmIChcbiAgICAgICAgdGhpcy5oYXNOZXdNZXNzYWdlcyAmJlxuICAgICAgICAodGhpcy5pc05ld01lc3NhZ2VTZW50QnlVc2VyIHx8ICF0aGlzLmlzVXNlclNjcm9sbGVkKVxuICAgICAgKSB7XG4gICAgICAgIHRoaXMuaXNMYXRlc3RNZXNzYWdlSW5MaXN0XG4gICAgICAgICAgPyB0aGlzLnNjcm9sbFRvVG9wKClcbiAgICAgICAgICA6IHRoaXMuanVtcFRvTGF0ZXN0TWVzc2FnZSgpO1xuICAgICAgICB0aGlzLmhhc05ld01lc3NhZ2VzID0gZmFsc2U7XG4gICAgICAgIHRoaXMuY29udGFpbmVySGVpZ2h0ID0gdGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxIZWlnaHQ7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0aGlzLmhhc05ld01lc3NhZ2VzKSB7XG4gICAgICAgIGlmICghdGhpcy5pc1VzZXJTY3JvbGxlZCB8fCB0aGlzLmlzTmV3TWVzc2FnZVNlbnRCeVVzZXIpIHtcbiAgICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQ/LmxvZ2dlcj8uKFxuICAgICAgICAgICAgJ2luZm8nLFxuICAgICAgICAgICAgYFVzZXIgaGFzIG5ldyBtZXNzYWdlcywgYW5kIG5vdCBzY3JvbGxlZCBvciBzZW50IG5ldyBtZXNzYWdlcywgdGhlcmVmb3JlIHdlICR7XG4gICAgICAgICAgICAgIHRoaXMuaXNMYXRlc3RNZXNzYWdlSW5MaXN0ID8gJ3Njcm9sbCcgOiAnanVtcCdcbiAgICAgICAgICAgIH0gdG8gbGF0ZXN0IG1lc3NhZ2VgLFxuICAgICAgICAgICAgeyB0YWdzOiBgbWVzc2FnZSBsaXN0ICR7dGhpcy5tb2RlfWAgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgdGhpcy5pc0xhdGVzdE1lc3NhZ2VJbkxpc3RcbiAgICAgICAgICAgID8gdGhpcy5zY3JvbGxUb0JvdHRvbSgpXG4gICAgICAgICAgICA6IHRoaXMuanVtcFRvTGF0ZXN0TWVzc2FnZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuaGFzTmV3TWVzc2FnZXMgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jb250YWluZXJIZWlnaHQgPSB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnNjcm9sbEhlaWdodDtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5vbGRlck1hc3NhZ2VzTG9hZGVkKSB7XG4gICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudD8ubG9nZ2VyPy4oXG4gICAgICAgICAgJ2luZm8nLFxuICAgICAgICAgIGBPbGRlciBtZXNzYWdlcyBhcmUgbG9hZGVkLCB3ZSBwcmVzZXJ2ZSB0aGUgc2Nyb2xsIHBvc2l0aW9uYCxcbiAgICAgICAgICB7IHRhZ3M6IGBtZXNzYWdlIGxpc3QgJHt0aGlzLm1vZGV9YCB9XG4gICAgICAgICk7XG4gICAgICAgIHRoaXMucHJlc2VydmVTY3JvbGxiYXJQb3NpdGlvbigpO1xuICAgICAgICB0aGlzLmNvbnRhaW5lckhlaWdodCA9IHRoaXMuc2Nyb2xsQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsSGVpZ2h0O1xuICAgICAgICB0aGlzLm9sZGVyTWFzc2FnZXNMb2FkZWQgPSBmYWxzZTtcbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIHRoaXMuZ2V0U2Nyb2xsUG9zaXRpb24oKSAhPT0gJ2JvdHRvbScgJiZcbiAgICAgICAgIXRoaXMuaXNVc2VyU2Nyb2xsZWQgJiZcbiAgICAgICAgIXRoaXMuaGlnaGxpZ2h0ZWRNZXNzYWdlSWRcbiAgICAgICkge1xuICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQ/LmxvZ2dlcj8uKFxuICAgICAgICAgICdpbmZvJyxcbiAgICAgICAgICBgQ29udGFpbmVyIGdyZXcgYW5kIHVzZXIgZGlkbid0IHNjcm9sbCB0aGVyZWZvcmUgd2UgJHtcbiAgICAgICAgICAgIHRoaXMuaXNMYXRlc3RNZXNzYWdlSW5MaXN0ID8gJ3Njcm9sbCcgOiAnanVtcCdcbiAgICAgICAgICB9IHRvIGxhdGVzdCBtZXNzYWdlYCxcbiAgICAgICAgICB7IHRhZ3M6IGBtZXNzYWdlIGxpc3QgJHt0aGlzLm1vZGV9YCB9XG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuaXNMYXRlc3RNZXNzYWdlSW5MaXN0XG4gICAgICAgICAgPyB0aGlzLnNjcm9sbFRvQm90dG9tKClcbiAgICAgICAgICA6IHRoaXMuanVtcFRvTGF0ZXN0TWVzc2FnZSgpO1xuICAgICAgICB0aGlzLmNvbnRhaW5lckhlaWdodCA9IHRoaXMuc2Nyb2xsQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsSGVpZ2h0O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5mb3JFYWNoKChzKSA9PiBzLnVuc3Vic2NyaWJlKCkpO1xuICAgIHRoaXMubmV3TWVzc2FnZVN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICBpZiAodGhpcy5zY3JvbGxFbmRUaW1lb3V0KSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5zY3JvbGxFbmRUaW1lb3V0KTtcbiAgICB9XG4gICAgaWYgKHRoaXMuY2hlY2tJZlVucmVhZE5vdGlmaWNhdGlvbklzVmlzaWJsZVRpbWVvdXQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmNoZWNrSWZVbnJlYWROb3RpZmljYXRpb25Jc1Zpc2libGVUaW1lb3V0KTtcbiAgICB9XG4gICAgaWYgKHRoaXMuanVtcFRvTGF0ZXN0QnV0dG9uVmlzaWJpbGl0eVRpbWVvdXQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmp1bXBUb0xhdGVzdEJ1dHRvblZpc2liaWxpdHlUaW1lb3V0KTtcbiAgICB9XG4gIH1cblxuICB0cmFja0J5TWVzc2FnZUlkKGluZGV4OiBudW1iZXIsIGl0ZW06IFN0cmVhbU1lc3NhZ2UpIHtcbiAgICByZXR1cm4gaXRlbS5pZDtcbiAgfVxuXG4gIHRyYWNrQnlVc2VySWQoaW5kZXg6IG51bWJlciwgdXNlcjogVXNlclJlc3BvbnNlKSB7XG4gICAgcmV0dXJuIHVzZXIuaWQ7XG4gIH1cblxuICBqdW1wVG9MYXRlc3RNZXNzYWdlKCkge1xuICAgIHZvaWQgdGhpcy5jaGFubmVsU2VydmljZS5qdW1wVG9NZXNzYWdlKFxuICAgICAgJ2xhdGVzdCcsXG4gICAgICB0aGlzLm1vZGUgPT09ICd0aHJlYWQnID8gdGhpcy5wYXJlbnRNZXNzYWdlPy5pZCA6IHVuZGVmaW5lZFxuICAgICk7XG4gIH1cblxuICBzY3JvbGxUb0JvdHRvbSgpOiB2b2lkIHtcbiAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnNjcm9sbFRvcCA9XG4gICAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnNjcm9sbEhlaWdodCArIDAuMTtcbiAgICB0aGlzLmZvcmNlUmVwYWludCgpO1xuICB9XG5cbiAgc2Nyb2xsVG9Ub3AoKSB7XG4gICAgdGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxUb3AgPSAwO1xuICB9XG5cbiAgc2Nyb2xsZWQoKSB7XG4gICAgaWYgKFxuICAgICAgdGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxIZWlnaHQgPT09XG4gICAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LmNsaWVudEhlaWdodFxuICAgICkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBzY3JvbGxQb3NpdGlvbiA9IHRoaXMuZ2V0U2Nyb2xsUG9zaXRpb24oKTtcbiAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQ/LmxvZ2dlcj8uKFxuICAgICAgJ2luZm8nLFxuICAgICAgYFNjcm9sbGVkIC0gc2Nyb2xsIHBvc2l0aW9uOiAke3Njcm9sbFBvc2l0aW9ufSwgY29udGFpbmVyIGhlaWdodDogJHt0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnNjcm9sbEhlaWdodH1gLFxuICAgICAgeyB0YWdzOiBgbWVzc2FnZSBsaXN0ICR7dGhpcy5tb2RlfWAgfVxuICAgICk7XG5cbiAgICBjb25zdCBpc1VzZXJTY3JvbGxlZCA9XG4gICAgICAodGhpcy5kaXJlY3Rpb24gPT09ICdib3R0b20tdG8tdG9wJ1xuICAgICAgICA/IHNjcm9sbFBvc2l0aW9uICE9PSAnYm90dG9tJ1xuICAgICAgICA6IHNjcm9sbFBvc2l0aW9uICE9PSAndG9wJykgfHwgIXRoaXMuaXNMYXRlc3RNZXNzYWdlSW5MaXN0O1xuICAgIGlmICh0aGlzLmlzVXNlclNjcm9sbGVkICE9PSBpc1VzZXJTY3JvbGxlZCkge1xuICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgdGhpcy5pc1VzZXJTY3JvbGxlZCA9IGlzVXNlclNjcm9sbGVkO1xuICAgICAgICBpZiAoIXRoaXMuaXNVc2VyU2Nyb2xsZWQpIHtcbiAgICAgICAgICB0aGlzLm5ld01lc3NhZ2VDb3VudFdoaWxlQmVpbmdTY3JvbGxlZCA9IDA7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5oaWRlSnVtcFRvTGF0ZXN0QnV0dG9uRHVyaW5nU2Nyb2xsKSB7XG4gICAgICBpZiAodGhpcy5pc0p1bXBUb0xhdGVzdEJ1dHRvblZpc2libGUpIHtcbiAgICAgICAgdGhpcy5pc0p1bXBUb0xhdGVzdEJ1dHRvblZpc2libGUgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5qdW1wVG9MYXRlc3RCdXR0b25WaXNpYmlsaXR5VGltZW91dCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5qdW1wVG9MYXRlc3RCdXR0b25WaXNpYmlsaXR5VGltZW91dCk7XG4gICAgICB9XG4gICAgICB0aGlzLmp1bXBUb0xhdGVzdEJ1dHRvblZpc2liaWxpdHlUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmlzVXNlclNjcm9sbGVkKSB7XG4gICAgICAgICAgdGhpcy5pc0p1bXBUb0xhdGVzdEJ1dHRvblZpc2libGUgPSB0cnVlO1xuICAgICAgICAgIHRoaXMuanVtcFRvTGF0ZXN0QnV0dG9uVmlzaWJpbGl0eVRpbWVvdXQgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgIH1cbiAgICAgIH0sIDEwMCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc2hvdWxkTG9hZE1vcmVNZXNzYWdlcyhzY3JvbGxQb3NpdGlvbikpIHtcbiAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgIHRoaXMuY29udGFpbmVySGVpZ2h0ID0gdGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxIZWlnaHQ7XG4gICAgICAgIGxldCBkaXJlY3Rpb246ICduZXdlcicgfCAnb2xkZXInO1xuICAgICAgICBpZiAodGhpcy5kaXJlY3Rpb24gPT09ICd0b3AtdG8tYm90dG9tJykge1xuICAgICAgICAgIGRpcmVjdGlvbiA9IHNjcm9sbFBvc2l0aW9uID09PSAndG9wJyA/ICduZXdlcicgOiAnb2xkZXInO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGRpcmVjdGlvbiA9IHNjcm9sbFBvc2l0aW9uID09PSAndG9wJyA/ICdvbGRlcicgOiAnbmV3ZXInO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9XG4gICAgICAgICAgdGhpcy5tb2RlID09PSAnbWFpbidcbiAgICAgICAgICAgID8gdGhpcy5jaGFubmVsU2VydmljZS5sb2FkTW9yZU1lc3NhZ2VzKGRpcmVjdGlvbilcbiAgICAgICAgICAgIDogdGhpcy5jaGFubmVsU2VydmljZS5sb2FkTW9yZVRocmVhZFJlcGxpZXMoZGlyZWN0aW9uKTtcbiAgICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudD8ubG9nZ2VyPy4oXG4gICAgICAgICAgICAnaW5mbycsXG4gICAgICAgICAgICBgRGlzcGxheWluZyBsb2FkaW5nIGluZGljYXRvcmAsXG4gICAgICAgICAgICB7IHRhZ3M6IGBtZXNzYWdlIGxpc3QgJHt0aGlzLm1vZGV9YCB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICB0aGlzLmlzTG9hZGluZyA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgdGhpcy5wcmV2U2Nyb2xsVG9wID0gdGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxUb3A7XG4gIH1cblxuICBqdW1wVG9GaXJzdFVucmVhZE1lc3NhZ2UoKSB7XG4gICAgaWYgKCF0aGlzLmxhc3RSZWFkTWVzc2FnZUlkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuaXNKdW1waW5nVG9MYXRlc3RVbnJlYWRNZXNzYWdlID0gdHJ1ZTtcbiAgICB2b2lkIHRoaXMuY2hhbm5lbFNlcnZpY2UuanVtcFRvTWVzc2FnZSh0aGlzLmxhc3RSZWFkTWVzc2FnZUlkKTtcbiAgfVxuXG4gIGdldFR5cGluZ0luZGljYXRvckNvbnRleHQoKTogVHlwaW5nSW5kaWNhdG9yQ29udGV4dCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHVzZXJzVHlwaW5nJDogdGhpcy51c2Vyc1R5cGluZyQsXG4gICAgfTtcbiAgfVxuXG4gIGdldFR5cGluZ0luZGljYXRvclRleHQodXNlcnM6IFVzZXJSZXNwb25zZVtdKSB7XG4gICAgY29uc3QgdGV4dCA9IGxpc3RVc2Vycyh1c2Vycyk7XG5cbiAgICByZXR1cm4gdGV4dDtcbiAgfVxuXG4gIGlzU2VudEJ5Q3VycmVudFVzZXIobWVzc2FnZT86IFN0cmVhbU1lc3NhZ2UpIHtcbiAgICBpZiAoIW1lc3NhZ2UpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIG1lc3NhZ2UudXNlcj8uaWQgPT09IHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC51c2VyPy5pZDtcbiAgfVxuXG4gIHBhcnNlRGF0ZShkYXRlOiBEYXRlKSB7XG4gICAgaWYgKHRoaXMucGFyc2VkRGF0ZXMuaGFzKGRhdGUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5wYXJzZWREYXRlcy5nZXQoZGF0ZSk7XG4gICAgfVxuICAgIGNvbnN0IHBhcnNlZERhdGUgPSB0aGlzLmRhdGVQYXJzZXIucGFyc2VEYXRlKGRhdGUpO1xuICAgIHRoaXMucGFyc2VkRGF0ZXMuc2V0KGRhdGUsIHBhcnNlZERhdGUpO1xuICAgIHJldHVybiBwYXJzZWREYXRlO1xuICB9XG5cbiAgZ2V0IHJlcGx5Q291bnRQYXJhbSgpIHtcbiAgICByZXR1cm4geyByZXBseUNvdW50OiB0aGlzLnBhcmVudE1lc3NhZ2U/LnJlcGx5X2NvdW50IH07XG4gIH1cblxuICBnZXQgZW1wdHlMaXN0VGVtcGxhdGUoKSB7XG4gICAgcmV0dXJuIHRoaXMubW9kZSA9PT0gJ21haW4nXG4gICAgICA/IHRoaXMuZW1wdHlNYWluTWVzc2FnZUxpc3RUZW1wbGF0ZVxuICAgICAgOiB0aGlzLmVtcHR5VGhyZWFkTWVzc2FnZUxpc3RUZW1wbGF0ZTtcbiAgfVxuXG4gIHByaXZhdGUgcHJlc2VydmVTY3JvbGxiYXJQb3NpdGlvbigpIHtcbiAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnNjcm9sbFRvcCA9XG4gICAgICAodGhpcy5wcmV2U2Nyb2xsVG9wIHx8IDApICtcbiAgICAgICh0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnNjcm9sbEhlaWdodCAtIHRoaXMuY29udGFpbmVySGVpZ2h0ISk7XG4gIH1cblxuICBwcml2YXRlIGZvcmNlUmVwYWludCgpIHtcbiAgICAvLyBTb2x2ZXMgdGhlIGlzc3VlIG9mIGVtcHR5IHNjcmVlbiBvbiBTYWZhcmkgd2hlbiBzY3JvbGxpbmdcbiAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgdGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5vZmZzZXRIZWlnaHQ7IC8vIG5vIG5lZWQgdG8gc3RvcmUgdGhpcyBhbnl3aGVyZSwgdGhlIHJlZmVyZW5jZSBpcyBlbm91Z2hcbiAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnJztcbiAgfVxuXG4gIHByaXZhdGUgZ2V0U2Nyb2xsUG9zaXRpb24oKTogJ3RvcCcgfCAnYm90dG9tJyB8ICdtaWRkbGUnIHtcbiAgICBsZXQgcG9zaXRpb246ICd0b3AnIHwgJ2JvdHRvbScgfCAnbWlkZGxlJyA9ICdtaWRkbGUnO1xuICAgIGlmIChcbiAgICAgIE1hdGguZmxvb3IodGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxUb3ApIDw9XG4gICAgICAgICh0aGlzLnBhcmVudE1lc3NhZ2VFbGVtZW50Py5uYXRpdmVFbGVtZW50LmNsaWVudEhlaWdodCB8fCAwKSAmJlxuICAgICAgKHRoaXMucHJldlNjcm9sbFRvcCA9PT0gdW5kZWZpbmVkIHx8XG4gICAgICAgIHRoaXMucHJldlNjcm9sbFRvcCA+XG4gICAgICAgICAgKHRoaXMucGFyZW50TWVzc2FnZUVsZW1lbnQ/Lm5hdGl2ZUVsZW1lbnQuY2xpZW50SGVpZ2h0IHx8IDApKVxuICAgICkge1xuICAgICAgcG9zaXRpb24gPSAndG9wJztcbiAgICB9IGVsc2UgaWYgKFxuICAgICAgTWF0aC5jZWlsKHRoaXMuc2Nyb2xsQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsVG9wKSArXG4gICAgICAgIHRoaXMuc2Nyb2xsQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuY2xpZW50SGVpZ2h0ID49XG4gICAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnNjcm9sbEhlaWdodFxuICAgICkge1xuICAgICAgcG9zaXRpb24gPSAnYm90dG9tJztcbiAgICB9XG5cbiAgICByZXR1cm4gcG9zaXRpb247XG4gIH1cblxuICBwcml2YXRlIHNob3VsZExvYWRNb3JlTWVzc2FnZXMoc2Nyb2xsUG9zaXRpb246ICd0b3AnIHwgJ2JvdHRvbScgfCAnbWlkZGxlJykge1xuICAgIHJldHVybiBzY3JvbGxQb3NpdGlvbiAhPT0gJ21pZGRsZScgJiYgIXRoaXMuaGlnaGxpZ2h0ZWRNZXNzYWdlSWQ7XG4gIH1cblxuICBwcml2YXRlIHNldE1lc3NhZ2VzJCgpIHtcbiAgICB0aGlzLm1lc3NhZ2VzJCA9IChcbiAgICAgIHRoaXMubW9kZSA9PT0gJ21haW4nXG4gICAgICAgID8gdGhpcy5jaGFubmVsU2VydmljZS5hY3RpdmVDaGFubmVsTWVzc2FnZXMkXG4gICAgICAgIDogdGhpcy5jaGFubmVsU2VydmljZS5hY3RpdmVUaHJlYWRNZXNzYWdlcyRcbiAgICApLnBpcGUoXG4gICAgICB0YXAoKG1lc3NhZ2VzKSA9PiB7XG4gICAgICAgIHRoaXMuaXNMb2FkaW5nID0gZmFsc2U7XG4gICAgICAgIGlmIChtZXNzYWdlcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQ/LmxvZ2dlcj8uKFxuICAgICAgICAgICAgJ2luZm8nLFxuICAgICAgICAgICAgYEVtcHR5IG1lc3NhZ2VzIGFycmF5LCByZXNldGluZyBzY3JvbGwgc3RhdGVgLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICB0YWdzOiBgbWVzc2FnZSBsaXN0ICR7dGhpcy5tb2RlfWAsXG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICB0aGlzLnJlc2V0U2Nyb2xsU3RhdGUoKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuaXNFbXB0eSkge1xuICAgICAgICAgIC8vIGNkUmVmLmRldGVjdENoYW5nZXMoKSBpc24ndCBlbm91Z2ggaGVyZSwgdGVzdCB3aWxsIGZhaWxcbiAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+ICh0aGlzLmlzRW1wdHkgPSBmYWxzZSksIDApO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudD8ubG9nZ2VyPy4oXG4gICAgICAgICAgJ2luZm8nLFxuICAgICAgICAgIGBSZWNlaXZlZCBvbmUgb3IgbW9yZSBtZXNzYWdlc2AsXG4gICAgICAgICAge1xuICAgICAgICAgICAgdGFnczogYG1lc3NhZ2UgbGlzdCAke3RoaXMubW9kZX1gLFxuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgY3VycmVudExhdGVzdE1lc3NhZ2VJblN0YXRlID0gbWVzc2FnZXNbbWVzc2FnZXMubGVuZ3RoIC0gMV07XG4gICAgICAgIHRoaXMubmV3TWVzc2FnZVJlY2VpdmVkKGN1cnJlbnRMYXRlc3RNZXNzYWdlSW5TdGF0ZSk7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRPbGRlc3RNZXNzYWdlID0gbWVzc2FnZXNbMF07XG4gICAgICAgIGlmIChcbiAgICAgICAgICAhdGhpcy5vbGRlc3RNZXNzYWdlIHx8XG4gICAgICAgICAgIW1lc3NhZ2VzLmZpbmQoKG0pID0+IG0uaWQgPT09IHRoaXMub2xkZXN0TWVzc2FnZSEuaWQpXG4gICAgICAgICkge1xuICAgICAgICAgIHRoaXMub2xkZXN0TWVzc2FnZSA9IGN1cnJlbnRPbGRlc3RNZXNzYWdlO1xuICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgIHRoaXMub2xkZXN0TWVzc2FnZS5jcmVhdGVkX2F0LmdldFRpbWUoKSA+XG4gICAgICAgICAgY3VycmVudE9sZGVzdE1lc3NhZ2UuY3JlYXRlZF9hdC5nZXRUaW1lKClcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGhpcy5vbGRlc3RNZXNzYWdlID0gY3VycmVudE9sZGVzdE1lc3NhZ2U7XG4gICAgICAgICAgdGhpcy5vbGRlck1hc3NhZ2VzTG9hZGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSksXG4gICAgICB0YXAoKG1lc3NhZ2VzKSA9PiB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICB0aGlzLmlzSnVtcGluZ1RvTGF0ZXN0VW5yZWFkTWVzc2FnZSAmJlxuICAgICAgICAgICF0aGlzLmZpcnN0VW5yZWFkTWVzc2FnZUlkICYmXG4gICAgICAgICAgdGhpcy5sYXN0UmVhZE1lc3NhZ2VJZFxuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCBsYXN0UmVhZEluZGV4ID0gbWVzc2FnZXMuZmluZEluZGV4KFxuICAgICAgICAgICAgKG0pID0+IG0uaWQgPT09IHRoaXMubGFzdFJlYWRNZXNzYWdlSWRcbiAgICAgICAgICApO1xuICAgICAgICAgIHRoaXMuZmlyc3RVbnJlYWRNZXNzYWdlSWQgPVxuICAgICAgICAgICAgbWVzc2FnZXNbbGFzdFJlYWRJbmRleCArIDFdPy5pZCB8fCB0aGlzLmxhc3RSZWFkTWVzc2FnZUlkO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICAgIHRhcChcbiAgICAgICAgKG1lc3NhZ2VzKSA9PlxuICAgICAgICAgICh0aGlzLmxhc3RTZW50TWVzc2FnZUlkID0gWy4uLm1lc3NhZ2VzXVxuICAgICAgICAgICAgLnJldmVyc2UoKVxuICAgICAgICAgICAgLmZpbmQoXG4gICAgICAgICAgICAgIChtKSA9PlxuICAgICAgICAgICAgICAgIG0udXNlcj8uaWQgPT09IHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudD8udXNlcj8uaWQgJiZcbiAgICAgICAgICAgICAgICBtLnN0YXR1cyAhPT0gJ3NlbmRpbmcnXG4gICAgICAgICAgICApPy5pZClcbiAgICAgICksXG4gICAgICB0YXAoKG1lc3NhZ2VzKSA9PiB7XG4gICAgICAgIHRoaXMuaXNMYXRlc3RNZXNzYWdlSW5MaXN0ID1cbiAgICAgICAgICAhdGhpcy5sYXRlc3RNZXNzYWdlIHx8XG4gICAgICAgICAgbWVzc2FnZXMubGVuZ3RoID09PSAwIHx8XG4gICAgICAgICAgbWVzc2FnZXNbbWVzc2FnZXMubGVuZ3RoIC0gMV0uaWQgPT09IHRoaXMubGF0ZXN0TWVzc2FnZS5pZCB8fFxuICAgICAgICAgIHRoaXMubW9kZSA9PT0gJ3RocmVhZCc7XG4gICAgICAgIGlmICghdGhpcy5pc0xhdGVzdE1lc3NhZ2VJbkxpc3QpIHtcbiAgICAgICAgICB0aGlzLmlzVXNlclNjcm9sbGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSksXG4gICAgICBtYXAoKG1lc3NhZ2VzKSA9PlxuICAgICAgICB0aGlzLmRpcmVjdGlvbiA9PT0gJ2JvdHRvbS10by10b3AnID8gbWVzc2FnZXMgOiBbLi4ubWVzc2FnZXNdLnJldmVyc2UoKVxuICAgICAgKSxcbiAgICAgIHRhcCgobWVzc2FnZXMpID0+IHtcbiAgICAgICAgdGhpcy5ncm91cFN0eWxlcyA9IG1lc3NhZ2VzLm1hcCgobSwgaSkgPT5cbiAgICAgICAgICBnZXRHcm91cFN0eWxlcyhtLCBtZXNzYWdlc1tpIC0gMV0sIG1lc3NhZ2VzW2kgKyAxXSwge1xuICAgICAgICAgICAgbGFzdFJlYWRNZXNzYWdlSWQ6IHRoaXMubGFzdFJlYWRNZXNzYWdlSWQsXG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5pc05leHRNZXNzYWdlT25TZXBhcmF0ZURhdGUgPSBtZXNzYWdlcy5tYXAoKG0sIGkpID0+XG4gICAgICAgICAgdGhpcy5jaGVja0lmT25TZXBhcmF0ZURhdGVzKG0sIG1lc3NhZ2VzW2kgKyAxXSlcbiAgICAgICAgKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzZXRTY3JvbGxTdGF0ZSgpIHtcbiAgICB0aGlzLmlzRW1wdHkgPSB0cnVlO1xuICAgIHRoaXMubGF0ZXN0TWVzc2FnZSA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmhhc05ld01lc3NhZ2VzID0gdHJ1ZTtcbiAgICB0aGlzLmlzVXNlclNjcm9sbGVkID0gZmFsc2U7XG4gICAgdGhpcy5jb250YWluZXJIZWlnaHQgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5vbGRlck1hc3NhZ2VzTG9hZGVkID0gZmFsc2U7XG4gICAgdGhpcy5vbGRlc3RNZXNzYWdlID0gdW5kZWZpbmVkO1xuICAgIHRoaXMubmV3TWVzc2FnZUNvdW50V2hpbGVCZWluZ1Njcm9sbGVkID0gMDtcbiAgICB0aGlzLnByZXZTY3JvbGxUb3AgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5pc05ld01lc3NhZ2VTZW50QnlVc2VyID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuaXNMYXRlc3RNZXNzYWdlSW5MaXN0ID0gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IHVzZXJzVHlwaW5nJCgpIHtcbiAgICByZXR1cm4gdGhpcy5tb2RlID09PSAndGhyZWFkJ1xuICAgICAgPyB0aGlzLnVzZXJzVHlwaW5nSW5UaHJlYWQkXG4gICAgICA6IHRoaXMudXNlcnNUeXBpbmdJbkNoYW5uZWwkO1xuICB9XG5cbiAgcHJpdmF0ZSBzY3JvbGxNZXNzYWdlSW50b1ZpZXcobWVzc2FnZUlkOiBzdHJpbmcsIHdpdGhSZXRyeSA9IHRydWUpIHtcbiAgICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQobWVzc2FnZUlkKTtcbiAgICBpZiAoIWVsZW1lbnQgJiYgd2l0aFJldHJ5KSB7XG4gICAgICAvLyBJZiB0aGUgbWVzc2FnZSB3YXMgbmV3bHkgaW5zZXJ0ZWQgaW50byBhY3RpdmVDaGFubmVsTWVzc2FnZXMkLCB0aGUgbWVzc2FnZSB3aWxsIGJlIHJlbmRlcmVkIGFmdGVyIHRoZSBjdXJyZW50IGNoYW5nZSBkZXRlY3Rpb24gY3ljbGUgLT4gd2FpdCBmb3IgdGhpcyBjeWNsZSB0byBjb21wbGV0ZVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnNjcm9sbE1lc3NhZ2VJbnRvVmlldyhtZXNzYWdlSWQsIGZhbHNlKSk7XG4gICAgfSBlbHNlIGlmIChlbGVtZW50KSB7XG4gICAgICBlbGVtZW50LnNjcm9sbEludG9WaWV3KHtcbiAgICAgICAgYmxvY2s6ICdjZW50ZXInLFxuICAgICAgfSk7XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgdGhpcy5oaWdobGlnaHRlZE1lc3NhZ2VJZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5maXJzdFVucmVhZE1lc3NhZ2VJZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5pc0p1bXBpbmdUb0xhdGVzdFVucmVhZE1lc3NhZ2UgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB9LCAxMDAwKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNjcm9sbFRvTGF0ZXN0TWVzc2FnZSh3aXRoUmV0cnkgPSB0cnVlKSB7XG4gICAgaWYgKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMubGF0ZXN0TWVzc2FnZSEuaWQpKSB7XG4gICAgICB0aGlzLmRpcmVjdGlvbiA9PT0gJ2JvdHRvbS10by10b3AnXG4gICAgICAgID8gdGhpcy5zY3JvbGxUb0JvdHRvbSgpXG4gICAgICAgIDogdGhpcy5zY3JvbGxUb1RvcCgpO1xuICAgIH0gZWxzZSBpZiAod2l0aFJldHJ5KSB7XG4gICAgICAvLyBJZiB0aGUgbWVzc2FnZSB3YXMgbmV3bHkgaW5zZXJ0ZWQgaW50byBhY3RpdmVDaGFubmVsTWVzc2FnZXMkLCB0aGUgbWVzc2FnZSB3aWxsIGJlIHJlbmRlcmVkIGFmdGVyIHRoZSBjdXJyZW50IGNoYW5nZSBkZXRlY3Rpb24gY3ljbGUgLT4gd2FpdCBmb3IgdGhpcyBjeWNsZSB0byBjb21wbGV0ZVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnNjcm9sbFRvTGF0ZXN0TWVzc2FnZShmYWxzZSksIDApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbmV3TWVzc2FnZVJlY2VpdmVkKG1lc3NhZ2U6IHtcbiAgICBpZDogc3RyaW5nO1xuICAgIGNyZWF0ZWRfYXQ6IERhdGU7XG4gICAgdXNlcj86IHsgaWQ6IHN0cmluZyB9IHwgbnVsbDtcbiAgfSkge1xuICAgIGNvbnN0IGxhdGVzdE1lc3NhZ2VzID1cbiAgICAgIHRoaXMuY2hhbm5lbFNlcnZpY2UuYWN0aXZlQ2hhbm5lbD8uc3RhdGU/LmxhdGVzdE1lc3NhZ2VzO1xuICAgIGlmIChcbiAgICAgICF0aGlzLmxhdGVzdE1lc3NhZ2UgfHxcbiAgICAgIHRoaXMubGF0ZXN0TWVzc2FnZS5jcmVhdGVkX2F0Py5nZXRUaW1lKCkgPCBtZXNzYWdlLmNyZWF0ZWRfYXQuZ2V0VGltZSgpIHx8XG4gICAgICAodGhpcy5tb2RlID09PSAnbWFpbicgJiZcbiAgICAgICAgbGF0ZXN0TWVzc2FnZXMgJiZcbiAgICAgICAgdGhpcy5sYXRlc3RNZXNzYWdlICYmXG4gICAgICAgIGxhdGVzdE1lc3NhZ2VzW2xhdGVzdE1lc3NhZ2VzLmxlbmd0aCAtIDFdPy5pZCAhPT0gdGhpcy5sYXRlc3RNZXNzYWdlLmlkKVxuICAgICkge1xuICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50Py5sb2dnZXI/LihcbiAgICAgICAgJ2luZm8nLFxuICAgICAgICBgUmVjZWl2ZWQgbmV3IG1lc3NhZ2VgLFxuICAgICAgICB7IHRhZ3M6IGBtZXNzYWdlIGxpc3QgJHt0aGlzLm1vZGV9YCB9XG4gICAgICApO1xuICAgICAgY29uc3QgaXNOZXdDaGFubmVsID0gIXRoaXMubGF0ZXN0TWVzc2FnZTtcbiAgICAgIHRoaXMubGF0ZXN0TWVzc2FnZSA9IG1lc3NhZ2U7XG4gICAgICB0aGlzLmhhc05ld01lc3NhZ2VzID0gdHJ1ZTtcbiAgICAgIHRoaXMuaXNOZXdNZXNzYWdlU2VudEJ5VXNlciA9XG4gICAgICAgIG1lc3NhZ2UudXNlcj8uaWQgPT09IHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudD8udXNlcj8uaWQ7XG4gICAgICBpZiAodGhpcy5pc1VzZXJTY3JvbGxlZCkge1xuICAgICAgICB0aGlzLm5ld01lc3NhZ2VDb3VudFdoaWxlQmVpbmdTY3JvbGxlZCsrO1xuICAgICAgfVxuICAgICAgaWYgKFxuICAgICAgICAhdGhpcy5pc05ld01lc3NhZ2VTZW50QnlVc2VyICYmXG4gICAgICAgIHRoaXMudW5yZWFkQ291bnQgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAhaXNOZXdDaGFubmVsXG4gICAgICApIHtcbiAgICAgICAgdGhpcy51bnJlYWRDb3VudCsrO1xuICAgICAgfVxuICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjaGVja0lmT25TZXBhcmF0ZURhdGVzKFxuICAgIG1lc3NhZ2U/OiBTdHJlYW1NZXNzYWdlLFxuICAgIG5leHRNZXNzYWdlPzogU3RyZWFtTWVzc2FnZVxuICApIHtcbiAgICBpZiAoIW1lc3NhZ2UgfHwgIW5leHRNZXNzYWdlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiBpc09uU2VwYXJhdGVEYXRlKG1lc3NhZ2UuY3JlYXRlZF9hdCwgbmV4dE1lc3NhZ2UuY3JlYXRlZF9hdCk7XG4gIH1cbn1cbiIsIjxuZy1jb250YWluZXJcbiAgKm5nSWY9XCJcbiAgICBsYXN0UmVhZE1lc3NhZ2VJZCAmJlxuICAgIGlzVW5yZWFkTm90aWZpY2F0aW9uVmlzaWJsZSAmJlxuICAgIG9wZW5NZXNzYWdlTGlzdEF0ID09PSAnbGFzdC1tZXNzYWdlJyAmJlxuICAgIGRpc3BsYXlVbnJlYWRTZXBhcmF0b3JcbiAgXCJcbj5cbiAgPG5nLWNvbnRhaW5lclxuICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICBjdXN0b21uZXdNZXNzYWdlc05vdGlmaWNhdGlvblRlbXBsYXRlIHx8XG4gICAgICAgIGRlZmF1bHRVbnJlYWRNZXNzYWdlc05vdGlmaWNhdGlvbjtcbiAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgdW5yZWFkQ291bnQ6IHVucmVhZENvdW50LFxuICAgICAgICBvbkRpc21pc3M6IG1lc3NhZ2VOb3RpZmljYXRpb25EaXNtaXNzQ2xpY2tlZCxcbiAgICAgICAgb25KdW1wOiBtZXNzYWdlTm90aWZpY2F0aW9uSnVtcENsaWNrZWRcbiAgICAgIH1cbiAgICBcIlxuICA+PC9uZy1jb250YWluZXI+XG48L25nLWNvbnRhaW5lcj5cbjxuZy10ZW1wbGF0ZVxuICAjZGVmYXVsdFVucmVhZE1lc3NhZ2VzTm90aWZpY2F0aW9uXG4gIGxldC11bnJlYWRDb3VudD1cInVucmVhZENvdW50XCJcbiAgbGV0LW9uRGlzbWlzcz1cIm9uRGlzbWlzc1wiXG4gIGxldC1vbkp1bXA9XCJvbkp1bXBcIlxuPlxuICA8ZGl2XG4gICAgY2xhc3M9XCJzdHItY2hhdF9fdW5yZWFkLW1lc3NhZ2VzLW5vdGlmaWNhdGlvblwiXG4gICAgZGF0YS10ZXN0aWQ9XCJ1bnJlYWQtbWVzc2FnZXMtbm90aWZpY2F0aW9uXCJcbiAgPlxuICAgIDxidXR0b25cbiAgICAgIGRhdGEtdGVzdGlkPVwidW5yZWFkLW1lc3NhZ2VzLW5vdGlmaWNhdGlvbi1qdW1wLXRvLW1lc3NhZ2VcIlxuICAgICAgKGNsaWNrKT1cIm9uSnVtcCgpXCJcbiAgICA+XG4gICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICpuZ0lmPVwiXG4gICAgICAgICAgdW5yZWFkQ291bnQgPiAwICYmICFoaWRlVW5yZWFkQ291bnRGb3JOb3RpZmljYXRpb25BbmRJbmRpY2F0b3I7XG4gICAgICAgICAgZWxzZSBub1VucmVhZENvdW50XG4gICAgICAgIFwiXG4gICAgICA+XG4gICAgICAgIHt7XG4gICAgICAgICAgKHVucmVhZENvdW50ID09PSAxXG4gICAgICAgICAgICA/IFwic3RyZWFtQ2hhdC5cXHtcXHtjb3VudFxcfVxcfSB1bnJlYWQgbWVzc2FnZVwiXG4gICAgICAgICAgICA6IFwic3RyZWFtQ2hhdC5cXHtcXHtjb3VudFxcfVxcfSB1bnJlYWQgbWVzc2FnZXNcIlxuICAgICAgICAgICkgfCB0cmFuc2xhdGU6IHsgY291bnQ6IHVucmVhZENvdW50IH1cbiAgICAgICAgfX1cbiAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPG5nLXRlbXBsYXRlICNub1VucmVhZENvdW50PlxuICAgICAgICB7eyBcInN0cmVhbUNoYXQuVW5yZWFkIG1lc3NhZ2VzXCIgfCB0cmFuc2xhdGUgfX1cbiAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPC9idXR0b24+XG4gICAgPGJ1dHRvblxuICAgICAgZGF0YS10ZXN0aWQ9XCJ1bnJlYWQtbWVzc2FnZXMtbm90aWZpY2F0aW9uLWRpc21pc3NcIlxuICAgICAgKGNsaWNrKT1cIm9uRGlzbWlzcygpXCJcbiAgICA+XG4gICAgICA8c3RyZWFtLWljb24tcGxhY2Vob2xkZXIgaWNvbj1cImNsb3NlXCI+PC9zdHJlYW0taWNvbi1wbGFjZWhvbGRlcj5cbiAgICA8L2J1dHRvbj5cbiAgPC9kaXY+XG48L25nLXRlbXBsYXRlPlxuPGRpdiAjc2Nyb2xsQ29udGFpbmVyIGRhdGEtdGVzdGlkPVwic2Nyb2xsLWNvbnRhaW5lclwiIGNsYXNzPVwic3RyLWNoYXRfX2xpc3RcIj5cbiAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIm1vZGUgPT09ICdtYWluJyAmJiBpc0VtcHR5ICYmIGVtcHR5TGlzdFRlbXBsYXRlXCI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImVtcHR5TGlzdFRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG4gIDwvbmctY29udGFpbmVyPlxuICA8ZGl2IGNsYXNzPVwic3RyLWNoYXRfX3JldmVyc2UtaW5maW5pdGUtc2Nyb2xsIHN0ci1jaGF0X19tZXNzYWdlLWxpc3Qtc2Nyb2xsXCI+XG4gICAgPHVsXG4gICAgICBjbGFzcz1cInN0ci1jaGF0X191bFwiXG4gICAgICBbY2xhc3Muc3RyLWNoYXRfX21lc3NhZ2Utb3B0aW9ucy1pbi1idWJibGVdPVwiXG4gICAgICAgIG1lc3NhZ2VPcHRpb25zVHJpZ2dlciA9PT0gJ21lc3NhZ2UtYnViYmxlJ1xuICAgICAgXCJcbiAgICA+XG4gICAgICA8bGlcbiAgICAgICAgKm5nSWY9XCJtb2RlID09PSAndGhyZWFkJyAmJiBwYXJlbnRNZXNzYWdlXCJcbiAgICAgICAgI3BhcmVudE1lc3NhZ2VFbGVtZW50XG4gICAgICAgIGRhdGEtdGVzdGlkPVwicGFyZW50LW1lc3NhZ2VcIlxuICAgICAgICBjbGFzcz1cInN0ci1jaGF0X19wYXJlbnQtbWVzc2FnZS1saVwiXG4gICAgICA+XG4gICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAqbmdUZW1wbGF0ZU91dGxldD1cIlxuICAgICAgICAgICAgbWVzc2FnZVRlbXBsYXRlQ29udGFpbmVyO1xuICAgICAgICAgICAgY29udGV4dDogeyBtZXNzYWdlOiBwYXJlbnRNZXNzYWdlLCBpbmRleDogJ3BhcmVudCcgfVxuICAgICAgICAgIFwiXG4gICAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPGRpdiBkYXRhLXRlc3RpZD1cInJlcGx5LWNvdW50XCIgY2xhc3M9XCJzdHItY2hhdF9fdGhyZWFkLXN0YXJ0XCI+XG4gICAgICAgICAge3twYXJlbnRNZXNzYWdlLnJlcGx5X2NvdW50ID09PSAxID8gKCdzdHJlYW1DaGF0LjEgcmVwbHknIHwgdHJhbnNsYXRlKSA6ICgnc3RyZWFtQ2hhdC57eyByZXBseUNvdW50IH19XG4gICAgICAgICAgcmVwbGllcycgfCB0cmFuc2xhdGU6cmVwbHlDb3VudFBhcmFtKX19XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9saT5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJtb2RlID09PSAndGhyZWFkJyAmJiBpc0VtcHR5ICYmIGVtcHR5TGlzdFRlbXBsYXRlXCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJlbXB0eUxpc3RUZW1wbGF0ZVwiPjwvbmctY29udGFpbmVyPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8c3RyZWFtLWxvYWRpbmctaW5kaWNhdG9yXG4gICAgICAgICpuZ0lmPVwiXG4gICAgICAgICAgaXNMb2FkaW5nICYmIGRpcmVjdGlvbiA9PT0gJ2JvdHRvbS10by10b3AnICYmIGRpc3BsYXlMb2FkaW5nSW5kaWNhdG9yXG4gICAgICAgIFwiXG4gICAgICAgIGRhdGEtdGVzdGlkPVwidG9wLWxvYWRpbmctaW5kaWNhdG9yXCJcbiAgICAgID48L3N0cmVhbS1sb2FkaW5nLWluZGljYXRvcj5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJtZXNzYWdlcyQgfCBhc3luYyBhcyBtZXNzYWdlc1wiPlxuICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgKm5nRm9yPVwiXG4gICAgICAgICAgICBsZXQgbWVzc2FnZSBvZiBtZXNzYWdlcztcbiAgICAgICAgICAgIGxldCBpID0gaW5kZXg7XG4gICAgICAgICAgICBsZXQgaXNGaXJzdCA9IGZpcnN0O1xuICAgICAgICAgICAgbGV0IGlzTGFzdCA9IGxhc3Q7XG4gICAgICAgICAgICB0cmFja0J5OiB0cmFja0J5TWVzc2FnZUlkXG4gICAgICAgICAgXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJpc0ZpcnN0XCI+XG4gICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgICAgICAgICAgZGF0ZVNlcGFyYXRvcjtcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7XG4gICAgICAgICAgICAgICAgICBkYXRlOiBtZXNzYWdlLmNyZWF0ZWRfYXQsXG4gICAgICAgICAgICAgICAgICBwYXJzZWREYXRlOiBwYXJzZURhdGUobWVzc2FnZS5jcmVhdGVkX2F0KVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8bGlcbiAgICAgICAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAgICAgICBkYXRhLXRlc3RjbGFzcz1cIm1lc3NhZ2VcIlxuICAgICAgICAgICAgY2xhc3M9XCJzdHItY2hhdF9fbGkgc3RyLWNoYXRfX2xpLS17eyBncm91cFN0eWxlc1tpXSB9fVwiXG4gICAgICAgICAgICBpZD1cInt7IG1lc3NhZ2UuaWQgfX1cIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJcbiAgICAgICAgICAgICAgICBtZXNzYWdlVGVtcGxhdGVDb250YWluZXI7XG4gICAgICAgICAgICAgICAgY29udGV4dDogeyBtZXNzYWdlOiBtZXNzYWdlLCBpbmRleDogaSB9XG4gICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgPC9saT5cbiAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAqbmdJZj1cIlxuICAgICAgICAgICAgICAobGFzdFJlYWRNZXNzYWdlSWQgPT09IG1lc3NhZ2U/LmlkICYmXG4gICAgICAgICAgICAgICAgZGlyZWN0aW9uID09PSAnYm90dG9tLXRvLXRvcCcpIHx8XG4gICAgICAgICAgICAgIChkaXJlY3Rpb24gPT09ICd0b3AtdG8tYm90dG9tJyAmJlxuICAgICAgICAgICAgICAgIGxhc3RSZWFkTWVzc2FnZUlkID09PSBtZXNzYWdlc1tpICsgMV0/LmlkKVxuICAgICAgICAgICAgXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8bGlcbiAgICAgICAgICAgICAgKm5nSWY9XCJkaXNwbGF5VW5yZWFkU2VwYXJhdG9yXCJcbiAgICAgICAgICAgICAgaWQ9XCJzdHJlYW0tY2hhdC1uZXctbWVzc2FnZS1pbmRpY2F0b3JcIlxuICAgICAgICAgICAgICBkYXRhLXRlc3RpZD1cIm5ldy1tZXNzYWdlcy1pbmRpY2F0b3JcIlxuICAgICAgICAgICAgICBjbGFzcz1cInN0ci1jaGF0X19saSBzdHItY2hhdF9fdW5yZWFkLW1lc3NhZ2VzLXNlcGFyYXRvci13cmFwcGVyXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgICAgICAgICAgICBjdXN0b21uZXdNZXNzYWdlc0luZGljYXRvclRlbXBsYXRlIHx8XG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHROZXdNZXNzYWdlc0luZGljYXRvcjtcbiAgICAgICAgICAgICAgICAgIGNvbnRleHQ6IHsgdW5yZWFkQ291bnQ6IHVucmVhZENvdW50IH1cbiAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8L2xpPlxuICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJpc05leHRNZXNzYWdlT25TZXBhcmF0ZURhdGVbaV1cIj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJcbiAgICAgICAgICAgICAgICBkYXRlU2VwYXJhdG9yO1xuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgICAgICAgICAgIGRhdGU6IG1lc3NhZ2VzW2kgKyAxXS5jcmVhdGVkX2F0LFxuICAgICAgICAgICAgICAgICAgcGFyc2VkRGF0ZTogcGFyc2VEYXRlKG1lc3NhZ2VzW2kgKyAxXS5jcmVhdGVkX2F0KVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDxzdHJlYW0tbG9hZGluZy1pbmRpY2F0b3JcbiAgICAgICAgKm5nSWY9XCJcbiAgICAgICAgICBpc0xvYWRpbmcgJiYgZGlyZWN0aW9uID09PSAndG9wLXRvLWJvdHRvbScgJiYgZGlzcGxheUxvYWRpbmdJbmRpY2F0b3JcbiAgICAgICAgXCJcbiAgICAgICAgZGF0YS10ZXN0aWQ9XCJib3R0b20tbG9hZGluZy1pbmRpY2F0b3JcIlxuICAgICAgPjwvc3RyZWFtLWxvYWRpbmctaW5kaWNhdG9yPlxuICAgIDwvdWw+XG4gICAgPG5nLXRlbXBsYXRlICNkZWZhdWx0VHlwaW5nSW5kaWNhdG9yIGxldC11c2Vyc1R5cGluZyQ9XCJ1c2Vyc1R5cGluZyRcIj5cbiAgICAgIDwhLS0gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC90ZW1wbGF0ZS9uby1hbnkgLS0+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiJGFueSh1c2Vyc1R5cGluZyQgfCBhc3luYykgYXMgdXNlcnNcIj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgICpuZ0lmPVwidXNlcnMubGVuZ3RoID4gMFwiXG4gICAgICAgICAgZGF0YS10ZXN0aWQ9XCJ0eXBpbmctaW5kaWNhdG9yXCJcbiAgICAgICAgICBjbGFzcz1cInN0ci1jaGF0X190eXBpbmctaW5kaWNhdG9yIHN0ci1jaGF0X190eXBpbmctaW5kaWNhdG9yLS10eXBpbmdcIlxuICAgICAgICA+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0ci1jaGF0X190eXBpbmctaW5kaWNhdG9yX19kb3RzXCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInN0ci1jaGF0X190eXBpbmctaW5kaWNhdG9yX19kb3RcIj48L3NwYW4+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInN0ci1jaGF0X190eXBpbmctaW5kaWNhdG9yX19kb3RcIj48L3NwYW4+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInN0ci1jaGF0X190eXBpbmctaW5kaWNhdG9yX19kb3RcIj48L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgZGF0YS10ZXN0aWQ9XCJ0eXBpbmctdXNlcnNcIlxuICAgICAgICAgICAgY2xhc3M9XCJzdHItY2hhdF9fdHlwaW5nLWluZGljYXRvcl9fdXNlcnNcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIHt7XG4gICAgICAgICAgICAgIHVzZXJzLmxlbmd0aCA9PT0gMVxuICAgICAgICAgICAgICAgID8gKFwic3RyZWFtQ2hhdC51c2VyIGlzIHR5cGluZ1wiXG4gICAgICAgICAgICAgICAgICB8IHRyYW5zbGF0ZTogeyB1c2VyOiBnZXRUeXBpbmdJbmRpY2F0b3JUZXh0KHVzZXJzKSB9KVxuICAgICAgICAgICAgICAgIDogKFwic3RyZWFtQ2hhdC51c2VycyBhcmUgdHlwaW5nXCJcbiAgICAgICAgICAgICAgICAgIHwgdHJhbnNsYXRlOiB7IHVzZXJzOiBnZXRUeXBpbmdJbmRpY2F0b3JUZXh0KHVzZXJzKSB9KVxuICAgICAgICAgICAgfX1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLXRlbXBsYXRlPlxuICAgIDxuZy1jb250YWluZXJcbiAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgIHR5cGluZ0luZGljYXRvclRlbXBsYXRlIHx8IGRlZmF1bHRUeXBpbmdJbmRpY2F0b3I7XG4gICAgICAgIGNvbnRleHQ6IGdldFR5cGluZ0luZGljYXRvckNvbnRleHQoKVxuICAgICAgXCJcbiAgICA+PC9uZy1jb250YWluZXI+XG4gIDwvZGl2PlxuPC9kaXY+XG48ZGl2IGNsYXNzPVwic3RyLWNoYXRfX2p1bXAtdG8tbGF0ZXN0LW1lc3NhZ2VcIj5cbiAgPGJ1dHRvblxuICAgICpuZ0lmPVwiaXNVc2VyU2Nyb2xsZWQgJiYgaXNKdW1wVG9MYXRlc3RCdXR0b25WaXNpYmxlXCJcbiAgICBkYXRhLXRlc3RpZD1cInNjcm9sbC10by1sYXRlc3RcIlxuICAgIGNsYXNzPVwiXG4gICAgICBzdHItY2hhdF9fbWVzc2FnZS1ub3RpZmljYXRpb24tc2Nyb2xsLXRvLWxhdGVzdFxuICAgICAgc3RyLWNoYXRfX21lc3NhZ2Utbm90aWZpY2F0aW9uLXNjcm9sbC10by1sYXRlc3QtcmlnaHRcbiAgICAgIHN0ci1jaGF0X19jaXJjbGUtZmFiXG4gICAgXCJcbiAgICAoa2V5dXAuZW50ZXIpPVwianVtcFRvTGF0ZXN0TWVzc2FnZSgpXCJcbiAgICAoY2xpY2spPVwianVtcFRvTGF0ZXN0TWVzc2FnZSgpXCJcbiAgPlxuICAgIDxzdHJlYW0taWNvblxuICAgICAgY2xhc3M9XCJzdHItY2hhdF9fanVtcC10by1sYXRlc3QtaWNvbiBzdHItY2hhdF9fY2lyY2xlLWZhYi1pY29uXCJcbiAgICAgIFtpY29uXT1cImRpcmVjdGlvbiA9PT0gJ2JvdHRvbS10by10b3AnID8gJ2Fycm93LWRvd24nIDogJ2Fycm93LXVwJ1wiXG4gICAgPjwvc3RyZWFtLWljb24+XG4gICAgPGRpdlxuICAgICAgKm5nSWY9XCJuZXdNZXNzYWdlQ291bnRXaGlsZUJlaW5nU2Nyb2xsZWQgPiAwXCJcbiAgICAgIGNsYXNzPVwiXG4gICAgICAgIHN0ci1jaGF0X19tZXNzYWdlLW5vdGlmaWNhdGlvblxuICAgICAgICBzdHItY2hhdF9fbWVzc2FnZS1ub3RpZmljYXRpb24tc2Nyb2xsLXRvLWxhdGVzdC11bnJlYWQtY291bnRcbiAgICAgICAgc3RyLWNoYXRfX2p1bXAtdG8tbGF0ZXN0LXVucmVhZC1jb3VudFxuICAgICAgXCJcbiAgICA+XG4gICAgICB7eyBuZXdNZXNzYWdlQ291bnRXaGlsZUJlaW5nU2Nyb2xsZWQgfX1cbiAgICA8L2Rpdj5cbiAgPC9idXR0b24+XG48L2Rpdj5cblxuPG5nLXRlbXBsYXRlICNtZXNzYWdlVGVtcGxhdGVDb250YWluZXIgbGV0LW1lc3NhZ2U9XCJtZXNzYWdlXCIgbGV0LWluZGV4PVwiaW5kZXhcIj5cbiAgPG5nLXRlbXBsYXRlXG4gICAgI2RlZmF1bHRNZXNzYWdlVGVtcGxhdGVcbiAgICBsZXQtbWVzc2FnZUlucHV0PVwibWVzc2FnZVwiXG4gICAgbGV0LWlzTGFzdFNlbnRNZXNzYWdlPVwiaXNMYXN0U2VudE1lc3NhZ2VcIlxuICAgIGxldC1lbmFibGVkTWVzc2FnZUFjdGlvbnM9XCJlbmFibGVkTWVzc2FnZUFjdGlvbnNcIlxuICAgIGxldC1tb2RlPVwibW9kZVwiXG4gICAgbGV0LWlzSGlnaGxpZ2h0ZWQ9XCJpc0hpZ2hsaWdodGVkXCJcbiAgPlxuICAgIDxzdHJlYW0tbWVzc2FnZVxuICAgICAgW21lc3NhZ2VdPVwibWVzc2FnZUlucHV0XCJcbiAgICAgIFtpc0xhc3RTZW50TWVzc2FnZV09XCJpc0xhc3RTZW50TWVzc2FnZVwiXG4gICAgICBbZW5hYmxlZE1lc3NhZ2VBY3Rpb25zXT1cImVuYWJsZWRNZXNzYWdlQWN0aW9uc1wiXG4gICAgICBbbW9kZV09XCJtb2RlXCJcbiAgICAgIFtpc0hpZ2hsaWdodGVkXT1cImlzSGlnaGxpZ2h0ZWRcIlxuICAgID48L3N0cmVhbS1tZXNzYWdlPlxuICA8L25nLXRlbXBsYXRlPlxuICA8bmctY29udGFpbmVyXG4gICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJcbiAgICAgIG1lc3NhZ2VUZW1wbGF0ZSB8fCBkZWZhdWx0TWVzc2FnZVRlbXBsYXRlO1xuICAgICAgY29udGV4dDoge1xuICAgICAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgICAgICBpc0xhc3RTZW50TWVzc2FnZTogISEoXG4gICAgICAgICAgbGFzdFNlbnRNZXNzYWdlSWQgJiYgbWVzc2FnZT8uaWQgPT09IGxhc3RTZW50TWVzc2FnZUlkXG4gICAgICAgICksXG4gICAgICAgIGVuYWJsZWRNZXNzYWdlQWN0aW9uczogZW5hYmxlZE1lc3NhZ2VBY3Rpb25zLFxuICAgICAgICBtb2RlOiBtb2RlLFxuICAgICAgICBpc0hpZ2hsaWdodGVkOiBtZXNzYWdlPy5pZCA9PT0gaGlnaGxpZ2h0ZWRNZXNzYWdlSWRcbiAgICAgIH1cbiAgICBcIlxuICA+PC9uZy1jb250YWluZXI+XG48L25nLXRlbXBsYXRlPlxuXG48bmctdGVtcGxhdGUgI2RhdGVTZXBhcmF0b3IgbGV0LWRhdGU9XCJkYXRlXCIgbGV0LXBhcnNlZERhdGU9XCJwYXJzZWREYXRlXCI+XG4gIDxuZy1jb250YWluZXIgKm5nSWY9XCJkaXNwbGF5RGF0ZVNlcGFyYXRvclwiPlxuICAgIDxuZy1jb250YWluZXJcbiAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgIGN1c3RvbURhdGVTZXBhcmF0b3JUZW1wbGF0ZSB8fCBkZWZhdWx0RGF0ZVNlcGFyYXRvcjtcbiAgICAgICAgY29udGV4dDoge1xuICAgICAgICAgIGRhdGU6IGRhdGUsXG4gICAgICAgICAgcGFyc2VkRGF0ZTogcGFyc2VkRGF0ZVxuICAgICAgICB9XG4gICAgICBcIlxuICAgID48L25nLWNvbnRhaW5lcj5cbiAgPC9uZy1jb250YWluZXI+XG5cbiAgPG5nLXRlbXBsYXRlXG4gICAgI2RlZmF1bHREYXRlU2VwYXJhdG9yXG4gICAgbGV0LWRhdGU9XCJkYXRlXCJcbiAgICBsZXQtcGFyc2VkRGF0ZT1cInBhcnNlZERhdGVcIlxuICA+XG4gICAgPGRpdiBkYXRhLXRlc3RpZD1cImRhdGUtc2VwYXJhdG9yXCIgY2xhc3M9XCJzdHItY2hhdF9fZGF0ZS1zZXBhcmF0b3JcIj5cbiAgICAgIDxoclxuICAgICAgICAqbmdJZj1cIlxuICAgICAgICAgIGRhdGVTZXBhcmF0b3JUZXh0UG9zID09PSAncmlnaHQnIHx8IGRhdGVTZXBhcmF0b3JUZXh0UG9zID09PSAnY2VudGVyJ1xuICAgICAgICBcIlxuICAgICAgICBjbGFzcz1cInN0ci1jaGF0X19kYXRlLXNlcGFyYXRvci1saW5lXCJcbiAgICAgIC8+XG4gICAgICA8ZGl2IGNsYXNzPVwic3RyLWNoYXRfX2RhdGUtc2VwYXJhdG9yLWRhdGVcIj5cbiAgICAgICAge3sgcGFyc2VkRGF0ZSB9fVxuICAgICAgPC9kaXY+XG4gICAgICA8aHJcbiAgICAgICAgKm5nSWY9XCJcbiAgICAgICAgICBkYXRlU2VwYXJhdG9yVGV4dFBvcyA9PT0gJ2xlZnQnIHx8IGRhdGVTZXBhcmF0b3JUZXh0UG9zID09PSAnY2VudGVyJ1xuICAgICAgICBcIlxuICAgICAgICBjbGFzcz1cInN0ci1jaGF0X19kYXRlLXNlcGFyYXRvci1saW5lXCJcbiAgICAgIC8+XG4gICAgPC9kaXY+XG4gIDwvbmctdGVtcGxhdGU+XG48L25nLXRlbXBsYXRlPlxuXG48bmctdGVtcGxhdGUgI2RlZmF1bHROZXdNZXNzYWdlc0luZGljYXRvciBsZXQtdW5yZWFkQ291bnQ9XCJ1bnJlYWRDb3VudFwiPlxuICA8ZGl2IGNsYXNzPVwic3RyLWNoYXRfX3VucmVhZC1tZXNzYWdlcy1zZXBhcmF0b3JcIj5cbiAgICA8bmctY29udGFpbmVyXG4gICAgICAqbmdJZj1cIlxuICAgICAgICB1bnJlYWRDb3VudCA+IDAgJiYgIWhpZGVVbnJlYWRDb3VudEZvck5vdGlmaWNhdGlvbkFuZEluZGljYXRvcjtcbiAgICAgICAgZWxzZSBub1VucmVhZENvdW50XG4gICAgICBcIlxuICAgID5cbiAgICAgIHt7XG4gICAgICAgICh1bnJlYWRDb3VudCA9PT0gMVxuICAgICAgICAgID8gXCJzdHJlYW1DaGF0Llxce1xce2NvdW50XFx9XFx9IHVucmVhZCBtZXNzYWdlXCJcbiAgICAgICAgICA6IFwic3RyZWFtQ2hhdC5cXHtcXHtjb3VudFxcfVxcfSB1bnJlYWQgbWVzc2FnZXNcIlxuICAgICAgICApIHwgdHJhbnNsYXRlOiB7IGNvdW50OiB1bnJlYWRDb3VudCB9XG4gICAgICB9fVxuICAgIDwvbmctY29udGFpbmVyPlxuICAgIDxuZy10ZW1wbGF0ZSAjbm9VbnJlYWRDb3VudD5cbiAgICAgIHt7IFwic3RyZWFtQ2hhdC5VbnJlYWQgbWVzc2FnZXNcIiB8IHRyYW5zbGF0ZSB9fVxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvZGl2PlxuPC9uZy10ZW1wbGF0ZT5cbiJdfQ==