fmode-ng 0.0.113 → 0.0.115

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 (275) hide show
  1. package/LICENSE.md +8 -0
  2. package/README.md +37 -37
  3. package/esm2022/fmode-ng.mjs +10 -5
  4. package/esm2022/lib/aigc/agent/fm-agent-task/fm-agent-task.component.mjs +8 -92
  5. package/esm2022/lib/aigc/agent/index.mjs +10 -3
  6. package/esm2022/lib/aigc/avatar/avatar.module.mjs +10 -45
  7. package/esm2022/lib/aigc/avatar/comp-avatar-particle/avatar.role.mjs +10 -2
  8. package/esm2022/lib/aigc/avatar/comp-avatar-particle/comp-avatar-particle.component.mjs +10 -315
  9. package/esm2022/lib/aigc/avatar/comp-avatar-particle/index.mjs +10 -3
  10. package/esm2022/lib/aigc/avatar/comp-avatar-particle/role-points.class.mjs +10 -57
  11. package/esm2022/lib/aigc/avatar/comp-avatar-role-image/comp-avatar-role-image.component.mjs +10 -98
  12. package/esm2022/lib/aigc/avatar/comp-avatar-role-video/comp-avatar-role-video.component.mjs +10 -107
  13. package/esm2022/lib/aigc/avatar/comp-avatar-talk/comp-avatar-talk.component.mjs +10 -113
  14. package/esm2022/lib/aigc/avatar/index.mjs +10 -8
  15. package/esm2022/lib/aigc/avatar/interface-avatar-role.mjs +10 -2
  16. package/esm2022/lib/aigc/avatar/modal-chat-voice-input/modal-chat-voice-input.component.mjs +8 -164
  17. package/esm2022/lib/aigc/chat/chat-header-area/comp-header-area.component.mjs +10 -49
  18. package/esm2022/lib/aigc/chat/chat-header-area/index.mjs +10 -2
  19. package/esm2022/lib/aigc/chat/chat-list/chat-list.component.mjs +8 -155
  20. package/esm2022/lib/aigc/chat/chat-list/index.mjs +10 -2
  21. package/esm2022/lib/aigc/chat/chat-message-area/comp-message-area.component.mjs +10 -40
  22. package/esm2022/lib/aigc/chat/chat-message-area/index.mjs +10 -2
  23. package/esm2022/lib/aigc/chat/chat-message-card/comp-message-card.component.mjs +10 -140
  24. package/esm2022/lib/aigc/chat/chat-message-card/duration-str.pipe.mjs +10 -29
  25. package/esm2022/lib/aigc/chat/chat-message-card/index.mjs +10 -3
  26. package/esm2022/lib/aigc/chat/chat-modal-input/index.mjs +10 -3
  27. package/esm2022/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.mjs +8 -193
  28. package/esm2022/lib/aigc/chat/chat-modal-input/modal-input.component.mjs +10 -331
  29. package/esm2022/lib/aigc/chat/chat-panel/chat-panel.component.mjs +8 -249
  30. package/esm2022/lib/aigc/chat/comp-role-prompt/comp-role-prompt.component.mjs +10 -83
  31. package/esm2022/lib/aigc/chat/comp-role-prompt/index.mjs +10 -2
  32. package/esm2022/lib/aigc/chat/index.mjs +10 -8
  33. package/esm2022/lib/aigc/comp-markdown-preview/clipboard.service.mjs +10 -82
  34. package/esm2022/lib/aigc/comp-markdown-preview/markdown-parse.mjs +8 -367
  35. package/esm2022/lib/aigc/comp-markdown-preview/markdown-preview.component.mjs +10 -51
  36. package/esm2022/lib/aigc/comp-markdown-preview/markdown-preview.module.mjs +10 -24
  37. package/esm2022/lib/aigc/comp-markdown-preview/plugins/md-mathjax/index.mjs +10 -115
  38. package/esm2022/lib/aigc/index.mjs +10 -14
  39. package/esm2022/lib/aigc/service-fmai/fmai.service.mjs +10 -21
  40. package/esm2022/lib/aigc/service-fmai/service-chat/chat-class.mjs +10 -2
  41. package/esm2022/lib/aigc/service-fmai/service-chat/chat.service.mjs +8 -174
  42. package/esm2022/lib/aigc/service-fmai/service-chat/index.mjs +10 -7
  43. package/esm2022/lib/aigc/service-fmai/service-chat/mask-list.mjs +9 -194
  44. package/esm2022/lib/aigc/service-fmai/service-chat/pipes/chat-content.pipe.mjs +10 -27
  45. package/esm2022/lib/aigc/service-fmai/service-chat/pipes/hidexml.pipe.mjs +10 -27
  46. package/esm2022/lib/aigc/service-fmai/service-chat/utilnow.pipe.mjs +10 -68
  47. package/esm2022/lib/aigc/service-fmai/service-imagine/imagine-func.mjs +9 -162
  48. package/esm2022/lib/aigc/service-fmai/service-imagine/imagine-work.mjs +10 -68
  49. package/esm2022/lib/aigc/service-fmai/service-imagine/imagine.service.mjs +8 -313
  50. package/esm2022/lib/aigc/service-fmai/service-imagine/index.mjs +10 -4
  51. package/esm2022/lib/aigc/story/fm-office-viewer/fm-office-viewer.component.mjs +10 -62
  52. package/esm2022/lib/aigc/story/fm-story-card/fm-story-card.component.mjs +10 -87
  53. package/esm2022/lib/aigc/story/fm-story-list/fm-story-list.component.mjs +10 -345
  54. package/esm2022/lib/aigc/story/fm-story-list/story-preview.mjs +10 -81
  55. package/esm2022/lib/aigc/story/fm-story-loader/fm-story-loader.component.mjs +10 -152
  56. package/esm2022/lib/aigc/story/fm-story-splitter/fm-story-splitter.component.mjs +10 -42
  57. package/esm2022/lib/aigc/story/index.mjs +10 -6
  58. package/esm2022/lib/aigc/story/modal-chat-story/comp-chat-story-json/comp-chat-story-json.component.mjs +10 -47
  59. package/esm2022/lib/aigc/story/modal-chat-story/comp-diary-story/comp-diary-story.component.mjs +10 -95
  60. package/esm2022/lib/aigc/story/modal-chat-story/modal-chat-story.component.mjs +10 -253
  61. package/esm2022/lib/aigc/story/story.service.mjs +10 -35
  62. package/esm2022/lib/aigc/voice/fmode-voice.service.mjs +10 -636
  63. package/esm2022/lib/aigc/voice/index.mjs +10 -7
  64. package/esm2022/lib/aigc/voice/lib/audio/audio.player.mjs +10 -55
  65. package/esm2022/lib/aigc/voice/lib/audio/audio.streamer.mjs +10 -2
  66. package/esm2022/lib/aigc/voice/lib/audio/streamer.microsoft.mjs +10 -96
  67. package/esm2022/lib/aigc/voice/lib/audio/streamer.pcm.mjs +8 -177
  68. package/esm2022/lib/aigc/voice/lib/pcm2wav.mjs +10 -38
  69. package/esm2022/lib/aigc/voice/lib/recorder/extension-waveview.mjs +10 -215
  70. package/esm2022/lib/aigc/voice/lib/resample.mjs +10 -34
  71. package/esm2022/lib/aigc/voice/tts/fmode-tts-class.mjs +10 -189
  72. package/esm2022/lib/aigc/voice/tts/index.mjs +10 -5
  73. package/esm2022/lib/aigc/voice/tts/int-tts-provider.mjs +10 -2
  74. package/esm2022/lib/aigc/voice/tts/provider-doubao.mjs +8 -346
  75. package/esm2022/lib/code/fm-codemirror/fm-codemirror.component.mjs +8 -342
  76. package/esm2022/lib/code/index.mjs +10 -2
  77. package/esm2022/lib/core/agent/chat/completion/fmode-completion.mjs +8 -430
  78. package/esm2022/lib/core/agent/chat/completion/index.mjs +10 -2
  79. package/esm2022/lib/core/agent/chat/completion/int-gpt-chat-options.mjs +10 -2
  80. package/esm2022/lib/core/agent/chat/fmode-chat.mjs +8 -617
  81. package/esm2022/lib/core/agent/chat/index.mjs +10 -4
  82. package/esm2022/lib/core/agent/chat/interface.mjs +10 -2
  83. package/esm2022/lib/core/agent/index.mjs +10 -6
  84. package/esm2022/lib/core/agent/prompt/agent.prompt.mjs +10 -133
  85. package/esm2022/lib/core/agent/prompt/index.mjs +10 -2
  86. package/esm2022/lib/core/agent/prompt/prompt-util.mjs +10 -16
  87. package/esm2022/lib/core/agent/story/agent.story.mjs +10 -64
  88. package/esm2022/lib/core/agent/story/index.mjs +10 -2
  89. package/esm2022/lib/core/agent/task/agent.task.mjs +10 -90
  90. package/esm2022/lib/core/agent/task/index.mjs +10 -2
  91. package/esm2022/lib/core/agent/waiting/index.mjs +10 -3
  92. package/esm2022/lib/core/agent/waiting/loading/loading.ctrl.mjs +10 -279
  93. package/esm2022/lib/core/agent/waiting/tips/tips.ctrl.mjs +8 -190
  94. package/esm2022/lib/core/index.mjs +10 -4
  95. package/esm2022/lib/core/parse/datatype/acl.mjs +10 -57
  96. package/esm2022/lib/core/parse/datatype/file.mjs +10 -69
  97. package/esm2022/lib/core/parse/datatype/geopoint.mjs +10 -57
  98. package/esm2022/lib/core/parse/datatype/relation.mjs +10 -56
  99. package/esm2022/lib/core/parse/fmode.cloud.mjs +10 -0
  100. package/esm2022/lib/core/parse/fmode.object.mjs +10 -232
  101. package/esm2022/lib/core/parse/fmode.parse.mjs +10 -84
  102. package/esm2022/lib/core/parse/fmode.query.mjs +8 -500
  103. package/esm2022/lib/core/parse/fmode.user.mjs +10 -275
  104. package/esm2022/lib/core/parse/index.mjs +10 -5
  105. package/esm2022/lib/core/parse/types.mjs +10 -2
  106. package/esm2022/lib/core/voice/index.mjs +10 -3
  107. package/esm2022/lib/core/voice/tts/index.mjs +10 -2
  108. package/esm2022/lib/icon/filetype/audio.svg.mjs +10 -3
  109. package/esm2022/lib/icon/filetype/avatar.svg.mjs +10 -14
  110. package/esm2022/lib/icon/filetype/chat.svg.mjs +10 -3
  111. package/esm2022/lib/icon/filetype/docx.svg.mjs +10 -3
  112. package/esm2022/lib/icon/filetype/file.svg.mjs +10 -3
  113. package/esm2022/lib/icon/filetype/filetype.pipe.mjs +10 -57
  114. package/esm2022/lib/icon/filetype/index.mjs +10 -12
  115. package/esm2022/lib/icon/filetype/md.svg.mjs +10 -3
  116. package/esm2022/lib/icon/filetype/pdf.svg.mjs +10 -3
  117. package/esm2022/lib/icon/filetype/pptx.svg.mjs +10 -3
  118. package/esm2022/lib/icon/filetype/svgtoblob.mjs +10 -8
  119. package/esm2022/lib/icon/filetype/video.svg.mjs +10 -3
  120. package/esm2022/lib/icon/filetype/xlsx.svg.mjs +10 -3
  121. package/esm2022/lib/icon/index.mjs +10 -2
  122. package/esm2022/lib/map/comp-poi-picker/comp-poi-picker.component.mjs +10 -209
  123. package/esm2022/lib/map/comp-poi-picker/comp-poi-picker.module.mjs +10 -33
  124. package/esm2022/lib/map/index.mjs +10 -4
  125. package/esm2022/lib/map/map.module.mjs +10 -61
  126. package/esm2022/lib/map/page-loca-scatter/page-loca-scatter.component.mjs +10 -132
  127. package/esm2022/lib/map/page-map.start/page-map.start.component.mjs +8 -115
  128. package/esm2022/lib/map/page-plan-route/page-plan-route.component.mjs +8 -118
  129. package/esm2022/lib/nova-cloud/index.mjs +10 -3
  130. package/esm2022/lib/nova-cloud/ncloud-api-func.mjs +10 -91
  131. package/esm2022/lib/nova-cloud/nova-cloud.service.mjs +10 -53
  132. package/esm2022/lib/payment/index.mjs +10 -2
  133. package/esm2022/lib/payment/payment/payment.component.mjs +10 -543
  134. package/esm2022/lib/payment/payment.service.mjs +10 -202
  135. package/esm2022/lib/person/comp-person-gender-icon/comp-person-gender-icon.component.mjs +10 -48
  136. package/esm2022/lib/person/comp-person-item/comp-person-item.component.mjs +10 -29
  137. package/esm2022/lib/person/comp-person-story/comp-person-story.component.mjs +10 -211
  138. package/esm2022/lib/person/edit-upload/edit-upload.component.mjs +8 -412
  139. package/esm2022/lib/person/edit-upload/edit-upload.module.mjs +10 -50
  140. package/esm2022/lib/person/index.mjs +10 -5
  141. package/esm2022/lib/person/modal-person-select/modal-person-select.component.mjs +10 -144
  142. package/esm2022/lib/person/modal-user-verify/secret-text.pipe.mjs +10 -41
  143. package/esm2022/lib/person/modal-user-verify/user-verify.component.mjs +10 -595
  144. package/esm2022/lib/person/person-detail/person-detail.component.mjs +10 -172
  145. package/esm2022/lib/person/person.service.mjs +8 -193
  146. package/esm2022/lib/platform/cross.service.mjs +10 -62
  147. package/esm2022/lib/platform/index.mjs +10 -2
  148. package/esm2022/lib/social/index.mjs +10 -2
  149. package/esm2022/lib/social/wechat/wechat-jssdk.service.mjs +8 -230
  150. package/esm2022/lib/storage/comp-hwobs-manager/hwobs-manager.component.mjs +10 -59
  151. package/esm2022/lib/storage/index.mjs +10 -5
  152. package/esm2022/lib/storage/service-hwobs/hwobs.service.mjs +8 -131
  153. package/esm2022/lib/storage/service-hwobs/index.mjs +10 -3
  154. package/esm2022/lib/storage/service-hwobs/typings/esdk-obs-browser.mjs +1 -1
  155. package/esm2022/lib/storage/service-upload/index.mjs +10 -2
  156. package/esm2022/lib/storage/service-upload/nova-upload.service.mjs +8 -513
  157. package/esm2022/lib/storage/service-upload/util-file-md5.mjs +10 -28
  158. package/esm2022/lib/storage/service-upload/util-file-metadata.mjs +10 -93
  159. package/esm2022/lib/storage/storage.module.mjs +10 -42
  160. package/esm2022/lib/text/fm-article-editor/article-editor-topbar/article-editor-topbar.component.mjs +10 -72
  161. package/esm2022/lib/text/fm-article-editor/article.service.mjs +10 -237
  162. package/esm2022/lib/text/fm-article-editor/comp-upload-book-banners/comp-upload-book-banners.component.mjs +8 -72
  163. package/esm2022/lib/text/fm-article-editor/draft.service.mjs +10 -207
  164. package/esm2022/lib/text/fm-article-editor/fm-article-aitool/fm-article-aitool.component.mjs +8 -227
  165. package/esm2022/lib/text/fm-article-editor/fm-article-draft/fm-article-draft.component.mjs +10 -303
  166. package/esm2022/lib/text/fm-article-editor/fm-article-editor.component.mjs +8 -371
  167. package/esm2022/lib/text/fm-article-editor/fm-article-outline/fm-article-outline.component.mjs +10 -94
  168. package/esm2022/lib/text/fm-article-editor/fm-article-outline-leftitem/fm-article-outline-leftitem.component.mjs +10 -36
  169. package/esm2022/lib/text/fm-article-editor/fm-article-preview/fm-article-preview.component.mjs +10 -281
  170. package/esm2022/lib/text/fm-article-editor/fm-article-write-options/fm-article-write-options.component.mjs +10 -72
  171. package/esm2022/lib/text/fm-article-editor/outline-count.pipe.mjs +10 -22
  172. package/esm2022/lib/text/fm-article-editor/prompt/prompt-insertion-article.mjs +10 -169
  173. package/esm2022/lib/text/fm-article-editor/task-article-generation.mjs +10 -69
  174. package/esm2022/lib/text/fm-article-editor/tasks/task-article-draft-create.mjs +10 -65
  175. package/esm2022/lib/text/fm-article-editor/tasks/task-article-outline-edit.mjs +10 -55
  176. package/esm2022/lib/text/fm-article-editor/tasks/task-article-outline.mjs +10 -142
  177. package/esm2022/lib/text/fm-article-editor/tasks/task-article-preview.mjs +10 -35
  178. package/esm2022/lib/text/fm-article-editor/tasks/task-article-writing-options.mjs +10 -81
  179. package/esm2022/lib/text/fm-article-editor/tasks/task-document-select.mjs +10 -50
  180. package/esm2022/lib/text/fm-text-quill/fm-text-quill.component.mjs +10 -145
  181. package/esm2022/lib/text/index.mjs +10 -4
  182. package/esm2022/lib/user/account/account.service.mjs +10 -222
  183. package/esm2022/lib/user/captcha/captcha.component.mjs +10 -135
  184. package/esm2022/lib/user/comp-user-avatar/comp-user-avatar.component.mjs +10 -66
  185. package/esm2022/lib/user/index.mjs +10 -17
  186. package/esm2022/lib/user/login/auth.guard.mjs +10 -28
  187. package/esm2022/lib/user/login/auth.service.mjs +8 -433
  188. package/esm2022/lib/user/login/login.component.mjs +10 -916
  189. package/esm2022/lib/user/modal-user-login/modal-user-login.component.mjs +10 -311
  190. package/esm2022/lib/user/profile/auth-profile.guard.mjs +10 -27
  191. package/esm2022/lib/user/profile/auth-profile.service.mjs +10 -122
  192. package/esm2022/lib/user/profile/profile-bind/profile-bind.component.mjs +10 -164
  193. package/esm2022/lib/user/profile/profile-bind/profile-confirm-modal.component.mjs +10 -79
  194. package/esm2022/lib/user/profile/profile.module.mjs +10 -54
  195. package/esm2022/lib/user/staff/index.mjs +10 -4
  196. package/esm2022/lib/user/staff/staff.guard.mjs +10 -26
  197. package/esm2022/lib/user/staff/staff.module.mjs +10 -18
  198. package/esm2022/lib/user/staff/staff.service.mjs +10 -85
  199. package/esm2022/lib/user/user-name.pipe.mjs +10 -29
  200. package/esm2022/lib/user/user.module.mjs +10 -102
  201. package/esm2022/lib/video/fm-video/fm-video.component.mjs +10 -67
  202. package/esm2022/lib/video/index.mjs +10 -2
  203. package/esm2022/public-api.mjs +10 -21
  204. package/fesm2022/fmode-ng.mjs +7 -19788
  205. package/fesm2022/fmode-ng.mjs.map +1 -1
  206. package/lib/aigc/avatar/comp-avatar-role-image/comp-avatar-role-image.component.d.ts +2 -2
  207. package/lib/aigc/avatar/comp-avatar-role-video/comp-avatar-role-video.component.d.ts +2 -2
  208. package/lib/aigc/avatar/comp-avatar-talk/comp-avatar-talk.component.d.ts +2 -2
  209. package/lib/aigc/chat/chat-list/chat-list.component.d.ts +3 -2
  210. package/lib/aigc/chat/chat-message-card/comp-message-card.component.d.ts +3 -3
  211. package/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.d.ts +2 -2
  212. package/lib/aigc/chat/chat-modal-input/modal-input.component.d.ts +3 -3
  213. package/lib/aigc/service-fmai/service-imagine/imagine-func.d.ts +3 -3
  214. package/lib/aigc/service-fmai/service-imagine/imagine-work.d.ts +4 -4
  215. package/lib/aigc/service-fmai/service-imagine/imagine.service.d.ts +6 -6
  216. package/lib/aigc/story/fm-office-viewer/fm-office-viewer.component.d.ts +2 -2
  217. package/lib/aigc/story/fm-story-card/fm-story-card.component.d.ts +2 -1
  218. package/lib/aigc/story/fm-story-list/fm-story-list.component.d.ts +6 -6
  219. package/lib/aigc/story/fm-story-list/story-preview.d.ts +4 -4
  220. package/lib/aigc/story/fm-story-loader/fm-story-loader.component.d.ts +3 -3
  221. package/lib/aigc/story/fm-story-splitter/fm-story-splitter.component.d.ts +2 -2
  222. package/lib/aigc/story/modal-chat-story/comp-chat-story-json/comp-chat-story-json.component.d.ts +3 -2
  223. package/lib/aigc/story/modal-chat-story/comp-diary-story/comp-diary-story.component.d.ts +3 -2
  224. package/lib/aigc/story/modal-chat-story/modal-chat-story.component.d.ts +6 -6
  225. package/lib/aigc/story/story.service.d.ts +3 -2
  226. package/lib/aigc/voice/tts/fmode-tts-class.d.ts +2 -2
  227. package/lib/core/agent/chat/fmode-chat.d.ts +11 -11
  228. package/lib/core/agent/story/agent.story.d.ts +8 -8
  229. package/lib/core/parse/datatype/geopoint.d.ts +5 -1
  230. package/lib/core/parse/fmode.cloud.d.ts +32 -0
  231. package/lib/core/parse/fmode.object.d.ts +2 -2
  232. package/lib/core/parse/fmode.parse.d.ts +15 -9
  233. package/lib/core/parse/fmode.query.d.ts +41 -2
  234. package/lib/core/parse/fmode.user.d.ts +1 -0
  235. package/lib/core/parse/index.d.ts +1 -0
  236. package/lib/core/parse/types.d.ts +2 -0
  237. package/lib/map/comp-poi-picker/comp-poi-picker.component.d.ts +5 -5
  238. package/lib/payment/payment/payment.component.d.ts +3 -3
  239. package/lib/payment/payment.service.d.ts +4 -4
  240. package/lib/person/comp-person-gender-icon/comp-person-gender-icon.component.d.ts +2 -1
  241. package/lib/person/comp-person-item/comp-person-item.component.d.ts +2 -1
  242. package/lib/person/comp-person-story/comp-person-story.component.d.ts +13 -13
  243. package/lib/person/edit-upload/edit-upload.component.d.ts +1 -1
  244. package/lib/person/modal-person-select/modal-person-select.component.d.ts +5 -5
  245. package/lib/person/modal-user-verify/user-verify.component.d.ts +5 -5
  246. package/lib/person/person-detail/person-detail.component.d.ts +4 -4
  247. package/lib/person/person.service.d.ts +7 -7
  248. package/lib/storage/service-hwobs/hwobs.service.d.ts +4 -5
  249. package/lib/storage/service-upload/nova-upload.service.d.ts +5 -5
  250. package/lib/text/fm-article-editor/article-editor-topbar/article-editor-topbar.component.d.ts +2 -1
  251. package/lib/text/fm-article-editor/article.service.d.ts +12 -12
  252. package/lib/text/fm-article-editor/draft.service.d.ts +5 -5
  253. package/lib/text/fm-article-editor/fm-article-aitool/fm-article-aitool.component.d.ts +3 -2
  254. package/lib/text/fm-article-editor/fm-article-draft/fm-article-draft.component.d.ts +16 -17
  255. package/lib/text/fm-article-editor/fm-article-editor.component.d.ts +3 -3
  256. package/lib/text/fm-article-editor/fm-article-outline/fm-article-outline.component.d.ts +11 -10
  257. package/lib/text/fm-article-editor/fm-article-preview/fm-article-preview.component.d.ts +2 -2
  258. package/lib/text/fm-article-editor/prompt/prompt-insertion-article.d.ts +3 -3
  259. package/lib/text/fm-article-editor/task-article-generation.d.ts +5 -4
  260. package/lib/text/fm-article-editor/tasks/task-article-draft-create.d.ts +3 -3
  261. package/lib/text/fm-article-editor/tasks/task-article-outline-edit.d.ts +3 -3
  262. package/lib/text/fm-article-editor/tasks/task-article-outline.d.ts +3 -3
  263. package/lib/text/fm-article-editor/tasks/task-article-preview.d.ts +2 -1
  264. package/lib/text/fm-article-editor/tasks/task-article-writing-options.d.ts +3 -3
  265. package/lib/text/fm-article-editor/tasks/task-document-select.d.ts +3 -3
  266. package/lib/user/account/account.service.d.ts +2 -2
  267. package/lib/user/comp-user-avatar/comp-user-avatar.component.d.ts +2 -2
  268. package/lib/user/login/auth.service.d.ts +5 -5
  269. package/lib/user/login/login.component.d.ts +3 -3
  270. package/lib/user/profile/auth-profile.service.d.ts +8 -8
  271. package/lib/user/profile/profile-bind/profile-bind.component.d.ts +7 -7
  272. package/lib/user/profile/profile-bind/profile-confirm-modal.component.d.ts +2 -2
  273. package/lib/user/staff/staff.service.d.ts +3 -3
  274. package/lib/user/user-name.pipe.d.ts +2 -2
  275. package/package.json +12 -18
