@energycap/components 0.31.5 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/energycap-components.min.css +2 -2
  2. package/energycap-email.min.css +1 -1
  3. package/esm2020/energycap-components.mjs +5 -0
  4. package/esm2020/lib/components.module.mjs +386 -0
  5. package/esm2020/lib/controls/banner/banner.component.mjs +106 -0
  6. package/esm2020/lib/controls/button/button.component.mjs +106 -0
  7. package/esm2020/lib/controls/button/copy-button.directive.mjs +65 -0
  8. package/esm2020/lib/controls/checkbox/checkbox.component.mjs +139 -0
  9. package/esm2020/lib/controls/collapsible-toggle/collapsible-toggle.component.mjs +38 -0
  10. package/esm2020/lib/controls/combobox/combobox.component.mjs +841 -0
  11. package/esm2020/lib/controls/dropdown/dropdown.component.mjs +237 -0
  12. package/esm2020/lib/controls/file-upload/file-upload.component.mjs +169 -0
  13. package/esm2020/lib/controls/form-control/form-control.component.mjs +86 -0
  14. package/esm2020/lib/controls/form-control-base.mjs +143 -0
  15. package/esm2020/lib/controls/form-control-label/form-control-label.component.mjs +136 -0
  16. package/esm2020/lib/controls/form-group/form-group.component.mjs +252 -0
  17. package/esm2020/lib/controls/help-popover/help-popover.component.mjs +28 -0
  18. package/esm2020/lib/controls/item-picker/item-picker.component.mjs +233 -0
  19. package/esm2020/lib/controls/link-button/link-button.component.mjs +11 -0
  20. package/esm2020/lib/controls/menu/menu.component.mjs +443 -0
  21. package/{esm2015/lib/controls/navigation/link-item.js → esm2020/lib/controls/navigation/link-item.mjs} +0 -0
  22. package/{esm2015/lib/controls/navigation/nav-group.js → esm2020/lib/controls/navigation/nav-group.mjs} +0 -0
  23. package/esm2020/lib/controls/navigation/nav-item-active.directive.mjs +92 -0
  24. package/{esm2015/lib/controls/navigation/nav-item.js → esm2020/lib/controls/navigation/nav-item.mjs} +0 -0
  25. package/esm2020/lib/controls/numericbox/numericbox.component.mjs +371 -0
  26. package/esm2020/lib/controls/popover/popover.component.mjs +84 -0
  27. package/{esm2015/lib/controls/radio-button/radio-button-option.js → esm2020/lib/controls/radio-button/radio-button-option.mjs} +0 -0
  28. package/esm2020/lib/controls/radio-button/radio-button.component.mjs +81 -0
  29. package/esm2020/lib/controls/select/select.component.mjs +87 -0
  30. package/esm2020/lib/controls/tabs/tabs.component.mjs +47 -0
  31. package/esm2020/lib/controls/textbox/textbox.component.mjs +154 -0
  32. package/{esm2015/lib/core/cache.service.js → esm2020/lib/core/cache.service.mjs} +9 -8
  33. package/{esm2015/lib/core/custom-validators.js → esm2020/lib/core/custom-validators.mjs} +0 -0
  34. package/{esm2015/lib/core/date-time-helper.js → esm2020/lib/core/date-time-helper.mjs} +0 -0
  35. package/esm2020/lib/core/error.service.mjs +57 -0
  36. package/esm2020/lib/core/scroll.service.mjs +89 -0
  37. package/esm2020/lib/core/telemetry-tracker.service.mjs +16 -0
  38. package/esm2020/lib/core/telemetry.service.mjs +38 -0
  39. package/esm2020/lib/core/validation-message.service.mjs +181 -0
  40. package/{esm2015/lib/core/validation-patterns.js → esm2020/lib/core/validation-patterns.mjs} +0 -0
  41. package/esm2020/lib/core/window.service.mjs +182 -0
  42. package/esm2020/lib/display/app-bar/app-bar.component.mjs +46 -0
  43. package/esm2020/lib/display/avatar/avatar.component.mjs +67 -0
  44. package/{esm2015/lib/display/avatar/avatar.service.js → esm2020/lib/display/avatar/avatar.service.mjs} +9 -7
  45. package/esm2020/lib/display/confirm/confirm.component.mjs +131 -0
  46. package/{esm2015/lib/display/dialog/dialog-content.js → esm2020/lib/display/dialog/dialog-content.mjs} +0 -0
  47. package/esm2020/lib/display/dialog/dialog-group/dialog-group.component.mjs +63 -0
  48. package/{esm2015/lib/display/dialog/dialog-types.js → esm2020/lib/display/dialog/dialog-types.mjs} +0 -0
  49. package/esm2020/lib/display/dialog/dialog.component.mjs +242 -0
  50. package/esm2020/lib/display/dialog/dialog.service.mjs +71 -0
  51. package/{esm2015/lib/display/help/help-types.js → esm2020/lib/display/help/help-types.mjs} +0 -0
  52. package/esm2020/lib/display/hierarchy/hierarchy-base.mjs +106 -0
  53. package/{esm2015/lib/display/hierarchy/hierarchy-mocks.spec.js → esm2020/lib/display/hierarchy/hierarchy-mocks.spec.mjs} +5 -9
  54. package/esm2020/lib/display/hierarchy/hierarchy-tree/hierarchy-tree.component.mjs +59 -0
  55. package/esm2020/lib/display/item-display/item-display.component.mjs +67 -0
  56. package/esm2020/lib/display/json-display/json-display.component.mjs +47 -0
  57. package/esm2020/lib/display/resizable/resizable-base.mjs +120 -0
  58. package/esm2020/lib/display/resizable/resizable.component.mjs +57 -0
  59. package/esm2020/lib/display/spinner/spinner.component.mjs +12 -0
  60. package/esm2020/lib/display/splash/splash.component.mjs +42 -0
  61. package/esm2020/lib/display/splash/splash.service.mjs +35 -0
  62. package/esm2020/lib/display/table/resizable-column.component.mjs +20 -0
  63. package/esm2020/lib/display/table/resizable-table.directive.mjs +227 -0
  64. package/esm2020/lib/display/table/searchable-table.component.mjs +338 -0
  65. package/esm2020/lib/display/table/table-detail-row.component.mjs +27 -0
  66. package/esm2020/lib/display/table/table-locked-column.component.mjs +58 -0
  67. package/esm2020/lib/display/table/table-master-header-row.component.mjs +11 -0
  68. package/esm2020/lib/display/table/table-master-row.component.mjs +150 -0
  69. package/esm2020/lib/display/table/table-pagination.component.mjs +150 -0
  70. package/esm2020/lib/display/table/table-selectable-row.component.mjs +235 -0
  71. package/esm2020/lib/display/table/table.component.mjs +244 -0
  72. package/esm2020/lib/display/tags/tag.mjs +15 -0
  73. package/esm2020/lib/display/tags/tags.component.mjs +77 -0
  74. package/esm2020/lib/display/toast/toast/toast.component.mjs +77 -0
  75. package/{esm2015/lib/display/toast/toast-types.js → esm2020/lib/display/toast/toast-types.mjs} +0 -0
  76. package/esm2020/lib/display/toast/toast.service.mjs +35 -0
  77. package/esm2020/lib/display/toast/toaster/toaster.component.mjs +114 -0
  78. package/esm2020/lib/display/tooltip/tooltip.component.mjs +25 -0
  79. package/esm2020/lib/display/tooltip/tooltip.service.mjs +63 -0
  80. package/esm2020/lib/display/tree/tree.component.mjs +125 -0
  81. package/esm2020/lib/display/view-overlay/view-overlay.component.mjs +58 -0
  82. package/esm2020/lib/shared/directives/click-area-for/click-area-for.directive.mjs +32 -0
  83. package/esm2020/lib/shared/directives/if-viewport-width/if-viewport-width.directive.mjs +111 -0
  84. package/esm2020/lib/shared/directives/popup/popup-container.directive.mjs +163 -0
  85. package/esm2020/lib/shared/display/pipes/date-display.pipe.mjs +50 -0
  86. package/esm2020/lib/shared/display/pipes/highlight-text.pipe.mjs +30 -0
  87. package/esm2020/lib/shared/display/pipes/relative-date.pipe.mjs +48 -0
  88. package/esm2020/lib/shared/display/pipes/row-count.pipe.mjs +48 -0
  89. package/esm2020/lib/shared/display/pipes/time-display.pipe.mjs +41 -0
  90. package/{esm2015/lib/shared/display.js → esm2020/lib/shared/display.mjs} +0 -0
  91. package/esm2020/lib/shared/form-group.helper.mjs +67 -0
  92. package/{esm2015/lib/shared/json-helper.js → esm2020/lib/shared/json-helper.mjs} +0 -0
  93. package/{esm2015/lib/shared/lodash-helper.js → esm2020/lib/shared/lodash-helper.mjs} +0 -0
  94. package/esm2020/lib/shared/page/page-base/page-base.component.mjs +339 -0
  95. package/{esm2015/lib/shared/page/page-statuses.js → esm2020/lib/shared/page/page-statuses.mjs} +0 -0
  96. package/esm2020/lib/shared/page/page-title/page-title.component.mjs +23 -0
  97. package/esm2020/lib/shared/page/page-view/page-view.component.mjs +121 -0
  98. package/{esm2015/lib/shared/testing/hierarchy-base-test-injector-factory.spec.js → esm2020/lib/shared/testing/hierarchy-base-test-injector-factory.spec.mjs} +0 -0
  99. package/esm2020/lib/shared/testing/page-base-component-test-helper.spec.mjs +30 -0
  100. package/{esm2015/lib/shared/testing/page-base-component-test-injector-factory.spec.js → esm2020/lib/shared/testing/page-base-component-test-injector-factory.spec.mjs} +0 -0
  101. package/esm2020/lib/shared/testing/public-mocks.spec.mjs +132 -0
  102. package/{esm2015/lib/shared/testing/spy-factory.spec.js → esm2020/lib/shared/testing/spy-factory.spec.mjs} +0 -0
  103. package/{esm2015/lib/shared/testing/translation-mocks.spec.js → esm2020/lib/shared/testing/translation-mocks.spec.mjs} +0 -0
  104. package/esm2020/lib/shared/user-preference.service.mjs +17 -0
  105. package/esm2020/lib/shared/wizard/wizard-base/wizard-base.component.mjs +246 -0
  106. package/esm2020/lib/shared/wizard/wizard-buttons/wizard-buttons.component.mjs +68 -0
  107. package/esm2020/lib/shared/wizard/wizard-progress/wizard-progress.component.mjs +18 -0
  108. package/{esm2015/public-api.js → esm2020/public-api.mjs} +0 -0
  109. package/fesm2015/energycap-components.mjs +10090 -0
  110. package/fesm2015/energycap-components.mjs.map +1 -0
  111. package/fesm2020/energycap-components.mjs +9999 -0
  112. package/fesm2020/energycap-components.mjs.map +1 -0
  113. package/index.d.ts +5 -0
  114. package/lib/components.module.d.ts +72 -0
  115. package/lib/controls/banner/banner.component.d.ts +3 -0
  116. package/lib/controls/button/button.component.d.ts +3 -0
  117. package/lib/controls/button/copy-button.directive.d.ts +3 -0
  118. package/lib/controls/checkbox/checkbox.component.d.ts +3 -0
  119. package/lib/controls/collapsible-toggle/collapsible-toggle.component.d.ts +3 -0
  120. package/lib/controls/combobox/combobox.component.d.ts +5 -2
  121. package/lib/controls/dropdown/dropdown.component.d.ts +3 -0
  122. package/lib/controls/file-upload/file-upload.component.d.ts +5 -2
  123. package/lib/controls/form-control/form-control.component.d.ts +3 -0
  124. package/lib/controls/form-control-base.d.ts +3 -0
  125. package/lib/controls/form-control-label/form-control-label.component.d.ts +3 -0
  126. package/lib/controls/form-group/form-group.component.d.ts +6 -3
  127. package/lib/controls/help-popover/help-popover.component.d.ts +3 -0
  128. package/lib/controls/item-picker/item-picker.component.d.ts +5 -2
  129. package/lib/controls/link-button/link-button.component.d.ts +3 -0
  130. package/lib/controls/menu/menu.component.d.ts +3 -0
  131. package/lib/controls/navigation/nav-item-active.directive.d.ts +3 -0
  132. package/lib/controls/numericbox/numericbox.component.d.ts +5 -2
  133. package/lib/controls/popover/popover.component.d.ts +3 -0
  134. package/lib/controls/radio-button/radio-button.component.d.ts +3 -0
  135. package/lib/controls/select/select.component.d.ts +3 -0
  136. package/lib/controls/tabs/tabs.component.d.ts +3 -0
  137. package/lib/controls/textbox/textbox.component.d.ts +3 -0
  138. package/lib/core/cache.service.d.ts +3 -0
  139. package/lib/core/error.service.d.ts +3 -0
  140. package/lib/core/scroll.service.d.ts +3 -0
  141. package/lib/core/telemetry-tracker.service.d.ts +3 -0
  142. package/lib/core/telemetry.service.d.ts +3 -0
  143. package/lib/core/validation-message.service.d.ts +3 -0
  144. package/lib/core/window.service.d.ts +3 -0
  145. package/lib/display/app-bar/app-bar.component.d.ts +3 -0
  146. package/lib/display/avatar/avatar.component.d.ts +3 -0
  147. package/lib/display/avatar/avatar.service.d.ts +3 -0
  148. package/lib/display/confirm/confirm.component.d.ts +5 -2
  149. package/lib/display/dialog/dialog-group/dialog-group.component.d.ts +3 -0
  150. package/lib/display/dialog/dialog.component.d.ts +3 -0
  151. package/lib/display/dialog/dialog.service.d.ts +3 -0
  152. package/lib/display/hierarchy/hierarchy-base.d.ts +3 -0
  153. package/lib/display/hierarchy/hierarchy-tree/hierarchy-tree.component.d.ts +3 -0
  154. package/lib/display/item-display/item-display.component.d.ts +3 -0
  155. package/lib/display/json-display/json-display.component.d.ts +5 -2
  156. package/lib/display/resizable/resizable-base.d.ts +3 -0
  157. package/lib/display/resizable/resizable.component.d.ts +3 -0
  158. package/lib/display/spinner/spinner.component.d.ts +3 -0
  159. package/lib/display/splash/splash.component.d.ts +3 -0
  160. package/lib/display/splash/splash.service.d.ts +3 -0
  161. package/lib/display/table/resizable-column.component.d.ts +3 -0
  162. package/lib/display/table/resizable-table.directive.d.ts +3 -0
  163. package/lib/display/table/searchable-table.component.d.ts +6 -3
  164. package/lib/display/table/table-detail-row.component.d.ts +3 -0
  165. package/lib/display/table/table-locked-column.component.d.ts +3 -0
  166. package/lib/display/table/table-master-header-row.component.d.ts +3 -0
  167. package/lib/display/table/table-master-row.component.d.ts +3 -0
  168. package/lib/display/table/table-pagination.component.d.ts +3 -0
  169. package/lib/display/table/table-selectable-row.component.d.ts +5 -2
  170. package/lib/display/table/table.component.d.ts +3 -0
  171. package/lib/display/tags/tags.component.d.ts +3 -0
  172. package/lib/display/toast/toast/toast.component.d.ts +3 -0
  173. package/lib/display/toast/toast.service.d.ts +3 -0
  174. package/lib/display/toast/toaster/toaster.component.d.ts +3 -0
  175. package/lib/display/tooltip/tooltip.component.d.ts +3 -0
  176. package/lib/display/tooltip/tooltip.service.d.ts +3 -0
  177. package/lib/display/tree/tree.component.d.ts +3 -0
  178. package/lib/display/view-overlay/view-overlay.component.d.ts +3 -0
  179. package/lib/shared/directives/click-area-for/click-area-for.directive.d.ts +3 -0
  180. package/lib/shared/directives/if-viewport-width/if-viewport-width.directive.d.ts +3 -0
  181. package/lib/shared/directives/popup/popup-container.directive.d.ts +3 -0
  182. package/lib/shared/display/pipes/date-display.pipe.d.ts +3 -0
  183. package/lib/shared/display/pipes/highlight-text.pipe.d.ts +3 -0
  184. package/lib/shared/display/pipes/relative-date.pipe.d.ts +3 -0
  185. package/lib/shared/display/pipes/row-count.pipe.d.ts +3 -0
  186. package/lib/shared/display/pipes/time-display.pipe.d.ts +3 -0
  187. package/lib/shared/form-group.helper.d.ts +5 -2
  188. package/lib/shared/page/page-base/page-base.component.d.ts +5 -2
  189. package/lib/shared/page/page-title/page-title.component.d.ts +3 -0
  190. package/lib/shared/page/page-view/page-view.component.d.ts +3 -0
  191. package/lib/shared/testing/public-mocks.spec.d.ts +7 -0
  192. package/lib/shared/user-preference.service.d.ts +3 -0
  193. package/lib/shared/wizard/wizard-base/wizard-base.component.d.ts +3 -0
  194. package/lib/shared/wizard/wizard-buttons/wizard-buttons.component.d.ts +3 -0
  195. package/lib/shared/wizard/wizard-progress/wizard-progress.component.d.ts +3 -0
  196. package/package.json +27 -15
  197. package/src/styles/_functions.scss +6 -4
  198. package/src/styles/_icons.scss +1 -1
  199. package/src/styles/mixins/_control-base.scss +2 -2
  200. package/src/styles/mixins/_form-control-base.scss +3 -1
  201. package/src/styles/mixins/_spinner-base.scss +3 -1
  202. package/bundles/energycap-components.umd.js +0 -10646
  203. package/bundles/energycap-components.umd.js.map +0 -1
  204. package/bundles/energycap-components.umd.min.js +0 -17
  205. package/bundles/energycap-components.umd.min.js.map +0 -1
  206. package/energycap-components.d.ts +0 -7
  207. package/energycap-components.metadata.json +0 -1
  208. package/esm2015/energycap-components.js +0 -8
  209. package/esm2015/lib/components.module.js +0 -238
  210. package/esm2015/lib/controls/banner/banner.component.js +0 -94
  211. package/esm2015/lib/controls/button/button.component.js +0 -89
  212. package/esm2015/lib/controls/button/copy-button.directive.js +0 -63
  213. package/esm2015/lib/controls/checkbox/checkbox.component.js +0 -137
  214. package/esm2015/lib/controls/collapsible-toggle/collapsible-toggle.component.js +0 -35
  215. package/esm2015/lib/controls/combobox/combobox.component.js +0 -819
  216. package/esm2015/lib/controls/dropdown/dropdown.component.js +0 -207
  217. package/esm2015/lib/controls/file-upload/file-upload.component.js +0 -172
  218. package/esm2015/lib/controls/form-control/form-control.component.js +0 -65
  219. package/esm2015/lib/controls/form-control-base.js +0 -140
  220. package/esm2015/lib/controls/form-control-label/form-control-label.component.js +0 -139
  221. package/esm2015/lib/controls/form-group/form-group.component.js +0 -254
  222. package/esm2015/lib/controls/help-popover/help-popover.component.js +0 -22
  223. package/esm2015/lib/controls/item-picker/item-picker.component.js +0 -216
  224. package/esm2015/lib/controls/link-button/link-button.component.js +0 -12
  225. package/esm2015/lib/controls/menu/menu.component.js +0 -424
  226. package/esm2015/lib/controls/navigation/nav-item-active.directive.js +0 -86
  227. package/esm2015/lib/controls/numericbox/numericbox.component.js +0 -362
  228. package/esm2015/lib/controls/popover/popover.component.js +0 -85
  229. package/esm2015/lib/controls/radio-button/radio-button.component.js +0 -78
  230. package/esm2015/lib/controls/select/select.component.js +0 -89
  231. package/esm2015/lib/controls/tabs/tabs.component.js +0 -42
  232. package/esm2015/lib/controls/textbox/textbox.component.js +0 -149
  233. package/esm2015/lib/core/error.service.js +0 -56
  234. package/esm2015/lib/core/scroll.service.js +0 -88
  235. package/esm2015/lib/core/telemetry-tracker.service.js +0 -14
  236. package/esm2015/lib/core/telemetry.service.js +0 -40
  237. package/esm2015/lib/core/validation-message.service.js +0 -185
  238. package/esm2015/lib/core/window.service.js +0 -191
  239. package/esm2015/lib/display/app-bar/app-bar.component.js +0 -42
  240. package/esm2015/lib/display/avatar/avatar.component.js +0 -73
  241. package/esm2015/lib/display/confirm/confirm.component.js +0 -127
  242. package/esm2015/lib/display/dialog/dialog-group/dialog-group.component.js +0 -65
  243. package/esm2015/lib/display/dialog/dialog.component.js +0 -229
  244. package/esm2015/lib/display/dialog/dialog.service.js +0 -69
  245. package/esm2015/lib/display/hierarchy/hierarchy-base.js +0 -106
  246. package/esm2015/lib/display/hierarchy/hierarchy-tree/hierarchy-tree.component.js +0 -58
  247. package/esm2015/lib/display/item-display/item-display.component.js +0 -57
  248. package/esm2015/lib/display/json-display/json-display.component.js +0 -44
  249. package/esm2015/lib/display/resizable/resizable-base.js +0 -119
  250. package/esm2015/lib/display/resizable/resizable.component.js +0 -57
  251. package/esm2015/lib/display/spinner/spinner.component.js +0 -12
  252. package/esm2015/lib/display/splash/splash.component.js +0 -45
  253. package/esm2015/lib/display/splash/splash.service.js +0 -34
  254. package/esm2015/lib/display/table/resizable-column.component.js +0 -23
  255. package/esm2015/lib/display/table/resizable-table.directive.js +0 -223
  256. package/esm2015/lib/display/table/searchable-table.component.js +0 -303
  257. package/esm2015/lib/display/table/table-detail-row.component.js +0 -21
  258. package/esm2015/lib/display/table/table-locked-column.component.js +0 -53
  259. package/esm2015/lib/display/table/table-master-header-row.component.js +0 -11
  260. package/esm2015/lib/display/table/table-master-row.component.js +0 -141
  261. package/esm2015/lib/display/table/table-pagination.component.js +0 -146
  262. package/esm2015/lib/display/table/table-selectable-row.component.js +0 -216
  263. package/esm2015/lib/display/table/table.component.js +0 -210
  264. package/esm2015/lib/display/tags/tag.js +0 -15
  265. package/esm2015/lib/display/tags/tags.component.js +0 -73
  266. package/esm2015/lib/display/toast/toast/toast.component.js +0 -70
  267. package/esm2015/lib/display/toast/toast.service.js +0 -34
  268. package/esm2015/lib/display/toast/toaster/toaster.component.js +0 -117
  269. package/esm2015/lib/display/tooltip/tooltip.component.js +0 -24
  270. package/esm2015/lib/display/tooltip/tooltip.service.js +0 -64
  271. package/esm2015/lib/display/tree/tree.component.js +0 -100
  272. package/esm2015/lib/display/view-overlay/view-overlay.component.js +0 -50
  273. package/esm2015/lib/shared/directives/click-area-for/click-area-for.directive.js +0 -25
  274. package/esm2015/lib/shared/directives/if-viewport-width/if-viewport-width.directive.js +0 -112
  275. package/esm2015/lib/shared/directives/popup/popup-container.directive.js +0 -160
  276. package/esm2015/lib/shared/display/pipes/date-display.pipe.js +0 -49
  277. package/esm2015/lib/shared/display/pipes/highlight-text.pipe.js +0 -26
  278. package/esm2015/lib/shared/display/pipes/relative-date.pipe.js +0 -49
  279. package/esm2015/lib/shared/display/pipes/row-count.pipe.js +0 -47
  280. package/esm2015/lib/shared/display/pipes/time-display.pipe.js +0 -40
  281. package/esm2015/lib/shared/form-group.helper.js +0 -65
  282. package/esm2015/lib/shared/page/page-base/page-base.component.js +0 -356
  283. package/esm2015/lib/shared/page/page-title/page-title.component.js +0 -19
  284. package/esm2015/lib/shared/page/page-view/page-view.component.js +0 -94
  285. package/esm2015/lib/shared/testing/page-base-component-test-helper.spec.js +0 -35
  286. package/esm2015/lib/shared/testing/public-mocks.spec.js +0 -126
  287. package/esm2015/lib/shared/user-preference.service.js +0 -15
  288. package/esm2015/lib/shared/wizard/wizard-base/wizard-base.component.js +0 -260
  289. package/esm2015/lib/shared/wizard/wizard-buttons/wizard-buttons.component.js +0 -54
  290. package/esm2015/lib/shared/wizard/wizard-progress/wizard-progress.component.js +0 -18
  291. package/fesm2015/energycap-components.js +0 -9638
  292. package/fesm2015/energycap-components.js.map +0 -1