@@ -1,331 +1,10 @@
1
- import { Component, Input, ViewChild } from '@angular/core';
2
- import { Router, RouterModule } from '@angular/router';
3
- import { AlertController, ToastController } from '@ionic/angular';
4
- import { FmodeChat } from '../../service-fmai/service-chat';
5
- import { ChatService } from '../../service-fmai/service-chat';
6
- // import { AuthService } from 'fmode-ng';
7
- import Parse from "parse";
8
- import { ImagineService } from '../../service-fmai/service-imagine/imagine.service';
9
- import { IonButton, IonContent, IonIcon, IonInput, IonItem, IonList, IonModal, IonPopover, IonTextarea, IonToolbar, ModalController } from '@ionic/angular/standalone';
10
- import { CommonModule } from '@angular/common';
11
- import { FormsModule, ReactiveFormsModule } from '@angular/forms';
12
- import { ModalAudioMessageComponent } from "./modal-audio-message/modal-audio-message.component";
13
- import { FmChatMessageCard } from '../chat-message-card/comp-message-card.component';
14
- import { addIcons } from 'ionicons';
15
- import { imageOutline, chevronBackOutline, ellipsisHorizontalOutline, chevronDownOutline, chatboxEllipsesOutline, micOutline, paperPlaneOutline, shareSocialOutline, settingsOutline, alertOutline, colorWandOutline, peopleOutline } from 'ionicons/icons';
16
- import { AccountService } from '../../../user/account/account.service';
17
- import * as i0 from "@angular/core";
18
- import * as i1 from "@ionic/angular";
19
- import * as i2 from "@ionic/angular/standalone";
20
- import * as i3 from "@angular/router";
21
- import * as i4 from "../../service-fmai/service-imagine/imagine.service";
22
- import * as i5 from "../../service-fmai/service-chat";
23
- import * as i6 from "../../../user/account/account.service";
24
- import * as i7 from "@angular/common";
25
- import * as i8 from "@angular/forms";
26
- addIcons({ colorWandOutline, peopleOutline, alertOutline, imageOutline, chevronBackOutline, ellipsisHorizontalOutline, chevronDownOutline, chatboxEllipsesOutline, micOutline, paperPlaneOutline, shareSocialOutline, settingsOutline });
27
- export class FmChatModalInput {
28
- closeAudio() {
29
- this.audioComp?.cancel();
30
- this.isAudioModal = false;
31
- }
32
- async startTalk() {
33
- // Check if already sending
34
- if (this.isSending) {
35
- return false;
36
- }
37
- let height = document.body.clientHeight || 960;
38
- this.audioModalHeightPoint = Number((165 / height).toFixed(2));
39
- this.chat.stopPlayingVoice();
40
- // 弹出认证组件
41
- let modal;
42
- modal = await this.modalCtrl.create({
43
- component: ModalAudioMessageComponent,
44
- componentProps: {
45
- chat: this.chat,
46
- modal: modal,
47
- onBreakPointSet: () => {
48
- modal?.setCurrentBreakpoint(this.audioModalHeightPoint);
49
- }
50
- },
51
- breakpoints: [this.audioModalHeightPoint],
52
- initialBreakpoint: this.audioModalHeightPoint,
53
- });
54
- modal.present();
55
- // this.isAudioModal=true;
56
- }
57
- constructor(toastCtrl, alertCtrl, modalCtrl, router, imagineServ,
58
- // private authServ:AuthService,
59
- chatServ, account) {
60
- this.toastCtrl = toastCtrl;
61
- this.alertCtrl = alertCtrl;
62
- this.modalCtrl = modalCtrl;
63
- this.router = router;
64
- this.imagineServ = imagineServ;
65
- this.chatServ = chatServ;
66
- this.account = account;
67
- this.errorText = ``;
68
- // 语音输入控制
69
- this.isAudioModal = false;
70
- this.audioModalHeightPoint = 0.35;
71
- // 发送消息 防抖机制
72
- this.isSending = false;
73
- this.lastMessageTimestamp = 0;
74
- this.replyTimeout = 15000; // 15 seconds timeout
75
- //分享弹框组件
76
- this.isShare = false;
77
- // this.chatServ.getChatSession().then(()=>{
78
- // console.log(this.chatServ.chatList);
79
- // })
80
- this.user = Parse.User.current();
81
- }
82
- ngOnInit() {
83
- this.loadModel();
84
- // console.log(this.chat);
85
- let that = this;
86
- this.chat.focusUserInput = () => {
87
- that.chat.isVoiceInputMode = false;
88
- that.userInputComp.setFocus();
89
- };
90
- }
91
- // ngAfterViewInit(): void {
92
- // console.log(this.chat)
93
- // }
94
- async loadModel() {
95
- let model = this.chat?.role?.get("model");
96
- await this.chat.loadModelList(model);
97
- }
98
- async setMessageImage() {
99
- // let url = `https://file-cloud.fmode.cn/Svehl6FceL/20240515/061503671.jpeg`;
100
- let url = await this.imagineServ.getimg();
101
- this.chat.userImage = url;
102
- console.log(this.chat?.userImage);
103
- // content是数组,添加
104
- // content非数组,重组
105
- }
106
- onInputFocus() {
107
- // console.log("onInputFocus",this.chat.scrollToBottom)
108
- this.chat.isTexting = true;
109
- this.chat.scrollToBottom && this.chat.scrollToBottom();
110
- }
111
- onKeyDown(event) {
112
- // 检查是否按下了Ctrl键和Enter键
113
- if (event.ctrlKey && event.key === 'Enter') {
114
- // 执行相应的逻辑
115
- console.log('Ctrl+Enter 被按下');
116
- this.sendMessage();
117
- }
118
- }
119
- async sendMessage() {
120
- // Check if already sending
121
- if (this.isSending) {
122
- return false;
123
- }
124
- // Check if waiting for previous reply
125
- const now = Date.now();
126
- if (this.lastMessageTimestamp > 0 && (now - this.lastMessageTimestamp) < this.replyTimeout) {
127
- this.errorText = `请等待上一条消息的回复或稍后再试`;
128
- let toast = await this.toastCtrl.create({
129
- message: this.errorText,
130
- position: "top",
131
- icon: 'alert',
132
- color: "warning",
133
- duration: 1000
134
- });
135
- toast.present();
136
- return false;
137
- }
138
- this.isSending = true;
139
- this.lastMessageTimestamp = Date.now();
140
- // 检测用户登录情况
141
- // let isLoginLock = await this.authServ.checkLoginLock()
142
- // if(!isLoginLock) return false
143
- // 检测余额及模型付费限制
144
- let payCheck = await this.checkBalance();
145
- if (!payCheck) {
146
- this.isSending = false;
147
- return false;
148
- }
149
- // 检测用户输入内容空值
150
- if (!this.chat.userInput) {
151
- this.errorText = `内容不能为空`;
152
- let toast = await this.toastCtrl.create({
153
- message: this.errorText,
154
- position: "top",
155
- icon: 'alert',
156
- color: "warning-circle",
157
- duration: 1000
158
- });
159
- toast.present();
160
- this.isSending = false;
161
- return;
162
- }
163
- // Clear any existing timeout
164
- if (this.lastMessageTimeout) {
165
- clearTimeout(this.lastMessageTimeout);
166
- }
167
- // Set timeout to reset sending state if no reply
168
- this.lastMessageTimeout = setTimeout(() => {
169
- this.isSending = false;
170
- this.lastMessageTimestamp = 0;
171
- }, this.replyTimeout);
172
- // 正常发送消息
173
- // this.chat.isTalkMode=true; // 开启说话模式
174
- this.chat?.sendMessage(this.chat?.userInput, this.chat?.userImage, (msg) => { }, {
175
- onMessageStart: (message) => {
176
- // When reply comes, clear timeout and reset state
177
- clearTimeout(this.lastMessageTimeout);
178
- this.isSending = false;
179
- this.lastMessageTimestamp = 0;
180
- },
181
- onSSMLComplete: (voice) => {
182
- console.log(voice);
183
- }
184
- });
185
- this.chat.userInput = ``;
186
- this.chat.userImage = ``;
187
- }
188
- async checkBalance() {
189
- let price = 10;
190
- // 校验账户余额
191
- let billing = await this.account.getBilling();
192
- if (billing?.credit?.balance >= price) {
193
- this.chat.isDirect = true; // 余额充足,不限速
194
- }
195
- // 模型是否开启付费限制
196
- if (!this.chat?.currentModel?.get("payLimit")) {
197
- return true;
198
- }
199
- // let price = await this.calcPrice()
200
- if (billing?.credit?.balance < price) {
201
- let alert = await this.alertCtrl.create({
202
- header: "注意",
203
- subHeader: "您的余额不足,请充值后解锁高级模型",
204
- buttons: [
205
- {
206
- role: "cancel",
207
- text: "取消"
208
- },
209
- {
210
- role: "destructive",
211
- text: "充值",
212
- handler: () => {
213
- // 待更换成原地弹窗,原地付费,避免页面跳转
214
- this.router.navigateByUrl("/account/billing");
215
- }
216
- }
217
- ]
218
- });
219
- alert.present();
220
- return false;
221
- }
222
- return true;
223
- }
224
- //查询问答内容分享数据表:ChatShare
225
- async getChatShare() {
226
- this.user = Parse.User.current();
227
- let query = new Parse.Query('ChatShare');
228
- query.equalTo('user', Parse.User.current().id);
229
- query.equalTo('session', this.chat?.sessionId);
230
- let chatShare = await query.first();
231
- // console.log(chatShare);
232
- }
233
- async toggleChatShare() {
234
- //获取ChatShare数据表
235
- let query = new Parse.Query('ChatShare');
236
- query.equalTo('user', Parse.User.current().id);
237
- query.equalTo('role', this.chat?.role.id);
238
- query.equalTo('session', this.chat?.sessionId);
239
- // query.equalTo('messageList', this.chat?.messageList);
240
- query.select('objectId');
241
- let share = await query.first();
242
- // console.log(share);
243
- //如果id不存在,在数据表内创建新的记录
244
- if (!share?.id) {
245
- let obj = Parse.Object.extend('ChatShare');
246
- share = new obj();
247
- share.set('user', {
248
- "__type": "Pointer",
249
- "className": "_User",
250
- "objectId": Parse.User.current()?.id
251
- });
252
- share.set('session', {
253
- "__type": "Pointer",
254
- "className": "ChatSession",
255
- "objectId": this.chat?.sessionId
256
- });
257
- share.set('role', {
258
- "__type": "Pointer",
259
- "className": "AvatarRole",
260
- "objectId": this.chat?.role.id
261
- });
262
- share.set('company', {
263
- "__type": "Pointer",
264
- "className": "Company",
265
- "objectId": "E4KpGvTEto"
266
- });
267
- share.set('messageList', this.chat?.messageList);
268
- }
269
- else {
270
- //id存在,点击分享按钮执行更新messageList数据的操作
271
- share.set('messageList', this.chat?.messageList);
272
- }
273
- await share.save();
274
- this.getChatShare();
275
- }
276
- async chatShareSuccessMessage() {
277
- let toast = await this.toastCtrl.create({
278
- duration: 1000,
279
- message: "分享成功",
280
- color: 'primary',
281
- icon: "information-circle",
282
- position: "top"
283
- });
284
- toast.present();
285
- return;
286
- }
287
- showShare() {
288
- this.isShare = true;
289
- }
290
- handleOkShare() {
291
- // console.log(this.chat);
292
- // console.log(this.chat?.sessionId);
293
- // console.log(this.chat?.messageList);
294
- // console.log(this.chat?.role.id);
295
- this.toggleChatShare();
296
- this.chatShareSuccessMessage();
297
- this.isShare = false;
298
- }
299
- handleCancelShare() {
300
- this.isShare = false;
301
- }
302
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FmChatModalInput, deps: [{ token: i1.ToastController }, { token: i1.AlertController }, { token: i2.ModalController }, { token: i3.Router }, { token: i4.ImagineService }, { token: i5.ChatService }, { token: i6.AccountService }], target: i0.ɵɵFactoryTarget.Component }); }
303
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FmChatModalInput, isStandalone: true, selector: "fm-chat-modal-input", inputs: { chat: "chat", message: "message", role: "role" }, viewQueries: [{ propertyName: "audioComp", first: true, predicate: ModalAudioMessageComponent, descendants: true }, { propertyName: "userInputComp", first: true, predicate: ["userInput"], descendants: true }], ngImport: i0, template: "<ion-toolbar>\r\n <ion-item class=\"button-item\" lines=\"none\">\r\n <!-- \u8BBE\u7F6E -->\r\n <!-- <ion-button fill=\"outline\" slot=\"start\">\r\n <ion-icon name=\"settings-outline\"></ion-icon> \r\n </ion-button> -->\r\n <ng-container *ngFor=\"let button of chat?.leftButtons\">\r\n <ion-button style=\"--padding-start:10px;--padding-end:10px;\"\r\n shape=\"round\" *ngIf=\"button?.show&&button?.show()\" fill=\"outline\" [title]=\"button?.title\" slot=\"start\" (click)=\"button.onClick()\">\r\n <ion-icon [name]=\"button?.icon\" [slot]=\"button?.showTitle?'start':'icon-only'\"></ion-icon>\r\n {{button?.showTitle&&button?.title}}\r\n </ion-button>\r\n </ng-container>\r\n\r\n <ng-container *ngFor=\"let button of chat?.role?.get('buttons')\">\r\n <ion-button shape=\"round\" (click)=\"chatServ.doButtonAction(button)\" fill=\"outline\" slot=\"start\">\r\n {{button?.name}}\r\n </ion-button>\r\n </ng-container>\r\n\r\n <!--\u5206\u4EAB\u6309\u94AE-->\r\n @if(!chat?.hideShare){\r\n <ion-button shape=\"round\" *ngIf=\"chat?.messageList?.length>1\" (click)=\"showShare()\" fill=\"outline\" title=\"\u5206\u4EAB\" slot=\"end\">\r\n <ion-icon name=\"share-social-outline\"></ion-icon>\r\n </ion-button>\r\n }\r\n <ion-modal [isOpen]=\"isShare\">\r\n <ng-template>\r\n <ion-header>\r\n <ion-toolbar>\r\n <ion-buttons slot=\"start\">\r\n <ion-button (click)=\"handleCancelShare()\">\u53D6\u6D88</ion-button>\r\n </ion-buttons>\r\n <ion-title>\u5BF9\u8BDD\u5206\u4EAB</ion-title>\r\n <ion-buttons slot=\"end\">\r\n <ion-button (click)=\"handleOkShare()\">\u5206\u4EAB</ion-button>\r\n </ion-buttons>\r\n </ion-toolbar>\r\n </ion-header>\r\n <ion-content class=\"ion-padding\">\r\n <ng-container *ngFor=\"let message of chat?.messageList;let index=index;\">\r\n <!-- \u5185\u5BB9\u683C\u5F0F\u5316\u533A\u57DF -->\r\n <fm-chat-message-card [chat]=\"chat\" *ngIf=\"!message?.hidden\" [index]=\"index\" [message]=\"message\" [role]=\"chat?.role\"></fm-chat-message-card>\r\n </ng-container>\r\n\r\n <div *ngIf=\"false\" class=\"popup-content\">\r\n <div *ngFor=\"let message of chat?.messageList\">\r\n <!-- \u5934\u50CF -->\r\n <div class=\"item-row user\" *ngIf=\"message?.role!='system'\">\r\n <div>\r\n <img class=\"avatar\" *ngIf=\"message?.role!='user'\" [src]=\"(chat?.role?.get('avatar') || chat?.role?.get('thumb') || 'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png')+'?'+'x-image-process=image/resize,m_fixed,w_100'+'&imageView2/1/w/32/h/32'\" >\r\n </div>\r\n <div class=\"user-question\">\r\n <app-comp-user-avatar [user]=\"user\" *ngIf=\"message?.role=='user'\"></app-comp-user-avatar>\r\n </div>\r\n </div>\r\n <!-- \u5185\u5BB9 -->\r\n <div class=\"message-wrapper\">\r\n <div class=\"message-content-user\">\r\n <div class=\"user-message\" *ngIf=\"message?.role === 'user'\">\r\n <div class=\"item-content\">\r\n <!-- <fm-markdown-preview *ngIf=\"!message?.complete\" class=\"content-style\" [content]=\"message?.content\" [render]=\"false\"></fm-markdown-preview> -->\r\n <fm-markdown-preview *ngIf=\"message?.complete\" class=\"content-style\" [content]=\"message?.content\"></fm-markdown-preview>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"message-content-role\">\r\n <div class=\"role-message\" *ngIf=\"message?.role !== 'user' && message?.role !== 'system'\">\r\n <div class=\"item-content\">\r\n <!-- <fm-markdown-preview *ngIf=\"!message?.complete\" class=\"content-style\" [content]=\"message?.content\" [render]=\"false\"></fm-markdown-preview> -->\r\n <fm-markdown-preview *ngIf=\"message?.complete\" class=\"content-style\" [content]=\"message?.content\"></fm-markdown-preview>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"message-content-system\">\r\n <div class=\"system-message\" *ngIf=\"message?.role === 'system'\">\r\n <div class=\"item-content\">\r\n <!-- <fm-markdown-preview *ngIf=\"!message?.complete\" class=\"content-style\" [content]=\"message?.content\" [render]=\"false\"></fm-markdown-preview> -->\r\n <fm-markdown-preview *ngIf=\"message?.complete\" class=\"content-style\" [content]=\"message?.content\"></fm-markdown-preview>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"chat-time\" *ngIf=\"message?.createdAt\" [ngClass]=\"{'role-time': message?.role !== 'user'}\">\r\n <span>{{message?.createdAt | date:\"dd/MM/yyyy, HH/mm/ss a\"}}</span>\r\n </div>\r\n </div>\r\n </div> \r\n </ion-content>\r\n </ng-template>\r\n </ion-modal>\r\n\r\n <!-- \u56FE\u7247 -->\r\n <ion-button shape=\"round\" *ngIf=\"chat?.currentModel?.get('config')?.imageEnabled\" fill=\"outline\" slot=\"end\" (click)=\"setMessageImage()\">\r\n <ion-icon name=\"image-outline\"></ion-icon>\r\n </ion-button>\r\n <!-- \u6A21\u578B -->\r\n @if(!chat?.hideModalSelect){\r\n <ion-button shape=\"round\" fill=\"outline\" slot=\"end\" id=\"model-button\">\r\n <ion-icon name=\"chevron-down-outline\"></ion-icon>\r\n {{chat?.currentModel?.get&&chat?.currentModel?.get(\"name\")||\"Fmode-C1.0-128k\"}}\r\n </ion-button>\r\n <ion-popover trigger=\"model-button\" [dismissOnSelect]=\"true\">\r\n <ng-template>\r\n <ion-content>\r\n <ion-list>\r\n <ng-container *ngFor=\"let model of chat.modelList\">\r\n <ion-item (click)=\"chat.currentModel = model\" [button]=\"true\" [detail]=\"false\">\r\n {{model?.get(\"name\")}}\r\n <ion-note slot=\"end\">{{model?.get(\"credit\")}}/k</ion-note>\r\n </ion-item>\r\n </ng-container>\r\n </ion-list>\r\n </ion-content>\r\n </ng-template>\r\n </ion-popover>\r\n }\r\n\r\n </ion-item>\r\n\r\n <ion-item class=\"input-item\" lines=\"none\">\r\n <!-- \u8BED\u97F3\u6D88\u606F\u8F93\u5165 -->\r\n <ng-container *ngIf=\"chat?.isVoiceInputMode\">\r\n <!-- \u5207\u6362\u6587\u672C\u8F93\u5165 -->\r\n <ion-button class=\"btn-input-change\" color=\"primary\" (click)=\"chat.isVoiceInputMode=false\" shape=\"round\" size=\"large\">\r\n <ion-icon name=\"chatbox-ellipses-outline\" slot=\"icon-only\"></ion-icon>\r\n </ion-button>\r\n \r\n <div class=\"btn-voice-start\" (click)=\"startTalk()\" [class.disabled]=\"isSending\">\r\n <span>\r\n \u70B9\u51FB\u8BB2\u8BDD\r\n </span> \r\n </div>\r\n </ng-container>\r\n\r\n <!-- \u6587\u672C\u6D88\u606F\u8F93\u5165 -->\r\n <ng-container *ngIf=\"!chat?.isVoiceInputMode\">\r\n <!-- \u5207\u6362\u8BED\u97F3\u8F93\u5165 -->\r\n <ion-button [style.display]=\"chat.isTexting?'none':'flex'\" class=\"btn-input-change\" color=\"primary\" *ngIf=\"chat?.role?.get('voiceConfig')\" (click)=\"chat.isVoiceInputMode=true\" shape=\"round\" size=\"large\">\r\n <ion-icon name=\"mic-outline\" slot=\"icon-only\"></ion-icon>\r\n </ion-button>\r\n\r\n <!-- \u6587\u672C\u8F93\u5165\u533A\u57DF -->\r\n <ion-textarea\r\n #userInput\r\n *ngIf=\"chat\" (keydown)=\"onKeyDown($event)\"\r\n [errorText]=\"errorText\"\r\n [(ngModel)]=\"chat.userInput\"\r\n (ionFocus)=\"onInputFocus()\"\r\n (ionBlur)=\"chat.isTexting=false\"\r\n [autoGrow]=\"true\" shape=\"round\" fill=\"outline\"\r\n label=\"Ctrl + Enter \u53D1\u9001\u6D88\u606F\" placeholder=\"\u8BF7\u8F93\u5165\u60A8\u7684\u63D0\u793A\u8BCD\"\r\n labelPlacement=\"floating\"></ion-textarea>\r\n \r\n <!-- \u6587\u672C\u53D1\u9001\u6309\u94AE -->\r\n <ion-button [disabled]=\"isSending\"\r\n color=\"primary\" shape=\"round\" size=\"large\" (click)=\"sendMessage()\">\r\n <ion-icon name=\"paper-plane-outline\" slot=\"icon-only\"></ion-icon>\r\n </ion-button>\r\n </ng-container>\r\n </ion-item>\r\n</ion-toolbar>\r\n\r\n\r\n<!-- \u8BED\u97F3\u6D88\u606F\u8F93\u5165\uFF1A\u5F39\u51FA\u533A\u57DF -->\r\n<!-- <ion-modal #audioModal [isOpen]=\"isAudioModal\" (willDismiss)=\"closeAudio()\" [initialBreakpoint]=\"audioModalHeightPoint\" [breakpoints]=\"[0, audioModalHeightPoint]\">\r\n <ng-template>\r\n <fm-modal-audio-message #audioComp *ngIf=\"isAudioModal\" [chat]=\"chat\" [modal]=\"audioModal\"></fm-modal-audio-message>\r\n </ng-template>\r\n</ion-modal> -->", styles: ["@charset \"UTF-8\";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}.disabled{opacity:.5;pointer-events:none}.avatar{border-radius:50%;width:32px;height:32px;object-fit:cover}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i7.DatePipe, name: "date" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "component", type: IonPopover, selector: "ion-popover" }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type:
304
- //
305
- FmChatMessageCard, selector: "fm-chat-message-card", inputs: ["index", "message", "role", "chat"] }] }); }
306
- }
307
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FmChatModalInput, decorators: [{
308
- type: Component,
309
- args: [{ selector: 'fm-chat-modal-input', standalone: true, imports: [
310
- CommonModule, FormsModule, ReactiveFormsModule,
311
- RouterModule,
312
- IonToolbar, IonItem, IonButton, IonList, IonModal,
313
- IonInput, IonIcon, IonTextarea, IonPopover, IonContent,
314
- //
315
- FmChatMessageCard,
316
- ModalAudioMessageComponent
317
- ], template: "<ion-toolbar>\r\n <ion-item class=\"button-item\" lines=\"none\">\r\n <!-- \u8BBE\u7F6E -->\r\n <!-- <ion-button fill=\"outline\" slot=\"start\">\r\n <ion-icon name=\"settings-outline\"></ion-icon> \r\n </ion-button> -->\r\n <ng-container *ngFor=\"let button of chat?.leftButtons\">\r\n <ion-button style=\"--padding-start:10px;--padding-end:10px;\"\r\n shape=\"round\" *ngIf=\"button?.show&&button?.show()\" fill=\"outline\" [title]=\"button?.title\" slot=\"start\" (click)=\"button.onClick()\">\r\n <ion-icon [name]=\"button?.icon\" [slot]=\"button?.showTitle?'start':'icon-only'\"></ion-icon>\r\n {{button?.showTitle&&button?.title}}\r\n </ion-button>\r\n </ng-container>\r\n\r\n <ng-container *ngFor=\"let button of chat?.role?.get('buttons')\">\r\n <ion-button shape=\"round\" (click)=\"chatServ.doButtonAction(button)\" fill=\"outline\" slot=\"start\">\r\n {{button?.name}}\r\n </ion-button>\r\n </ng-container>\r\n\r\n <!--\u5206\u4EAB\u6309\u94AE-->\r\n @if(!chat?.hideShare){\r\n <ion-button shape=\"round\" *ngIf=\"chat?.messageList?.length>1\" (click)=\"showShare()\" fill=\"outline\" title=\"\u5206\u4EAB\" slot=\"end\">\r\n <ion-icon name=\"share-social-outline\"></ion-icon>\r\n </ion-button>\r\n }\r\n <ion-modal [isOpen]=\"isShare\">\r\n <ng-template>\r\n <ion-header>\r\n <ion-toolbar>\r\n <ion-buttons slot=\"start\">\r\n <ion-button (click)=\"handleCancelShare()\">\u53D6\u6D88</ion-button>\r\n </ion-buttons>\r\n <ion-title>\u5BF9\u8BDD\u5206\u4EAB</ion-title>\r\n <ion-buttons slot=\"end\">\r\n <ion-button (click)=\"handleOkShare()\">\u5206\u4EAB</ion-button>\r\n </ion-buttons>\r\n </ion-toolbar>\r\n </ion-header>\r\n <ion-content class=\"ion-padding\">\r\n <ng-container *ngFor=\"let message of chat?.messageList;let index=index;\">\r\n <!-- \u5185\u5BB9\u683C\u5F0F\u5316\u533A\u57DF -->\r\n <fm-chat-message-card [chat]=\"chat\" *ngIf=\"!message?.hidden\" [index]=\"index\" [message]=\"message\" [role]=\"chat?.role\"></fm-chat-message-card>\r\n </ng-container>\r\n\r\n <div *ngIf=\"false\" class=\"popup-content\">\r\n <div *ngFor=\"let message of chat?.messageList\">\r\n <!-- \u5934\u50CF -->\r\n <div class=\"item-row user\" *ngIf=\"message?.role!='system'\">\r\n <div>\r\n <img class=\"avatar\" *ngIf=\"message?.role!='user'\" [src]=\"(chat?.role?.get('avatar') || chat?.role?.get('thumb') || 'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png')+'?'+'x-image-process=image/resize,m_fixed,w_100'+'&imageView2/1/w/32/h/32'\" >\r\n </div>\r\n <div class=\"user-question\">\r\n <app-comp-user-avatar [user]=\"user\" *ngIf=\"message?.role=='user'\"></app-comp-user-avatar>\r\n </div>\r\n </div>\r\n <!-- \u5185\u5BB9 -->\r\n <div class=\"message-wrapper\">\r\n <div class=\"message-content-user\">\r\n <div class=\"user-message\" *ngIf=\"message?.role === 'user'\">\r\n <div class=\"item-content\">\r\n <!-- <fm-markdown-preview *ngIf=\"!message?.complete\" class=\"content-style\" [content]=\"message?.content\" [render]=\"false\"></fm-markdown-preview> -->\r\n <fm-markdown-preview *ngIf=\"message?.complete\" class=\"content-style\" [content]=\"message?.content\"></fm-markdown-preview>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"message-content-role\">\r\n <div class=\"role-message\" *ngIf=\"message?.role !== 'user' && message?.role !== 'system'\">\r\n <div class=\"item-content\">\r\n <!-- <fm-markdown-preview *ngIf=\"!message?.complete\" class=\"content-style\" [content]=\"message?.content\" [render]=\"false\"></fm-markdown-preview> -->\r\n <fm-markdown-preview *ngIf=\"message?.complete\" class=\"content-style\" [content]=\"message?.content\"></fm-markdown-preview>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"message-content-system\">\r\n <div class=\"system-message\" *ngIf=\"message?.role === 'system'\">\r\n <div class=\"item-content\">\r\n <!-- <fm-markdown-preview *ngIf=\"!message?.complete\" class=\"content-style\" [content]=\"message?.content\" [render]=\"false\"></fm-markdown-preview> -->\r\n <fm-markdown-preview *ngIf=\"message?.complete\" class=\"content-style\" [content]=\"message?.content\"></fm-markdown-preview>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"chat-time\" *ngIf=\"message?.createdAt\" [ngClass]=\"{'role-time': message?.role !== 'user'}\">\r\n <span>{{message?.createdAt | date:\"dd/MM/yyyy, HH/mm/ss a\"}}</span>\r\n </div>\r\n </div>\r\n </div> \r\n </ion-content>\r\n </ng-template>\r\n </ion-modal>\r\n\r\n <!-- \u56FE\u7247 -->\r\n <ion-button shape=\"round\" *ngIf=\"chat?.currentModel?.get('config')?.imageEnabled\" fill=\"outline\" slot=\"end\" (click)=\"setMessageImage()\">\r\n <ion-icon name=\"image-outline\"></ion-icon>\r\n </ion-button>\r\n <!-- \u6A21\u578B -->\r\n @if(!chat?.hideModalSelect){\r\n <ion-button shape=\"round\" fill=\"outline\" slot=\"end\" id=\"model-button\">\r\n <ion-icon name=\"chevron-down-outline\"></ion-icon>\r\n {{chat?.currentModel?.get&&chat?.currentModel?.get(\"name\")||\"Fmode-C1.0-128k\"}}\r\n </ion-button>\r\n <ion-popover trigger=\"model-button\" [dismissOnSelect]=\"true\">\r\n <ng-template>\r\n <ion-content>\r\n <ion-list>\r\n <ng-container *ngFor=\"let model of chat.modelList\">\r\n <ion-item (click)=\"chat.currentModel = model\" [button]=\"true\" [detail]=\"false\">\r\n {{model?.get(\"name\")}}\r\n <ion-note slot=\"end\">{{model?.get(\"credit\")}}/k</ion-note>\r\n </ion-item>\r\n </ng-container>\r\n </ion-list>\r\n </ion-content>\r\n </ng-template>\r\n </ion-popover>\r\n }\r\n\r\n </ion-item>\r\n\r\n <ion-item class=\"input-item\" lines=\"none\">\r\n <!-- \u8BED\u97F3\u6D88\u606F\u8F93\u5165 -->\r\n <ng-container *ngIf=\"chat?.isVoiceInputMode\">\r\n <!-- \u5207\u6362\u6587\u672C\u8F93\u5165 -->\r\n <ion-button class=\"btn-input-change\" color=\"primary\" (click)=\"chat.isVoiceInputMode=false\" shape=\"round\" size=\"large\">\r\n <ion-icon name=\"chatbox-ellipses-outline\" slot=\"icon-only\"></ion-icon>\r\n </ion-button>\r\n \r\n <div class=\"btn-voice-start\" (click)=\"startTalk()\" [class.disabled]=\"isSending\">\r\n <span>\r\n \u70B9\u51FB\u8BB2\u8BDD\r\n </span> \r\n </div>\r\n </ng-container>\r\n\r\n <!-- \u6587\u672C\u6D88\u606F\u8F93\u5165 -->\r\n <ng-container *ngIf=\"!chat?.isVoiceInputMode\">\r\n <!-- \u5207\u6362\u8BED\u97F3\u8F93\u5165 -->\r\n <ion-button [style.display]=\"chat.isTexting?'none':'flex'\" class=\"btn-input-change\" color=\"primary\" *ngIf=\"chat?.role?.get('voiceConfig')\" (click)=\"chat.isVoiceInputMode=true\" shape=\"round\" size=\"large\">\r\n <ion-icon name=\"mic-outline\" slot=\"icon-only\"></ion-icon>\r\n </ion-button>\r\n\r\n <!-- \u6587\u672C\u8F93\u5165\u533A\u57DF -->\r\n <ion-textarea\r\n #userInput\r\n *ngIf=\"chat\" (keydown)=\"onKeyDown($event)\"\r\n [errorText]=\"errorText\"\r\n [(ngModel)]=\"chat.userInput\"\r\n (ionFocus)=\"onInputFocus()\"\r\n (ionBlur)=\"chat.isTexting=false\"\r\n [autoGrow]=\"true\" shape=\"round\" fill=\"outline\"\r\n label=\"Ctrl + Enter \u53D1\u9001\u6D88\u606F\" placeholder=\"\u8BF7\u8F93\u5165\u60A8\u7684\u63D0\u793A\u8BCD\"\r\n labelPlacement=\"floating\"></ion-textarea>\r\n \r\n <!-- \u6587\u672C\u53D1\u9001\u6309\u94AE -->\r\n <ion-button [disabled]=\"isSending\"\r\n color=\"primary\" shape=\"round\" size=\"large\" (click)=\"sendMessage()\">\r\n <ion-icon name=\"paper-plane-outline\" slot=\"icon-only\"></ion-icon>\r\n </ion-button>\r\n </ng-container>\r\n </ion-item>\r\n</ion-toolbar>\r\n\r\n\r\n<!-- \u8BED\u97F3\u6D88\u606F\u8F93\u5165\uFF1A\u5F39\u51FA\u533A\u57DF -->\r\n<!-- <ion-modal #audioModal [isOpen]=\"isAudioModal\" (willDismiss)=\"closeAudio()\" [initialBreakpoint]=\"audioModalHeightPoint\" [breakpoints]=\"[0, audioModalHeightPoint]\">\r\n <ng-template>\r\n <fm-modal-audio-message #audioComp *ngIf=\"isAudioModal\" [chat]=\"chat\" [modal]=\"audioModal\"></fm-modal-audio-message>\r\n </ng-template>\r\n</ion-modal> -->", styles: ["@charset \"UTF-8\";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}.disabled{opacity:.5;pointer-events:none}.avatar{border-radius:50%;width:32px;height:32px;object-fit:cover}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n"] }]
318
- }], ctorParameters: () => [{ type: i1.ToastController }, { type: i1.AlertController }, { type: i2.ModalController }, { type: i3.Router }, { type: i4.ImagineService }, { type: i5.ChatService }, { type: i6.AccountService }], propDecorators: { audioComp: [{
319
- type: ViewChild,
320
- args: [ModalAudioMessageComponent]
321
- }], userInputComp: [{
322
- type: ViewChild,
323
- args: ["userInput"]
324
- }], chat: [{
325
- type: Input
326
- }], message: [{
327
- type: Input
328
- }], role: [{
329
- type: Input
330
- }] } });
331
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kYWwtaW5wdXQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZm1vZGUtbmcvc3JjL2xpYi9haWdjL2NoYXQvY2hhdC1tb2RhbC1pbnB1dC9tb2RhbC1pbnB1dC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9mbW9kZS1uZy9zcmMvbGliL2FpZ2MvY2hhdC9jaGF0LW1vZGFsLWlucHV0L21vZGFsLWlucHV0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFnQyxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDMUYsT0FBTyxFQUFpQixNQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdEUsT0FBTyxFQUFFLGVBQWUsRUFBMkIsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0YsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzVELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCwwQ0FBMEM7QUFDMUMsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxvREFBb0QsQ0FBQztBQUNwRixPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3ZLLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFbEUsT0FBTyxFQUFF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Q0FBQztRQUN2QixJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztRQUMvQixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUN2QixDQUFDO0lBRUQsaUJBQWlCO1FBQ2YsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDdkIsQ0FBQzsrR0F2VFUsZ0JBQWdCO21HQUFoQixnQkFBZ0Isc0xBQ2hCLDBCQUEwQiw2SUN0Q3ZDLHN3VEF5S2dCLHcxRUQ3SVosWUFBWSxnWkFBQyxXQUFXLDhWQUFDLG1CQUFtQiw4QkFDNUMsWUFBWSwrQkFDWixVQUFVLG1GQUFDLE9BQU8sME5BQUMsU0FBUyxvUEFBQyxPQUFPLHlGQUFDLFFBQVEsc0RBQ3BDLE9BQU8sMkpBQUMsV0FBVyxpYUFBQyxVQUFVLHdEQUFDLFVBQVU7Z0JBQ2xELEdBQUc7Z0JBQ0gsaUJBQWlCOzs0RkFJUixnQkFBZ0I7a0JBZjVCLFNBQVM7K0JBQ0UscUJBQXFCLGNBR3BCLElBQUksV0FDUDt3QkFDTixZQUFZLEVBQUMsV0FBVyxFQUFDLG1CQUFtQjt3QkFDNUMsWUFBWTt3QkFDWixVQUFVLEVBQUMsT0FBTyxFQUFDLFNBQVMsRUFBQyxPQUFPLEVBQUMsUUFBUTt3QkFDN0MsUUFBUSxFQUFDLE9BQU8sRUFBQyxXQUFXLEVBQUMsVUFBVSxFQUFDLFVBQVU7d0JBQ2xELEdBQUc7d0JBQ0gsaUJBQWlCO3dCQUNqQiwwQkFBMEI7cUJBQzNCO3lQQUdzQyxTQUFTO3NCQUEvQyxTQUFTO3VCQUFDLDBCQUEwQjtnQkFDYixhQUFhO3NCQUFwQyxTQUFTO3VCQUFDLFdBQVc7Z0JBR2IsSUFBSTtzQkFBWixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxJQUFJO3NCQUFaLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPbkluaXQsQWZ0ZXJWaWV3SW5pdCwgT3V0cHV0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsUm91dGVyLCBSb3V0ZXJNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xyXG5pbXBvcnQgeyBBbGVydENvbnRyb2xsZXIsIE5hdkNvbnRyb2xsZXIsIFBsYXRmb3JtLCBUb2FzdENvbnRyb2xsZXIgfSBmcm9tICdAaW9uaWMvYW5ndWxhcic7XHJcbmltcG9ydCB7IEZtb2RlQ2hhdCB9IGZyb20gJy4uLy4uL3NlcnZpY2UtZm1haS9zZXJ2aWNlLWNoYXQnO1xyXG5pbXBvcnQgeyBDaGF0U2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2UtZm1haS9zZXJ2aWNlLWNoYXQnO1xyXG5cclxuLy8gaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICdmbW9kZS1uZyc7XHJcbmltcG9ydCBQYXJzZSBmcm9tIFwicGFyc2VcIjtcclxuaW1wb3J0IHsgSW1hZ2luZVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlLWZtYWkvc2VydmljZS1pbWFnaW5lL2ltYWdpbmUuc2VydmljZSc7XHJcbmltcG9ydCB7IElvbkJ1dHRvbiwgSW9uQ29udGVudCwgSW9uSWNvbiwgSW9uSW5wdXQsIElvbkl0ZW0sIElvbkxpc3QsIElvbk1vZGFsLCBJb25Qb3BvdmVyLCBJb25UZXh0YXJlYSwgSW9uVG9vbGJhciwgTW9kYWxDb250cm9sbGVyIH0gZnJvbSAnQGlvbmljL2FuZ3VsYXIvc3RhbmRhbG9uZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IEZvcm1zTW9kdWxlLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5cclxuaW1wb3J0IHsgTW9kYWxBdWRpb01lc3NhZ2VDb21wb25lbnQgfSBmcm9tIFwiLi9tb2RhbC1hdWRpby1tZXNzYWdlL21vZGFsLWF1ZGlvLW1lc3NhZ2UuY29tcG9uZW50XCI7XHJcbmltcG9ydCB7IEZtQ2hhdE1lc3NhZ2VDYXJkIH0gZnJvbSAnLi4vY2hhdC1tZXNzYWdlLWNhcmQvY29tcC1tZXNzYWdlLWNhcmQuY29tcG9uZW50JztcclxuXHJcbmltcG9ydCB7IGFkZEljb25zIH0gZnJvbSAnaW9uaWNvbnMnO1xyXG5pbXBvcnQge2ltYWdlT3V0bGluZSxjaGV2cm9uQmFja091dGxpbmUsZWxsaXBzaXNIb3Jpem9udGFsT3V0bGluZSxjaGV2cm9uRG93bk91dGxpbmUsY2hhdGJveEVsbGlwc2VzT3V0bGluZSxtaWNPdXRsaW5lLHBhcGVyUGxhbmVPdXRsaW5lLHNoYXJlU29jaWFsT3V0bGluZSxzZXR0aW5nc091dGxpbmUsIGFsZXJ0T3V0bGluZSwgY29sb3JXYW5kT3V0bGluZSwgcGVvcGxlT3V0bGluZX0gZnJvbSAnaW9uaWNvbnMvaWNvbnMnO1xyXG5pbXBvcnQgeyBBY2NvdW50U2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3VzZXIvYWNjb3VudC9hY2NvdW50LnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBGbW9kZUNoYXRNZXNzYWdlIH0gZnJvbSAnLi4vLi4vLi4vY29yZS9hZ2VudC9jaGF0L2ludGVyZmFjZSc7XHJcbmFkZEljb25zKHtjb2xvcldhbmRPdXRsaW5lLHBlb3BsZU91dGxpbmUsYWxlcnRPdXRsaW5lLGltYWdlT3V0bGluZSxjaGV2cm9uQmFja091dGxpbmUsZWxsaXBzaXNIb3Jpem9udGFsT3V0bGluZSxjaGV2cm9uRG93bk91dGxpbmUsY2hhdGJveEVsbGlwc2VzT3V0bGluZSxtaWNPdXRsaW5lLHBhcGVyUGxhbmVPdXRsaW5lLHNoYXJlU29jaWFsT3V0bGluZSxzZXR0aW5nc091dGxpbmV9KVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdmbS1jaGF0LW1vZGFsLWlucHV0JyxcclxuICB0ZW1wbGF0ZVVybDogJy4vbW9kYWwtaW5wdXQuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL21vZGFsLWlucHV0LmNvbXBvbmVudC5zY3NzJ10sXHJcbiAgc3RhbmRhbG9uZTp0cnVlLFxyXG4gIGltcG9ydHM6W1xyXG4gICAgQ29tbW9uTW9kdWxlLEZvcm1zTW9kdWxlLFJlYWN0aXZlRm9ybXNNb2R1bGUsXHJcbiAgICBSb3V0ZXJNb2R1bGUsXHJcbiAgICBJb25Ub29sYmFyLElvbkl0ZW0sSW9uQnV0dG9uLElvbkxpc3QsSW9uTW9kYWwsXHJcbiAgICBJb25JbnB1dCxJb25JY29uLElvblRleHRhcmVhLElvblBvcG92ZXIsSW9uQ29udGVudCxcclxuICAgIC8vIFxyXG4gICAgRm1DaGF0TWVzc2FnZUNhcmQsXHJcbiAgICBNb2RhbEF1ZGlvTWVzc2FnZUNvbXBvbmVudFxyXG4gIF1cclxufSlcclxuZXhwb3J0IGNsYXNzIEZtQ2hhdE1vZGFsSW5wdXQgaW1wbGVtZW50cyBPbkluaXR7XHJcbiAgQFZpZXdDaGlsZChNb2RhbEF1ZGlvTWVzc2FnZUNvbXBvbmVudCkgYXVkaW9Db21wOk1vZGFsQXVkaW9NZXNzYWdlQ29tcG9uZW50XHJcbiAgQFZpZXdDaGlsZChcInVzZXJJbnB1dFwiKSB1c2VySW5wdXRDb21wOklvblRleHRhcmVhXHJcblxyXG5cclxuICBASW5wdXQoKSBjaGF0OkZtb2RlQ2hhdDtcclxuICBASW5wdXQoKSBtZXNzYWdlOkZtb2RlQ2hhdE1lc3NhZ2VcclxuICBASW5wdXQoKSByb2xlOlBhcnNlLk9iamVjdFxyXG4gIHVzZXI6UGFyc2UuVXNlclxyXG4gIGVycm9yVGV4dDpzdHJpbmcgPSBgYFxyXG5cclxuICAvLyDor63pn7PovpPlhaXmjqfliLZcclxuICBpc0F1ZGlvTW9kYWw6Ym9vbGVhbiA9IGZhbHNlO1xyXG4gIGNsb3NlQXVkaW8oKXtcclxuICAgIHRoaXMuYXVkaW9Db21wPy5jYW5jZWwoKTtcclxuICAgIHRoaXMuaXNBdWRpb01vZGFsPWZhbHNlO1xyXG4gIH1cclxuICBhdWRpb01vZGFsSGVpZ2h0UG9pbnQgPSAwLjM1O1xyXG4gIGFzeW5jIHN0YXJ0VGFsaygpe1xyXG4gICAgLy8gQ2hlY2sgaWYgYWxyZWFkeSBzZW5kaW5nXHJcbiAgICBpZiAodGhpcy5pc1NlbmRpbmcpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBoZWlnaHQgPSBkb2N1bWVudC5ib2R5LmNsaWVudEhlaWdodCB8fCA5NjA7XHJcbiAgICB0aGlzLmF1ZGlvTW9kYWxIZWlnaHRQb2ludCA9IE51bWJlcigoMTY1L2hlaWdodCkudG9GaXhlZCgyKSlcclxuXHJcbiAgICB0aGlzLmNoYXQuc3RvcFBsYXlpbmdWb2ljZSgpO1xyXG5cclxuICAgICAgLy8g5by55Ye66K6k6K+B57uE5Lu2XHJcbiAgICBsZXQgbW9kYWw6YW55IFxyXG4gICAgbW9kYWwgPSBhd2FpdCB0aGlzLm1vZGFsQ3RybC5jcmVhdGUoe1xyXG4gICAgICBjb21wb25lbnQ6TW9kYWxBdWRpb01lc3NhZ2VDb21wb25lbnQsXHJcbiAgICAgIGNvbXBvbmVudFByb3BzOntcclxuICAgICAgICBjaGF0OnRoaXMuY2hhdCxcclxuICAgICAgICBtb2RhbDptb2RhbCxcclxuICAgICAgICBvbkJyZWFrUG9pbnRTZXQ6KCk9PntcclxuICAgICAgICAgIG1vZGFsPy5zZXRDdXJyZW50QnJlYWtwb2ludCh0aGlzLmF1ZGlvTW9kYWxIZWlnaHRQb2ludClcclxuICAgICAgfX0sXHJcbiAgICAgIGJyZWFrcG9pbnRzOlt0aGlzLmF1ZGlvTW9kYWxIZWlnaHRQb2ludF0sXHJcbiAgICAgIGluaXRpYWxCcmVha3BvaW50OnRoaXMuYXVkaW9Nb2RhbEhlaWdodFBvaW50LFxyXG4gICAgfSlcclxuICAgIG1vZGFsLnByZXNlbnQoKVxyXG4gICAgLy8gdGhpcy5pc0F1ZGlvTW9kYWw9dHJ1ZTtcclxuICB9XHJcbiAgLy8gYWNjb3VudDphbnk7XHJcbiAgYXV0aFNlcnY6YW55O1xyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgcHJpdmF0ZSB0b2FzdEN0cmw6VG9hc3RDb250cm9sbGVyLFxyXG4gICAgcHJpdmF0ZSBhbGVydEN0cmw6QWxlcnRDb250cm9sbGVyLFxyXG4gICAgcHJpdmF0ZSBtb2RhbEN0cmw6TW9kYWxDb250cm9sbGVyLFxyXG4gICAgcHJpdmF0ZSByb3V0ZXI6Um91dGVyLFxyXG4gICAgcHJpdmF0ZSBpbWFnaW5lU2VydjpJbWFnaW5lU2VydmljZSxcclxuICAgIC8vIHByaXZhdGUgYXV0aFNlcnY6QXV0aFNlcnZpY2UsXHJcbiAgICBwdWJsaWMgY2hhdFNlcnY6Q2hhdFNlcnZpY2UsXHJcbiAgICBwcml2YXRlIGFjY291bnQ6QWNjb3VudFNlcnZpY2UsXHJcbiAgKXtcclxuICAgIC8vIHRoaXMuY2hhdFNlcnYuZ2V0Q2hhdFNlc3Npb24oKS50aGVuKCgpPT57XHJcbiAgICAvLyAgIGNvbnNvbGUubG9nKHRoaXMuY2hhdFNlcnYuY2hhdExpc3QpO1xyXG4gICAgLy8gfSlcclxuICAgIHRoaXMudXNlciA9IFBhcnNlLlVzZXIuY3VycmVudCgpO1xyXG5cclxuICB9XHJcbiAgbmdPbkluaXQoKXtcclxuICAgIHRoaXMubG9hZE1vZGVsKCk7XHJcbiAgICAvLyBjb25zb2xlLmxvZyh0aGlzLmNoYXQpO1xyXG4gICAgbGV0IHRoYXQgPSB0aGlzO1xyXG4gICAgdGhpcy5jaGF0LmZvY3VzVXNlcklucHV0ID0gKCk9PntcclxuICAgICAgdGhhdC5jaGF0LmlzVm9pY2VJbnB1dE1vZGUgPSBmYWxzZTtcclxuICAgICAgdGhhdC51c2VySW5wdXRDb21wLnNldEZvY3VzKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XHJcbiAgLy8gICBjb25zb2xlLmxvZyh0aGlzLmNoYXQpXHJcbiAgLy8gfVxyXG5cclxuICBhc3luYyBsb2FkTW9kZWwoKXtcclxuICAgIGxldCBtb2RlbCA9IHRoaXMuY2hhdD8ucm9sZT8uZ2V0KFwibW9kZWxcIilcclxuICAgIGF3YWl0IHRoaXMuY2hhdC5sb2FkTW9kZWxMaXN0KG1vZGVsKVxyXG4gIH1cclxuICBcclxuICBhc3luYyBzZXRNZXNzYWdlSW1hZ2UoKXtcclxuICAgIC8vIGxldCB1cmwgPSBgaHR0cHM6Ly9maWxlLWNsb3VkLmZtb2RlLmNuL1N2ZWhsNkZjZUwvMjAyNDA1MTUvMDYxNTAzNjcxLmpwZWdgO1xyXG4gICAgbGV0IHVybCA9IGF3YWl0IHRoaXMuaW1hZ2luZVNlcnYuZ2V0aW1nKCk7XHJcbiAgICB0aGlzLmNoYXQudXNlckltYWdlID0gdXJsO1xyXG4gICAgY29uc29sZS5sb2codGhpcy5jaGF0Py51c2VySW1hZ2UpO1xyXG4gICAgLy8gY29udGVudOaYr+aVsOe7hO+8jOa3u+WKoFxyXG4gICAgLy8gY29udGVudOmdnuaVsOe7hO+8jOmHjee7hFxyXG4gIH1cclxuIFxyXG4gIG9uSW5wdXRGb2N1cygpe1xyXG4gICAgLy8gY29uc29sZS5sb2coXCJvbklucHV0Rm9jdXNcIix0aGlzLmNoYXQuc2Nyb2xsVG9Cb3R0b20pXHJcbiAgICB0aGlzLmNoYXQuaXNUZXh0aW5nPXRydWU7XHJcbiAgICB0aGlzLmNoYXQuc2Nyb2xsVG9Cb3R0b20mJnRoaXMuY2hhdC5zY3JvbGxUb0JvdHRvbSgpO1xyXG4gIH1cclxuICBcclxuICBvbktleURvd24oZXZlbnQ6S2V5Ym9hcmRFdmVudCl7XHJcbiAgICAvLyDmo4Dmn6XmmK/lkKbmjInkuIvkuoZDdHJs6ZSu5ZKMRW50ZXLplK5cclxuICAgIGlmIChldmVudC5jdHJsS2V5ICYmIGV2ZW50LmtleSA9PT0gJ0VudGVyJykge1xyXG4gICAgICAvLyDmiafooYznm7jlupTnmoTpgLvovpFcclxuICAgICAgY29uc29sZS5sb2coJ0N0cmwrRW50ZXIg6KKr5oyJ5LiLJyk7XHJcbiAgICAgIHRoaXMuc2VuZE1lc3NhZ2UoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIOWPkemAgea2iOaBryDpmLLmipbmnLrliLZcclxuICBpc1NlbmRpbmcgPSBmYWxzZTtcclxuICBsYXN0TWVzc2FnZVRpbWVvdXQ6IGFueTtcclxuICBsYXN0TWVzc2FnZVRpbWVzdGFtcDogbnVtYmVyID0gMDtcclxuICByZXBseVRpbWVvdXQgPSAxNTAwMDsgLy8gMTUgc2Vjb25kcyB0aW1lb3V0XHJcbiAgYXN5bmMgc2VuZE1lc3NhZ2UoKXtcclxuICAgIC8vIENoZWNrIGlmIGFscmVhZHkgc2VuZGluZ1xyXG4gICAgaWYgKHRoaXMuaXNTZW5kaW5nKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgICAvLyBDaGVjayBpZiB3YWl0aW5nIGZvciBwcmV2aW91cyByZXBseVxyXG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcclxuICAgIGlmICh0aGlzLmxhc3RNZXNzYWdlVGltZXN0YW1wID4gMCAmJiAobm93IC0gdGhpcy5sYXN0TWVzc2FnZVRpbWVzdGFtcCkgPCB0aGlzLnJlcGx5VGltZW91dCkge1xyXG4gICAgICB0aGlzLmVycm9yVGV4dCA9IGDor7fnrYnlvoXkuIrkuIDmnaHmtojmga/nmoTlm57lpI3miJbnqI3lkI7lho3or5VgO1xyXG4gICAgICBsZXQgdG9hc3QgPSBhd2FpdCB0aGlzLnRvYXN0Q3RybC5jcmVhdGUoe1xyXG4gICAgICAgIG1lc3NhZ2U6IHRoaXMuZXJyb3JUZXh0LFxyXG4gICAgICAgIHBvc2l0aW9uOiBcInRvcFwiLFxyXG4gICAgICAgIGljb246ICdhbGVydCcsXHJcbiAgICAgICAgY29sb3I6IFwid2FybmluZ1wiLFxyXG4gICAgICAgIGR1cmF0aW9uOiAxMDAwXHJcbiAgICAgIH0pO1xyXG4gICAgICB0b2FzdC5wcmVzZW50KCk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmlzU2VuZGluZyA9IHRydWU7XHJcbiAgICB0aGlzLmxhc3RNZXNzYWdlVGltZXN0YW1wID0gRGF0ZS5ub3coKTtcclxuXHJcbiAgICAvLyDmo4DmtYvnlKjmiLfnmbvlvZXmg4XlhrVcclxuICAgIC8vIGxldCBpc0xvZ2luTG9jayA9IGF3YWl0IHRoaXMuYXV0aFNlcnYuY2hlY2tMb2dpbkxvY2soKVxyXG4gICAgLy8gaWYoIWlzTG9naW5Mb2NrKSByZXR1cm4gZmFsc2VcclxuXHJcbiAgICAvLyDmo4DmtYvkvZnpop3lj4rmqKHlnovku5jotLnpmZDliLZcclxuICAgIGxldCBwYXlDaGVjayA9IGF3YWl0IHRoaXMuY2hlY2tCYWxhbmNlKClcclxuICAgIGlmKCFwYXlDaGVjaykge1xyXG4gICAgICB0aGlzLmlzU2VuZGluZyA9IGZhbHNlO1xyXG4gICAgICByZXR1cm4gZmFsc2VcclxuICAgIH1cclxuXHJcbiAgICAvLyDmo4DmtYvnlKjmiLfovpPlhaXlhoXlrrnnqbrlgLxcclxuICAgIGlmKCF0aGlzLmNoYXQudXNlcklucHV0KXtcclxuICAgICAgdGhpcy5lcnJvclRleHQgPSBg5YaF5a655LiN6IO95Li656m6YFxyXG4gICAgICBsZXQgdG9hc3QgPSBhd2FpdCB0aGlzLnRvYXN0Q3RybC5jcmVhdGUoe1xyXG4gICAgICAgIG1lc3NhZ2U6dGhpcy5lcnJvclRleHQsXHJcbiAgICAgICAgcG9zaXRpb246XCJ0b3BcIixcclxuICAgICAgICBpY29uOidhbGVydCcsXHJcbiAgICAgICAgY29sb3I6XCJ3YXJuaW5nLWNpcmNsZVwiLFxyXG4gICAgICAgIGR1cmF0aW9uOjEwMDBcclxuICAgICAgfSlcclxuICAgICAgdG9hc3QucHJlc2VudCgpO1xyXG4gICAgICB0aGlzLmlzU2VuZGluZyA9IGZhbHNlO1xyXG4gICAgICByZXR1cm5cclxuICAgIH1cclxuXHJcbiAgICAgLy8gQ2xlYXIgYW55IGV4aXN0aW5nIHRpbWVvdXRcclxuICAgIGlmICh0aGlzLmxhc3RNZXNzYWdlVGltZW91dCkge1xyXG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5sYXN0TWVzc2FnZVRpbWVvdXQpO1xyXG4gICAgfVxyXG4gICAgLy8gU2V0IHRpbWVvdXQgdG8gcmVzZXQgc2VuZGluZyBzdGF0ZSBpZiBubyByZXBseVxyXG4gICAgdGhpcy5sYXN0TWVzc2FnZVRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgdGhpcy5pc1NlbmRpbmcgPSBmYWxzZTtcclxuICAgICAgdGhpcy5sYXN0TWVzc2FnZVRpbWVzdGFtcCA9IDA7XHJcbiAgICB9LCB0aGlzLnJlcGx5VGltZW91dCk7XHJcblxyXG4gICAgLy8g5q2j5bi45Y+R6YCB5raI5oGvXHJcbiAgICAvLyB0aGlzLmNoYXQuaXNUYWxrTW9kZT10cnVlOyAvLyDlvIDlkK/or7Tor53mqKHlvI9cclxuICAgIHRoaXMuY2hhdD8uc2VuZE1lc3NhZ2UodGhpcy5jaGF0Py51c2VySW5wdXQsdGhpcy5jaGF0Py51c2VySW1hZ2UsKG1zZyk9Pnt9LHtcclxuICAgICAgb25NZXNzYWdlU3RhcnQ6KG1lc3NhZ2U6YW55KT0+e1xyXG4gICAgICAgICAvLyBXaGVuIHJlcGx5IGNvbWVzLCBjbGVhciB0aW1lb3V0IGFuZCByZXNldCBzdGF0ZVxyXG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLmxhc3RNZXNzYWdlVGltZW91dCk7XHJcbiAgICAgICAgdGhpcy5pc1NlbmRpbmcgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLmxhc3RNZXNzYWdlVGltZXN0YW1wID0gMDtcclxuICAgICAgfSxcclxuICAgICAgb25TU01MQ29tcGxldGU6KHZvaWNlOmFueSk9PntcclxuICAgICAgICBjb25zb2xlLmxvZyh2b2ljZSlcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICB0aGlzLmNoYXQudXNlcklucHV0ID0gYGBcclxuICAgIHRoaXMuY2hhdC51c2VySW1hZ2UgPSBgYFxyXG4gIH1cclxuICBhc3luYyBjaGVja0JhbGFuY2UoKXtcclxuICAgIGxldCBwcmljZSA9IDEwO1xyXG4gICAgXHJcbiAgICAvLyDmoKHpqozotKbmiLfkvZnpop1cclxuICAgIGxldCBiaWxsaW5nID0gYXdhaXQgdGhpcy5hY2NvdW50LmdldEJpbGxpbmcoKTtcclxuICAgIGlmIChiaWxsaW5nPy5jcmVkaXQ/LmJhbGFuY2UgPj0gcHJpY2UpIHtcclxuICAgICAgdGhpcy5jaGF0LmlzRGlyZWN0ID0gdHJ1ZTsgLy8g5L2Z6aKd5YWF6Laz77yM5LiN6ZmQ6YCfXHJcbiAgICB9XHJcblxyXG4gICAgIC8vIOaooeWei+aYr+WQpuW8gOWQr+S7mOi0uemZkOWItlxyXG4gICAgIGlmKCF0aGlzLmNoYXQ/LmN1cnJlbnRNb2RlbD8uZ2V0KFwicGF5TGltaXRcIikpIHtcclxuICAgICAgcmV0dXJuIHRydWVcclxuICAgIH1cclxuXHJcbiAgICAvLyBsZXQgcHJpY2UgPSBhd2FpdCB0aGlzLmNhbGNQcmljZSgpXHJcbiAgICBpZiAoYmlsbGluZz8uY3JlZGl0Py5iYWxhbmNlIDwgcHJpY2UpIHtcclxuICAgICAgbGV0IGFsZXJ0ID0gYXdhaXQgdGhpcy5hbGVydEN0cmwuY3JlYXRlKHtcclxuICAgICAgICBoZWFkZXI6XCLms6jmhI9cIixcclxuICAgICAgICBzdWJIZWFkZXI6XCLmgqjnmoTkvZnpop3kuI3otrPvvIzor7flhYXlgLzlkI7op6PplIHpq5jnuqfmqKHlnotcIixcclxuICAgICAgICBidXR0b25zOltcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgcm9sZTpcImNhbmNlbFwiLFxyXG4gICAgICAgICAgICB0ZXh0Olwi5Y+W5raIXCJcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHJvbGU6XCJkZXN0cnVjdGl2ZVwiLFxyXG4gICAgICAgICAgICB0ZXh0Olwi5YWF5YC8XCIsXHJcbiAgICAgICAgICAgIGhhbmRsZXI6KCk9PntcclxuICAgICAgICAgICAgICAvLyDlvoXmm7TmjaLmiJDljp/lnLDlvLnnqpfvvIzljp/lnLDku5jotLnvvIzpgb/lhY3pobXpnaLot7PovaxcclxuICAgICAgICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZUJ5VXJsKFwiL2FjY291bnQvYmlsbGluZ1wiKVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgXVxyXG4gICAgICB9KVxyXG4gICAgICBhbGVydC5wcmVzZW50KClcclxuICAgICAgcmV0dXJuIGZhbHNlXHJcbiAgICB9XHJcbiAgICByZXR1cm4gdHJ1ZVxyXG4gIH1cclxuXHJcbiAgLy/mn6Xor6Lpl67nrZTlhoXlrrnliIbkuqvmlbDmja7ooajvvJpDaGF0U2hhcmVcclxuICBhc3luYyBnZXRDaGF0U2hhcmUoKXtcclxuICAgIHRoaXMudXNlciA9IFBhcnNlLlVzZXIuY3VycmVudCgpO1xyXG4gICAgbGV0IHF1ZXJ5ID0gbmV3IFBhcnNlLlF1ZXJ5KCdDaGF0U2hhcmUnKTtcclxuICAgIHF1ZXJ5LmVxdWFsVG8oJ3VzZXInLCBQYXJzZS5Vc2VyLmN1cnJlbnQoKS5pZCk7XHJcbiAgICBxdWVyeS5lcXVhbFRvKCdzZXNzaW9uJywgdGhpcy5jaGF0Py5zZXNzaW9uSWQpXHJcbiAgICBsZXQgY2hhdFNoYXJlID0gYXdhaXQgcXVlcnkuZmlyc3QoKVxyXG4gICAgLy8gY29uc29sZS5sb2coY2hhdFNoYXJlKTtcclxuICB9XHJcblxyXG4gIGFzeW5jIHRvZ2dsZUNoYXRTaGFyZSgpIHtcclxuICAgIC8v6I635Y+WQ2hhdFNoYXJl5pWw5o2u6KGoXHJcbiAgICBsZXQgcXVlcnkgPSBuZXcgUGFyc2UuUXVlcnkoJ0NoYXRTaGFyZScpO1xyXG4gICAgcXVlcnkuZXF1YWxUbygndXNlcicsIFBhcnNlLlVzZXIuY3VycmVudCgpLmlkKTtcclxuICAgIHF1ZXJ5LmVxdWFsVG8oJ3JvbGUnLCB0aGlzLmNoYXQ/LnJvbGUuaWQpO1xyXG4gICAgcXVlcnkuZXF1YWxUbygnc2Vzc2lvbicsIHRoaXMuY2hhdD8uc2Vzc2lvbklkKTtcclxuICAgIC8vIHF1ZXJ5LmVxdWFsVG8oJ21lc3NhZ2VMaXN0JywgdGhpcy5jaGF0Py5tZXNzYWdlTGlzdCk7XHJcbiAgICBxdWVyeS5zZWxlY3QoJ29iamVjdElkJylcclxuICAgIGxldCBzaGFyZSA9IGF3YWl0IHF1ZXJ5LmZpcnN0KCk7XHJcbiAgICAvLyBjb25zb2xlLmxvZyhzaGFyZSk7XHJcblxyXG4gICAgLy/lpoLmnpxpZOS4jeWtmOWcqO+8jOWcqOaVsOaNruihqOWGheWIm+W7uuaWsOeahOiusOW9lVxyXG4gICAgaWYoIXNoYXJlPy5pZCl7XHJcbiAgICAgIGxldCBvYmogPSBQYXJzZS5PYmplY3QuZXh0ZW5kKCdDaGF0U2hhcmUnKVxyXG4gICAgICBzaGFyZSA9IG5ldyBvYmooKVxyXG4gICAgICBzaGFyZS5zZXQoJ3VzZXInLCB7XHJcbiAgICAgICAgXCJfX3R5cGVcIjogXCJQb2ludGVyXCIsXHJcbiAgICAgICAgXCJjbGFzc05hbWVcIjogXCJfVXNlclwiLFxyXG4gICAgICAgIFwib2JqZWN0SWRcIjogUGFyc2UuVXNlci5jdXJyZW50KCk/LmlkXHJcbiAgICAgIH0pXHJcbiAgICAgIHNoYXJlLnNldCgnc2Vzc2lvbicsIHtcclxuICAgICAgICBcIl9fdHlwZVwiOiBcIlBvaW50ZXJcIixcclxuICAgICAgICBcImNsYXNzTmFtZVwiOiBcIkNoYXRTZXNzaW9uXCIsXHJcbiAgICAgICAgXCJvYmplY3RJZFwiOiB0aGlzLmNoYXQ/LnNlc3Npb25JZFxyXG4gICAgICB9KVxyXG4gICAgICBzaGFyZS5zZXQoJ3JvbGUnLCB7XHJcbiAgICAgICAgXCJfX3R5cGVcIjogXCJQb2ludGVyXCIsXHJcbiAgICAgICAgXCJjbGFzc05hbWVcIjogXCJBdmF0YXJSb2xlXCIsXHJcbiAgICAgICAgXCJvYmplY3RJZFwiOiB0aGlzLmNoYXQ/LnJvbGUuaWRcclxuICAgICAgfSlcclxuICAgICAgc2hhcmUuc2V0KCdjb21wYW55Jywge1xyXG4gICAgICAgIFwiX190eXBlXCI6IFwiUG9pbnRlclwiLFxyXG4gICAgICAgIFwiY2xhc3NOYW1lXCI6IFwiQ29tcGFueVwiLFxyXG4gICAgICAgIFwib2JqZWN0SWRcIjogXCJFNEtwR3ZURXRvXCJcclxuICAgICAgfSlcclxuICAgICAgc2hhcmUuc2V0KCdtZXNzYWdlTGlzdCcsIHRoaXMuY2hhdD8ubWVzc2FnZUxpc3QpXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvL2lk5a2Y5Zyo77yM54K55Ye75YiG5Lqr5oyJ6ZKu5omn6KGM5pu05pawbWVzc2FnZUxpc3TmlbDmja7nmoTmk43kvZxcclxuICAgICAgc2hhcmUuc2V0KCdtZXNzYWdlTGlzdCcsIHRoaXMuY2hhdD8ubWVzc2FnZUxpc3QpXHJcbiAgICB9XHJcbiAgICBhd2FpdCBzaGFyZS5zYXZlKCk7XHJcbiAgICB0aGlzLmdldENoYXRTaGFyZSgpO1xyXG59XHJcblxyXG5hc3luYyBjaGF0U2hhcmVTdWNjZXNzTWVzc2FnZSgpIHtcclxuICAgIGxldCB0b2FzdCA9IGF3YWl0IHRoaXMudG9hc3RDdHJsLmNyZWF0ZSh7XHJcbiAgICAgIGR1cmF0aW9uOjEwMDAsXHJcbiAgICAgIG1lc3NhZ2U6XCLliIbkuqvmiJDlip9cIixcclxuICAgICAgY29sb3I6J3ByaW1hcnknLFxyXG4gICAgICBpY29uOlwiaW5mb3JtYXRpb24tY2lyY2xlXCIsXHJcbiAgICAgIHBvc2l0aW9uOlwidG9wXCJcclxuICAgIH0pXHJcbiAgICB0b2FzdC5wcmVzZW50KCk7XHJcbiAgICByZXR1cm5cclxufVxyXG5cclxuICAvL+WIhuS6q+W8ueahhue7hOS7tlxyXG4gIGlzU2hhcmUgPSBmYWxzZTtcclxuXHJcbiAgc2hvd1NoYXJlKCk6IHZvaWQge1xyXG4gICAgdGhpcy5pc1NoYXJlID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIGhhbmRsZU9rU2hhcmUoKTogdm9pZCB7XHJcbiAgICAvLyBjb25zb2xlLmxvZyh0aGlzLmNoYXQpO1xyXG4gICAgLy8gY29uc29sZS5sb2codGhpcy5jaGF0Py5zZXNzaW9uSWQpO1xyXG4gICAgLy8gY29uc29sZS5sb2codGhpcy5jaGF0Py5tZXNzYWdlTGlzdCk7XHJcbiAgICAvLyBjb25zb2xlLmxvZyh0aGlzLmNoYXQ/LnJvbGUuaWQpO1xyXG4gICAgdGhpcy50b2dnbGVDaGF0U2hhcmUoKTtcclxuICAgIHRoaXMuY2hhdFNoYXJlU3VjY2Vzc01lc3NhZ2UoKTtcclxuICAgIHRoaXMuaXNTaGFyZSA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgaGFuZGxlQ2FuY2VsU2hhcmUoKTogdm9pZCB7XHJcbiAgICB0aGlzLmlzU2hhcmUgPSBmYWxzZTtcclxuICB9XHJcbn1cclxuIiwiPGlvbi10b29sYmFyPlxyXG4gICAgPGlvbi1pdGVtIGNsYXNzPVwiYnV0dG9uLWl0ZW1cIiBsaW5lcz1cIm5vbmVcIj5cclxuICAgICAgICA8IS0tIOiuvue9riAtLT5cclxuICAgICAgICA8IS0tIDxpb24tYnV0dG9uIGZpbGw9XCJvdXRsaW5lXCIgc2xvdD1cInN0YXJ0XCI+XHJcbiAgICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwic2V0dGluZ3Mtb3V0bGluZVwiPjwvaW9uLWljb24+IFxyXG4gICAgICAgIDwvaW9uLWJ1dHRvbj4gLS0+XHJcbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgYnV0dG9uIG9mIGNoYXQ/LmxlZnRCdXR0b25zXCI+XHJcbiAgICAgICAgICA8aW9uLWJ1dHRvbiBzdHlsZT1cIi0tcGFkZGluZy1zdGFydDoxMHB4Oy0tcGFkZGluZy1lbmQ6MTBweDtcIlxyXG4gICAgICAgICAgIHNoYXBlPVwicm91bmRcIiAqbmdJZj1cImJ1dHRvbj8uc2hvdyYmYnV0dG9uPy5zaG93KClcIiBmaWxsPVwib3V0bGluZVwiIFt0aXRsZV09XCJidXR0b24/LnRpdGxlXCIgc2xvdD1cInN0YXJ0XCIgKGNsaWNrKT1cImJ1dHRvbi5vbkNsaWNrKClcIj5cclxuICAgICAgICAgICAgPGlvbi1pY29uIFtuYW1lXT1cImJ1dHRvbj8uaWNvblwiIFtzbG90XT1cImJ1dHRvbj8uc2hvd1RpdGxlPydzdGFydCc6J2ljb24tb25seSdcIj48L2lvbi1pY29uPlxyXG4gICAgICAgICAgICB7e2J1dHRvbj8uc2hvd1RpdGxlJiZidXR0b24/LnRpdGxlfX1cclxuICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cclxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cclxuXHJcbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgYnV0dG9uIG9mIGNoYXQ/LnJvbGU/LmdldCgnYnV0dG9ucycpXCI+XHJcbiAgICAgICAgICAgIDxpb24tYnV0dG9uIHNoYXBlPVwicm91bmRcIiAoY2xpY2spPVwiY2hhdFNlcnYuZG9CdXR0b25BY3Rpb24oYnV0dG9uKVwiIGZpbGw9XCJvdXRsaW5lXCIgIHNsb3Q9XCJzdGFydFwiPlxyXG4gICAgICAgICAgICAgICAge3tidXR0b24/Lm5hbWV9fVxyXG4gICAgICAgICAgICA8L2lvbi1idXR0b24+XHJcbiAgICAgICAgPC9uZy1jb250YWluZXI+XHJcblxyXG4gICAgICAgIDwhLS3liIbkuqvmjInpkq4tLT5cclxuICAgICAgICBAaWYoIWNoYXQ/LmhpZGVTaGFyZSl7XHJcbiAgICAgICAgICA8aW9uLWJ1dHRvbiBzaGFwZT1cInJvdW5kXCIgKm5nSWY9XCJjaGF0Py5tZXNzYWdlTGlzdD8ubGVuZ3RoPjFcIiAoY2xpY2spPVwic2hvd1NoYXJlKClcIiBmaWxsPVwib3V0bGluZVwiIHRpdGxlPVwi5YiG5LqrXCIgc2xvdD1cImVuZFwiPlxyXG4gICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cInNoYXJlLXNvY2lhbC1vdXRsaW5lXCI+PC9pb24taWNvbj5cclxuICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cclxuICAgICAgICB9XHJcbiAgICAgICAgICA8aW9uLW1vZGFsIFtpc09wZW5dPVwiaXNTaGFyZVwiPlxyXG4gICAgICAgICAgICA8bmctdGVtcGxhdGU+XHJcbiAgICAgICAgICAgICAgPGlvbi1oZWFkZXI+XHJcbiAgICAgICAgICAgICAgICA8aW9uLXRvb2xiYXI+XHJcbiAgICAgICAgICAgICAgICAgIDxpb24tYnV0dG9ucyBzbG90PVwic3RhcnRcIj5cclxuICAgICAgICAgICAgICAgICAgICA8aW9uLWJ1dHRvbiAoY2xpY2spPVwiaGFuZGxlQ2FuY2VsU2hhcmUoKVwiPuWPlua2iDwvaW9uLWJ1dHRvbj5cclxuICAgICAgICAgICAgICAgICAgPC9pb24tYnV0dG9ucz5cclxuICAgICAgICAgICAgICAgICAgPGlvbi10aXRsZT7lr7nor53liIbkuqs8L2lvbi10aXRsZT5cclxuICAgICAgICAgICAgICAgICAgPGlvbi1idXR0b25zIHNsb3Q9XCJlbmRcIj5cclxuICAgICAgICAgICAgICAgICAgICA8aW9uLWJ1dHRvbiAoY2xpY2spPVwiaGFuZGxlT2tTaGFyZSgpXCI+5YiG5LqrPC9pb24tYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgICA8L2lvbi1idXR0b25zPlxyXG4gICAgICAgICAgICAgICAgPC9pb24tdG9vbGJhcj5cclxuICAgICAgICAgICAgICA8L2lvbi1oZWFkZXI+XHJcbiAgICAgICAgICAgICAgPGlvbi1jb250ZW50IGNsYXNzPVwiaW9uLXBhZGRpbmdcIj5cclxuICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IG1lc3NhZ2Ugb2YgY2hhdD8ubWVzc2FnZUxpc3Q7bGV0IGluZGV4PWluZGV4O1wiPlxyXG4gICAgICAgICAgICAgICAgICAgIDwhLS0g5YaF5a655qC85byP5YyW5Yy65Z+fIC0tPlxyXG4gICAgICAgICAgICAgICAgICAgIDxmbS1jaGF0LW1lc3NhZ2UtY2FyZCBbY2hhdF09XCJjaGF0XCIgKm5nSWY9XCIhbWVzc2FnZT8uaGlkZGVuXCIgW2luZGV4XT1cImluZGV4XCIgW21lc3NhZ2VdPVwibWVzc2FnZVwiIFtyb2xlXT1cImNoYXQ/LnJvbGVcIj48L2ZtLWNoYXQtbWVzc2FnZS1jYXJkPlxyXG4gICAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XHJcblxyXG4gICAgICAgICAgICAgICAgPGRpdiAqbmdJZj1cImZhbHNlXCIgY2xhc3M9XCJwb3B1cC1jb250ZW50XCI+XHJcbiAgICAgICAgICAgICAgICAgIDxkaXYgKm5nRm9yPVwibGV0IG1lc3NhZ2Ugb2YgY2hhdD8ubWVzc2FnZUxpc3RcIj5cclxuICAgICAgICAgICAgICAgICAgICA8IS0tIOWktOWDjyAtLT5cclxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaXRlbS1yb3cgdXNlclwiICpuZ0lmPVwibWVzc2FnZT8ucm9sZSE9J3N5c3RlbSdcIj5cclxuICAgICAgICAgICAgICAgICAgICAgIDxkaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxpbWcgY2xhc3M9XCJhdmF0YXJcIiAqbmdJZj1cIm1lc3NhZ2U/LnJvbGUhPSd1c2VyJ1wiIFtzcmNdPVwiKGNoYXQ/LnJvbGU/LmdldCgnYXZhdGFyJykgfHwgY2hhdD8ucm9sZT8uZ2V0KCd0aHVtYicpIHx8ICdodHRwczovL2ZpbGUtY2xvdWQuZm1vZGUuY24vRTRLcEd2VEV0by8yMDIzMDkzMC9sNDEzZTYwOTA3MzE4NTQucG5nJykrJz8nKyd4LWltYWdlLXByb2Nlc3M9aW1hZ2UvcmVzaXplLG1fZml4ZWQsd18xMDAnKycmaW1hZ2VWaWV3Mi8xL3cvMzIvaC8zMidcIiA+XHJcbiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ1c2VyLXF1ZXN0aW9uXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxhcHAtY29tcC11c2VyLWF2YXRhciBbdXNlcl09XCJ1c2VyXCIgKm5nSWY9XCJtZXNzYWdlPy5yb2xlPT0ndXNlcidcIj48L2FwcC1jb21wLXVzZXItYXZhdGFyPlxyXG4gICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgPCEtLSDlhoXlrrkgLS0+XHJcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1lc3NhZ2Utd3JhcHBlclwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1lc3NhZ2UtY29udGVudC11c2VyXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ1c2VyLW1lc3NhZ2VcIiAqbmdJZj1cIm1lc3NhZ2U/LnJvbGUgPT09ICd1c2VyJ1wiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJpdGVtLWNvbnRlbnRcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS0gPGZtLW1hcmtkb3duLXByZXZpZXcgKm5nSWY9XCIhbWVzc2FnZT8uY29tcGxldGVcIiBjbGFzcz1cImNvbnRlbnQtc3R5bGVcIiBbY29udGVudF09XCJtZXNzYWdlPy5jb250ZW50XCIgW3JlbmRlcl09XCJmYWxzZVwiPjwvZm0tbWFya2Rvd24tcHJldmlldz4gLS0+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Zm0tbWFya2Rvd24tcHJldmlldyAqbmdJZj1cIm1lc3NhZ2U/LmNvbXBsZXRlXCIgY2xhc3M9XCJjb250ZW50LXN0eWxlXCIgW2NvbnRlbnRdPVwibWVzc2FnZT8uY29udGVudFwiPjwvZm0tbWFya2Rvd24tcHJldmlldz5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtZXNzYWdlLWNvbnRlbnQtcm9sZVwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicm9sZS1tZXNzYWdlXCIgKm5nSWY9XCJtZXNzYWdlPy5yb2xlICE9PSAndXNlcicgJiYgbWVzc2FnZT8ucm9sZSAhPT0gJ3N5c3RlbSdcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaXRlbS1jb250ZW50XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tIDxmbS1tYXJrZG93bi1wcmV2aWV3ICpuZ0lmPVwiIW1lc3NhZ2U/LmNvbXBsZXRlXCIgY2xhc3M9XCJjb250ZW50LXN0eWxlXCIgW2NvbnRlbnRdPVwibWVzc2FnZT8uY29udGVudFwiIFtyZW5kZXJdPVwiZmFsc2VcIj48L2ZtLW1hcmtkb3duLXByZXZpZXc+IC0tPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGZtLW1hcmtkb3duLXByZXZpZXcgKm5nSWY9XCJtZXNzYWdlPy5jb21wbGV0ZVwiIGNsYXNzPVwiY29udGVudC1zdHlsZVwiIFtjb250ZW50XT1cIm1lc3NhZ2U/LmNvbnRlbnRcIj48L2ZtLW1hcmtkb3duLXByZXZpZXc+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibWVzc2FnZS1jb250ZW50LXN5c3RlbVwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3lzdGVtLW1lc3NhZ2VcIiAqbmdJZj1cIm1lc3NhZ2U/LnJvbGUgPT09ICdzeXN0ZW0nXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIml0ZW0tY29udGVudFwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPCEtLSA8Zm0tbWFya2Rvd24tcHJldmlldyAqbmdJZj1cIiFtZXNzYWdlPy5jb21wbGV0ZVwiIGNsYXNzPVwiY29udGVudC1zdHlsZVwiIFtjb250ZW50XT1cIm1lc3NhZ2U/LmNvbnRlbnRcIiBbcmVuZGVyXT1cImZhbHNlXCI+PC9mbS1tYXJrZG93bi1wcmV2aWV3PiAtLT5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxmbS1tYXJrZG93bi1wcmV2aWV3ICpuZ0lmPVwibWVzc2FnZT8uY29tcGxldGVcIiBjbGFzcz1cImNvbnRlbnQtc3R5bGVcIiBbY29udGVudF09XCJtZXNzYWdlPy5jb250ZW50XCI+PC9mbS1tYXJrZG93bi1wcmV2aWV3PlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjaGF0LXRpbWVcIiAqbmdJZj1cIm1lc3NhZ2U/LmNyZWF0ZWRBdFwiIFtuZ0NsYXNzXT1cInsncm9sZS10aW1lJzogbWVzc2FnZT8ucm9sZSAhPT0gJ3VzZXInfVwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3ttZXNzYWdlPy5jcmVhdGVkQXQgfCBkYXRlOlwiZGQvTU0veXl5eSwgSEgvbW0vc3MgYVwifX08L3NwYW4+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgPC9kaXY+ICAgXHJcbiAgICAgICAgICAgICAgPC9pb24tY29udGVudD5cclxuICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cclxuICAgICAgICAgIDwvaW9uLW1vZGFsPlxyXG5cclxuICAgICAgICA8IS0tIOWbvueJhyAtLT5cclxuICAgICAgICA8aW9uLWJ1dHRvbiBzaGFwZT1cInJvdW5kXCIgKm5nSWY9XCJjaGF0Py5jdXJyZW50TW9kZWw/LmdldCgnY29uZmlnJyk/LmltYWdlRW5hYmxlZFwiIGZpbGw9XCJvdXRsaW5lXCIgIHNsb3Q9XCJlbmRcIiAoY2xpY2spPVwic2V0TWVzc2FnZUltYWdlKClcIj5cclxuICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwiaW1hZ2Utb3V0bGluZVwiPjwvaW9uLWljb24+XHJcbiAgICAgICAgPC9pb24tYnV0dG9uPlxyXG4gICAgICAgIDwhLS0g5qih5Z6LIC0tPlxyXG4gICAgICAgIEBpZighY2hhdD8uaGlkZU1vZGFsU2VsZWN0KXtcclxuICAgICAgICAgIDxpb24tYnV0dG9uIHNoYXBlPVwicm91bmRcIiBmaWxsPVwib3V0bGluZVwiIHNsb3Q9XCJlbmRcIiAgaWQ9XCJtb2RlbC1idXR0b25cIj5cclxuICAgICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cImNoZXZyb24tZG93bi1vdXRsaW5lXCI+PC9pb24taWNvbj5cclxuICAgICAgICAgICAgICB7e2NoYXQ/LmN1cnJlbnRNb2RlbD8uZ2V0JiZjaGF0Py5jdXJyZW50TW9kZWw/LmdldChcIm5hbWVcIil8fFwiRm1vZGUtQzEuMC0xMjhrXCJ9fVxyXG4gICAgICAgICAgPC9pb24tYnV0dG9uPlxyXG4gICAgICAgICAgPGlvbi1wb3BvdmVyIHRyaWdnZXI9XCJtb2RlbC1idXR0b25cIiBbZGlzbWlzc09uU2VsZWN0XT1cInRydWVcIj5cclxuICAgICAgICAgICAgICA8bmctdGVtcGxhdGU+XHJcbiAgICAgICAgICAgICAgICA8aW9uLWNvbnRlbnQ+XHJcbiAgICAgICAgICAgICAgICAgIDxpb24tbGlzdD5cclxuICAgICAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IG1vZGVsIG9mIGNoYXQubW9kZWxMaXN0XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1pdGVtIChjbGljayk9XCJjaGF0LmN1cnJlbnRNb2RlbCA9IG1vZGVsXCIgW2J1dHRvbl09XCJ0cnVlXCIgW2RldGFpbF09XCJmYWxzZVwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge3ttb2RlbD8uZ2V0KFwibmFtZVwiKX19XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8aW9uLW5vdGUgc2xvdD1cImVuZFwiPnt7bW9kZWw/LmdldChcImNyZWRpdFwiKX19L2s8L2lvbi1ub3RlPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIDwvaW9uLWl0ZW0+XHJcbiAgICAgICAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cclxuICAgICAgICAgICAgICAgICAgPC9pb24tbGlzdD5cclxuICAgICAgICAgICAgICAgIDwvaW9uLWNvbnRlbnQ+XHJcbiAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cclxuICAgICAgICAgICAgPC9pb24tcG9wb3Zlcj5cclxuICAgICAgICAgIH1cclxuXHJcbiAgICA8L2lvbi1pdGVtPlxyXG5cclxuICAgIDxpb24taXRlbSBjbGFzcz1cImlucHV0LWl0ZW1cIiBsaW5lcz1cIm5vbmVcIj5cclxuICAgICAgICA8IS0tIOivremfs+a2iOaBr+i+k+WFpSAtLT5cclxuICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiY2hhdD8uaXNWb2ljZUlucHV0TW9kZVwiPlxyXG4gICAgICAgICAgPCEtLSDliIfmjaLmlofmnKzovpPlhaUgLS0+XHJcbiAgICAgICAgICA8aW9uLWJ1dHRvbiBjbGFzcz1cImJ0bi1pbnB1dC1jaGFuZ2VcIiBjb2xvcj1cInByaW1hcnlcIiAoY2xpY2spPVwiY2hhdC5pc1ZvaWNlSW5wdXRNb2RlPWZhbHNlXCIgc2hhcGU9XCJyb3VuZFwiIHNpemU9XCJsYXJnZVwiPlxyXG4gICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cImNoYXRib3gtZWxsaXBzZXMtb3V0bGluZVwiIHNsb3Q9XCJpY29uLW9ubHlcIj48L2lvbi1pY29uPlxyXG4gICAgICAgICAgPC9pb24tYnV0dG9uPlxyXG4gICAgICAgICAgXHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYnRuLXZvaWNlLXN0YXJ0XCIgKGNsaWNrKT1cInN0YXJ0VGFsaygpXCIgW2NsYXNzLmRpc2FibGVkXT1cImlzU2VuZGluZ1wiPlxyXG4gICAgICAgICAgICA8c3Bhbj5cclxuICAgICAgICAgICAgICDngrnlh7vorrLor51cclxuICAgICAgICAgICAgPC9zcGFuPiBcclxuICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvbmctY29udGFpbmVyPlxyXG5cclxuICAgICAgICA8IS0tIOaWh+acrOa2iOaBr+i+k+WFpSAtLT5cclxuICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWNoYXQ/LmlzVm9pY2VJbnB1dE1vZGVcIj5cclxuICAgICAgICAgIDwhLS0g5YiH5o2i6K+t6Z+z6L6T5YWlIC0tPlxyXG4gICAgICAgICAgPGlvbi1idXR0b24gW3N0eWxlLmRpc3BsYXldPVwiY2hhdC5pc1RleHRpbmc/J25vbmUnOidmbGV4J1wiIGNsYXNzPVwiYnRuLWlucHV0LWNoYW5nZVwiIGNvbG9yPVwicHJpbWFyeVwiICpuZ0lmPVwiY2hhdD8ucm9sZT8uZ2V0KCd2b2ljZUNvbmZpZycpXCIgKGNsaWNrKT1cImNoYXQuaXNWb2ljZUlucHV0TW9kZT10cnVlXCIgc2hhcGU9XCJyb3VuZFwiIHNpemU9XCJsYXJnZVwiPlxyXG4gICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cIm1pYy1vdXRsaW5lXCIgc2xvdD1cImljb24tb25seVwiPjwvaW9uLWljb24+XHJcbiAgICAgICAgICA8L2lvbi1idXR0b24+XHJcblxyXG4gICAgICAgICAgPCEtLSDmlofmnKzovpPlhaXljLrln58gLS0+XHJcbiAgICAgICAgICA8aW9uLXRleHRhcmVhXHJcbiAgICAgICAgICAjdXNlcklucHV0XHJcbiAgICAgICAgICAqbmdJZj1cImNoYXRcIiAoa2V5ZG93bik9XCJvbktleURvd24oJGV2ZW50KVwiXHJcbiAgICAgICAgICBbZXJyb3JUZXh0XT1cImVycm9yVGV4dFwiXHJcbiAgICAgICAgICBbKG5nTW9kZWwpXT1cImNoYXQudXNlcklucHV0XCJcclxuICAgICAgICAgIChpb25Gb2N1cyk9XCJvbklucHV0Rm9jdXMoKVwiXHJcbiAgICAgICAgICAoaW9uQmx1cik9XCJjaGF0LmlzVGV4dGluZz1mYWxzZVwiXHJcbiAgICAgICAgICBbYXV0b0dyb3ddPVwidHJ1ZVwiIHNoYXBlPVwicm91bmRcIiBmaWxsPVwib3V0bGluZVwiXHJcbiAgICAgICAgICBsYWJlbD1cIkN0cmwgKyBFbnRlciDlj5HpgIHmtojmga9cIiBwbGFjZWhvbGRlcj1cIuivt+i+k+WFpeaCqOeahOaPkOekuuivjVwiXHJcbiAgICAgICAgICBsYWJlbFBsYWNlbWVudD1cImZsb2F0aW5nXCI+PC9pb24tdGV4dGFyZWE+XHJcbiAgICAgICAgICBcclxuICAgICAgICAgIDwhLS0g5paH5pys5Y+R6YCB5oyJ6ZKuIC0tPlxyXG4gICAgICAgICAgPGlvbi1idXR0b24gW2Rpc2FibGVkXT1cImlzU2VuZGluZ1wiXHJcbiAgICAgICAgICBjb2xvcj1cInByaW1hcnlcIiBzaGFwZT1cInJvdW5kXCIgc2l6ZT1cImxhcmdlXCIgKGNsaWNrKT1cInNlbmRNZXNzYWdlKClcIj5cclxuICAgICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJwYXBlci1wbGFuZS1vdXRsaW5lXCIgc2xvdD1cImljb24tb25seVwiPjwvaW9uLWljb24+XHJcbiAgICAgICAgICA8L2lvbi1idXR0b24+XHJcbiAgICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICA8L2lvbi1pdGVtPlxyXG48L2lvbi10b29sYmFyPlxyXG5cclxuXHJcbjwhLS0g6K+t6Z+z5raI5oGv6L6T5YWl77ya5by55Ye65Yy65Z+fIC0tPlxyXG48IS0tIDxpb24tbW9kYWwgI2F1ZGlvTW9kYWwgW2lzT3Blbl09XCJpc0F1ZGlvTW9kYWxcIiAod2lsbERpc21pc3MpPVwiY2xvc2VBdWRpbygpXCIgW2luaXRpYWxCcmVha3BvaW50XT1cImF1ZGlvTW9kYWxIZWlnaHRQb2ludFwiIFticmVha3BvaW50c109XCJbMCwgYXVkaW9Nb2RhbEhlaWdodFBvaW50XVwiPlxyXG4gIDxuZy10ZW1wbGF0ZT5cclxuICAgIDxmbS1tb2RhbC1hdWRpby1tZXNzYWdlICNhdWRpb0NvbXAgKm5nSWY9XCJpc0F1ZGlvTW9kYWxcIiBbY2hhdF09XCJjaGF0XCIgW21vZGFsXT1cImF1ZGlvTW9kYWxcIj48L2ZtLW1vZGFsLWF1ZGlvLW1lc3NhZ2U+XHJcbiAgPC9uZy10ZW1wbGF0ZT5cclxuPC9pb24tbW9kYWw+IC0tPiJdfQ==
1
+
2
+ /**
3
+ * @copyright © 未来飞马 © 未来全栈 www.fmode.cn
4
+ * 版权所有 © 未来飞马 © 江西脑控科技有限公司 Copyright © Fmode Technology Co., Ltd.
5
+ * 保留所有权利 All Rights Reserved.
6
+ * /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-modal-input/modal-input.component.mjs
7
+ */
8
+ import{Component,Input,ViewChild}from"@angular/core";import{Router,RouterModule}from"@angular/router";import{AlertController,ToastController}from"@ionic/angular";import{FmodeChat}from"../../service-fmai/service-chat";import{ChatService}from"../../service-fmai/service-chat";import{FmodeParse,FmodeObject}from"@fmode/parse";import{ImagineService}from"../../service-fmai/service-imagine/imagine.service";import{IonButton,IonContent,IonIcon,IonInput,IonItem,IonList,IonModal,IonPopover,IonTextarea,IonToolbar,ModalController}from"@ionic/angular/standalone";import{CommonModule}from"@angular/common";import{FormsModule,ReactiveFormsModule}from"@angular/forms";import{ModalAudioMessageComponent}from"./modal-audio-message/modal-audio-message.component";import{FmChatMessageCard}from"../chat-message-card/comp-message-card.component";import{addIcons}from"ionicons";import{imageOutline,chevronBackOutline,ellipsisHorizontalOutline,chevronDownOutline,chatboxEllipsesOutline,micOutline,paperPlaneOutline,shareSocialOutline,settingsOutline,alertOutline,colorWandOutline,peopleOutline}from"ionicons/icons";import{AccountService}from"../../../user/account/account.service";import*as i0 from"@angular/core";import*as i1 from"@ionic/angular";import*as i2 from"@ionic/angular/standalone";import*as i3 from"@angular/router";import*as i4 from"../../service-fmai/service-imagine/imagine.service";import*as i5 from"../../service-fmai/service-chat";import*as i6 from"../../../user/account/account.service";import*as i7 from"@angular/common";import*as i8 from"@angular/forms";const Parse=FmodeParse.with("nova");addIcons({colorWandOutline:colorWandOutline,peopleOutline:peopleOutline,alertOutline:alertOutline,imageOutline:imageOutline,chevronBackOutline:chevronBackOutline,ellipsisHorizontalOutline:ellipsisHorizontalOutline,chevronDownOutline:chevronDownOutline,chatboxEllipsesOutline:chatboxEllipsesOutline,micOutline:micOutline,paperPlaneOutline:paperPlaneOutline,shareSocialOutline:shareSocialOutline,settingsOutline:settingsOutline});export class FmChatModalInput{closeAudio(){this.audioComp?.cancel(),this.isAudioModal=!1}async startTalk(){if(this.isSending)return!1;let e,n=document.body.clientHeight||960;this.audioModalHeightPoint=Number((165/n).toFixed(2)),this.chat.stopPlayingVoice(),e=await this.modalCtrl.create({component:ModalAudioMessageComponent,componentProps:{chat:this.chat,modal:e,onBreakPointSet:()=>{e?.setCurrentBreakpoint(this.audioModalHeightPoint)}},breakpoints:[this.audioModalHeightPoint],initialBreakpoint:this.audioModalHeightPoint}),e.present()}constructor(e,n,t,o,i,a,s){this.toastCtrl=e,this.alertCtrl=n,this.modalCtrl=t,this.router=o,this.imagineServ=i,this.chatServ=a,this.account=s,this.errorText="",this.isAudioModal=!1,this.audioModalHeightPoint=.35,this.isSending=!1,this.lastMessageTimestamp=0,this.replyTimeout=15e3,this.isShare=!1,this.user=Parse.User.current()}ngOnInit(){this.loadModel();let e=this;this.chat.focusUserInput=()=>{e.chat.isVoiceInputMode=!1,e.userInputComp.setFocus()}}async loadModel(){let e=this.chat?.role?.get("model");await this.chat.loadModelList(e)}async setMessageImage(){let e=await this.imagineServ.getimg();this.chat.userImage=e,console.log(this.chat?.userImage)}onInputFocus(){this.chat.isTexting=!0,this.chat.scrollToBottom&&this.chat.scrollToBottom()}onKeyDown(e){e.ctrlKey&&"Enter"===e.key&&(console.log("Ctrl+Enter 被按下"),this.sendMessage())}async sendMessage(){if(this.isSending)return!1;const e=Date.now();if(this.lastMessageTimestamp>0&&e-this.lastMessageTimestamp<this.replyTimeout){return this.errorText="请等待上一条消息的回复或稍后再试",(await this.toastCtrl.create({message:this.errorText,position:"top",icon:"alert",color:"warning",duration:1e3})).present(),!1}if(this.isSending=!0,this.lastMessageTimestamp=Date.now(),!await this.checkBalance())return this.isSending=!1,!1;if(!this.chat.userInput){return this.errorText="内容不能为空",(await this.toastCtrl.create({message:this.errorText,position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present(),void(this.isSending=!1)}this.lastMessageTimeout&&clearTimeout(this.lastMessageTimeout),this.lastMessageTimeout=setTimeout((()=>{this.isSending=!1,this.lastMessageTimestamp=0}),this.replyTimeout),this.chat?.sendMessage(this.chat?.userInput,this.chat?.userImage,(e=>{}),{onMessageStart:e=>{clearTimeout(this.lastMessageTimeout),this.isSending=!1,this.lastMessageTimestamp=0},onSSMLComplete:e=>{console.log(e)}}),this.chat.userInput="",this.chat.userImage=""}async checkBalance(){let e=await this.account.getBilling();if(e?.credit?.balance>=10&&(this.chat.isDirect=!0),!this.chat?.currentModel?.get?.("payLimit"))return!0;if(e?.credit?.balance<10){return(await this.alertCtrl.create({header:"注意",subHeader:"您的余额不足,请充值后解锁高级模型",buttons:[{role:"cancel",text:"取消"},{role:"destructive",text:"充值",handler:()=>{this.router.navigateByUrl("/account/billing")}}]})).present(),!1}return!0}async getChatShare(){this.user=Parse.User.current();let e=new Parse.Query("ChatShare");e.equalTo("user",Parse.User.current().id),e.equalTo("session",this.chat?.sessionId);await e.first()}async toggleChatShare(){let e=new Parse.Query("ChatShare");e.equalTo("user",Parse.User.current().id),e.equalTo("role",this.chat?.role.id),e.equalTo("session",this.chat?.sessionId),e.select("objectId");let n=await e.first();if(n?.id)n.set("messageList",this.chat?.messageList);else{n=new(Parse.Object.extend("ChatShare")),n.set("user",{__type:"Pointer",className:"_User",objectId:Parse.User.current()?.id}),n.set("session",{__type:"Pointer",className:"ChatSession",objectId:this.chat?.sessionId}),n.set("role",{__type:"Pointer",className:"AvatarRole",objectId:this.chat?.role.id}),n.set("company",{__type:"Pointer",className:"Company",objectId:"E4KpGvTEto"}),n.set("messageList",this.chat?.messageList)}await n.save(),this.getChatShare()}async chatShareSuccessMessage(){(await this.toastCtrl.create({duration:1e3,message:"分享成功",color:"primary",icon:"information-circle",position:"top"})).present()}showShare(){this.isShare=!0}handleOkShare(){this.toggleChatShare(),this.chatShareSuccessMessage(),this.isShare=!1}handleCancelShare(){this.isShare=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,deps:[{token:i1.ToastController},{token:i1.AlertController},{token:i2.ModalController},{token:i3.Router},{token:i4.ImagineService},{token:i5.ChatService},{token:i6.AccountService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"17.3.12",type:FmChatModalInput,isStandalone:!0,selector:"fm-chat-modal-input",inputs:{chat:"chat",message:"message",role:"role"},viewQueries:[{propertyName:"audioComp",first:!0,predicate:ModalAudioMessageComponent,descendants:!0},{propertyName:"userInputComp",first:!0,predicate:["userInput"],descendants:!0}],ngImport:i0,template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button style="--padding-start:10px;--padding-end:10px;"\n shape="round" *ngIf="button?.show&&button?.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon" [slot]="button?.showTitle?\'start\':\'icon-only\'"></ion-icon>\n {{button?.showTitle&&button?.title}}\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n @if(!chat?.hideShare){\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="end">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n }\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <ng-container *ngFor="let message of chat?.messageList;let index=index;">\n \x3c!-- 内容格式化区域 --\x3e\n <fm-chat-message-card [chat]="chat" *ngIf="!message?.hidden" [index]="index" [message]="message" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n <div *ngIf="false" class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <img class="avatar" *ngIf="message?.role!=\'user\'" [src]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" >\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chat?.currentModel?.get?.(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n @if(!chat?.hideModalSelect){\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chat?.currentModel?.get&&chat?.currentModel?.get?.("name")||"Fmode-C1.0-128k"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chat.modelList">\n <ion-item (click)="chat.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n }\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="startTalk()" [class.disabled]="isSending">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea\n #userInput\n *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="onInputFocus()"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button [disabled]="isSending"\n color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n\x3c!-- <ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="audioModalHeightPoint" [breakpoints]="[0, audioModalHeightPoint]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal> --\x3e',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}.disabled{opacity:.5;pointer-events:none}.avatar{border-radius:50%;width:32px;height:32px;object-fit:cover}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i7.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:i7.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i7.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i7.DatePipe,name:"date"},{kind:"ngmodule",type:FormsModule},{kind:"directive",type:i8.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:i8.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"ngmodule",type:RouterModule},{kind:"component",type:IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonTextarea,selector:"ion-textarea",inputs:["autoGrow","autocapitalize","autofocus","clearOnEdit","color","cols","counter","counterFormatter","debounce","disabled","enterkeyhint","errorText","fill","helperText","inputmode","label","labelPlacement","maxlength","minlength","mode","name","placeholder","readonly","required","rows","shape","spellcheck","value","wrap"]},{kind:"component",type:IonPopover,selector:"ion-popover"},{kind:"component",type:IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"component",type:FmChatMessageCard,selector:"fm-chat-message-card",inputs:["index","message","role","chat"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,decorators:[{type:Component,args:[{selector:"fm-chat-modal-input",standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,RouterModule,IonToolbar,IonItem,IonButton,IonList,IonModal,IonInput,IonIcon,IonTextarea,IonPopover,IonContent,FmChatMessageCard,ModalAudioMessageComponent],template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button style="--padding-start:10px;--padding-end:10px;"\n shape="round" *ngIf="button?.show&&button?.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon" [slot]="button?.showTitle?\'start\':\'icon-only\'"></ion-icon>\n {{button?.showTitle&&button?.title}}\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n @if(!chat?.hideShare){\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="end">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n }\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <ng-container *ngFor="let message of chat?.messageList;let index=index;">\n \x3c!-- 内容格式化区域 --\x3e\n <fm-chat-message-card [chat]="chat" *ngIf="!message?.hidden" [index]="index" [message]="message" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n <div *ngIf="false" class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <img class="avatar" *ngIf="message?.role!=\'user\'" [src]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" >\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chat?.currentModel?.get?.(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n @if(!chat?.hideModalSelect){\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chat?.currentModel?.get&&chat?.currentModel?.get?.("name")||"Fmode-C1.0-128k"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chat.modelList">\n <ion-item (click)="chat.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n }\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="startTalk()" [class.disabled]="isSending">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea\n #userInput\n *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="onInputFocus()"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button [disabled]="isSending"\n color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n\x3c!-- <ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="audioModalHeightPoint" [breakpoints]="[0, audioModalHeightPoint]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal> --\x3e',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}.disabled{opacity:.5;pointer-events:none}.avatar{border-radius:50%;width:32px;height:32px;object-fit:cover}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n']}]}],ctorParameters:()=>[{type:i1.ToastController},{type:i1.AlertController},{type:i2.ModalController},{type:i3.Router},{type:i4.ImagineService},{type:i5.ChatService},{type:i6.AccountService}],propDecorators:{audioComp:[{type:ViewChild,args:[ModalAudioMessageComponent]}],userInputComp:[{type:ViewChild,args:["userInput"]}],chat:[{type:Input}],message:[{type:Input}],role:[{type:Input}]}});
9
+ var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1tb2RhbC1pbnB1dC9tb2RhbC1pbnB1dC5jb21wb25lbnQubWpz`
10
+