@@ -0,0 +1,841 @@
1
+ import { Component, Input, Output, EventEmitter, ViewChild, HostListener } from '@angular/core';
2
+ import { UntypedFormControl, Validators } from "@angular/forms";
3
+ import { FormControlBase } from '../form-control-base';
4
+ import { takeUntil, take } from 'rxjs/operators';
5
+ import { PopupContainerDirective } from '../../shared/directives/popup/popup-container.directive';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "../../core/validation-message.service";
8
+ import * as i2 from "../../shared/form-group.helper";
9
+ import * as i3 from "@ngx-translate/core";
10
+ import * as i4 from "../../core/scroll.service";
11
+ import * as i5 from "@angular/common";
12
+ import * as i6 from "../button/button.component";
13
+ import * as i7 from "../textbox/textbox.component";
14
+ import * as i8 from "../../display/view-overlay/view-overlay.component";
15
+ import * as i9 from "../menu/menu.component";
16
+ import * as i10 from "../../shared/directives/popup/popup-container.directive";
17
+ /**
18
+ * Select box (select, autocomplete, combobox)
19
+ *
20
+ * NOTE: Min/max length validation is implemented on the internal ec-textbox.
21
+ * Values passed in via input properties (@see maxlength , @see minlength )
22
+ * are used to create validators on the textbox. When the validation on the
23
+ * textbox fails, the validation error(s) get passed up to the {@see formModel }.
24
+ * When setting up this component's {@see FormControl }, you do NOT need to set the
25
+ * Validators.minLength or Validators.maxLength validators.
26
+ *
27
+ * Required is also passed via input property, but you SHOULD also set up the
28
+ * Validators.required validator on this component's FormControl.
29
+ *
30
+ * @export
31
+ */
32
+ export class ComboboxComponent extends FormControlBase {
33
+ constructor(validationMessageService, formGroupHelper, translate, scrollService) {
34
+ super(validationMessageService, formGroupHelper);
35
+ this.validationMessageService = validationMessageService;
36
+ this.formGroupHelper = formGroupHelper;
37
+ this.translate = translate;
38
+ this.scrollService = scrollService;
39
+ /**
40
+ * Position of the menu relative to the text box
41
+ * @default 'bottom_right'
42
+ * @memberof ComboboxComponent
43
+ */
44
+ this.menuPosition = 'bottom_right';
45
+ /**
46
+ * Items to show in combobox menu
47
+ *
48
+ * @memberof ComboboxComponent
49
+ */
50
+ this.options = [];
51
+ /**
52
+ * Display template for menu items
53
+ *
54
+ * @memberof ComboboxComponent
55
+ */
56
+ this.templateType = 'label';
57
+ /**
58
+ * Position the menu as fixed, ideal when comboboxes are inside dialogs
59
+ * Defaulting to true so all menus will be at least the width of the
60
+ * textbox + button, but can grow wider if the inner elements need it
61
+ */
62
+ this.popupFixed = true;
63
+ /**
64
+ * If set to true, we will upperCase the text box and apply the class on the add box
65
+ */
66
+ this.upperCase = false;
67
+ /**The placeholder to show in the combobox. Leave empty to use default behavior determined
68
+ * by whether Add New is enabled
69
+ */
70
+ this.placeholder = '';
71
+ /** Do not display the toggle button when true */
72
+ this.hideToggleButton = false;
73
+ /**
74
+ * Always show the menu when the formModel has a value. Sets
75
+ * hideToggleButton to true and menuStatus to visible as well.
76
+ */
77
+ this.alwaysOpen = false;
78
+ /**
79
+ * Additonal classes to apply to the ec-menu element
80
+ */
81
+ this.menuElementClasses = [];
82
+ /**
83
+ * Additional classes to apply to the .textbox-group element
84
+ */
85
+ this.textboxElementClasses = [];
86
+ /** Hide 'No matches' message when true */
87
+ this.hideNoMatches = false;
88
+ /**
89
+ * Text to show when the menu is empty. "No matches" is the default.
90
+ */
91
+ this.noMatchesText = 'NoMatches_SC';
92
+ /**
93
+ * Notify the parent that the add new button was clicked
94
+ * @todo discuss if we need to send along the value or should
95
+ * the parent get it from the formModel
96
+ * (lwf 2017.07.13): I think we might as well send the value along and
97
+ * leave it up to the parent to decide how to handle it.
98
+ */
99
+ this.addNewClick = new EventEmitter();
100
+ /**
101
+ * Notify parent when text typed into textbox
102
+ */
103
+ this.search = new EventEmitter();
104
+ /**
105
+ * Filtered Items to show in combobox menu
106
+ */
107
+ this.filteredOptions = [];
108
+ /**
109
+ * Tracks if the menu is open or hidden
110
+ */
111
+ this.menuStatus = 'hidden';
112
+ /**
113
+ * Placeholder to assign to textbox
114
+ */
115
+ this.effectivePlaceholder = '';
116
+ /**
117
+ * Reference to the currently-selected menu item
118
+ */
119
+ this.selectedItem = null;
120
+ /**
121
+ * FormControl for the textbox
122
+ */
123
+ this.textboxFormModel = new UntypedFormControl('');
124
+ /**
125
+ * Tracks whether the add new button is selected
126
+ */
127
+ this.addNewSelected = false;
128
+ /**
129
+ * Tracks whether the textboxFormModel value matches an item in the filteredOptions
130
+ */
131
+ this.foundMatch = false;
132
+ /**
133
+ * Index of the currently-selected options
134
+ */
135
+ this.selectedItemIndex = -1;
136
+ /** Placeholder text for 'Choose or Add...' */
137
+ this.chooseOrAddPlaceholder = '';
138
+ /** Placeholder text for 'Choose' */
139
+ this.choosePlaceholder = '';
140
+ this.hasDataBeenLoadedOnOpen = false;
141
+ }
142
+ /**
143
+ * Close the popup menu on resize so the width and positioning can be recalculated
144
+ * correctly. Cannot be placed on the popupDirective because of a bug where
145
+ * HostListeners for global events don't fire
146
+ * @see https://github.com/angular/angular/issues/14191
147
+ */
148
+ onResize() {
149
+ if (this.popup)
150
+ this.popup.hide();
151
+ }
152
+ /**
153
+ * The angular onChanges lifecycle event
154
+ * @see https://angular.io/guide/lifecycle-hooks
155
+ */
156
+ ngOnChanges(changes) {
157
+ super.ngOnChanges(changes);
158
+ // when options changes
159
+ if (changes.options) {
160
+ this.resetOptions();
161
+ // Update the popup position
162
+ if (this.popup) {
163
+ this.popup.update();
164
+ }
165
+ }
166
+ // update validators on the textbox
167
+ if (changes.required || changes.minlength || changes.maxlength) {
168
+ this.setTextboxFormModelValidators();
169
+ }
170
+ // Update placeholder text when 'Add New' is conditional.
171
+ // ngOnChanges() kicks off before ngOnInit, so in order
172
+ // to not overwrite a user-provided placeholder, do not
173
+ // update placeholder on first change (ngOnInit will take care of it).
174
+ if ((changes.addNew && !changes.addNew.isFirstChange()) || changes.placeholder) {
175
+ this.updatePlaceholderText();
176
+ }
177
+ }
178
+ /**
179
+ * The angular onInit lifecycle hook
180
+ * @see https://angular.io/guide/lifecycle-hooks
181
+ */
182
+ ngOnInit() {
183
+ super.ngOnInit();
184
+ if (this.alwaysOpen) {
185
+ this.hideToggleButton = true;
186
+ this.menuStatus = 'visible';
187
+ }
188
+ // Get translated placeholder text
189
+ this.chooseOrAddPlaceholder = `${this.translate.instant('Choose or add')}...`;
190
+ this.choosePlaceholder = `${this.translate.instant('Choose')}`;
191
+ this.formModelChanged(this.formModel.value);
192
+ this.setTextboxFormModelValidators();
193
+ // Errors for this component are displayed via the validationErrors property, which is
194
+ // populated when translateValidationMessages is run.
195
+ // When the internal TextboxComponent has validation errors, we set them on the
196
+ // formModel as well. This updates the validity of our ComboboxComponent control,
197
+ // but does not trigger translation. Subscribe to statusChanges here so component
198
+ // validation errors will appear along with the ComboboxComponent's label.
199
+ this.formModel.valueChanges.pipe(takeUntil(this.componentDestroyed)).subscribe(data => this.formModelChanged(data));
200
+ this.textboxFormModel.statusChanges.pipe(takeUntil(this.componentDestroyed)).subscribe(data => this.setFormModelValidationErrors(data));
201
+ // default placeholder
202
+ this.updatePlaceholderText();
203
+ }
204
+ /**
205
+ * The angular afterViewInit lifecycle hook
206
+ * @see https://angular.io/guide/lifecycle-hooks
207
+ */
208
+ ngAfterViewInit() {
209
+ if (!this.popup) {
210
+ return;
211
+ }
212
+ // allow overflow out of the scrollParent
213
+ // prevents menu from obscuring the combobox
214
+ let popperOptions = {
215
+ modifiers: {
216
+ preventOverflow: {
217
+ boundariesElement: 'viewport'
218
+ }
219
+ }
220
+ };
221
+ // convert the ComboboxMenuPosition into a PopperPlacement
222
+ switch (this.menuPosition) {
223
+ case ("top_left"):
224
+ popperOptions.placement = 'top-start';
225
+ break;
226
+ case ("top_right"):
227
+ popperOptions.placement = 'top-end';
228
+ break;
229
+ case ("bottom_left"):
230
+ popperOptions.placement = 'bottom-start';
231
+ break;
232
+ case ("bottom_right"):
233
+ popperOptions.placement = 'bottom-end';
234
+ break;
235
+ default:
236
+ throw new Error(`Invalid menuPosition for ComboboxComponent.`);
237
+ }
238
+ // Scroll the menu to the selected item once the popup menu is ready
239
+ popperOptions.onCreate = () => {
240
+ this.scrollMenu();
241
+ if (this.popupFixed) {
242
+ this.popup.fixPosition();
243
+ }
244
+ };
245
+ if (this.popupFixed) {
246
+ popperOptions.onUpdate = () => {
247
+ this.popup.fixPosition();
248
+ };
249
+ }
250
+ this.popup.popperOptions = popperOptions;
251
+ this.popup.popperStatusChange.pipe(takeUntil(this.componentDestroyed)).subscribe((event) => {
252
+ this.menuStatus = event;
253
+ // Synchronize the formModel and textFormModel values when the
254
+ // popup menu closes and un-filter the options and reset the
255
+ // selectedItem and index
256
+ if (event === 'hidden') {
257
+ this.syncModelValues();
258
+ this.resetOptions();
259
+ }
260
+ });
261
+ }
262
+ /**
263
+ * Set errors on the textboxFormModel, which will then set errors on the
264
+ * formModel. Also mark the formModel as touched to display any errors.
265
+ * @param errors key(s) of ValidationMessageService errors to display or remove
266
+ * @memberof ComoboboxComponent
267
+ */
268
+ setErrors(errors) {
269
+ this.textboxFormModel.setErrors(errors);
270
+ this.formModel.markAsTouched();
271
+ }
272
+ /**
273
+ * Unfilter options and update the selectedItem and selectedItemIndex
274
+ * @memberof ComboboxComponent
275
+ */
276
+ resetOptions(options) {
277
+ this.filteredOptions = options || this.options;
278
+ //if they have no search term, don't try to select anything so they can clear the box out by hitting enter
279
+ //if they have a search term and the options changed, select an option from the menu so they will get it automatically if they hit enter
280
+ if (this.textboxFormModel.value !== '') {
281
+ this.selectedItemIndex = this.findDefaultSelectionIndex(this.filteredOptions, this.textboxFormModel.value);
282
+ this.selectedItem = this.filteredOptions[this.selectedItemIndex] || null;
283
+ this.scrollMenu(this.selectedItemIndex);
284
+ }
285
+ else {
286
+ //if they have no search term and the options are reset, don't auto-pick the first one
287
+ //so that enter will allow them to wipe out their last selection
288
+ this.clearSelectedItem();
289
+ }
290
+ }
291
+ /**
292
+ * Listen to the selected changed event from {@link MenuComponent} and update the form
293
+ * model and close menu
294
+ */
295
+ selectedChanged(item) {
296
+ this.setFormModelValue(item);
297
+ this.toggleMenu();
298
+ }
299
+ /**
300
+ * Show and hide the popup menu
301
+ *
302
+ * @memberof ComboboxComponent
303
+ */
304
+ toggleMenu(event) {
305
+ if (!this.popup) {
306
+ return;
307
+ }
308
+ if (event) {
309
+ event.stopPropagation();
310
+ }
311
+ if (!this.formModel.disabled) {
312
+ if (this.menuStatus === 'visible') {
313
+ // When the popup is hidden it will emit its changed status and
314
+ // we will reset values if need be.
315
+ this.popup.hide();
316
+ }
317
+ else {
318
+ if (this.loadOnOpenObservable && !this.hasDataBeenLoadedOnOpen) {
319
+ this.pending = true;
320
+ this.loadOnOpenObservable.pipe(take(1)).subscribe((result) => {
321
+ this.hasDataBeenLoadedOnOpen = true;
322
+ this.pending = false;
323
+ this.options = result;
324
+ this.resetOptions();
325
+ this.popup.show();
326
+ });
327
+ }
328
+ else {
329
+ this.popup.show();
330
+ }
331
+ }
332
+ }
333
+ }
334
+ onBlur() {
335
+ this.formModel.markAsTouched();
336
+ }
337
+ /**
338
+ * Control the menu with keyboard navigation
339
+ *
340
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key#Example | KeyboardEvent.key}
341
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values | Key Values}
342
+ *
343
+ * @memberof ComboboxComponent
344
+ */
345
+ keyNavigate(event) {
346
+ switch (event.key) {
347
+ case "ArrowDown":
348
+ case "Down":
349
+ case "ArrowUp":
350
+ case "Up":
351
+ event.stopPropagation();
352
+ event.preventDefault();
353
+ this.onArrowDownUp(event);
354
+ break;
355
+ case "Backspace":
356
+ case "Delete":
357
+ case "Del":
358
+ if (this.menuStatus === 'hidden') {
359
+ this.toggleMenu();
360
+ }
361
+ break;
362
+ case "Tab":
363
+ // If tabbing from the textbox to the button, override the textbox as being
364
+ // marked touched so we don't see the invalid state. Only show the invalid state
365
+ // when tabbing out of combobox from the button or back tabbing from the textbox
366
+ // if (event.key === 'Tab' && event.srcElement && event.srcElement.tagName === 'INPUT') {
367
+ // if (event.shiftKey) {
368
+ // this.textboxFormModel.markAsTouched();
369
+ // this.formModel.markAsTouched();
370
+ // } else {
371
+ // this.textboxFormModel.markAsUntouched();
372
+ // }
373
+ // } else if (event.key === 'Tab' && event.srcElement && event.srcElement.tagName === 'BUTTON') {
374
+ // if (!event.shiftKey) {
375
+ // this.formModel.markAsTouched();
376
+ // }
377
+ // }
378
+ if (this.menuStatus === 'visible') {
379
+ //if the selected option is the add new button let it fire but don't allow
380
+ //the tab event to carry them forward from wherever they land - they would skip the first box on the add new form
381
+ //In the normal case we want to allow the default behavior or they won't be able to tab out of the control at all.
382
+ if (this.addNewSelected) {
383
+ event.preventDefault();
384
+ }
385
+ this.commitSelection(event);
386
+ }
387
+ break;
388
+ case "Enter":
389
+ event.preventDefault();
390
+ if (this.menuStatus === 'visible') {
391
+ this.commitSelection(event);
392
+ }
393
+ break;
394
+ case "Escape":
395
+ case "Esc":
396
+ if (this.menuStatus === 'visible') {
397
+ // Just close the menu, do not focus the next element on tab
398
+ // unless the menu is hidden
399
+ event.preventDefault();
400
+ // Close the menu before we reset selectedItem so we don't see the highlight changing
401
+ // when reset the selected item back to the formModel
402
+ this.toggleMenu();
403
+ }
404
+ break;
405
+ case " ":
406
+ case "Spacebar":
407
+ if (this.menuStatus === 'hidden') {
408
+ event.preventDefault();
409
+ this.toggleMenu();
410
+ }
411
+ break;
412
+ default:
413
+ if (this.menuStatus === 'hidden' && event.key !== 'Shift') {
414
+ this.toggleMenu();
415
+ }
416
+ break;
417
+ }
418
+ }
419
+ /**
420
+ * Facilitates adding items to a combobox
421
+ *
422
+ * @param addFn Function from parent that should make an API request to add a new item to the combobox's options
423
+ * @memberof ComboboxComponent
424
+ */
425
+ async addNewItem(addFn) {
426
+ this.pending = true;
427
+ try {
428
+ await addFn();
429
+ }
430
+ catch (e) {
431
+ // We gave it our best try, something is really whack, so let's just set the error
432
+ this.setErrors({ 'addnew': true });
433
+ }
434
+ this.pending = false;
435
+ this.toggleMenu();
436
+ }
437
+ /**
438
+ * Figure out whether they are adding new or have an item selected, and commit it to the form model
439
+ */
440
+ commitSelection(event) {
441
+ if (this.addNewSelected) {
442
+ event.stopPropagation();
443
+ this.onAddNew(event);
444
+ }
445
+ else {
446
+ this.setFormModelValue(this.selectedItem);
447
+ this.toggleMenu();
448
+ }
449
+ }
450
+ /**
451
+ * Send the current value of the textbox to the parent when the add new button is
452
+ * clicked
453
+ *
454
+ * @param event Add new button click or enter key event
455
+ * @memberof ComboboxComponent
456
+ */
457
+ onAddNew(event) {
458
+ event.stopPropagation();
459
+ this.addNewSelected = false;
460
+ this.addNewClick.emit(this.textboxFormModel.value);
461
+ }
462
+ /**
463
+ * Navigate the dropdown menu using up and down arrow keys
464
+ *
465
+ * @param event Up or down arrow keydown event
466
+ * @memberof ComboboxComponent
467
+ */
468
+ onArrowDownUp(event) {
469
+ switch (event.key) {
470
+ case "ArrowDown":
471
+ case "Down":
472
+ if (this.selectedItemIndex === -1 && this.addNewButton && !this.addNewButton.nativeElement.hidden && !this.addNewSelected) {
473
+ this.addNewSelected = true;
474
+ }
475
+ else if (this.selectedItemIndex < this.filteredOptions.length - 1) {
476
+ if (this.addNewSelected) {
477
+ this.addNewSelected = false;
478
+ }
479
+ //if the last item is a heading and we are on the second last item, we shouldn't increment the selectedItemIndex because that would select the heading
480
+ if (!(this.selectedItemIndex == this.filteredOptions.length - 2 && this.filteredOptions[this.selectedItemIndex + 1].display === 'heading')) {
481
+ this.selectedItemIndex++;
482
+ // Skip any in-menu heading items
483
+ if (this.selectedItemIndex < this.filteredOptions.length - 1 && this.filteredOptions[this.selectedItemIndex].display === 'heading') {
484
+ this.selectedItemIndex++;
485
+ }
486
+ }
487
+ }
488
+ break;
489
+ case "ArrowUp":
490
+ case "Up":
491
+ if (this.selectedItemIndex === -1 && this.addNewButton && !this.addNewButton.nativeElement.hidden && this.addNewSelected) {
492
+ this.addNewSelected = false;
493
+ }
494
+ else if (this.selectedItemIndex > -1) {
495
+ if (this.selectedItemIndex === 0 && this.addNewButton && !this.addNewButton.nativeElement.hidden) {
496
+ this.addNewSelected = true;
497
+ }
498
+ this.selectedItemIndex--;
499
+ // Skip any in-menu heading items
500
+ if (this.selectedItemIndex > -1 && this.filteredOptions[this.selectedItemIndex].display === 'heading') {
501
+ this.selectedItemIndex--;
502
+ //if the selectedItemIndex is -1, that means the very first item was a heading and we just skipped over it.
503
+ if (this.selectedItemIndex == -1) {
504
+ //if there is an add new button we should select it. otherwise we should lock them at index 1 (right before the heading)
505
+ if (this.addNewButton && !this.addNewButton.nativeElement.hidden) {
506
+ this.addNewSelected = true;
507
+ }
508
+ else {
509
+ this.selectedItemIndex = 1;
510
+ }
511
+ }
512
+ }
513
+ }
514
+ break;
515
+ default:
516
+ return;
517
+ }
518
+ this.selectedItem = this.filteredOptions[this.selectedItemIndex];
519
+ if (this.menuStatus === 'hidden') {
520
+ this.setFormModelValue(this.selectedItem);
521
+ }
522
+ else {
523
+ this.scrollMenu();
524
+ }
525
+ }
526
+ /**
527
+
528
+ * Filter array of options by label (contains)
529
+ *
530
+ * @param filterText The value of textbox that we will filter our options by
531
+ *
532
+ * @memberof ComboboxComponent
533
+ */
534
+ filterOptionsArray(filterText) {
535
+ let searchText = filterText.toLowerCase();
536
+ if (filterText && filterText !== '') {
537
+ return this.options.filter(item => {
538
+ return item.label.toLowerCase().indexOf(searchText) >= 0;
539
+ });
540
+ }
541
+ else {
542
+ return this.options;
543
+ }
544
+ }
545
+ /**
546
+ * Find a given item's index in the filtered items array.
547
+ *
548
+ * Returns -1 if not found
549
+ * @param item The matching item to find in the
550
+ * filterdOptions array. Will use the selectedItem if nothing is passed.
551
+ * @memberof ComboboxComponent
552
+ */
553
+ findSelectedItemIndex(item) {
554
+ let itemToFind = item ? item : this.selectedItem;
555
+ if (itemToFind) {
556
+ return this.filteredOptions.findIndex(item => {
557
+ if (item.id && itemToFind.id) {
558
+ return item.label === itemToFind.label && item.id === itemToFind.id;
559
+ }
560
+ else {
561
+ return item.label === itemToFind.label;
562
+ }
563
+ });
564
+ }
565
+ return -1;
566
+ }
567
+ /**
568
+ * React to our formModel changing
569
+ *
570
+ * The formModel represents the currently selected ModelItem
571
+ * When changed, set the value of the TextboxComponent and
572
+ * find index of item in options list.
573
+ *
574
+ * @memberof ComboboxComponent
575
+ */
576
+ formModelChanged(data) {
577
+ this.synchronizeDisabledAttributes();
578
+ if (data) {
579
+ this.textboxFormModel.setValue(data.label);
580
+ this.selectedItemIndex = this.findSelectedItemIndex(data);
581
+ if (this.selectedItemIndex >= 0) {
582
+ this.selectedItem = this.filteredOptions[this.selectedItemIndex];
583
+ }
584
+ }
585
+ else {
586
+ //The host wiped out the data externally, clear the textbox and the tracking state
587
+ this.textboxFormModel.reset();
588
+ this.clearSelectedItem();
589
+ }
590
+ }
591
+ /**
592
+ * Scroll the menu if the current selectedItemIndex is out of view
593
+ *
594
+ * @memberof ComboboxComponent
595
+ */
596
+ scrollMenu(knownIndex) {
597
+ if (this.filteredOptions.length > 0) {
598
+ // Update the selectedItemIndex in case our options changed
599
+ this.selectedItemIndex = knownIndex === undefined ? this.findSelectedItemIndex() : knownIndex;
600
+ if (this.selectedItemIndex > -1 && this.selectedItem) {
601
+ // The menu component will automatically generate ids for the menu items if they dont have them,
602
+ // so they need to be accounted for here since the combobox doesn't know about those ids
603
+ let itemSelector = this.selectedItem.id ? `#${this.selectedItem.id}` : `#${this.id}_menu_item${this.selectedItemIndex}`;
604
+ //trigger the scrolling after a tick to allow the menu to be up to date (and pending mask cleared) before measuring
605
+ setTimeout(() => {
606
+ this.scrollService.scrollItemCentered(`#${this.id}_menu_list`, itemSelector);
607
+ }, 0);
608
+ }
609
+ else {
610
+ this.selectedItem = null;
611
+ }
612
+ }
613
+ }
614
+ /**
615
+ * Search/Filter based on textbox input
616
+ * NOTE: so as not to receive a notification on every key event, we suggest you debounce your
617
+ * subscription
618
+ * @see {@link http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-debounceTime | Observable.debounceTime}
619
+ *
620
+ * @memberof ComboboxComponent
621
+ */
622
+ searchAndFilter(searchText) {
623
+ // always emit
624
+ this.search.emit(searchText);
625
+ // do internal filtering if no one's subscribed to our search emitter
626
+ if (this.search.observers.length === 0 && searchText !== undefined) {
627
+ this.resetOptions(this.filterOptionsArray(searchText));
628
+ if (this.addNewSelected && !this.addNewButton) {
629
+ this.addNewSelected = false;
630
+ }
631
+ }
632
+ }
633
+ /**
634
+ * Set {@link formModel }'s validation errors equal to the internal textbox's.
635
+ *
636
+ * When the internal textbox is invalid, need to set this control's
637
+ * errors because we are using our own label, not TextboxControl's.
638
+ * We use our own label so label text will wrap at the end of the button,
639
+ * not at the end of the textbox.
640
+ *
641
+ * @memberof ComboboxComponent
642
+ */
643
+ setFormModelValidationErrors(data) {
644
+ if (this.textboxFormModel.invalid) {
645
+ this.formModel.setErrors(this.textboxFormModel.errors);
646
+ }
647
+ else {
648
+ this.formModel.setErrors(null);
649
+ }
650
+ }
651
+ /**
652
+ * Update the form model value with the selected item or reset form model value if item is null
653
+ *
654
+ * @memberof ComboboxComponent
655
+ */
656
+ setFormModelValue(item) {
657
+ this.textboxFormModel.setValue(item ? item.label : '');
658
+ this.formModel.setValue(item);
659
+ this.formModel.markAsDirty();
660
+ }
661
+ /**
662
+ * Set validators on the {@see textboxFormModel }
663
+ *
664
+ * Validators are currently set based on the {@see maxlength },
665
+ * {@see minlength }, and {@see required } inputs. This works well
666
+ * with {@see TextboxComponent }, which needs these inputs to apply
667
+ * the proper attributes to its inputs.
668
+ *
669
+ * A future release of Angular will supposedly add these attributes
670
+ * for you, which will eliminate the need for TextboxComponent to have
671
+ * such inputs. This component, however, will still need these inputs
672
+ * as there is no current way to know which validators are applied to it
673
+ * from its parent View Component.
674
+ *
675
+ *
676
+ * @memberof ComboboxComponent
677
+ */
678
+ setTextboxFormModelValidators() {
679
+ let validators = [];
680
+ if (this.required) {
681
+ validators.push(Validators.required);
682
+ }
683
+ if (this.minlength) {
684
+ validators.push(Validators.minLength(this.minlength));
685
+ }
686
+ if (this.maxlength) {
687
+ validators.push(Validators.maxLength(this.maxlength));
688
+ }
689
+ this.textboxFormModel.setValidators(validators);
690
+ this.textboxFormModel.updateValueAndValidity();
691
+ }
692
+ /**
693
+ * Keep textbox's disabled status in-sync with combobox's
694
+ *
695
+ * {@link TextboxComponent} gets its disabled status from its {@link FormControl}
696
+ *
697
+ * @memberof ComboboxComponent
698
+ */
699
+ synchronizeDisabledAttributes() {
700
+ if (this.formModel.disabled !== this.textboxFormModel.disabled) {
701
+ if (this.formModel.disabled) {
702
+ this.textboxFormModel.disable();
703
+ }
704
+ else {
705
+ this.textboxFormModel.enable();
706
+ }
707
+ }
708
+ }
709
+ /**
710
+ * If the formModel value and textbox value do not match, reset the textbox and selectedItem to
711
+ * the formModle value. If there is no formModel value, make sure we clear the textbox. Reset the
712
+ * filteredOptions to the full list and update the selectedItemIndex
713
+ *
714
+ */
715
+ syncModelValues() {
716
+ // If there is a formModel value, reset the selected item. If there isn't, make
717
+ // sure we clear the textbox
718
+ if (this.formModel.value && this.formModel.value.label !== this.textboxFormModel.value) {
719
+ this.textboxFormModel.setValue(this.formModel.value.label);
720
+ }
721
+ else if (!this.formModel.value) {
722
+ this.textboxFormModel.setValue('');
723
+ }
724
+ }
725
+ /**
726
+ * Search and filter the options list when the value of the textbox input changes. If addNew is
727
+ * set also check for matches in our filteredOptions to conditionally show and hide the add new
728
+ * button
729
+ *
730
+ * @see https://developer.mozilla.org/en-US/docs/Web/Events/input
731
+ */
732
+ textboxValueChanged(event) {
733
+ this.searchAndFilter(this.textboxFormModel.value);
734
+ if (this.textboxFormModel.value === '') {
735
+ this.clearSelectedItem();
736
+ }
737
+ if (this.addNew) {
738
+ let match = this.filteredOptions.find((option) => {
739
+ return option.label.toLowerCase() === this.textboxFormModel.value.toLowerCase();
740
+ });
741
+ this.foundMatch = match ? true : false;
742
+ }
743
+ // Update the popup menu position when input value changes
744
+ if (this.popup) {
745
+ this.popup.update();
746
+ }
747
+ }
748
+ clearSelectedItem() {
749
+ this.selectedItem = null;
750
+ this.selectedItemIndex = -1;
751
+ }
752
+ /**Recompute what the placeholder should be based on whether the user provided one and the current state of the addNew input */
753
+ updatePlaceholderText() {
754
+ if (this.placeholder) {
755
+ this.effectivePlaceholder = this.translate.instant(this.placeholder);
756
+ }
757
+ else if (this.addNew) {
758
+ this.effectivePlaceholder = this.chooseOrAddPlaceholder;
759
+ }
760
+ else {
761
+ this.effectivePlaceholder = this.choosePlaceholder;
762
+ }
763
+ }
764
+ /**Find the option we want to be the default selection. If there is an exact match, use that
765
+ * otherwise if there are items, return zero to indicate the first item. Otherwise return -1
766
+ * to indicate no selection
767
+ */
768
+ findDefaultSelectionIndex(options, searchText) {
769
+ let index = -1;
770
+ if (options && options.length) {
771
+ index = options.findIndex(option => option != null && option.display !== 'heading');
772
+ if (searchText) {
773
+ searchText = searchText.toLowerCase().trim();
774
+ let exactMatchIndex = options.findIndex(option => option.label.toLowerCase() == searchText && option.display !== 'heading');
775
+ if (exactMatchIndex >= 0) {
776
+ index = exactMatchIndex;
777
+ }
778
+ }
779
+ }
780
+ return index;
781
+ }
782
+ }
783
+ ComboboxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: ComboboxComponent, deps: [{ token: i1.ValidationMessageService }, { token: i2.FormGroupHelper }, { token: i3.TranslateService }, { token: i4.ScrollService }], target: i0.ɵɵFactoryTarget.Component });
784
+ ComboboxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.0", type: ComboboxComponent, selector: "ec-combobox", inputs: { addNew: "addNew", maxlength: "maxlength", menuPosition: "menuPosition", minlength: "minlength", options: "options", templateType: "templateType", customMenuTemplate: "customMenuTemplate", popupFixed: "popupFixed", totalRecords: "totalRecords", upperCase: "upperCase", placeholder: "placeholder", loadOnOpenObservable: "loadOnOpenObservable", hideToggleButton: "hideToggleButton", alwaysOpen: "alwaysOpen", menuElementClasses: "menuElementClasses", textboxElementClasses: "textboxElementClasses", hideNoMatches: "hideNoMatches", noMatchesText: "noMatchesText" }, outputs: { addNewClick: "addNewClick", search: "search" }, host: { listeners: { "window:resize": "onResize()" } }, viewQueries: [{ propertyName: "textbox", first: true, predicate: ["textbox"], descendants: true }, { propertyName: "popup", first: true, predicate: PopupContainerDirective, descendants: true }, { propertyName: "addNewButton", first: true, predicate: ["addNewButton"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"control control-label-{{labelPosition}}\"\r\n [ngClass]=\"{'open': menuStatus === 'visible',\r\n 'invalid': formModel.touched && formModel.invalid,\r\n 'has-icon': (templateType === 'iconAndLabel' && formModel.value && formModel.value.icon && formModel.value.label === textboxFormModel.value),\r\n 'is-readonly': readonly,\r\n 'is-disabled': formModel.disabled,\r\n 'is-always-open': alwaysOpen}\">\r\n\r\n <label *ngIf=\"label\" ngPreserveWhitespaces>\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">{{validationErrors}}</span>\r\n </label>\r\n\r\n <ng-container *ngIf=\"alwaysOpen; else popupTarget\">\r\n <div class=\"textbox-group control-input\" [ngClass]=\"textboxElementClasses\">\r\n <ng-container *ngTemplateOutlet=\"textbox\"></ng-container>\r\n </div>\r\n\r\n <ng-container *ngIf=\"filteredOptions.length > 0 || textboxFormModel.value\">\r\n <ng-container *ngTemplateOutlet=\"dropdownmenu\"></ng-container>\r\n </ng-container>\r\n </ng-container>\r\n</div>\r\n\r\n<ng-template #popupTarget>\r\n <div class=\"textbox-group control-input\" [ngClass]=\"textboxElementClasses\" *ecPopup=\"dropdownmenu\">\r\n <ng-container *ngTemplateOutlet=\"textbox\"></ng-container>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #textbox>\r\n <i class=\"ec-icon {{formModel.value?.icon}}\"></i>\r\n\r\n <ec-textbox class=\"textbox-group-input mb-0\"\r\n #textbox\r\n [id]=\"id\"\r\n [autofocus]=\"autofocus\"\r\n [formModel]=\"textboxFormModel\"\r\n [maxlength]=\"maxlength\"\r\n [minlength]=\"minlength\"\r\n [placeholder]=\"effectivePlaceholder\"\r\n [required]=\"required\"\r\n [tabindex]=\"tabindex\"\r\n [readonly]=\"readonly\"\r\n (input)=\"textboxValueChanged($event)\"\r\n (keydown)=\"keyNavigate($event)\"\r\n (focusout)=\"onBlur()\"\r\n [upperCase]=\"upperCase\"\r\n [pending]=\"pending && alwaysOpen\"\r\n [autocomplete]=\"'off'\"></ec-textbox>\r\n\r\n <ec-button class=\"textbox-group-btn-right\"\r\n *ngIf=\"!hideToggleButton\"\r\n [id]=\"id + '_button'\"\r\n [disabled]=\"formModel.disabled\"\r\n icon=\"icon-caret-down\"\r\n [tabindex]=\"-1\"\r\n type=\"secondary\"\r\n (click)=\"toggleMenu($event)\"\r\n (keydown)=\"keyNavigate($event)\"></ec-button>\r\n</ng-template>\r\n\r\n<ng-template #dropdownmenu>\r\n <div class=\"popup\"\r\n ecOverlay\r\n [status]=\"pending && !alwaysOpen ? 'pending' : 'hasData'\">\r\n\r\n <button class=\"add-new\"\r\n id=\"{{id}}_addNew\"\r\n #addNewButton\r\n [class.is-selected]=\"addNewSelected\"\r\n *ngIf=\"addNew\"\r\n [hidden]=\"foundMatch || (addNew === 'dynamic' && (!textboxFormModel.value || (formModel.value && textboxFormModel.value === formModel.value.label)))\"\r\n\r\n (click)=\"onAddNew($event)\">\r\n <span class=\"add-new-label ec-util-truncate\">\r\n <span *ngIf=\"addNew === 'static' || addNew === true\" translate>Add new...</span>\r\n <span *ngIf=\"addNew === 'dynamic'\">{{'Add' | translate}} <strong class=\"ec-util-truncate\" [ngClass]=\"{'text-uppercase': upperCase}\">{{textboxFormModel.value}}</strong></span>\r\n </span>\r\n <i class=\"ec-icon icon-add\"></i>\r\n </button>\r\n\r\n <ec-menu id=\"{{id}}_menu\"\r\n [class.border-top-0]=\"!filteredOptions.length && hideNoMatches\"\r\n [ngClass]=\"menuElementClasses\"\r\n [templateType]=\"templateType\"\r\n [customMenuTemplate]=\"customMenuTemplate\"\r\n [showNoItems]=\"!hideNoMatches\"\r\n [noDataText]=\"noMatchesText\"\r\n [items]=\"filteredOptions\"\r\n [selected]=\"selectedItem\"\r\n (selectedChanged)=\"selectedChanged($event)\"></ec-menu>\r\n\r\n <footer *ngIf=\"totalRecords && totalRecords > filteredOptions.length && filteredOptions.length > 0\">\r\n <span>{{filteredOptions.length}} {{'of' | translate}} {{totalRecords}}</span>\r\n </footer>\r\n </div>\r\n</ng-template>\r\n", styles: [":root{--ec-font-size-icon: 1rem;--ec-color-icon: rgba(26, 26, 35, .66)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}:root{--ec-font-size-icon: 1rem;--ec-color-icon: rgba(26, 26, 35, .66)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}:host{color:var(--ec-color-primary-dark);font-family:var(--ec-font-family);font-size:var(--ec-font-size-body);display:block;margin-bottom:1rem;width:100%}:host :host-context(.form-condensed){margin-bottom:.5rem}:host .control{width:100%;display:flex;flex-direction:column}:host .control.control-label-bottom{flex-direction:column-reverse}:host .control.control-label-left{flex-direction:row}:host .control.control-label-left label{margin-right:.25rem}:host .control.control-label-right{flex-direction:row-reverse}:host .control.control-label-right label{margin-left:.25rem}:host .control.control-label-left,:host .control.control-label-right{align-items:center}:host .control.control-label-left label,:host .control.control-label-right label{flex:1 1;margin-top:0;margin-bottom:0}:host .control.control-label-left .control-input,:host .control.control-label-right .control-input{flex:2 2}:host .control.is-readonly input,:host .control.is-readonly select{border-color:transparent;background-color:#1a1a231f;background-clip:border-box;background-image:none;color:var(--ec-color-primary-dark);opacity:1;-webkit-user-select:none;user-select:none;pointer-events:none;overflow:hidden;white-space:nowrap}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid{background-color:var(--ec-background-color-caution);background-image:url('data:image/svg+xml;charset=utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path fill=\"rgba(26, 26, 35, 0.66)\" d=\"M20.21 20.21h-8.42L10.95 0h10.1l-.84 20.21zm-8.42 3.37h8.42V32h-8.42z\"/></svg>');background-repeat:no-repeat;background-position:.25rem center;background-size:1rem,1rem;padding-left:1.5rem}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid:not(:focus),:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid:not(:focus){border-color:var(--ec-color-caution)}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button{background-color:var(--ec-background-color-caution)}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button:not(:focus){border-color:var(--ec-color-caution)}:host .textbox-group{display:flex;position:relative}:host textarea:focus,:host input:focus,:host select:focus{outline:none}:host(.invalid) .control .textbox-group-input ::ng-deep .control input.ng-invalid,:host(.invalid) .control .textbox-group-input ::ng-deep .control input.ng-valid{background-color:var(--ec-background-color-caution);background-image:url('data:image/svg+xml;charset=utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path fill=\"rgba(26, 26, 35, 0.66)\" d=\"M20.21 20.21h-8.42L10.95 0h10.1l-.84 20.21zm-8.42 3.37h8.42V32h-8.42z\"/></svg>');background-repeat:no-repeat;background-position:.25rem center;background-size:1rem,1rem;padding-left:1.5rem}:host(.invalid) .control .textbox-group-input ::ng-deep .control input.ng-invalid:not(:focus),:host(.invalid) .control .textbox-group-input ::ng-deep .control input.ng-valid:not(:focus){border-color:var(--ec-color-caution)}:host(.invalid) .control:not(.open) .textbox-group-btn-right ::ng-deep button{background-color:var(--ec-background-color-caution)}:host(.invalid) .control:not(.open) .textbox-group-btn-right ::ng-deep button:not(:focus){border-color:var(--ec-color-caution)}.control{position:relative}.control ec-textbox ::ng-deep input.ng-invalid.ng-touched{background-image:none;padding-left:.5rem}.control ec-textbox ::ng-deep input.ng-invalid.ng-touched:not(.is-empty)~.units-left{left:0}.control ec-textbox ::ng-deep input:required:not(:disabled).is-empty{border-color:var(--ec-border-color-legacy);background-color:var(--ec-background-color);background-image:url('data:image/svg+xml;charset=utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path fill=\"%23ffe433\" d=\"M31.32 21.69l-.09.18-2.48 4.35c-.36.54-.77.62-1.25.27-.12 0-.2 0-.2-.09L19.53 22v9.37a1.26 1.26 0 0 1-.72.67h-5.26c-.59 0-.83-.3-.83-.89 0-.12.15-.21.15-.27V22l-8 4.71h-.12c-.42.66-.8.21-1.16-.27L1 21.82a.82.82 0 0 1 .35-1.26l.18-.1L9 16 .87 11.47v-.09c0-.36-.39-.74-.09-1.16l2.75-4.35v-.09c0-.42.82-.54 1.29-.36l8 4.62V.89c0-.59.18-.89.77-.89h5c.65 0 .91.3.91.89V10l7.94-4.53c.48-.29.72-.21 1.08.27l2.32 4.35v.09c.66.48.45.89-.08 1.25L23 16l7.91 4.53v.09c-.04.18.53.54.41 1.07z\"/></svg>');background-repeat:no-repeat;background-position:.25rem center;background-size:1rem,1rem;padding-left:1.5rem}.control ec-textbox ::ng-deep input:required:not(:disabled).is-empty:focus{border-color:var(--ec-color-interactive);box-shadow:0 0 0 .0625rem var(--ec-color-interactive);position:relative;z-index:1}.control .textbox-group .ec-icon{display:none;position:absolute;top:.5rem;left:.5rem;z-index:2}.control.has-icon:not(.invalid) .ec-icon{display:inline-flex}.control.has-icon:not(.invalid) ec-textbox ::ng-deep input{padding-left:1.75rem}.control.is-disabled .ec-icon{filter:grayscale(100%);opacity:.65}.control.is-readonly ec-textbox ::ng-deep input{border-right-width:.0625rem;border-top-right-radius:var(--ec-border-radius);border-bottom-right-radius:var(--ec-border-radius)}.control.is-readonly ec-button{display:none}.control.is-always-open{height:100%}.control.is-always-open label,.control.is-always-open .textbox-group{margin-left:1rem;margin-right:1rem}.control.is-always-open .textbox-group{margin-bottom:1rem}.control.is-always-open .popup{background-color:transparent;box-shadow:none;flex:1 1;border:0;margin:0;z-index:0;min-height:0}.control.is-always-open ec-menu{border-top:1px solid var(--ec-border-color)}.control.is-always-open ec-menu ::ng-deep ul{max-height:none}label{color:var(--ec-color-secondary-dark);display:block;font-size:var(--ec-font-size-label);line-height:1;margin:calc(var(--ec-font-size-label) / 2) 0}.popup{background-color:var(--ec-background-color);border-radius:var(--ec-border-radius-card);box-shadow:var(--ec-box-shadow-overlay);margin-top:.25rem;overflow:hidden;z-index:var(--ec-z-index-popup)}ec-menu{display:block}ec-menu:not(:first-child){border-top:1px solid var(--ec-border-color)}ec-menu ::ng-deep ul{max-height:30vh}ec-menu ::ng-deep ul li{white-space:nowrap}.add-new{height:2rem;line-height:1.25;padding:.25rem .5rem;align-items:center;background-color:var(--ec-background-color);display:flex;cursor:pointer;border:0;width:100%}.add-new.is-selected,.add-new.is-highlighted{background-color:#d9edf2}.add-new:focus{background-color:var(--ec-color-disabled-dark);position:relative;z-index:1;outline:none}.add-new:active{background-color:var(--ec-color-interactive);color:var(--ec-color-primary-light)}.add-new:disabled,.add-new.is-disabled{color:var(--ec-color-secondary-dark);opacity:.65;cursor:default}.add-new .label{align-items:center;display:flex;flex:auto}.add-new .ec-icon+.label{margin:0 .375rem}.add-new:hover:not(:active),.add-new.is-selected{background-color:#bfe0e9}.add-new:active .ec-icon{color:inherit}.add-new-label{flex:1 1;margin-right:.5rem;text-align:left}.add-new .ec-icon{flex:0 0 auto}footer{padding:.5rem;border-top:1px solid var(--ec-border-color);color:var(--ec-color-hint-dark);font-size:var(--ec-font-size-label);text-align:right;line-height:1}ec-button ::ng-deep button .ec-icon{background-size:1em;background-position:center}.open:not(.is-always-open) .textbox-group ec-textbox ::ng-deep input{border-color:var(--ec-border-color-legacy);box-shadow:none}.open:not(.is-always-open) .textbox-group ec-button ::ng-deep button{background-color:var(--ec-background-color-hover);box-shadow:none}\n"], dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: i6.ButtonComponent, selector: "ec-button", inputs: ["id", "disabled", "icon", "label", "badge", "tabindex", "type", "pending", "pendingIcon", "customTemplate", "isSubmit", "autofocus"], outputs: ["clicked"] }, { kind: "component", type: i7.TextboxComponent, selector: "ec-textbox", inputs: ["autocomplete", "type", "placeholder", "maxlength", "minlength", "rows", "selectOnAutofocus", "upperCase"] }, { kind: "component", type: i8.ViewOverlayComponent, selector: "[ecOverlay]", inputs: ["status", "message", "action", "noDataTemplate", "displayAsMask", "overlayClassList"] }, { kind: "component", type: i9.MenuComponent, selector: "ec-menu", inputs: ["id", "items", "selected", "parent", "templateType", "customMenuTemplate", "title", "showNoItems", "noDataText", "enableKeyNav", "highlightedItem", "maintainSelectedItem", "truncateItems", "preserveIconSpace"], outputs: ["selectedChanged", "menuClosed"] }, { kind: "directive", type: i10.PopupContainerDirective, selector: "[ecPopup]", inputs: ["ecPopup", "options"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
785
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: ComboboxComponent, decorators: [{
786
+ type: Component,
787
+ args: [{ selector: 'ec-combobox', template: "<div class=\"control control-label-{{labelPosition}}\"\r\n [ngClass]=\"{'open': menuStatus === 'visible',\r\n 'invalid': formModel.touched && formModel.invalid,\r\n 'has-icon': (templateType === 'iconAndLabel' && formModel.value && formModel.value.icon && formModel.value.label === textboxFormModel.value),\r\n 'is-readonly': readonly,\r\n 'is-disabled': formModel.disabled,\r\n 'is-always-open': alwaysOpen}\">\r\n\r\n <label *ngIf=\"label\" ngPreserveWhitespaces>\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">{{validationErrors}}</span>\r\n </label>\r\n\r\n <ng-container *ngIf=\"alwaysOpen; else popupTarget\">\r\n <div class=\"textbox-group control-input\" [ngClass]=\"textboxElementClasses\">\r\n <ng-container *ngTemplateOutlet=\"textbox\"></ng-container>\r\n </div>\r\n\r\n <ng-container *ngIf=\"filteredOptions.length > 0 || textboxFormModel.value\">\r\n <ng-container *ngTemplateOutlet=\"dropdownmenu\"></ng-container>\r\n </ng-container>\r\n </ng-container>\r\n</div>\r\n\r\n<ng-template #popupTarget>\r\n <div class=\"textbox-group control-input\" [ngClass]=\"textboxElementClasses\" *ecPopup=\"dropdownmenu\">\r\n <ng-container *ngTemplateOutlet=\"textbox\"></ng-container>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #textbox>\r\n <i class=\"ec-icon {{formModel.value?.icon}}\"></i>\r\n\r\n <ec-textbox class=\"textbox-group-input mb-0\"\r\n #textbox\r\n [id]=\"id\"\r\n [autofocus]=\"autofocus\"\r\n [formModel]=\"textboxFormModel\"\r\n [maxlength]=\"maxlength\"\r\n [minlength]=\"minlength\"\r\n [placeholder]=\"effectivePlaceholder\"\r\n [required]=\"required\"\r\n [tabindex]=\"tabindex\"\r\n [readonly]=\"readonly\"\r\n (input)=\"textboxValueChanged($event)\"\r\n (keydown)=\"keyNavigate($event)\"\r\n (focusout)=\"onBlur()\"\r\n [upperCase]=\"upperCase\"\r\n [pending]=\"pending && alwaysOpen\"\r\n [autocomplete]=\"'off'\"></ec-textbox>\r\n\r\n <ec-button class=\"textbox-group-btn-right\"\r\n *ngIf=\"!hideToggleButton\"\r\n [id]=\"id + '_button'\"\r\n [disabled]=\"formModel.disabled\"\r\n icon=\"icon-caret-down\"\r\n [tabindex]=\"-1\"\r\n type=\"secondary\"\r\n (click)=\"toggleMenu($event)\"\r\n (keydown)=\"keyNavigate($event)\"></ec-button>\r\n</ng-template>\r\n\r\n<ng-template #dropdownmenu>\r\n <div class=\"popup\"\r\n ecOverlay\r\n [status]=\"pending && !alwaysOpen ? 'pending' : 'hasData'\">\r\n\r\n <button class=\"add-new\"\r\n id=\"{{id}}_addNew\"\r\n #addNewButton\r\n [class.is-selected]=\"addNewSelected\"\r\n *ngIf=\"addNew\"\r\n [hidden]=\"foundMatch || (addNew === 'dynamic' && (!textboxFormModel.value || (formModel.value && textboxFormModel.value === formModel.value.label)))\"\r\n\r\n (click)=\"onAddNew($event)\">\r\n <span class=\"add-new-label ec-util-truncate\">\r\n <span *ngIf=\"addNew === 'static' || addNew === true\" translate>Add new...</span>\r\n <span *ngIf=\"addNew === 'dynamic'\">{{'Add' | translate}} <strong class=\"ec-util-truncate\" [ngClass]=\"{'text-uppercase': upperCase}\">{{textboxFormModel.value}}</strong></span>\r\n </span>\r\n <i class=\"ec-icon icon-add\"></i>\r\n </button>\r\n\r\n <ec-menu id=\"{{id}}_menu\"\r\n [class.border-top-0]=\"!filteredOptions.length && hideNoMatches\"\r\n [ngClass]=\"menuElementClasses\"\r\n [templateType]=\"templateType\"\r\n [customMenuTemplate]=\"customMenuTemplate\"\r\n [showNoItems]=\"!hideNoMatches\"\r\n [noDataText]=\"noMatchesText\"\r\n [items]=\"filteredOptions\"\r\n [selected]=\"selectedItem\"\r\n (selectedChanged)=\"selectedChanged($event)\"></ec-menu>\r\n\r\n <footer *ngIf=\"totalRecords && totalRecords > filteredOptions.length && filteredOptions.length > 0\">\r\n <span>{{filteredOptions.length}} {{'of' | translate}} {{totalRecords}}</span>\r\n </footer>\r\n </div>\r\n</ng-template>\r\n", styles: [":root{--ec-font-size-icon: 1rem;--ec-color-icon: rgba(26, 26, 35, .66)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}:root{--ec-font-size-icon: 1rem;--ec-color-icon: rgba(26, 26, 35, .66)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}:host{color:var(--ec-color-primary-dark);font-family:var(--ec-font-family);font-size:var(--ec-font-size-body);display:block;margin-bottom:1rem;width:100%}:host :host-context(.form-condensed){margin-bottom:.5rem}:host .control{width:100%;display:flex;flex-direction:column}:host .control.control-label-bottom{flex-direction:column-reverse}:host .control.control-label-left{flex-direction:row}:host .control.control-label-left label{margin-right:.25rem}:host .control.control-label-right{flex-direction:row-reverse}:host .control.control-label-right label{margin-left:.25rem}:host .control.control-label-left,:host .control.control-label-right{align-items:center}:host .control.control-label-left label,:host .control.control-label-right label{flex:1 1;margin-top:0;margin-bottom:0}:host .control.control-label-left .control-input,:host .control.control-label-right .control-input{flex:2 2}:host .control.is-readonly input,:host .control.is-readonly select{border-color:transparent;background-color:#1a1a231f;background-clip:border-box;background-image:none;color:var(--ec-color-primary-dark);opacity:1;-webkit-user-select:none;user-select:none;pointer-events:none;overflow:hidden;white-space:nowrap}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid{background-color:var(--ec-background-color-caution);background-image:url('data:image/svg+xml;charset=utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path fill=\"rgba(26, 26, 35, 0.66)\" d=\"M20.21 20.21h-8.42L10.95 0h10.1l-.84 20.21zm-8.42 3.37h8.42V32h-8.42z\"/></svg>');background-repeat:no-repeat;background-position:.25rem center;background-size:1rem,1rem;padding-left:1.5rem}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid:not(:focus),:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid:not(:focus){border-color:var(--ec-color-caution)}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button{background-color:var(--ec-background-color-caution)}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button:not(:focus){border-color:var(--ec-color-caution)}:host .textbox-group{display:flex;position:relative}:host textarea:focus,:host input:focus,:host select:focus{outline:none}:host(.invalid) .control .textbox-group-input ::ng-deep .control input.ng-invalid,:host(.invalid) .control .textbox-group-input ::ng-deep .control input.ng-valid{background-color:var(--ec-background-color-caution);background-image:url('data:image/svg+xml;charset=utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path fill=\"rgba(26, 26, 35, 0.66)\" d=\"M20.21 20.21h-8.42L10.95 0h10.1l-.84 20.21zm-8.42 3.37h8.42V32h-8.42z\"/></svg>');background-repeat:no-repeat;background-position:.25rem center;background-size:1rem,1rem;padding-left:1.5rem}:host(.invalid) .control .textbox-group-input ::ng-deep .control input.ng-invalid:not(:focus),:host(.invalid) .control .textbox-group-input ::ng-deep .control input.ng-valid:not(:focus){border-color:var(--ec-color-caution)}:host(.invalid) .control:not(.open) .textbox-group-btn-right ::ng-deep button{background-color:var(--ec-background-color-caution)}:host(.invalid) .control:not(.open) .textbox-group-btn-right ::ng-deep button:not(:focus){border-color:var(--ec-color-caution)}.control{position:relative}.control ec-textbox ::ng-deep input.ng-invalid.ng-touched{background-image:none;padding-left:.5rem}.control ec-textbox ::ng-deep input.ng-invalid.ng-touched:not(.is-empty)~.units-left{left:0}.control ec-textbox ::ng-deep input:required:not(:disabled).is-empty{border-color:var(--ec-border-color-legacy);background-color:var(--ec-background-color);background-image:url('data:image/svg+xml;charset=utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path fill=\"%23ffe433\" d=\"M31.32 21.69l-.09.18-2.48 4.35c-.36.54-.77.62-1.25.27-.12 0-.2 0-.2-.09L19.53 22v9.37a1.26 1.26 0 0 1-.72.67h-5.26c-.59 0-.83-.3-.83-.89 0-.12.15-.21.15-.27V22l-8 4.71h-.12c-.42.66-.8.21-1.16-.27L1 21.82a.82.82 0 0 1 .35-1.26l.18-.1L9 16 .87 11.47v-.09c0-.36-.39-.74-.09-1.16l2.75-4.35v-.09c0-.42.82-.54 1.29-.36l8 4.62V.89c0-.59.18-.89.77-.89h5c.65 0 .91.3.91.89V10l7.94-4.53c.48-.29.72-.21 1.08.27l2.32 4.35v.09c.66.48.45.89-.08 1.25L23 16l7.91 4.53v.09c-.04.18.53.54.41 1.07z\"/></svg>');background-repeat:no-repeat;background-position:.25rem center;background-size:1rem,1rem;padding-left:1.5rem}.control ec-textbox ::ng-deep input:required:not(:disabled).is-empty:focus{border-color:var(--ec-color-interactive);box-shadow:0 0 0 .0625rem var(--ec-color-interactive);position:relative;z-index:1}.control .textbox-group .ec-icon{display:none;position:absolute;top:.5rem;left:.5rem;z-index:2}.control.has-icon:not(.invalid) .ec-icon{display:inline-flex}.control.has-icon:not(.invalid) ec-textbox ::ng-deep input{padding-left:1.75rem}.control.is-disabled .ec-icon{filter:grayscale(100%);opacity:.65}.control.is-readonly ec-textbox ::ng-deep input{border-right-width:.0625rem;border-top-right-radius:var(--ec-border-radius);border-bottom-right-radius:var(--ec-border-radius)}.control.is-readonly ec-button{display:none}.control.is-always-open{height:100%}.control.is-always-open label,.control.is-always-open .textbox-group{margin-left:1rem;margin-right:1rem}.control.is-always-open .textbox-group{margin-bottom:1rem}.control.is-always-open .popup{background-color:transparent;box-shadow:none;flex:1 1;border:0;margin:0;z-index:0;min-height:0}.control.is-always-open ec-menu{border-top:1px solid var(--ec-border-color)}.control.is-always-open ec-menu ::ng-deep ul{max-height:none}label{color:var(--ec-color-secondary-dark);display:block;font-size:var(--ec-font-size-label);line-height:1;margin:calc(var(--ec-font-size-label) / 2) 0}.popup{background-color:var(--ec-background-color);border-radius:var(--ec-border-radius-card);box-shadow:var(--ec-box-shadow-overlay);margin-top:.25rem;overflow:hidden;z-index:var(--ec-z-index-popup)}ec-menu{display:block}ec-menu:not(:first-child){border-top:1px solid var(--ec-border-color)}ec-menu ::ng-deep ul{max-height:30vh}ec-menu ::ng-deep ul li{white-space:nowrap}.add-new{height:2rem;line-height:1.25;padding:.25rem .5rem;align-items:center;background-color:var(--ec-background-color);display:flex;cursor:pointer;border:0;width:100%}.add-new.is-selected,.add-new.is-highlighted{background-color:#d9edf2}.add-new:focus{background-color:var(--ec-color-disabled-dark);position:relative;z-index:1;outline:none}.add-new:active{background-color:var(--ec-color-interactive);color:var(--ec-color-primary-light)}.add-new:disabled,.add-new.is-disabled{color:var(--ec-color-secondary-dark);opacity:.65;cursor:default}.add-new .label{align-items:center;display:flex;flex:auto}.add-new .ec-icon+.label{margin:0 .375rem}.add-new:hover:not(:active),.add-new.is-selected{background-color:#bfe0e9}.add-new:active .ec-icon{color:inherit}.add-new-label{flex:1 1;margin-right:.5rem;text-align:left}.add-new .ec-icon{flex:0 0 auto}footer{padding:.5rem;border-top:1px solid var(--ec-border-color);color:var(--ec-color-hint-dark);font-size:var(--ec-font-size-label);text-align:right;line-height:1}ec-button ::ng-deep button .ec-icon{background-size:1em;background-position:center}.open:not(.is-always-open) .textbox-group ec-textbox ::ng-deep input{border-color:var(--ec-border-color-legacy);box-shadow:none}.open:not(.is-always-open) .textbox-group ec-button ::ng-deep button{background-color:var(--ec-background-color-hover);box-shadow:none}\n"] }]
788
+ }], ctorParameters: function () { return [{ type: i1.ValidationMessageService }, { type: i2.FormGroupHelper }, { type: i3.TranslateService }, { type: i4.ScrollService }]; }, propDecorators: { onResize: [{
789
+ type: HostListener,
790
+ args: ['window:resize']
791
+ }], addNew: [{
792
+ type: Input
793
+ }], maxlength: [{
794
+ type: Input
795
+ }], menuPosition: [{
796
+ type: Input
797
+ }], minlength: [{
798
+ type: Input
799
+ }], options: [{
800
+ type: Input
801
+ }], templateType: [{
802
+ type: Input
803
+ }], customMenuTemplate: [{
804
+ type: Input
805
+ }], popupFixed: [{
806
+ type: Input
807
+ }], totalRecords: [{
808
+ type: Input
809
+ }], upperCase: [{
810
+ type: Input
811
+ }], placeholder: [{
812
+ type: Input
813
+ }], loadOnOpenObservable: [{
814
+ type: Input
815
+ }], hideToggleButton: [{
816
+ type: Input
817
+ }], alwaysOpen: [{
818
+ type: Input
819
+ }], menuElementClasses: [{
820
+ type: Input
821
+ }], textboxElementClasses: [{
822
+ type: Input
823
+ }], hideNoMatches: [{
824
+ type: Input
825
+ }], noMatchesText: [{
826
+ type: Input
827
+ }], addNewClick: [{
828
+ type: Output
829
+ }], search: [{
830
+ type: Output
831
+ }], textbox: [{
832
+ type: ViewChild,
833
+ args: ['textbox']
834
+ }], popup: [{
835
+ type: ViewChild,
836
+ args: [PopupContainerDirective]
837
+ }], addNewButton: [{
838
+ type: ViewChild,
839
+ args: ['addNewButton']
840
+ }] } });
841
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tYm9ib3guY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY29tcG9uZW50cy9zcmMvbGliL2NvbnRyb2xzL2NvbWJvYm94L2NvbWJvYm94LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbXBvbmVudHMvc3JjL2xpYi9jb250cm9scy9jb21ib2JveC9jb21ib2JveC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFtRCxTQUFTLEVBQWMsWUFBWSxFQUFlLE1BQU0sZUFBZSxDQUFDO0FBQzFLLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxVQUFVLEVBQWUsTUFBTSxnQkFBZ0IsQ0FBQztBQUU3RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFdkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUtqRCxPQUFPLEVBQUUsdUJBQXVCLEVBQWUsTUFBTSx5REFBeUQsQ0FBQzs7Ozs7Ozs7Ozs7O0FBZ0IvRzs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQU1ILE1BQU0sT0FBTyxpQkFBa0IsU0FBUSxlQUFlO0lBK01yRCxZQUNXLHdCQUFrRCxFQUNsRCxlQUFnQyxFQUNoQyxTQUEyQixFQUMzQixhQUE0QjtRQUV0QyxLQUFLLENBQUMsd0JBQXdCLEVBQUUsZUFBZSxDQUFDLENBQUM7UUFMdkMsNkJBQXdCLEdBQXhCLHdCQUF3QixDQUEwQjtRQUNsRCxvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsY0FBUyxHQUFULFNBQVMsQ0FBa0I7UUFDM0Isa0JBQWEsR0FBYixhQUFhLENBQWU7UUF6THZDOzs7O1dBSUc7UUFDYSxpQkFBWSxHQUEwQixjQUFjLENBQUM7UUFXckU7Ozs7V0FJRztRQUNh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VSxZQUFZO3NCQUEzQixLQUFLO2dCQVFVLFNBQVM7c0JBQXhCLEtBQUs7Z0JBUVUsT0FBTztzQkFBdEIsS0FBSztnQkFRVSxZQUFZO3NCQUEzQixLQUFLO2dCQVVhLGtCQUFrQjtzQkFBakMsS0FBSztnQkFRTyxVQUFVO3NCQUF6QixLQUFLO2dCQU1VLFlBQVk7c0JBQTNCLEtBQUs7Z0JBS1UsU0FBUztzQkFBeEIsS0FBSztnQkFNVSxXQUFXO3NCQUExQixLQUFLO2dCQUdVLG9CQUFvQjtzQkFBbkMsS0FBSztnQkFHVSxnQkFBZ0I7c0JBQS9CLEtBQUs7Z0JBTVUsVUFBVTtzQkFBekIsS0FBSztnQkFLVSxrQkFBa0I7c0JBQWpDLEtBQUs7Z0JBS1UscUJBQXFCO3NCQUFwQyxLQUFLO2dCQUdVLGFBQWE7c0JBQTVCLEtBQUs7Z0JBS2EsYUFBYTtzQkFBNUIsS0FBSztnQkFTUSxXQUFXO3NCQUEzQixNQUFNO2dCQU1VLE1BQU07c0JBQXRCLE1BQU07Z0JBR3NCLE9BQU87c0JBQW5DLFNBQVM7dUJBQUMsU0FBUztnQkFLd0IsS0FBSztzQkFBaEQsU0FBUzt1QkFBQyx1QkFBdUI7Z0JBTUMsWUFBWTtzQkFBOUMsU0FBUzt1QkFBQyxjQUFjIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIsIE9uSW5pdCwgT25DaGFuZ2VzLCBTaW1wbGVDaGFuZ2VzLCBBZnRlclZpZXdJbml0LCBWaWV3Q2hpbGQsIEVsZW1lbnRSZWYsIEhvc3RMaXN0ZW5lciwgVGVtcGxhdGVSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgVW50eXBlZEZvcm1Db250cm9sLCBWYWxpZGF0b3JzLCBWYWxpZGF0b3JGbiB9IGZyb20gXCJAYW5ndWxhci9mb3Jtc1wiO1xyXG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSBcIkBuZ3gtdHJhbnNsYXRlL2NvcmVcIjtcclxuaW1wb3J0IHsgRm9ybUNvbnRyb2xCYXNlIH0gZnJvbSAnLi4vZm9ybS1jb250cm9sLWJhc2UnO1xyXG5pbXBvcnQgeyBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IHRha2VVbnRpbCwgdGFrZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgVGV4dGJveENvbXBvbmVudCB9IGZyb20gJy4uL3RleHRib3gvdGV4dGJveC5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBWYWxpZGF0aW9uTWVzc2FnZVNlcnZpY2UgfSBmcm9tICcuLi8uLi9jb3JlL3ZhbGlkYXRpb24tbWVzc2FnZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgRm9ybUdyb3VwSGVscGVyIH0gZnJvbSAnLi4vLi4vc2hhcmVkL2Zvcm0tZ3JvdXAuaGVscGVyJztcclxuaW1wb3J0IHsgTWVudUl0ZW0sIE1lbnVUZW1wbGF0ZVR5cGUsIE1lbnVIb3N0RWxlbWVudENsYXNzZXMgfSBmcm9tICcuLi9tZW51L21lbnUuY29tcG9uZW50JztcclxuaW1wb3J0IHsgUG9wdXBDb250YWluZXJEaXJlY3RpdmUsIFBvcHVwU3RhdHVzIH0gZnJvbSAnLi4vLi4vc2hhcmVkL2RpcmVjdGl2ZXMvcG9wdXAvcG9wdXAtY29udGFpbmVyLmRpcmVjdGl2ZSc7XHJcbmltcG9ydCB7IFNjcm9sbFNlcnZpY2UgfSBmcm9tICcuLi8uLi9jb3JlL3Njcm9sbC5zZXJ2aWNlJztcclxuXHJcbi8qKlxyXG4gKiBQb3NpdGlvbiBvZiB0aGUgbWVudSByZWxhdGl2ZSB0byB0aGUgaW5wdXRcclxuICovXHJcbmV4cG9ydCB0eXBlIENvbWJvYm94TWVudVBvc2l0aW9uID0gXCJ0b3BfcmlnaHRcIiB8IFwidG9wX2xlZnRcIiB8IFwiYm90dG9tX2xlZnRcIiB8IFwiYm90dG9tX3JpZ2h0XCI7XHJcblxyXG5cclxuLyoqXHJcbiAqIFRoZSB0eXBlIG9mIGFkZCBuZXcgaW1wbGVtZW50YXRpb24uIFN0YXRpYyBkaXNwbGF5cyBhIHNpbXBsZSBzdGF0aWMgYnV0dG9uIHdoaWxlIGR5bmFtaWMgdXBkYXRlc1xyXG4gKiB0aGUgbGFiZWwgb2YgdGhlIGJ1dHRvbiB3aXRoIHZhbHVlIG9mIHRoZSB0ZXh0Ym94XHJcbiAqL1xyXG50eXBlIEFkZE5ld1R5cGUgPSBcImR5bmFtaWNcIiB8IFwic3RhdGljXCIgfCBib29sZWFuO1xyXG5cclxuXHJcbi8qKlxyXG4gKiBTZWxlY3QgYm94IChzZWxlY3QsIGF1dG9jb21wbGV0ZSwgY29tYm9ib3gpXHJcbiAqXHJcbiAqIE5PVEU6IE1pbi9tYXggbGVuZ3RoIHZhbGlkYXRpb24gaXMgaW1wbGVtZW50ZWQgb24gdGhlIGludGVybmFsIGVjLXRleHRib3guXHJcbiAqIFZhbHVlcyBwYXNzZWQgaW4gdmlhIGlucHV0IHByb3BlcnRpZXMgKEBzZWUgbWF4bGVuZ3RoICwgQHNlZSBtaW5sZW5ndGggKVxyXG4gKiBhcmUgdXNlZCB0byBjcmVhdGUgdmFsaWRhdG9ycyBvbiB0aGUgdGV4dGJveC4gIFdoZW4gdGhlIHZhbGlkYXRpb24gb24gdGhlXHJcbiAqIHRleHRib3ggZmFpbHMsIHRoZSB2YWxpZGF0aW9uIGVycm9yKHMpIGdldCBwYXNzZWQgdXAgdG8gdGhlIHtAc2VlIGZvcm1Nb2RlbCB9LlxyXG4gKiBXaGVuIHNldHRpbmcgdXAgdGhpcyBjb21wb25lbnQncyB7QHNlZSBGb3JtQ29udHJvbCB9LCB5b3UgZG8gTk9UIG5lZWQgdG8gc2V0IHRoZVxyXG4gKiBWYWxpZGF0b3JzLm1pbkxlbmd0aCBvciBWYWxpZGF0b3JzLm1heExlbmd0aCB2YWxpZGF0b3JzLlxyXG4gKlxyXG4gKiBSZXF1aXJlZCBpcyBhbHNvIHBhc3NlZCB2aWEgaW5wdXQgcHJvcGVydHksIGJ1dCB5b3UgU0hPVUxEIGFsc28gc2V0IHVwIHRoZVxyXG4gKiBWYWxpZGF0b3JzLnJlcXVpcmVkIHZhbGlkYXRvciBvbiB0aGlzIGNvbXBvbmVudCdzIEZvcm1Db250cm9sLlxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5AQ29tcG9uZW50KHtcclxuXHRzZWxlY3RvcjogJ2VjLWNvbWJvYm94JyxcclxuXHR0ZW1wbGF0ZVVybDogJ2NvbWJvYm94LmNvbXBvbmVudC5odG1sJyxcclxuXHRzdHlsZVVybHM6IFsnLi9jb21ib2JveC5jb21wb25lbnQuc2NzcyddXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBDb21ib2JveENvbXBvbmVudCBleHRlbmRzIEZvcm1Db250cm9sQmFzZSBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBBZnRlclZpZXdJbml0IHtcclxuXHJcblx0LyoqXHJcblx0ICogQ2xvc2UgdGhlIHBvcHVwIG1lbnUgb24gcmVzaXplIHNvIHRoZSB3aWR0aCBhbmQgcG9zaXRpb25pbmcgY2FuIGJlIHJlY2FsY3VsYXRlZFxyXG5cdCAqIGNvcnJlY3RseS4gQ2Fubm90IGJlIHBsYWNlZCBvbiB0aGUgcG9wdXBEaXJlY3RpdmUgYmVjYXVzZSBvZiBhIGJ1ZyB3aGVyZVxyXG5cdCAqIEhvc3RMaXN0ZW5lcnMgZm9yIGdsb2JhbCBldmVudHMgZG9uJ3QgZmlyZVxyXG5cdCAqIEBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2FuZ3VsYXIvYW5ndWxhci9pc3N1ZXMvMTQxOTFcclxuXHQgKi9cclxuXHRASG9zdExpc3RlbmVyKCd3aW5kb3c6cmVzaXplJykgb25SZXNpemUoKSB7XHJcblx0XHRpZiAodGhpcy5wb3B1cCkgdGhpcy5wb3B1cC5oaWRlKCk7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBTaG93IHRoZSBhZGQgbmV3IGJ1dHRvbiBpbiB0aGUgcG9wdXBcclxuXHQgKi9cclxuXHRASW5wdXQoKSBwdWJsaWMgYWRkTmV3PzogQWRkTmV3VHlwZTtcclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFRoZSBtYXhpbXVtIG51bWJlciBvZiBjaGFyYWN0ZXJzIGFsbG93ZWQgaW4gdGhlIGlucHV0LlxyXG5cdCAqXHJcblx0ICogQG1lbWJlcm9mIFRleHRib3hDb21wb25lbnRcclxuXHQgKi9cclxuXHRASW5wdXQoKSBwdWJsaWMgbWF4bGVuZ3RoPzogbnVtYmVyO1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogUG9zaXRpb24gb2YgdGhlIG1lbnUgcmVsYXRpdmUgdG8gdGhlIHRleHQgYm94XHJcblx0ICogQGRlZmF1bHQgJ2JvdHRvbV9yaWdodCdcclxuXHQgKiBAbWVtYmVyb2YgQ29tYm9ib3hDb21wb25lbnRcclxuXHQgKi9cclxuXHRASW5wdXQoKSBwdWJsaWMgbWVudVBvc2l0aW9uPzogQ29tYm9ib3hNZW51UG9zaXRpb24gPSAnYm90dG9tX3JpZ2h0JztcclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFRoZSBtaW5pbXVtIG51bWJlciBvZiBjaGFyYWN0ZXJzIGFsbG93ZWQgaW4gdGhlIGlucHV0XHJcblx0ICpcclxuXHQgKiBAbWVtYmVyb2YgVGV4dGJveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIHB1YmxpYyBtaW5sZW5ndGg/OiBudW1iZXI7XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBJdGVtcyB0byBzaG93IGluIGNvbWJvYm94IG1lbnVcclxuXHQgKlxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIHB1YmxpYyBvcHRpb25zOiBBcnJheTxNZW51SXRlbT4gPSBbXTtcclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIERpc3BsYXkgdGVtcGxhdGUgZm9yIG1lbnUgaXRlbXNcclxuXHQgKlxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIHB1YmxpYyB0ZW1wbGF0ZVR5cGU6IE1lbnVUZW1wbGF0ZVR5cGUgPSAnbGFiZWwnO1xyXG5cclxuXHQvKipcclxuICAgICAqIE9wdGlvbmFsIGN1c3RvbSB0ZW1wbGF0ZSBmb3IgdGhlIG1lbnUgaXRlbXMuIE11c3QgZGVjbGFyZSBhIHRlbXBsYXRlIFxyXG5cdCAqIGlucHV0IHZhcmlhYmxlIGNhbGxlZCBcIml0ZW1cIiBsaWtlIHNvOiA8bmctdGVtcGxhdGUgI3RlbXBsYXRlTmFtZSBsZXQtaXRlbT4sIFxyXG5cdCAqIHdoZXJlIGl0ZW0gcmVwcmVzZW50cyB0aGUgbWVudUl0ZW0uXHJcbiAgICAgKiBXaWxsIG92ZXJyaWRlIHRoZSBjaG9pY2UgZm9yIHRlbXBsYXRlVHlwZSBpZiBwcm92aWRlZC5cclxuXHQgKiBcclxuXHQgKiBAbWVtYmVyb2YgQ29tYm9ib3hDb21wb25lbnRcclxuICAgICAqL1xyXG4gICAgQElucHV0KCkgcHVibGljIGN1c3RvbU1lbnVUZW1wbGF0ZT86IFRlbXBsYXRlUmVmPGFueT47XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBQb3NpdGlvbiB0aGUgbWVudSBhcyBmaXhlZCwgaWRlYWwgd2hlbiBjb21ib2JveGVzIGFyZSBpbnNpZGUgZGlhbG9nc1xyXG5cdCAqIERlZmF1bHRpbmcgdG8gdHJ1ZSBzbyBhbGwgbWVudXMgd2lsbCBiZSBhdCBsZWFzdCB0aGUgd2lkdGggb2YgdGhlXHJcblx0ICogdGV4dGJveCArIGJ1dHRvbiwgYnV0IGNhbiBncm93IHdpZGVyIGlmIHRoZSBpbm5lciBlbGVtZW50cyBuZWVkIGl0XHJcblx0ICovXHJcblx0QElucHV0KCkgcHVibGljIHBvcHVwRml4ZWQ6IGJvb2xlYW4gPSB0cnVlO1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogVGhlIHRvdGFsIG51bWJlciBvZiByZWNvcmRzIGZyb20gdGhlIGRhdGFzb3VyY2VcclxuXHQgKi9cclxuXHRASW5wdXQoKSBwdWJsaWMgdG90YWxSZWNvcmRzPzogbnVtYmVyO1xyXG5cclxuXHQvKipcclxuXHQgKiBJZiBzZXQgdG8gdHJ1ZSwgd2Ugd2lsbCB1cHBlckNhc2UgdGhlIHRleHQgYm94IGFuZCBhcHBseSB0aGUgY2xhc3Mgb24gdGhlIGFkZCBib3hcclxuXHQgKi9cclxuXHRASW5wdXQoKSBwdWJsaWMgdXBwZXJDYXNlOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG5cclxuXHQvKipUaGUgcGxhY2Vob2xkZXIgdG8gc2hvdyBpbiB0aGUgY29tYm9ib3guIExlYXZlIGVtcHR5IHRvIHVzZSBkZWZhdWx0IGJlaGF2aW9yIGRldGVybWluZWRcclxuXHQgKiBieSB3aGV0aGVyIEFkZCBOZXcgaXMgZW5hYmxlZFxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIHB1YmxpYyBwbGFjZWhvbGRlcjogc3RyaW5nID0gJyc7XHJcblxyXG5cdC8qKiBPYnNlcnZhYmxlIHRvIHN1YnNjcmliZSB0byB3aGVuIHRoZSBjb21ib2JveCBtZW51IGlzIG9wZW5lZCBmb3IgdGhlIGZpcnN0IHRpbWUgKi9cclxuXHRASW5wdXQoKSBwdWJsaWMgbG9hZE9uT3Blbk9ic2VydmFibGU/OiBPYnNlcnZhYmxlPE1lbnVJdGVtW10+IHwgdW5kZWZpbmVkO1xyXG5cclxuXHQvKiogRG8gbm90IGRpc3BsYXkgdGhlIHRvZ2dsZSBidXR0b24gd2hlbiB0cnVlICovXHJcblx0QElucHV0KCkgcHVibGljIGhpZGVUb2dnbGVCdXR0b24gPSBmYWxzZTtcclxuXHJcblx0LyoqXHJcblx0ICogQWx3YXlzIHNob3cgdGhlIG1lbnUgd2hlbiB0aGUgZm9ybU1vZGVsIGhhcyBhIHZhbHVlLiBTZXRzXHJcblx0ICogaGlkZVRvZ2dsZUJ1dHRvbiB0byB0cnVlIGFuZCBtZW51U3RhdHVzIHRvIHZpc2libGUgYXMgd2VsbC5cclxuXHQgKi9cclxuXHRASW5wdXQoKSBwdWJsaWMgYWx3YXlzT3BlbiA9IGZhbHNlO1xyXG5cclxuXHQvKipcclxuXHQgKiBBZGRpdG9uYWwgY2xhc3NlcyB0byBhcHBseSB0byB0aGUgZWMtbWVudSBlbGVtZW50XHJcblx0ICovXHJcblx0QElucHV0KCkgcHVibGljIG1lbnVFbGVtZW50Q2xhc3NlczogTWVudUhvc3RFbGVtZW50Q2xhc3NlcyB8IHN0cmluZ1tdID0gW107XHJcblxyXG5cdC8qKlxyXG5cdCAqIEFkZGl0aW9uYWwgY2xhc3NlcyB0byBhcHBseSB0byB0aGUgLnRleHRib3gtZ3JvdXAgZWxlbWVudFxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIHB1YmxpYyB0ZXh0Ym94RWxlbWVudENsYXNzZXM6IHN0cmluZ1tdID0gW107XHJcblxyXG5cdC8qKiBIaWRlICdObyBtYXRjaGVzJyBtZXNzYWdlIHdoZW4gdHJ1ZSAqL1xyXG5cdEBJbnB1dCgpIHB1YmxpYyBoaWRlTm9NYXRjaGVzOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG5cdC8qKlxyXG4gICAgICogVGV4dCB0byBzaG93IHdoZW4gdGhlIG1lbnUgaXMgZW1wdHkuIFwiTm8gbWF0Y2hlc1wiIGlzIHRoZSBkZWZhdWx0LlxyXG4gICAgICovXHJcbiAgICBASW5wdXQoKSBwdWJsaWMgbm9NYXRjaGVzVGV4dDogc3RyaW5nID0gJ05vTWF0Y2hlc19TQyc7XHJcblxyXG5cdC8qKlxyXG5cdCAqIE5vdGlmeSB0aGUgcGFyZW50IHRoYXQgdGhlIGFkZCBuZXcgYnV0dG9uIHdhcyBjbGlja2VkXHJcblx0ICogQHRvZG8gZGlzY3VzcyBpZiB3ZSBuZWVkIHRvIHNlbmQgYWxvbmcgdGhlIHZhbHVlIG9yIHNob3VsZFxyXG5cdCAqIHRoZSBwYXJlbnQgZ2V0IGl0IGZyb20gdGhlIGZvcm1Nb2RlbFxyXG5cdCAqIChsd2YgMjAxNy4wNy4xMyk6IEkgdGhpbmsgd2UgbWlnaHQgYXMgd2VsbCBzZW5kIHRoZSB2YWx1ZSBhbG9uZyBhbmRcclxuXHQgKiBsZWF2ZSBpdCB1cCB0byB0aGUgcGFyZW50IHRvIGRlY2lkZSBob3cgdG8gaGFuZGxlIGl0LlxyXG5cdCAqL1xyXG5cdEBPdXRwdXQoKSBwdWJsaWMgYWRkTmV3Q2xpY2s6IEV2ZW50RW1pdHRlcjxzdHJpbmc+ID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBOb3RpZnkgcGFyZW50IHdoZW4gdGV4dCB0eXBlZCBpbnRvIHRleHRib3hcclxuXHQgKi9cclxuXHRAT3V0cHV0KCkgcHVibGljIHNlYXJjaDogRXZlbnRFbWl0dGVyPHN0cmluZz4gPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcclxuXHJcblxyXG5cdEBWaWV3Q2hpbGQoJ3RleHRib3gnKSBwdWJsaWMgdGV4dGJveCE6IFRleHRib3hDb21wb25lbnQ7XHJcblxyXG5cdC8qKlxyXG5cdCAqIEFjY2VzcyB0byB0aGUgbWVudSdzIGNvbXBvbmVudCB2aWEgdGhlICB7QGxpbmsgUG9wdXBDb250YWluZXJEaXJlY3RpdmV9XHJcblx0ICovXHJcblx0QFZpZXdDaGlsZChQb3B1cENvbnRhaW5lckRpcmVjdGl2ZSkgcHJpdmF0ZSBwb3B1cD86IFBvcHVwQ29udGFpbmVyRGlyZWN0aXZlO1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogUmVmZXJlbmNlIHRoZSBhZGQtbmV3IGJ1dHRvbiBlbGVtZW50XHJcblx0ICovXHJcblx0QFZpZXdDaGlsZCgnYWRkTmV3QnV0dG9uJykgcHJpdmF0ZSBhZGROZXdCdXR0b24hOiBFbGVtZW50UmVmO1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICAgKiBGaWx0ZXJlZCBJdGVtcyB0byBzaG93IGluIGNvbWJvYm94IG1lbnVcclxuXHQgICAqL1xyXG5cdHB1YmxpYyBmaWx0ZXJlZE9wdGlvbnM6IEFycmF5PE1lbnVJdGVtPiA9IFtdO1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogVHJhY2tzIGlmIHRoZSBtZW51IGlzIG9wZW4gb3IgaGlkZGVuXHJcblx0ICovXHJcblx0cHVibGljIG1lbnVTdGF0dXM6IFBvcHVwU3RhdHVzID0gJ2hpZGRlbic7XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBQbGFjZWhvbGRlciB0byBhc3NpZ24gdG8gdGV4dGJveFxyXG5cdCAqL1xyXG5cdHB1YmxpYyBlZmZlY3RpdmVQbGFjZWhvbGRlcjogc3RyaW5nID0gJyc7XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBSZWZlcmVuY2UgdG8gdGhlIGN1cnJlbnRseS1zZWxlY3RlZCBtZW51IGl0ZW1cclxuXHQgKi9cclxuXHRwdWJsaWMgc2VsZWN0ZWRJdGVtOiBNZW51SXRlbSB8IG51bGwgPSBudWxsO1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogRm9ybUNvbnRyb2wgZm9yIHRoZSB0ZXh0Ym94XHJcblx0ICovXHJcblx0cHVibGljIHRleHRib3hGb3JtTW9kZWw6IFVudHlwZWRGb3JtQ29udHJvbCA9IG5ldyBVbnR5cGVkRm9ybUNvbnRyb2woJycpO1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogVHJhY2tzIHdoZXRoZXIgdGhlIGFkZCBuZXcgYnV0dG9uIGlzIHNlbGVjdGVkXHJcblx0ICovXHJcblx0cHVibGljIGFkZE5ld1NlbGVjdGVkOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBUcmFja3Mgd2hldGhlciB0aGUgdGV4dGJveEZvcm1Nb2RlbCB2YWx1ZSBtYXRjaGVzIGFuIGl0ZW0gaW4gdGhlIGZpbHRlcmVkT3B0aW9uc1xyXG5cdCAqL1xyXG5cdHB1YmxpYyBmb3VuZE1hdGNoOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBJbmRleCBvZiB0aGUgY3VycmVudGx5LXNlbGVjdGVkIG9wdGlvbnNcclxuXHQgKi9cclxuXHRwcml2YXRlIHNlbGVjdGVkSXRlbUluZGV4OiBudW1iZXIgPSAtMTtcclxuXHJcblx0LyoqIFBsYWNlaG9sZGVyIHRleHQgZm9yICdDaG9vc2Ugb3IgQWRkLi4uJyAqL1xyXG5cdHByaXZhdGUgY2hvb3NlT3JBZGRQbGFjZWhvbGRlcjogc3RyaW5nID0gJyc7XHJcblxyXG5cdC8qKiBQbGFjZWhvbGRlciB0ZXh0IGZvciAnQ2hvb3NlJyAqL1xyXG5cdHByaXZhdGUgY2hvb3NlUGxhY2Vob2xkZXI6IHN0cmluZyA9ICcnO1xyXG5cclxuXHRwcml2YXRlIGhhc0RhdGFCZWVuTG9hZGVkT25PcGVuOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG5cdGNvbnN0cnVjdG9yKFxyXG5cdFx0cHJvdGVjdGVkIHZhbGlkYXRpb25NZXNzYWdlU2VydmljZTogVmFsaWRhdGlvbk1lc3NhZ2VTZXJ2aWNlLFxyXG5cdFx0cHJvdGVjdGVkIGZvcm1Hcm91cEhlbHBlcjogRm9ybUdyb3VwSGVscGVyLFxyXG5cdFx0cHJvdGVjdGVkIHRyYW5zbGF0ZTogVHJhbnNsYXRlU2VydmljZSxcclxuXHRcdHByb3RlY3RlZCBzY3JvbGxTZXJ2aWNlOiBTY3JvbGxTZXJ2aWNlXHJcblx0KSB7XHJcblx0XHRzdXBlcih2YWxpZGF0aW9uTWVzc2FnZVNlcnZpY2UsIGZvcm1Hcm91cEhlbHBlcik7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogVGhlIGFuZ3VsYXIgb25DaGFuZ2VzIGxpZmVjeWNsZSBldmVudFxyXG5cdCAqIEBzZWUgaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2xpZmVjeWNsZS1ob29rc1xyXG5cdCAqL1xyXG5cdHB1YmxpYyBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcblx0XHRzdXBlci5uZ09uQ2hhbmdlcyhjaGFuZ2VzKTtcclxuXHJcblx0XHQvLyB3aGVuIG9wdGlvbnMgY2hhbmdlc1xyXG5cdFx0aWYgKGNoYW5nZXMub3B0aW9ucykge1xyXG5cdFx0XHR0aGlzLnJlc2V0T3B0aW9ucygpO1xyXG5cclxuXHRcdFx0Ly8gVXBkYXRlIHRoZSBwb3B1cCBwb3NpdGlvblxyXG5cdFx0XHRpZiAodGhpcy5wb3B1cCkge1xyXG5cdFx0XHRcdHRoaXMucG9wdXAudXBkYXRlKCk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvLyB1cGRhdGUgdmFsaWRhdG9ycyBvbiB0aGUgdGV4dGJveFxyXG5cdFx0aWYgKGNoYW5nZXMucmVxdWlyZWQgfHwgY2hhbmdlcy5taW5sZW5ndGggfHwgY2hhbmdlcy5tYXhsZW5ndGgpIHtcclxuXHRcdFx0dGhpcy5zZXRUZXh0Ym94Rm9ybU1vZGVsVmFsaWRhdG9ycygpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFVwZGF0ZSBwbGFjZWhvbGRlciB0ZXh0IHdoZW4gJ0FkZCBOZXcnIGlzIGNvbmRpdGlvbmFsLlxyXG5cdFx0Ly8gbmdPbkNoYW5nZXMoKSBraWNrcyBvZmYgYmVmb3JlIG5nT25Jbml0LCBzbyBpbiBvcmRlclxyXG5cdFx0Ly8gdG8gbm90IG92ZXJ3cml0ZSBhIHVzZXItcHJvdmlkZWQgcGxhY2Vob2xkZXIsIGRvIG5vdFxyXG5cdFx0Ly8gdXBkYXRlIHBsYWNlaG9sZGVyIG9uIGZpcnN0IGNoYW5nZSAobmdPbkluaXQgd2lsbCB0YWtlIGNhcmUgb2YgaXQpLlxyXG5cdFx0aWYgKChjaGFuZ2VzLmFkZE5ldyAmJiAhY2hhbmdlcy5hZGROZXcuaXNGaXJzdENoYW5nZSgpKSB8fCBjaGFuZ2VzLnBsYWNlaG9sZGVyKSB7XHJcblx0XHRcdHRoaXMudXBkYXRlUGxhY2Vob2xkZXJUZXh0KCk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBUaGUgYW5ndWxhciBvbkluaXQgbGlmZWN5Y2xlIGhvb2tcclxuXHQgKiBAc2VlIGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9saWZlY3ljbGUtaG9va3NcclxuXHQgKi9cclxuXHRwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XHJcblx0XHRzdXBlci5uZ09uSW5pdCgpO1xyXG5cclxuXHRcdGlmICh0aGlzLmFsd2F5c09wZW4pIHtcclxuXHRcdFx0dGhpcy5oaWRlVG9nZ2xlQnV0dG9uID0gdHJ1ZTtcclxuXHRcdFx0dGhpcy5tZW51U3RhdHVzID0gJ3Zpc2libGUnO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEdldCB0cmFuc2xhdGVkIHBsYWNlaG9sZGVyIHRleHRcclxuXHRcdHRoaXMuY2hvb3NlT3JBZGRQbGFjZWhvbGRlciA9IGAke3RoaXMudHJhbnNsYXRlLmluc3RhbnQoJ0Nob29zZSBvciBhZGQnKX0uLi5gO1xyXG5cdFx0dGhpcy5jaG9vc2VQbGFjZWhvbGRlciA9IGAke3RoaXMudHJhbnNsYXRlLmluc3RhbnQoJ0Nob29zZScpfWA7XHJcblxyXG5cdFx0dGhpcy5mb3JtTW9kZWxDaGFuZ2VkKHRoaXMuZm9ybU1vZGVsLnZhbHVlKTtcclxuXHRcdHRoaXMuc2V0VGV4dGJveEZvcm1Nb2RlbFZhbGlkYXRvcnMoKTtcclxuXHJcblx0XHQvLyBFcnJvcnMgZm9yIHRoaXMgY29tcG9uZW50IGFyZSBkaXNwbGF5ZWQgdmlhIHRoZSB2YWxpZGF0aW9uRXJyb3JzIHByb3BlcnR5LCB3aGljaCBpc1xyXG5cdFx0Ly8gcG9wdWxhdGVkIHdoZW4gdHJhbnNsYXRlVmFsaWRhdGlvbk1lc3NhZ2VzIGlzIHJ1bi5cclxuXHRcdC8vIFdoZW4gdGhlIGludGVybmFsIFRleHRib3hDb21wb25lbnQgaGFzIHZhbGlkYXRpb24gZXJyb3JzLCB3ZSBzZXQgdGhlbSBvbiB0aGVcclxuXHRcdC8vIGZvcm1Nb2RlbCBhcyB3ZWxsLiAgVGhpcyB1cGRhdGVzIHRoZSB2YWxpZGl0eSBvZiBvdXIgQ29tYm9ib3hDb21wb25lbnQgY29udHJvbCxcclxuXHRcdC8vIGJ1dCBkb2VzIG5vdCB0cmlnZ2VyIHRyYW5zbGF0aW9uLiAgU3Vic2NyaWJlIHRvIHN0YXR1c0NoYW5nZXMgaGVyZSBzbyBjb21wb25lbnRcclxuXHRcdC8vIHZhbGlkYXRpb24gZXJyb3JzIHdpbGwgYXBwZWFyIGFsb25nIHdpdGggdGhlIENvbWJvYm94Q29tcG9uZW50J3MgbGFiZWwuXHJcblx0XHR0aGlzLmZvcm1Nb2RlbC52YWx1ZUNoYW5nZXMucGlwZShcclxuXHRcdFx0dGFrZVVudGlsKHRoaXMuY29tcG9uZW50RGVzdHJveWVkKVxyXG5cdFx0KS5zdWJzY3JpYmUoZGF0YSA9PiB0aGlzLmZvcm1Nb2RlbENoYW5nZWQoZGF0YSkpO1xyXG5cclxuXHRcdHRoaXMudGV4dGJveEZvcm1Nb2RlbC5zdGF0dXNDaGFuZ2VzLnBpcGUoXHJcblx0XHRcdHRha2VVbnRpbCh0aGlzLmNvbXBvbmVudERlc3Ryb3llZClcclxuXHRcdCkuc3Vic2NyaWJlKGRhdGEgPT4gdGhpcy5zZXRGb3JtTW9kZWxWYWxpZGF0aW9uRXJyb3JzKGRhdGEpKTtcclxuXHJcblx0XHQvLyBkZWZhdWx0IHBsYWNlaG9sZGVyXHJcblx0XHR0aGlzLnVwZGF0ZVBsYWNlaG9sZGVyVGV4dCgpO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFRoZSBhbmd1bGFyIGFmdGVyVmlld0luaXQgbGlmZWN5Y2xlIGhvb2tcclxuXHQgKiBAc2VlIGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9saWZlY3ljbGUtaG9va3NcclxuXHQgKi9cclxuXHRwdWJsaWMgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xyXG5cdFx0aWYgKCF0aGlzLnBvcHVwKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBhbGxvdyBvdmVyZmxvdyBvdXQgb2YgdGhlIHNjcm9sbFBhcmVudFxyXG5cdFx0Ly8gcHJldmVudHMgbWVudSBmcm9tIG9ic2N1cmluZyB0aGUgY29tYm9ib3hcclxuXHRcdGxldCBwb3BwZXJPcHRpb25zOiBQb3BwZXIuUG9wcGVyT3B0aW9ucyA9IHtcclxuXHRcdFx0bW9kaWZpZXJzOiB7XHJcblx0XHRcdFx0cHJldmVudE92ZXJmbG93OiB7XHJcblx0XHRcdFx0XHRib3VuZGFyaWVzRWxlbWVudDogJ3ZpZXdwb3J0J1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHJcblx0XHQvLyBjb252ZXJ0IHRoZSBDb21ib2JveE1lbnVQb3NpdGlvbiBpbnRvIGEgUG9wcGVyUGxhY2VtZW50XHJcblx0XHRzd2l0Y2ggKHRoaXMubWVudVBvc2l0aW9uKSB7XHJcblx0XHRcdGNhc2UgKFwidG9wX2xlZnRcIik6XHJcblx0XHRcdFx0cG9wcGVyT3B0aW9ucy5wbGFjZW1lbnQgPSAndG9wLXN0YXJ0JztcclxuXHRcdFx0XHRicmVhaztcclxuXHRcdFx0Y2FzZSAoXCJ0b3BfcmlnaHRcIik6XHJcblx0XHRcdFx0cG9wcGVyT3B0aW9ucy5wbGFjZW1lbnQgPSAndG9wLWVuZCc7XHJcblx0XHRcdFx0YnJlYWs7XHJcblx0XHRcdGNhc2UgKFwiYm90dG9tX2xlZnRcIik6XHJcblx0XHRcdFx0cG9wcGVyT3B0aW9ucy5wbGFjZW1lbnQgPSAnYm90dG9tLXN0YXJ0JztcclxuXHRcdFx0XHRicmVhaztcclxuXHRcdFx0Y2FzZSAoXCJib3R0b21fcmlnaHRcIik6XHJcblx0XHRcdFx0cG9wcGVyT3B0aW9ucy5wbGFjZW1lbnQgPSAnYm90dG9tLWVuZCc7XHJcblx0XHRcdFx0YnJlYWs7XHJcblx0XHRcdGRlZmF1bHQ6XHJcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIG1lbnVQb3NpdGlvbiBmb3IgQ29tYm9ib3hDb21wb25lbnQuYClcclxuXHRcdH1cclxuXHJcblx0XHQvLyBTY3JvbGwgdGhlIG1lbnUgdG8gdGhlIHNlbGVjdGVkIGl0ZW0gb25jZSB0aGUgcG9wdXAgbWVudSBpcyByZWFkeVxyXG5cdFx0cG9wcGVyT3B0aW9ucy5vbkNyZWF0ZSA9ICgpID0+IHtcclxuXHRcdFx0dGhpcy5zY3JvbGxNZW51KCk7XHJcblxyXG5cdFx0XHRpZiAodGhpcy5wb3B1cEZpeGVkKSB7XHJcblx0XHRcdFx0dGhpcy5wb3B1cCEuZml4UG9zaXRpb24oKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh0aGlzLnBvcHVwRml4ZWQpIHtcclxuXHRcdFx0cG9wcGVyT3B0aW9ucy5vblVwZGF0ZSA9ICgpID0+IHtcclxuXHRcdFx0XHR0aGlzLnBvcHVwIS5maXhQb3NpdGlvbigpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5wb3B1cC5wb3BwZXJPcHRpb25zID0gcG9wcGVyT3B0aW9ucztcclxuXHJcblx0XHR0aGlzLnBvcHVwLnBvcHBlclN0YXR1c0NoYW5nZS5waXBlKFxyXG5cdFx0XHR0YWtlVW50aWwodGhpcy5jb21wb25lbnREZXN0cm95ZWQpXHJcblx0XHQpLnN1YnNjcmliZSgoZXZlbnQ6ICd2aXNpYmxlJyB8ICdoaWRkZW4nKSA9PiB7XHJcblx0XHRcdFx0dGhpcy5tZW51U3RhdHVzID0gZXZlbnQ7XHJcblxyXG5cdFx0XHRcdC8vIFN5bmNocm9uaXplIHRoZSBmb3JtTW9kZWwgYW5kIHRleHRGb3JtTW9kZWwgdmFsdWVzIHdoZW4gdGhlXHJcblx0XHRcdFx0Ly8gcG9wdXAgbWVudSBjbG9zZXMgYW5kIHVuLWZpbHRlciB0aGUgb3B0aW9ucyBhbmQgcmVzZXQgdGhlXHJcblx0XHRcdFx0Ly8gc2VsZWN0ZWRJdGVtIGFuZCBpbmRleFxyXG5cdFx0XHRcdGlmIChldmVudCA9PT0gJ2hpZGRlbicpIHtcclxuXHRcdFx0XHRcdHRoaXMuc3luY01vZGVsVmFsdWVzKCk7XHJcblx0XHRcdFx0XHR0aGlzLnJlc2V0T3B0aW9ucygpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSk7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogU2V0IGVycm9ycyBvbiB0aGUgdGV4dGJveEZvcm1Nb2RlbCwgd2hpY2ggd2lsbCB0aGVuIHNldCBlcnJvcnMgb24gdGhlXHJcblx0ICogZm9ybU1vZGVsLiBBbHNvIG1hcmsgdGhlIGZvcm1Nb2RlbCBhcyB0b3VjaGVkIHRvIGRpc3BsYXkgYW55IGVycm9ycy5cclxuXHQgKiBAcGFyYW0gZXJyb3JzIGtleShzKSBvZiBWYWxpZGF0aW9uTWVzc2FnZVNlcnZpY2UgZXJyb3JzIHRvIGRpc3BsYXkgb3IgcmVtb3ZlXHJcblx0ICogQG1lbWJlcm9mIENvbW9ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHB1YmxpYyBzZXRFcnJvcnMoZXJyb3JzOiB7IFtrZXk6IHN0cmluZ106IGJvb2xlYW4gfSk6IHZvaWQge1xyXG5cdFx0dGhpcy50ZXh0Ym94Rm9ybU1vZGVsLnNldEVycm9ycyhlcnJvcnMpO1xyXG5cdFx0dGhpcy5mb3JtTW9kZWwubWFya0FzVG91Y2hlZCgpO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFVuZmlsdGVyIG9wdGlvbnMgYW5kIHVwZGF0ZSB0aGUgc2VsZWN0ZWRJdGVtIGFuZCBzZWxlY3RlZEl0ZW1JbmRleFxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHB1YmxpYyByZXNldE9wdGlvbnMob3B0aW9ucz86IE1lbnVJdGVtW10pOiB2b2lkIHtcclxuXHRcdHRoaXMuZmlsdGVyZWRPcHRpb25zID0gb3B0aW9ucyB8fCB0aGlzLm9wdGlvbnM7XHJcblxyXG5cdFx0Ly9pZiB0aGV5IGhhdmUgbm8gc2VhcmNoIHRlcm0sIGRvbid0IHRyeSB0byBzZWxlY3QgYW55dGhpbmcgc28gdGhleSBjYW4gY2xlYXIgdGhlIGJveCBvdXQgYnkgaGl0dGluZyBlbnRlclxyXG5cdFx0Ly9pZiB0aGV5IGhhdmUgYSBzZWFyY2ggdGVybSBhbmQgdGhlIG9wdGlvbnMgY2hhbmdlZCwgc2VsZWN0IGFuIG9wdGlvbiBmcm9tIHRoZSBtZW51IHNvIHRoZXkgd2lsbCBnZXQgaXQgYXV0b21hdGljYWxseSBpZiB0aGV5IGhpdCBlbnRlclxyXG5cdFx0aWYgKHRoaXMudGV4dGJveEZvcm1Nb2RlbC52YWx1ZSAhPT0gJycpIHtcclxuXHRcdFx0dGhpcy5zZWxlY3RlZEl0ZW1JbmRleCA9IHRoaXMuZmluZERlZmF1bHRTZWxlY3Rpb25JbmRleCh0aGlzLmZpbHRlcmVkT3B0aW9ucywgdGhpcy50ZXh0Ym94Rm9ybU1vZGVsLnZhbHVlKTtcclxuXHRcdFx0dGhpcy5zZWxlY3RlZEl0ZW0gPSB0aGlzLmZpbHRlcmVkT3B0aW9uc1t0aGlzLnNlbGVjdGVkSXRlbUluZGV4XSB8fCBudWxsO1xyXG5cdFx0XHR0aGlzLnNjcm9sbE1lbnUodGhpcy5zZWxlY3RlZEl0ZW1JbmRleCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHQvL2lmIHRoZXkgaGF2ZSBubyBzZWFyY2ggdGVybSBhbmQgdGhlIG9wdGlvbnMgYXJlIHJlc2V0LCBkb24ndCBhdXRvLXBpY2sgdGhlIGZpcnN0IG9uZVxyXG5cdFx0XHQvL3NvIHRoYXQgZW50ZXIgd2lsbCBhbGxvdyB0aGVtIHRvIHdpcGUgb3V0IHRoZWlyIGxhc3Qgc2VsZWN0aW9uXHJcblx0XHRcdHRoaXMuY2xlYXJTZWxlY3RlZEl0ZW0oKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIExpc3RlbiB0byB0aGUgc2VsZWN0ZWQgY2hhbmdlZCBldmVudCBmcm9tIHtAbGluayBNZW51Q29tcG9uZW50fSBhbmQgdXBkYXRlIHRoZSBmb3JtXHJcblx0ICogbW9kZWwgYW5kIGNsb3NlIG1lbnVcclxuXHQgKi9cclxuXHRwdWJsaWMgc2VsZWN0ZWRDaGFuZ2VkKGl0ZW06IE1lbnVJdGVtKTogdm9pZCB7XHJcblx0XHR0aGlzLnNldEZvcm1Nb2RlbFZhbHVlKGl0ZW0pO1xyXG5cdFx0dGhpcy50b2dnbGVNZW51KCk7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogU2hvdyBhbmQgaGlkZSB0aGUgcG9wdXAgbWVudVxyXG5cdCAqXHJcblx0ICogQG1lbWJlcm9mIENvbWJvYm94Q29tcG9uZW50XHJcblx0ICovXHJcblx0cHVibGljIHRvZ2dsZU1lbnUoZXZlbnQ/OiBFdmVudCk6IHZvaWQge1xyXG5cdFx0aWYgKCF0aGlzLnBvcHVwKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoZXZlbnQpIHtcclxuXHRcdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCF0aGlzLmZvcm1Nb2RlbC5kaXNhYmxlZCkge1xyXG5cdFx0XHRpZiAodGhpcy5tZW51U3RhdHVzID09PSAndmlzaWJsZScpIHtcclxuXHRcdFx0XHQvLyBXaGVuIHRoZSBwb3B1cCBpcyBoaWRkZW4gaXQgd2lsbCBlbWl0IGl0cyBjaGFuZ2VkIHN0YXR1cyBhbmRcclxuXHRcdFx0XHQvLyB3ZSB3aWxsIHJlc2V0IHZhbHVlcyBpZiBuZWVkIGJlLlxyXG5cdFx0XHRcdHRoaXMucG9wdXAuaGlkZSgpO1xyXG5cdFx0XHR9XHJcblx0XHRcdGVsc2Uge1xyXG5cdFx0XHRcdGlmICh0aGlzLmxvYWRPbk9wZW5PYnNlcnZhYmxlICYmICF0aGlzLmhhc0RhdGFCZWVuTG9hZGVkT25PcGVuKSB7XHJcblx0XHRcdFx0XHR0aGlzLnBlbmRpbmcgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMubG9hZE9uT3Blbk9ic2VydmFibGUucGlwZSh0YWtlKDEpKS5zdWJzY3JpYmUoKHJlc3VsdDogTWVudUl0ZW1bXSkgPT4ge1xyXG5cdFx0XHRcdFx0XHR0aGlzLmhhc0RhdGFCZWVuTG9hZGVkT25PcGVuID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRcdHRoaXMucGVuZGluZyA9IGZhbHNlO1xyXG5cdFx0XHRcdFx0XHR0aGlzLm9wdGlvbnMgPSByZXN1bHQ7XHJcblxyXG5cdFx0XHRcdFx0XHR0aGlzLnJlc2V0T3B0aW9ucygpO1xyXG5cdFx0XHRcdFx0XHR0aGlzLnBvcHVwIS5zaG93KCk7XHJcblx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0dGhpcy5wb3B1cC5zaG93KCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRwdWJsaWMgb25CbHVyKCk6IHZvaWQge1xyXG5cdFx0dGhpcy5mb3JtTW9kZWwubWFya0FzVG91Y2hlZCgpO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIENvbnRyb2wgdGhlIG1lbnUgd2l0aCBrZXlib2FyZCBuYXZpZ2F0aW9uXHJcblx0ICpcclxuXHQgKiBAc2VlIHtAbGluayBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvS2V5Ym9hcmRFdmVudC9rZXkjRXhhbXBsZSB8IEtleWJvYXJkRXZlbnQua2V5fVxyXG5cdCAqIEBzZWUge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9LZXlib2FyZEV2ZW50L2tleS9LZXlfVmFsdWVzIHwgS2V5IFZhbHVlc31cclxuXHQgKlxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHB1YmxpYyBrZXlOYXZpZ2F0ZShldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xyXG5cdFx0c3dpdGNoIChldmVudC5rZXkpIHtcclxuXHRcdFx0Y2FzZSBcIkFycm93RG93blwiOlxyXG5cdFx0XHRjYXNlIFwiRG93blwiOlxyXG5cdFx0XHRjYXNlIFwiQXJyb3dVcFwiOlxyXG5cdFx0XHRjYXNlIFwiVXBcIjpcclxuXHRcdFx0XHRldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcclxuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cdFx0XHRcdHRoaXMub25BcnJvd0Rvd25VcChldmVudCk7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlIFwiQmFja3NwYWNlXCI6XHJcblx0XHRcdGNhc2UgXCJEZWxldGVcIjpcclxuXHRcdFx0Y2FzZSBcIkRlbFwiOlxyXG5cdFx0XHRcdGlmICh0aGlzLm1lbnVTdGF0dXMgPT09ICdoaWRkZW4nKSB7XHJcblx0XHRcdFx0XHR0aGlzLnRvZ2dsZU1lbnUoKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0YnJlYWs7XHJcblx0XHRcdGNhc2UgXCJUYWJcIjpcclxuXHRcdFx0XHQvLyBJZiB0YWJiaW5nIGZyb20gdGhlIHRleHRib3ggdG8gdGhlIGJ1dHRvbiwgb3ZlcnJpZGUgdGhlIHRleHRib3ggYXMgYmVpbmdcclxuXHRcdFx0XHQvLyBtYXJrZWQgdG91Y2hlZCBzbyB3ZSBkb24ndCBzZWUgdGhlIGludmFsaWQgc3RhdGUuIE9ubHkgc2hvdyB0aGUgaW52YWxpZCBzdGF0ZVxyXG5cdFx0XHRcdC8vIHdoZW4gdGFiYmluZyBvdXQgb2YgY29tYm9ib3ggZnJvbSB0aGUgYnV0dG9uIG9yIGJhY2sgdGFiYmluZyBmcm9tIHRoZSB0ZXh0Ym94XHJcblx0XHRcdFx0Ly8gaWYgKGV2ZW50LmtleSA9PT0gJ1RhYicgJiYgZXZlbnQuc3JjRWxlbWVudCAmJiBldmVudC5zcmNFbGVtZW50LnRhZ05hbWUgPT09ICdJTlBVVCcpIHtcclxuXHRcdFx0XHQvLyBcdGlmIChldmVudC5zaGlmdEtleSkge1xyXG5cdFx0XHRcdC8vIFx0XHR0aGlzLnRleHRib3hGb3JtTW9kZWwubWFya0FzVG91Y2hlZCgpO1xyXG5cdFx0XHRcdC8vIFx0XHR0aGlzLmZvcm1Nb2RlbC5tYXJrQXNUb3VjaGVkKCk7XHJcblx0XHRcdFx0Ly8gXHR9IGVsc2Uge1xyXG5cdFx0XHRcdC8vIFx0XHR0aGlzLnRleHRib3hGb3JtTW9kZWwubWFya0FzVW50b3VjaGVkKCk7XHJcblx0XHRcdFx0Ly8gXHR9XHJcblx0XHRcdFx0Ly8gfSBlbHNlIGlmIChldmVudC5rZXkgPT09ICdUYWInICYmIGV2ZW50LnNyY0VsZW1lbnQgJiYgZXZlbnQuc3JjRWxlbWVudC50YWdOYW1lID09PSAnQlVUVE9OJykge1xyXG5cdFx0XHRcdC8vIFx0aWYgKCFldmVudC5zaGlmdEtleSkge1xyXG5cdFx0XHRcdC8vIFx0XHR0aGlzLmZvcm1Nb2RlbC5tYXJrQXNUb3VjaGVkKCk7XHJcblx0XHRcdFx0Ly8gXHR9XHJcblx0XHRcdFx0Ly8gfVxyXG5cclxuXHRcdFx0XHRpZiAodGhpcy5tZW51U3RhdHVzID09PSAndmlzaWJsZScpIHtcclxuXHRcdFx0XHRcdC8vaWYgdGhlIHNlbGVjdGVkIG9wdGlvbiBpcyB0aGUgYWRkIG5ldyBidXR0b24gbGV0IGl0IGZpcmUgYnV0IGRvbid0IGFsbG93XHJcblx0XHRcdFx0XHQvL3RoZSB0YWIgZXZlbnQgdG8gY2FycnkgdGhlbSBmb3J3YXJkIGZyb20gd2hlcmV2ZXIgdGhleSBsYW5kIC0gdGhleSB3b3VsZCBza2lwIHRoZSBmaXJzdCBib3ggb24gdGhlIGFkZCBuZXcgZm9ybVxyXG5cdFx0XHRcdFx0Ly9JbiB0aGUgbm9ybWFsIGNhc2Ugd2Ugd2FudCB0byBhbGxvdyB0aGUgZGVmYXVsdCBiZWhhdmlvciBvciB0aGV5IHdvbid0IGJlIGFibGUgdG8gdGFiIG91dCBvZiB0aGUgY29udHJvbCBhdCBhbGwuXHJcblx0XHRcdFx0XHRpZih0aGlzLmFkZE5ld1NlbGVjdGVkKXtcclxuXHRcdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR0aGlzLmNvbW1pdFNlbGVjdGlvbihldmVudCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBcIkVudGVyXCI6XHJcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuXHJcblx0XHRcdFx0aWYgKHRoaXMubWVudVN0YXR1cyA9PT0gJ3Zpc2libGUnKSB7XHJcblx0XHRcdFx0XHR0aGlzLmNvbW1pdFNlbGVjdGlvbihldmVudCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBcIkVzY2FwZVwiOlxyXG5cdFx0XHRjYXNlIFwiRXNjXCI6XHJcblx0XHRcdFx0aWYgKHRoaXMubWVudVN0YXR1cyA9PT0gJ3Zpc2libGUnKSB7XHJcblx0XHRcdFx0XHQvLyBKdXN0IGNsb3NlIHRoZSBtZW51LCBkbyBub3QgZm9jdXMgdGhlIG5leHQgZWxlbWVudCBvbiB0YWJcclxuXHRcdFx0XHRcdC8vIHVubGVzcyB0aGUgbWVudSBpcyBoaWRkZW5cclxuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gQ2xvc2UgdGhlIG1lbnUgYmVmb3JlIHdlIHJlc2V0IHNlbGVjdGVkSXRlbSBzbyB3ZSBkb24ndCBzZWUgdGhlIGhpZ2hsaWdodCBjaGFuZ2luZ1xyXG5cdFx0XHRcdFx0Ly8gd2hlbiByZXNldCB0aGUgc2VsZWN0ZWQgaXRlbSBiYWNrIHRvIHRoZSBmb3JtTW9kZWxcclxuXHRcdFx0XHRcdHRoaXMudG9nZ2xlTWVudSgpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgXCIgXCI6XHJcblx0XHRcdGNhc2UgXCJTcGFjZWJhclwiOlxyXG5cdFx0XHRcdGlmICh0aGlzLm1lbnVTdGF0dXMgPT09ICdoaWRkZW4nKSB7XHJcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cdFx0XHRcdFx0dGhpcy50b2dnbGVNZW51KCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRpZiAodGhpcy5tZW51U3RhdHVzID09PSAnaGlkZGVuJyAmJiBldmVudC5rZXkgIT09ICdTaGlmdCcpIHtcclxuXHRcdFx0XHRcdHRoaXMudG9nZ2xlTWVudSgpO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBGYWNpbGl0YXRlcyBhZGRpbmcgaXRlbXMgdG8gYSBjb21ib2JveFxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGFkZEZuIEZ1bmN0aW9uIGZyb20gcGFyZW50IHRoYXQgc2hvdWxkIG1ha2UgYW4gQVBJIHJlcXVlc3QgdG8gYWRkIGEgbmV3IGl0ZW0gdG8gdGhlIGNvbWJvYm94J3Mgb3B0aW9uc1xyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHB1YmxpYyBhc3luYyBhZGROZXdJdGVtKGFkZEZuOiAoKSA9PiBQcm9taXNlPHZvaWQ+KSB7XHJcbiAgICAgICAgdGhpcy5wZW5kaW5nID0gdHJ1ZTtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBhZGRGbigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICAvLyBXZSBnYXZlIGl0IG91ciBiZXN0IHRyeSwgc29tZXRoaW5nIGlzIHJlYWxseSB3aGFjaywgc28gbGV0J3MganVzdCBzZXQgdGhlIGVycm9yXHJcbiAgICAgICAgICAgIHRoaXMuc2V0RXJyb3JzKHsgJ2FkZG5ldyc6IHRydWUgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMucGVuZGluZyA9IGZhbHNlO1xyXG4gICAgICAgIHRoaXMudG9nZ2xlTWVudSgpO1xyXG4gICAgfVxyXG5cclxuXHQvKipcclxuXHQgKiBGaWd1cmUgb3V0IHdoZXRoZXIgdGhleSBhcmUgYWRkaW5nIG5ldyBvciBoYXZlIGFuIGl0ZW0gc2VsZWN0ZWQsIGFuZCBjb21taXQgaXQgdG8gdGhlIGZvcm0gbW9kZWxcclxuXHQgKi9cclxuICBwcml2YXRlIGNvbW1pdFNlbGVjdGlvbihldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xyXG5cdFx0aWYgKHRoaXMuYWRkTmV3U2VsZWN0ZWQpIHtcclxuXHRcdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XHJcblx0XHRcdHRoaXMub25BZGROZXcoZXZlbnQpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dGhpcy5zZXRGb3JtTW9kZWxWYWx1ZSh0aGlzLnNlbGVjdGVkSXRlbSk7XHJcblx0XHRcdHRoaXMudG9nZ2xlTWVudSgpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogU2VuZCB0aGUgY3VycmVudCB2YWx1ZSBvZiB0aGUgdGV4dGJveCB0byB0aGUgcGFyZW50IHdoZW4gdGhlIGFkZCBuZXcgYnV0dG9uIGlzXHJcblx0ICogY2xpY2tlZFxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGV2ZW50IEFkZCBuZXcgYnV0dG9uIGNsaWNrIG9yIGVudGVyIGtleSBldmVudFxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHB1YmxpYyBvbkFkZE5ldyhldmVudDogRXZlbnQpOiB2b2lkIHtcclxuXHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xyXG5cdFx0dGhpcy5hZGROZXdTZWxlY3RlZCA9IGZhbHNlO1xyXG5cdFx0dGhpcy5hZGROZXdDbGljay5lbWl0KHRoaXMudGV4dGJveEZvcm1Nb2RlbC52YWx1ZSk7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogTmF2aWdhdGUgdGhlIGRyb3Bkb3duIG1lbnUgdXNpbmcgdXAgYW5kIGRvd24gYXJyb3cga2V5c1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIGV2ZW50IFVwIG9yIGRvd24gYXJyb3cga2V5ZG93biBldmVudFxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHByaXZhdGUgb25BcnJvd0Rvd25VcChldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xyXG5cdFx0c3dpdGNoIChldmVudC5rZXkpIHtcclxuXHRcdFx0Y2FzZSBcIkFycm93RG93blwiOlxyXG5cdFx0XHRjYXNlIFwiRG93blwiOlxyXG5cclxuXHRcdFx0XHRpZiAodGhpcy5zZWxlY3RlZEl0ZW1JbmRleCA9PT0gLTEgJiYgdGhpcy5hZGROZXdCdXR0b24gJiYgIXRoaXMuYWRkTmV3QnV0dG9uLm5hdGl2ZUVsZW1lbnQuaGlkZGVuICYmICF0aGlzLmFkZE5ld1NlbGVjdGVkKSB7XHJcblx0XHRcdFx0XHR0aGlzLmFkZE5ld1NlbGVjdGVkID0gdHJ1ZTtcclxuXHRcdFx0XHR9IGVsc2UgaWYgKHRoaXMuc2VsZWN0ZWRJdGVtSW5kZXggPCB0aGlzLmZpbHRlcmVkT3B0aW9ucy5sZW5ndGggLSAxKSB7XHJcblx0XHRcdFx0XHRpZiAodGhpcy5hZGROZXdTZWxlY3RlZCkge1xyXG5cdFx0XHRcdFx0XHR0aGlzLmFkZE5ld1NlbGVjdGVkID0gZmFsc2U7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHQvL2lmIHRoZSBsYXN0IGl0ZW0gaXMgYSBoZWFkaW5nIGFuZCB3ZSBhcmUgb24gdGhlIHNlY29uZCBsYXN0IGl0ZW0sIHdlIHNob3VsZG4ndCBpbmNyZW1lbnQgdGhlIHNlbGVjdGVkSXRlbUluZGV4IGJlY2F1c2UgdGhhdCB3b3VsZCBzZWxlY3QgdGhlIGhlYWRpbmdcclxuXHRcdFx0XHRcdGlmKCAhKHRoaXMuc2VsZWN0ZWRJdGVtSW5kZXggPT0gdGhpcy5maWx0ZXJlZE9wdGlvbnMubGVuZ3RoIC0gMiAmJiB0aGlzLmZpbHRlcmVkT3B0aW9uc1t0aGlzLnNlbGVjdGVkSXRlbUluZGV4KzFdLmRpc3BsYXkgPT09ICdoZWFkaW5nJykgKSB7XHJcblx0XHRcdFx0XHRcdHRoaXMuc2VsZWN0ZWRJdGVtSW5kZXgrKztcclxuXHRcdFx0XHRcdFx0Ly8gU2tpcCBhbnkgaW4tbWVudSBoZWFkaW5nIGl0ZW1zXHJcblx0XHRcdFx0XHRcdGlmICh0aGlzLnNlbGVjdGVkSXRlbUluZGV4IDwgdGhpcy5maWx0ZXJlZE9wdGlvbnMubGVuZ3RoIC0gMSAmJiB0aGlzLmZpbHRlcmVkT3B0aW9uc1t0aGlzLnNlbGVjdGVkSXRlbUluZGV4XS5kaXNwbGF5ID09PSAnaGVhZGluZycpIHtcclxuXHRcdFx0XHRcdFx0XHR0aGlzLnNlbGVjdGVkSXRlbUluZGV4Kys7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlIFwiQXJyb3dVcFwiOlxyXG5cdFx0XHRjYXNlIFwiVXBcIjpcclxuXHRcdFx0XHRpZiAodGhpcy5zZWxlY3RlZEl0ZW1JbmRleCA9PT0gLTEgJiYgdGhpcy5hZGROZXdCdXR0b24gJiYgIXRoaXMuYWRkTmV3QnV0dG9uLm5hdGl2ZUVsZW1lbnQuaGlkZGVuICYmIHRoaXMuYWRkTmV3U2VsZWN0ZWQpIHtcclxuXHRcdFx0XHRcdHRoaXMuYWRkTmV3U2VsZWN0ZWQgPSBmYWxzZTtcclxuXHRcdFx0XHR9IGVsc2UgaWYgKHRoaXMuc2VsZWN0ZWRJdGVtSW5kZXggPiAtMSkge1xyXG5cdFx0XHRcdFx0aWYgKHRoaXMuc2VsZWN0ZWRJdGVtSW5kZXggPT09IDAgJiYgdGhpcy5hZGROZXdCdXR0b24gJiYgIXRoaXMuYWRkTmV3QnV0dG9uLm5hdGl2ZUVsZW1lbnQuaGlkZGVuKSB7XHJcblx0XHRcdFx0XHRcdHRoaXMuYWRkTmV3U2VsZWN0ZWQgPSB0cnVlO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0dGhpcy5zZWxlY3RlZEl0ZW1JbmRleC0tO1xyXG5cdFx0XHRcdFx0Ly8gU2tpcCBhbnkgaW4tbWVudSBoZWFkaW5nIGl0ZW1zXHJcblx0XHRcdFx0XHRpZiAodGhpcy5zZWxlY3RlZEl0ZW1JbmRleCA+IC0xICYmIHRoaXMuZmlsdGVyZWRPcHRpb25zW3RoaXMuc2VsZWN0ZWRJdGVtSW5kZXhdLmRpc3BsYXkgPT09ICdoZWFkaW5nJykge1xyXG5cdFx0XHRcdFx0XHR0aGlzLnNlbGVjdGVkSXRlbUluZGV4LS07XHJcblxyXG5cdFx0XHRcdFx0XHQvL2lmIHRoZSBzZWxlY3RlZEl0ZW1JbmRleCBpcyAtMSwgdGhhdCBtZWFucyB0aGUgdmVyeSBmaXJzdCBpdGVtIHdhcyBhIGhlYWRpbmcgYW5kIHdlIGp1c3Qgc2tpcHBlZCBvdmVyIGl0LlxyXG5cdFx0XHRcdFx0XHRpZih0aGlzLnNlbGVjdGVkSXRlbUluZGV4ID09IC0xKSB7XHJcblx0XHRcdFx0XHRcdFx0Ly9pZiB0aGVyZSBpcyBhbiBhZGQgbmV3IGJ1dHRvbiB3ZSBzaG91bGQgc2VsZWN0IGl0LiBvdGhlcndpc2Ugd2Ugc2hvdWxkIGxvY2sgdGhlbSBhdCBpbmRleCAxIChyaWdodCBiZWZvcmUgdGhlIGhlYWRpbmcpXHJcblx0XHRcdFx0XHRcdFx0aWYodGhpcy5hZGROZXdCdXR0b24gJiYgIXRoaXMuYWRkTmV3QnV0dG9uLm5hdGl2ZUVsZW1lbnQuaGlkZGVuKSB7XHJcblx0XHRcdFx0XHRcdFx0XHR0aGlzLmFkZE5ld1NlbGVjdGVkID0gdHJ1ZTtcclxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5zZWxlY3RlZEl0ZW1JbmRleCA9IDE7XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9XHJcbiAgICAgICAgICBcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5zZWxlY3RlZEl0ZW0gPSB0aGlzLmZpbHRlcmVkT3B0aW9uc1t0aGlzLnNlbGVjdGVkSXRlbUluZGV4XTtcclxuXHJcblx0XHRpZiAodGhpcy5tZW51U3RhdHVzID09PSAnaGlkZGVuJykge1xyXG5cclxuXHRcdFx0dGhpcy5zZXRGb3JtTW9kZWxWYWx1ZSh0aGlzLnNlbGVjdGVkSXRlbSk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0aGlzLnNjcm9sbE1lbnUoKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cclxuXHJcblx0LyoqXHJcblxyXG5cdCAqIEZpbHRlciBhcnJheSBvZiBvcHRpb25zIGJ5IGxhYmVsIChjb250YWlucylcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBmaWx0ZXJUZXh0IFRoZSB2YWx1ZSBvZiB0ZXh0Ym94IHRoYXQgd2Ugd2lsbCBmaWx0ZXIgb3VyIG9wdGlvbnMgYnlcclxuXHQgKlxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHByaXZhdGUgZmlsdGVyT3B0aW9uc0FycmF5KGZpbHRlclRleHQ6IHN0cmluZyk6IEFycmF5PE1lbnVJdGVtPiB7XHJcblx0XHRsZXQgc2VhcmNoVGV4dCA9IGZpbHRlclRleHQudG9Mb3dlckNhc2UoKTtcclxuXHRcdGlmIChmaWx0ZXJUZXh0ICYmIGZpbHRlclRleHQgIT09ICcnKSB7XHJcblx0XHRcdHJldHVybiB0aGlzLm9wdGlvbnMuZmlsdGVyKGl0ZW0gPT4ge1xyXG5cdFx0XHRcdHJldHVybiBpdGVtLmxhYmVsLnRvTG93ZXJDYXNlKCkuaW5kZXhPZihzZWFyY2hUZXh0KSA+PSAwO1xyXG5cdFx0XHR9KVxyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0cmV0dXJuIHRoaXMub3B0aW9ucztcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBGaW5kIGEgZ2l2ZW4gaXRlbSdzIGluZGV4IGluIHRoZSBmaWx0ZXJlZCBpdGVtcyBhcnJheS5cclxuXHQgKlxyXG5cdCAqIFJldHVybnMgLTEgaWYgbm90IGZvdW5kXHJcblx0ICogQHBhcmFtIGl0ZW0gVGhlIG1hdGNoaW5nIGl0ZW0gdG8gZmluZCBpbiB0aGVcclxuXHQgKiBmaWx0ZXJkT3B0aW9ucyBhcnJheS4gV2lsbCB1c2UgdGhlIHNlbGVjdGVkSXRlbSBpZiBub3RoaW5nIGlzIHBhc3NlZC5cclxuXHQgKiBAbWVtYmVyb2YgQ29tYm9ib3hDb21wb25lbnRcclxuXHQgKi9cclxuXHRwcml2YXRlIGZpbmRTZWxlY3RlZEl0ZW1JbmRleChpdGVtPzogTWVudUl0ZW0pOiBudW1iZXIge1xyXG5cdFx0bGV0IGl0ZW1Ub0ZpbmQgPSBpdGVtID8gaXRlbSA6IHRoaXMuc2VsZWN0ZWRJdGVtO1xyXG5cclxuXHRcdGlmIChpdGVtVG9GaW5kKSB7XHJcblx0XHRcdHJldHVybiB0aGlzLmZpbHRlcmVkT3B0aW9ucy5maW5kSW5kZXgoaXRlbSA9PiB7XHJcblx0XHRcdFx0aWYoaXRlbS5pZCAmJiAoPE1lbnVJdGVtPml0ZW1Ub0ZpbmQpLmlkKSB7XHJcblx0XHRcdFx0XHRyZXR1cm4gaXRlbS5sYWJlbCA9PT0gKDxNZW51SXRlbT5pdGVtVG9GaW5kKS5sYWJlbCAmJiBpdGVtLmlkID09PSAoPE1lbnVJdGVtPml0ZW1Ub0ZpbmQpLmlkXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdHJldHVybiBpdGVtLmxhYmVsID09PSAoPE1lbnVJdGVtPml0ZW1Ub0ZpbmQpLmxhYmVsO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIC0xO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFJlYWN0IHRvIG91ciBmb3JtTW9kZWwgY2hhbmdpbmdcclxuXHQgKlxyXG5cdCAqIFRoZSBmb3JtTW9kZWwgcmVwcmVzZW50cyB0aGUgY3VycmVudGx5IHNlbGVjdGVkIE1vZGVsSXRlbVxyXG5cdCAqIFdoZW4gY2hhbmdlZCwgc2V0IHRoZSB2YWx1ZSBvZiB0aGUgVGV4dGJveENvbXBvbmVudCBhbmRcclxuXHQgKiBmaW5kIGluZGV4IG9mIGl0ZW0gaW4gb3B0aW9ucyBsaXN0LlxyXG5cdCAqXHJcblx0ICogQG1lbWJlcm9mIENvbWJvYm94Q29tcG9uZW50XHJcblx0ICovXHJcblx0cHJpdmF0ZSBmb3JtTW9kZWxDaGFuZ2VkKGRhdGE/OiBNZW51SXRlbSk6IHZvaWQge1xyXG5cdFx0dGhpcy5zeW5jaHJvbml6ZURpc2FibGVkQXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGlmIChkYXRhKSB7XHJcblx0XHRcdHRoaXMudGV4dGJveEZvcm1Nb2RlbC5zZXRWYWx1ZShkYXRhLmxhYmVsKTtcclxuXHJcblx0XHRcdHRoaXMuc2VsZWN0ZWRJdGVtSW5kZXggPSB0aGlzLmZpbmRTZWxlY3RlZEl0ZW1JbmRleChkYXRhKTtcclxuXHRcdFx0aWYgKHRoaXMuc2VsZWN0ZWRJdGVtSW5kZXggPj0gMCkge1xyXG5cdFx0XHRcdHRoaXMuc2VsZWN0ZWRJdGVtID0gdGhpcy5maWx0ZXJlZE9wdGlvbnNbdGhpcy5zZWxlY3RlZEl0ZW1JbmRleF07XHJcblx0XHRcdH1cclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdC8vVGhlIGhvc3Qgd2lwZWQgb3V0IHRoZSBkYXRhIGV4dGVybmFsbHksIGNsZWFyIHRoZSB0ZXh0Ym94IGFuZCB0aGUgdHJhY2tpbmcgc3RhdGVcclxuXHRcdFx0dGhpcy50ZXh0Ym94Rm9ybU1vZGVsLnJlc2V0KCk7XHJcblx0XHRcdHRoaXMuY2xlYXJTZWxlY3RlZEl0ZW0oKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBTY3JvbGwgdGhlIG1lbnUgaWYgdGhlIGN1cnJlbnQgc2VsZWN0ZWRJdGVtSW5kZXggaXMgb3V0IG9mIHZpZXdcclxuXHQgKlxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHByaXZhdGUgc2Nyb2xsTWVudShrbm93bkluZGV4PzogbnVtYmVyKTogdm9pZCB7XHJcblx0XHRpZiAodGhpcy5maWx0ZXJlZE9wdGlvbnMubGVuZ3RoID4gMCkge1xyXG5cdFx0XHQvLyBVcGRhdGUgdGhlIHNlbGVjdGVkSXRlbUluZGV4IGluIGNhc2Ugb3VyIG9wdGlvbnMgY2hhbmdlZFxyXG5cdFx0XHR0aGlzLnNlbGVjdGVkSXRlbUluZGV4ID0ga25vd25JbmRleCA9PT0gdW5kZWZpbmVkID8gdGhpcy5maW5kU2VsZWN0ZWRJdGVtSW5kZXgoKSA6IGtub3duSW5kZXg7XHJcblxyXG5cdFx0XHRpZiAodGhpcy5zZWxlY3RlZEl0ZW1JbmRleCA+IC0xICYmIHRoaXMuc2VsZWN0ZWRJdGVtKSB7XHJcblx0XHRcdFx0Ly8gVGhlIG1lbnUgY29tcG9uZW50IHdpbGwgYXV0b21hdGljYWxseSBnZW5lcmF0ZSBpZHMgZm9yIHRoZSBtZW51IGl0ZW1zIGlmIHRoZXkgZG9udCBoYXZlIHRoZW0sXHJcblx0XHRcdFx0Ly8gc28gdGhleSBuZWVkIHRvIGJlIGFjY291bnRlZCBmb3IgaGVyZSBzaW5jZSB0aGUgY29tYm9ib3ggZG9lc24ndCBrbm93IGFib3V0IHRob3NlIGlkc1xyXG5cdFx0XHRcdGxldCBpdGVtU2VsZWN0b3IgPSB0aGlzLnNlbGVjdGVkSXRlbS5pZCA/IGAjJHt0aGlzLnNlbGVjdGVkSXRlbS5pZH1gIDogYCMke3RoaXMuaWR9X21lbnVfaXRlbSR7dGhpcy5zZWxlY3RlZEl0ZW1JbmRleH1gO1xyXG5cclxuXHRcdFx0XHQvL3RyaWdnZXIgdGhlIHNjcm9sbGluZyBhZnRlciBhIHRpY2sgdG8gYWxsb3cgdGhlIG1lbnUgdG8gYmUgdXAgdG8gZGF0ZSAoYW5kIHBlbmRpbmcgbWFzayBjbGVhcmVkKSBiZWZvcmUgbWVhc3VyaW5nXHJcblx0XHRcdFx0c2V0VGltZW91dCgoKT0+e1xyXG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxTZXJ2aWNlLnNjcm9sbEl0ZW1DZW50ZXJlZChgIyR7dGhpcy5pZH1fbWVudV9saXN0YCwgaXRlbVNlbGVjdG9yKTtcclxuXHRcdFx0XHR9LCAwKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHR0aGlzLnNlbGVjdGVkSXRlbSA9IG51bGw7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBTZWFyY2gvRmlsdGVyIGJhc2VkIG9uIHRleHRib3ggaW5wdXRcclxuXHQgKiBOT1RFOiBzbyBhcyBub3QgdG8gcmVjZWl2ZSBhIG5vdGlmaWNhdGlvbiBvbiBldmVyeSBrZXkgZXZlbnQsIHdlIHN1Z2dlc3QgeW91IGRlYm91bmNlIHlvdXJcclxuXHQgKiBzdWJzY3JpcHRpb25cclxuXHQgKiBAc2VlIHtAbGluayBodHRwOi8vcmVhY3RpdmV4LmlvL3J4anMvY2xhc3MvZXM2L09ic2VydmFibGUuanN+T2JzZXJ2YWJsZS5odG1sI2luc3RhbmNlLW1ldGhvZC1kZWJvdW5jZVRpbWUgfCBPYnNlcnZhYmxlLmRlYm91bmNlVGltZX1cclxuXHQgKlxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHByaXZhdGUgc2VhcmNoQW5kRmlsdGVyKHNlYXJjaFRleHQ/OiBzdHJpbmcpOiB2b2lkIHtcclxuXHJcblx0XHQvLyBhbHdheXMgZW1pdFxyXG5cdFx0dGhpcy5zZWFyY2guZW1pdChzZWFyY2hUZXh0KTtcclxuXHJcblx0XHQvLyBkbyBpbnRlcm5hbCBmaWx0ZXJpbmcgaWYgbm8gb25lJ3Mgc3Vic2NyaWJlZCB0byBvdXIgc2VhcmNoIGVtaXR0ZXJcclxuXHRcdGlmICh0aGlzLnNlYXJjaC5vYnNlcnZlcnMubGVuZ3RoID09PSAwICYmIHNlYXJjaFRleHQgIT09IHVuZGVmaW5lZCkge1xyXG5cdFx0XHR0aGlzLnJlc2V0T3B0aW9ucyh0aGlzLmZpbHRlck9wdGlvbnNBcnJheShzZWFyY2hUZXh0KSk7XHJcblxyXG5cdFx0XHRpZiAodGhpcy5hZGROZXdTZWxlY3RlZCAmJiAhdGhpcy5hZGROZXdCdXR0b24pIHtcclxuXHRcdFx0XHR0aGlzLmFkZE5ld1NlbGVjdGVkID0gZmFsc2U7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBTZXQge0BsaW5rIGZvcm1Nb2RlbCB9J3MgdmFsaWRhdGlvbiBlcnJvcnMgZXF1YWwgdG8gdGhlIGludGVybmFsIHRleHRib3gncy5cclxuXHQgKlxyXG5cdCAqIFdoZW4gdGhlIGludGVybmFsIHRleHRib3ggaXMgaW52YWxpZCwgbmVlZCB0byBzZXQgdGhpcyBjb250cm9sJ3NcclxuXHQgKiBlcnJvcnMgYmVjYXVzZSB3ZSBhcmUgdXNpbmcgb3VyIG93biBsYWJlbCwgbm90IFRleHRib3hDb250cm9sJ3MuXHJcblx0ICogV2UgdXNlIG91ciBvd24gbGFiZWwgc28gbGFiZWwgdGV4dCB3aWxsIHdyYXAgYXQgdGhlIGVuZCBvZiB0aGUgYnV0dG9uLFxyXG5cdCAqIG5vdCBhdCB0aGUgZW5kIG9mIHRoZSB0ZXh0Ym94LlxyXG5cdCAqXHJcblx0ICogQG1lbWJlcm9mIENvbWJvYm94Q29tcG9uZW50XHJcblx0ICovXHJcblx0cHJpdmF0ZSBzZXRGb3JtTW9kZWxWYWxpZGF0aW9uRXJyb3JzKGRhdGE/OiBhbnkpOiB2b2lkIHtcclxuXHRcdGlmICh0aGlzLnRleHRib3hGb3JtTW9kZWwuaW52YWxpZCkge1xyXG5cdFx0XHR0aGlzLmZvcm1Nb2RlbC5zZXRFcnJvcnModGhpcy50ZXh0Ym94Rm9ybU1vZGVsLmVycm9ycyk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0aGlzLmZvcm1Nb2RlbC5zZXRFcnJvcnMobnVsbCk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBVcGRhdGUgdGhlIGZvcm0gbW9kZWwgdmFsdWUgd2l0aCB0aGUgc2VsZWN0ZWQgaXRlbSBvciByZXNldCBmb3JtIG1vZGVsIHZhbHVlIGlmIGl0ZW0gaXMgbnVsbFxyXG5cdCAqXHJcblx0ICogQG1lbWJlcm9mIENvbWJvYm94Q29tcG9uZW50XHJcblx0ICovXHJcblx0cHJpdmF0ZSBzZXRGb3JtTW9kZWxWYWx1ZShpdGVtOiBNZW51SXRlbSB8IG51bGwpOiB2b2lkIHtcclxuXHRcdHRoaXMudGV4dGJveEZvcm1Nb2RlbC5zZXRWYWx1ZShpdGVtID8gaXRlbS5sYWJlbCA6ICcnKTtcclxuXHRcdHRoaXMuZm9ybU1vZGVsLnNldFZhbHVlKGl0ZW0pO1xyXG5cdFx0dGhpcy5mb3JtTW9kZWwubWFya0FzRGlydHkoKTtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBTZXQgdmFsaWRhdG9ycyBvbiB0aGUge0BzZWUgdGV4dGJveEZvcm1Nb2RlbCB9XHJcblx0ICpcclxuXHQgKiBWYWxpZGF0b3JzIGFyZSBjdXJyZW50bHkgc2V0IGJhc2VkIG9uIHRoZSB7QHNlZSBtYXhsZW5ndGggfSxcclxuXHQgKiB7QHNlZSBtaW5sZW5ndGggfSwgYW5kIHtAc2VlIHJlcXVpcmVkIH0gaW5wdXRzLiAgVGhpcyB3b3JrcyB3ZWxsXHJcblx0ICogd2l0aCB7QHNlZSBUZXh0Ym94Q29tcG9uZW50IH0sIHdoaWNoIG5lZWRzIHRoZXNlIGlucHV0cyB0byBhcHBseVxyXG5cdCAqIHRoZSBwcm9wZXIgYXR0cmlidXRlcyB0byBpdHMgaW5wdXRzLlxyXG5cdCAqXHJcblx0ICogQSBmdXR1cmUgcmVsZWFzZSBvZiBBbmd1bGFyIHdpbGwgc3VwcG9zZWRseSBhZGQgdGhlc2UgYXR0cmlidXRlc1xyXG5cdCAqIGZvciB5b3UsIHdoaWNoIHdpbGwgZWxpbWluYXRlIHRoZSBuZWVkIGZvciBUZXh0Ym94Q29tcG9uZW50IHRvIGhhdmVcclxuXHQgKiBzdWNoIGlucHV0cy4gIFRoaXMgY29tcG9uZW50LCBob3dldmVyLCB3aWxsIHN0aWxsIG5lZWQgdGhlc2UgaW5wdXRzXHJcblx0ICogYXMgdGhlcmUgaXMgbm8gY3VycmVudCB3YXkgdG8ga25vdyB3aGljaCB2YWxpZGF0b3JzIGFyZSBhcHBsaWVkIHRvIGl0XHJcblx0ICogZnJvbSBpdHMgcGFyZW50IFZpZXcgQ29tcG9uZW50LlxyXG5cdCAqXHJcblx0ICpcclxuXHQgKiBAbWVtYmVyb2YgQ29tYm9ib3hDb21wb25lbnRcclxuXHQgKi9cclxuXHRwcml2YXRlIHNldFRleHRib3hGb3JtTW9kZWxWYWxpZGF0b3JzKCk6IHZvaWQge1xyXG5cdFx0bGV0IHZhbGlkYXRvcnM6IEFycmF5PFZhbGlkYXRvckZuPiA9IFtdO1xyXG5cclxuXHRcdGlmICh0aGlzLnJlcXVpcmVkKSB7XHJcblx0XHRcdHZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3JzLnJlcXVpcmVkKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5taW5sZW5ndGgpIHtcclxuXHRcdFx0dmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvcnMubWluTGVuZ3RoKHRoaXMubWlubGVuZ3RoKSk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKHRoaXMubWF4bGVuZ3RoKSB7XHJcblx0XHRcdHZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3JzLm1heExlbmd0aCh0aGlzLm1heGxlbmd0aCkpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudGV4dGJveEZvcm1Nb2RlbC5zZXRWYWxpZGF0b3JzKHZhbGlkYXRvcnMpO1xyXG5cclxuXHRcdHRoaXMudGV4dGJveEZvcm1Nb2RlbC51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KCk7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogS2VlcCB0ZXh0Ym94J3MgZGlzYWJsZWQgc3RhdHVzIGluLXN5bmMgd2l0aCBjb21ib2JveCdzXHJcblx0ICpcclxuXHQgKiB7QGxpbmsgVGV4dGJveENvbXBvbmVudH0gZ2V0cyBpdHMgZGlzYWJsZWQgc3RhdHVzIGZyb20gaXRzIHtAbGluayBGb3JtQ29udHJvbH1cclxuXHQgKlxyXG5cdCAqIEBtZW1iZXJvZiBDb21ib2JveENvbXBvbmVudFxyXG5cdCAqL1xyXG5cdHByaXZhdGUgc3luY2hyb25pemVEaXNhYmxlZEF0dHJpYnV0ZXMoKTogdm9pZCB7XHJcblx0XHRpZiAodGhpcy5mb3JtTW9kZWwuZGlzYWJsZWQgIT09IHRoaXMudGV4dGJveEZvcm1Nb2RlbC5kaXNhYmxlZCkge1xyXG5cdFx0XHRpZiAodGhpcy5mb3JtTW9kZWwuZGlzYWJsZWQpIHtcclxuXHRcdFx0XHR0aGlzLnRleHRib3hGb3JtTW9kZWwuZGlzYWJsZSgpO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHRoaXMudGV4dGJveEZvcm1Nb2RlbC5lbmFibGUoKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIElmIHRoZSBmb3JtTW9kZWwgdmFsdWUgYW5kIHRleHRib3ggdmFsdWUgZG8gbm90IG1hdGNoLCByZXNldCB0aGUgdGV4dGJveCBhbmQgc2VsZWN0ZWRJdGVtIHRvXHJcblx0ICogdGhlIGZvcm1Nb2RsZSB2YWx1ZS4gSWYgdGhlcmUgaXMgbm8gZm9ybU1vZGVsIHZhbHVlLCBtYWtlIHN1cmUgd2UgY2xlYXIgdGhlIHRleHRib3guIFJlc2V0IHRoZVxyXG5cdCAqIGZpbHRlcmVkT3B0aW9ucyB0byB0aGUgZnVsbCBsaXN0IGFuZCB1cGRhdGUgdGhlIHNlbGVjdGVkSXRlbUluZGV4XHJcblx0ICpcclxuXHQgKi9cclxuXHRwcml2YXRlIHN5bmNNb2RlbFZhbHVlcygpOiB2b2lkIHtcclxuXHRcdC8vIElmIHRoZXJlIGlzIGEgZm9ybU1vZGVsIHZhbHVlLCByZXNldCB0aGUgc2VsZWN0ZWQgaXRlbS4gSWYgdGhlcmUgaXNuJ3QsIG1ha2VcclxuXHRcdC8vIHN1cmUgd2UgY2xlYXIgdGhlIHRleHRib3hcclxuXHRcdGlmICh0aGlzLmZvcm1Nb2RlbC52YWx1ZSAmJiB0aGlzLmZvcm1Nb2RlbC52YWx1ZS5sYWJlbCAhPT0gdGhpcy50ZXh0Ym94Rm9ybU1vZGVsLnZhbHVlKSB7XHJcblx0XHRcdHRoaXMudGV4dGJveEZvcm1Nb2RlbC5zZXRWYWx1ZSh0aGlzLmZvcm1Nb2RlbC52YWx1ZS5sYWJlbCk7XHJcblx0XHR9IGVsc2UgaWYgKCF0aGlzLmZvcm1Nb2RlbC52YWx1ZSkge1xyXG5cdFx0XHR0aGlzLnRleHRib3hGb3JtTW9kZWwuc2V0VmFsdWUoJycpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFNlYXJjaCBhbmQgZmlsdGVyIHRoZSBvcHRpb25zIGxpc3Qgd2hlbiB0aGUgdmFsdWUgb2YgdGhlIHRleHRib3ggaW5wdXQgY2hhbmdlcy4gSWYgYWRkTmV3IGlzXHJcblx0ICogc2V0IGFsc28gY2hlY2sgZm9yIG1hdGNoZXMgaW4gb3VyIGZpbHRlcmVkT3B0aW9ucyB0byBjb25kaXRpb25hbGx5IHNob3cgYW5kIGhpZGUgdGhlIGFkZCBuZXdcclxuXHQgKiBidXR0b25cclxuXHQgKlxyXG5cdCAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvRXZlbnRzL2lucHV0XHJcblx0ICovXHJcblx0cHVibGljIHRleHRib3hWYWx1ZUNoYW5nZWQoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XHJcblx0XHR0aGlzLnNlYXJjaEFuZEZpbHRlcih0aGlzLnRleHRib3hGb3JtTW9kZWwudmFsdWUpO1xyXG5cclxuXHRcdGlmICh0aGlzLnRleHRib3hGb3JtTW9kZWwudmFsdWUgPT09ICcnKSB7XHJcblx0XHRcdHRoaXMuY2xlYXJTZWxlY3RlZEl0ZW0oKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5hZGROZXcpIHtcclxuXHRcdFx0bGV0IG1hdGNoID0gdGhpcy5maWx0ZXJlZE9wdGlvbnMuZmluZCgob3B0aW9uKSA9PiB7XHJcblx0XHRcdFx0cmV0dXJuIG9wdGlvbi5sYWJlbC50b0xvd2VyQ2FzZSgpID09PSB0aGlzLnRleHRib3hGb3JtTW9kZWwudmFsdWUudG9Mb3dlckNhc2UoKTtcclxuXHRcdFx0fSk7XHJcblx0XHRcdHRoaXMuZm91bmRNYXRjaCA9IG1hdGNoID8gdHJ1ZSA6IGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFVwZGF0ZSB0aGUgcG9wdXAgbWVudSBwb3NpdGlvbiB3aGVuIGlucHV0IHZhbHVlIGNoYW5nZXNcclxuXHRcdGlmICh0aGlzLnBvcHVwKSB7XHJcblx0XHRcdHRoaXMucG9wdXAudXBkYXRlKCk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIGNsZWFyU2VsZWN0ZWRJdGVtKCk6IHZvaWQge1xyXG5cdFx0dGhpcy5zZWxlY3RlZEl0ZW0gPSBudWxsO1xyXG5cdFx0dGhpcy5zZWxlY3RlZEl0ZW1JbmRleCA9IC0xO1xyXG5cdH1cclxuXHJcblx0LyoqUmVjb21wdXRlIHdoYXQgdGhlIHBsYWNlaG9sZGVyIHNob3VsZCBiZSBiYXNlZCBvbiB3aGV0aGVyIHRoZSB1c2VyIHByb3ZpZGVkIG9uZSBhbmQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIGFkZE5ldyBpbnB1dCAqL1xyXG5cdHByaXZhdGUgdXBkYXRlUGxhY2Vob2xkZXJUZXh0KCl7XHJcblx0XHRpZiAodGhpcy5wbGFjZWhvbGRlcikge1xyXG5cdFx0XHR0aGlzLmVmZmVjdGl2ZVBsYWNlaG9sZGVyID0gdGhpcy50cmFuc2xhdGUuaW5zdGFudCh0aGlzLnBsYWNlaG9sZGVyKTtcclxuXHRcdH0gZWxzZSBpZiAodGhpcy5hZGROZXcpIHtcclxuXHRcdFx0dGhpcy5lZmZlY3RpdmVQbGFjZWhvbGRlciA9IHRoaXMuY2hvb3NlT3JBZGRQbGFjZWhvbGRlcjtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHRoaXMuZWZmZWN0aXZlUGxhY2Vob2xkZXIgPSB0aGlzLmNob29zZVBsYWNlaG9sZGVyO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqRmluZCB0aGUgb3B0aW9uIHdlIHdhbnQgdG8gYmUgdGhlIGRlZmF1bHQgc2VsZWN0aW9uLiBJZiB0aGVyZSBpcyBhbiBleGFjdCBtYXRjaCwgdXNlIHRoYXRcclxuXHQgKiBvdGhlcndpc2UgaWYgdGhlcmUgYXJlIGl0ZW1zLCByZXR1cm4gemVybyB0byBpbmRpY2F0ZSB0aGUgZmlyc3QgaXRlbS4gT3RoZXJ3aXNlIHJldHVybiAtMVxyXG5cdCAqIHRvIGluZGljYXRlIG5vIHNlbGVjdGlvblxyXG5cdCAqL1xyXG5cdHByaXZhdGUgZmluZERlZmF1bHRTZWxlY3Rpb25JbmRleChvcHRpb25zOiBNZW51SXRlbVtdLCBzZWFyY2hUZXh0OiBzdHJpbmcpOiBudW1iZXIge1xyXG5cdFx0bGV0IGluZGV4ID0gLTE7XHJcblxyXG5cdFx0aWYob3B0aW9ucyAmJiBvcHRpb25zLmxlbmd0aCl7XHJcblx0XHRcdGluZGV4ID0gb3B0aW9ucy5maW5kSW5kZXgob3B0aW9uPT5vcHRpb24gIT0gbnVsbCAmJiBvcHRpb24uZGlzcGxheSAhPT0gJ2hlYWRpbmcnKTtcclxuXHRcdFx0XHJcblx0XHRcdGlmKHNlYXJjaFRleHQpe1xyXG5cdFx0XHRcdHNlYXJjaFRleHQgPSBzZWFyY2hUZXh0LnRvTG93ZXJDYXNlKCkudHJpbSgpO1xyXG5cdFx0XHRcdGxldCBleGFjdE1hdGNoSW5kZXggPSBvcHRpb25zLmZpbmRJbmRleChvcHRpb249Pm9wdGlvbi5sYWJlbC50b0xvd2VyQ2FzZSgpID09IHNlYXJjaFRleHQgJiYgb3B0aW9uLmRpc3BsYXkgIT09ICdoZWFkaW5nJyk7XHJcblx0XHRcdFx0aWYoZXhhY3RNYXRjaEluZGV4ID49MCl7XHJcblx0XHRcdFx0XHRpbmRleCA9IGV4YWN0TWF0Y2hJbmRleDtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdHJldHVybiBpbmRleDtcclxuXHR9XHJcblxyXG59XHJcbiIsIjxkaXYgY2xhc3M9XCJjb250cm9sIGNvbnRyb2wtbGFiZWwte3tsYWJlbFBvc2l0aW9ufX1cIlxyXG4gICAgIFtuZ0NsYXNzXT1cInsnb3Blbic6IG1lbnVTdGF0dXMgPT09ICd2aXNpYmxlJyxcclxuICAgICAgICAgICAgICAgICAnaW52YWxpZCc6IGZvcm1Nb2RlbC50b3VjaGVkICYmIGZvcm1Nb2RlbC5pbnZhbGlkLFxyXG4gICAgICAgICAgICAgICAgICdoYXMtaWNvbic6ICh0ZW1wbGF0ZVR5cGUgPT09ICdpY29uQW5kTGFiZWwnICYmIGZvcm1Nb2RlbC52YWx1ZSAmJiBmb3JtTW9kZWwudmFsdWUuaWNvbiAmJiBmb3JtTW9kZWwudmFsdWUubGFiZWwgPT09IHRleHRib3hGb3JtTW9kZWwudmFsdWUpLFxyXG4gICAgICAgICAgICAgICAgICdpcy1yZWFkb25seSc6IHJlYWRvbmx5LFxyXG4gICAgICAgICAgICAgICAgICdpcy1kaXNhYmxlZCc6IGZvcm1Nb2RlbC5kaXNhYmxlZCxcclxuICAgICAgICAgICAgICAgICAnaXMtYWx3YXlzLW9wZW4nOiBhbHdheXNPcGVufVwiPlxyXG5cclxuICA8bGFiZWwgKm5nSWY9XCJsYWJlbFwiIG5nUHJlc2VydmVXaGl0ZXNwYWNlcz5cclxuICAgICAgPHNwYW4+e3tsYWJlbCB8IHRyYW5zbGF0ZX19PC9zcGFuPlxyXG4gICAgICA8c3BhbiAqbmdJZj1cInZhbGlkYXRpb25FcnJvcnMubGVuZ3RoID4gMCAmJiBmb3JtTW9kZWwudG91Y2hlZCAmJiBmb3JtTW9kZWwuaW52YWxpZFwiPnt7dmFsaWRhdGlvbkVycm9yc319PC9zcGFuPlxyXG4gIDwvbGFiZWw+XHJcblxyXG4gIDxuZy1jb250YWluZXIgKm5nSWY9XCJhbHdheXNPcGVuOyBlbHNlIHBvcHVwVGFyZ2V0XCI+XHJcbiAgICA8ZGl2IGNsYXNzPVwidGV4dGJveC1ncm91cCBjb250cm9sLWlucHV0XCIgW25nQ2xhc3NdPVwidGV4dGJveEVsZW1lbnRDbGFzc2VzXCI+XHJcbiAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJ0ZXh0Ym94XCI+PC9uZy1jb250YWluZXI+XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZmlsdGVyZWRPcHRpb25zLmxlbmd0aCA+IDAgfHwgdGV4dGJveEZvcm1Nb2RlbC52YWx1ZVwiPlxyXG4gICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiZHJvcGRvd25tZW51XCI+PC9uZy1jb250YWluZXI+XHJcbiAgICA8L25nLWNvbnRhaW5lcj5cclxuICA8L25nLWNvbnRhaW5lcj5cclxuPC9kaXY+XHJcblxyXG48bmctdGVtcGxhdGUgI3BvcHVwVGFyZ2V0PlxyXG4gIDxkaXYgY2xhc3M9XCJ0ZXh0Ym94LWdyb3VwIGNvbnRyb2wtaW5wdXRcIiBbbmdDbGFzc109XCJ0ZXh0Ym94RWxlbWVudENsYXNzZXNcIiAqZWNQb3B1cD1cImRyb3Bkb3dubWVudVwiPlxyXG4gICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cInRleHRib3hcIj48L25nLWNvbnRhaW5lcj5cclxuICA8L2Rpdj5cclxuPC9uZy10ZW1wbGF0ZT5cclxuXHJcbjxuZy10ZW1wbGF0ZSAjdGV4dGJveD5cclxuICA8aSBjbGFzcz1cImVjLWljb24ge3tmb3JtTW9kZWwudmFsdWU/Lmljb259fVwiPjwvaT5cclxuXHJcbiAgICA8ZWMtdGV4dGJveCBjbGFzcz1cInRleHRib3gtZ3JvdXAtaW5wdXQgbWItMFwiXHJcbiAgICAgICAgICAgICAgICAjdGV4dGJveFxyXG4gICAgICAgICAgICAgICAgW2lkXT1cImlkXCJcclxuICAgICAgICAgICAgICAgIFthdXRvZm9jdXNdPVwiYXV0b2ZvY3VzXCJcclxuICAgICAgICAgICAgICAgIFtmb3JtTW9kZWxdPVwidGV4dGJveEZvcm1Nb2RlbFwiXHJcbiAgICAgICAgICAgICAgICBbbWF4bGVuZ3RoXT1cIm1heGxlbmd0aFwiXHJcbiAgICAgICAgICAgICAgICBbbWlubGVuZ3RoXT1cIm1pbmxlbmd0aFwiXHJcbiAgICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiZWZmZWN0aXZlUGxhY2Vob2xkZXJcIlxyXG4gICAgICAgICAgICAgICAgW3JlcXVpcmVkXT1cInJlcXVpcmVkXCJcclxuICAgICAgICAgICAgICAgIFt0YWJpbmRleF09XCJ0YWJpbmRleFwiXHJcbiAgICAgICAgICAgICAgICBbcmVhZG9ubHldPVwicmVhZG9ubHlcIlxyXG4gICAgICAgICAgICAgICAgKGlucHV0KT1cInRleHRib3hWYWx1ZUNoYW5nZWQoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgICAoa2V5ZG93bik9XCJrZXlOYXZpZ2F0ZSgkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgIChmb2N1c291dCk9XCJvbkJsdXIoKVwiXHJcbiAgICAgICAgICAgICAgICBbdXBwZXJDYXNlXT1cInVwcGVyQ2FzZVwiXHJcbiAgICAgICAgICAgICAgICBbcGVuZGluZ109XCJwZW5kaW5nICYmIGFsd2F5c09wZW5cIlxyXG4gICAgICAgICAgICAgICAgW2F1dG9jb21wbGV0ZV09XCInb2ZmJ1wiPjwvZWMtdGV4dGJveD5cclxuXHJcbiAgICA8ZWMtYnV0dG9uIGNsYXNzPVwidGV4dGJveC1ncm91cC1idG4tcmlnaHRcIlxyXG4gICAgICAgICAgICAgICAqbmdJZj1cIiFoaWRlVG9nZ2xlQnV0dG9uXCJcclxuICAgICAgICAgICAgICAgW2lkXT1cImlkICsgJ19idXR0b24nXCJcclxuICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImZvcm1Nb2RlbC5kaXNhYmxlZFwiXHJcbiAgICAgICAgICAgICAgIGljb249XCJpY29uLWNhcmV0LWRvd25cIlxyXG4gICAgICAgICAgICAgICBbdGFiaW5kZXhdPVwiLTFcIlxyXG4gICAgICAgICAgICAgICB0eXBlPVwic2Vjb25kYXJ5XCJcclxuICAgICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZU1lbnUoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgIChrZXlkb3duKT1cImtleU5hdmlnYXRlKCRldmVudClcIj48L2VjLWJ1dHRvbj5cclxuPC9uZy10ZW1wbGF0ZT5cclxuXHJcbjxuZy10ZW1wbGF0ZSAjZHJvcGRvd25tZW51PlxyXG4gIDxkaXYgY2xhc3M9XCJwb3B1cFwiXHJcbiAgICAgICBlY092ZXJsYXlcclxuICAgICAgIFtzdGF0dXNdPVwicGVuZGluZyAmJiAhYWx3YXlzT3BlbiA/ICdwZW5kaW5nJyA6ICdoYXNEYXRhJ1wiPlxyXG5cclxuICAgIDxidXR0b24gY2xhc3M9XCJhZGQtbmV3XCJcclxuICAgICAgICAgICAgaWQ9XCJ7e2lkfX1fYWRkTmV3XCJcclxuICAgICAgICAgICAgI2FkZE5ld0J1dHRvblxyXG4gICAgICAgICAgICBbY2xhc3MuaXMtc2VsZWN0ZWRdPVwiYWRkTmV3U2VsZWN0ZWRcIlxyXG4gICAgICAgICAgICAqbmdJZj1cImFkZE5ld1wiXHJcbiAgICAgICAgICAgIFtoaWRkZW5dPVwiZm91bmRNYXRjaCB8fCAoYWRkTmV3ID09PSAnZHluYW1pYycgJiYgKCF0ZXh0Ym94Rm9ybU1vZGVsLnZhbHVlIHx8IChmb3JtTW9kZWwudmFsdWUgJiYgdGV4dGJveEZvcm1Nb2RlbC52YWx1ZSA9PT0gZm9ybU1vZGVsLnZhbHVlLmxhYmVsKSkpXCJcclxuXHJcbiAgICAgICAgICAgIChjbGljayk9XCJvbkFkZE5ldygkZXZlbnQpXCI+XHJcbiAgICAgIDxzcGFuIGNsYXNzPVwiYWRkLW5ldy1sYWJlbCBlYy11dGlsLXRydW5jYXRlXCI+XHJcbiAgICAgICAgPHNwYW4gKm5nSWY9XCJhZGROZXcgPT09ICdzdGF0aWMnIHx8IGFkZE5ldyA9PT0gdHJ1ZVwiIHRyYW5zbGF0ZT5BZGQgbmV3Li4uPC9zcGFuPlxyXG4gICAgICAgIDxzcGFuICpuZ0lmPVwiYWRkTmV3ID09PSAnZHluYW1pYydcIj57eydBZGQnIHwgdHJhbnNsYXRlfX0gPHN0cm9uZyBjbGFzcz1cImVjLXV0aWwtdHJ1bmNhdGVcIiBbbmdDbGFzc109XCJ7J3RleHQtdXBwZXJjYXNlJzogdXBwZXJDYXNlfVwiPnt7dGV4dGJveEZvcm1Nb2RlbC52YWx1ZX19PC9zdHJvbmc+PC9zcGFuPlxyXG4gICAgICA8L3NwYW4+XHJcbiAgICAgIDxpIGNsYXNzPVwiZWMtaWNvbiBpY29uLWFkZFwiPjwvaT5cclxuICAgIDwvYnV0dG9uPlxyXG5cclxuICAgIDxlYy1tZW51IGlkPVwie3tpZH19X21lbnVcIlxyXG4gICAgICAgICAgICAgW2NsYXNzLmJvcmRlci10b3AtMF09XCIhZmlsdGVyZWRPcHRpb25zLmxlbmd0aCAmJiBoaWRlTm9NYXRjaGVzXCJcclxuICAgICAgICAgICAgIFtuZ0NsYXNzXT1cIm1lbnVFbGVtZW50Q2xhc3Nlc1wiXHJcbiAgICAgICAgICAgICBbdGVtcGxhdGVUeXBlXT1cInRlbXBsYXRlVHlwZVwiXHJcbiAgICAgICAgICAgICBbY3VzdG9tTWVudVRlbXBsYXRlXT1cImN1c3RvbU1lbnVUZW1wbGF0ZVwiXHJcbiAgICAgICAgICAgICBbc2hvd05vSXRlbXNdPVwiIWhpZGVOb01hdGNoZXNcIlxyXG4gICAgICAgICAgICAgW25vRGF0YVRleHRdPVwibm9NYXRjaGVzVGV4dFwiXHJcbiAgICAgICAgICAgICBbaXRlbXNdPVwiZmlsdGVyZWRPcHRpb25zXCJcclxuICAgICAgICAgICAgIFtzZWxlY3RlZF09XCJzZWxlY3RlZEl0ZW1cIlxyXG4gICAgICAgICAgICAgKHNlbGVjdGVkQ2hhbmdlZCk9XCJzZWxlY3RlZENoYW5nZWQoJGV2ZW50KVwiPjwvZWMtbWVudT5cclxuXHJcbiAgICA8Zm9vdGVyICpuZ0lmPVwidG90YWxSZWNvcmRzICYmIHRvdGFsUmVjb3JkcyA+IGZpbHRlcmVkT3B0aW9ucy5sZW5ndGggJiYgZmlsdGVyZWRPcHRpb25zLmxlbmd0aCA+IDBcIj5cclxuICAgICAgPHNwYW4+e3tmaWx0ZXJlZE9wdGlvbnMubGVuZ3RofX0ge3snb2YnIHwgdHJhbnNsYXRlfX0ge3t0b3RhbFJlY29yZHN9fTwvc3Bhbj5cclxuICAgIDwvZm9vdGVyPlxyXG4gIDwvZGl2PlxyXG48L25nLXRlbXBsYXRlPlxyXG4iXX0=