@sapui5/sap.fe.core 1.98.0 → 1.101.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 (318) hide show
  1. package/package.json +8 -5
  2. package/src/sap/fe/core/.library +2 -3
  3. package/src/sap/fe/core/AnnotationHelper.js +328 -405
  4. package/src/sap/fe/core/AnnotationHelper.ts +321 -0
  5. package/src/sap/fe/core/AppComponent.js +382 -399
  6. package/src/sap/fe/core/AppComponent.ts +397 -0
  7. package/src/sap/fe/core/AppStateHandler.js +198 -181
  8. package/src/sap/fe/core/AppStateHandler.ts +171 -0
  9. package/src/sap/fe/core/BaseController.js +83 -58
  10. package/src/sap/fe/core/BaseController.ts +67 -0
  11. package/src/sap/fe/core/BusyLocker.js +105 -121
  12. package/src/sap/fe/core/BusyLocker.ts +98 -0
  13. package/src/sap/fe/core/CommonUtils.js +2221 -2399
  14. package/src/sap/fe/core/CommonUtils.ts +2248 -0
  15. package/src/sap/fe/core/ExtensionAPI.js +280 -274
  16. package/src/sap/fe/core/ExtensionAPI.ts +242 -0
  17. package/src/sap/fe/core/PageController.js +219 -131
  18. package/src/sap/fe/core/PageController.ts +129 -0
  19. package/src/sap/fe/core/RouterProxy.js +936 -823
  20. package/src/sap/fe/core/RouterProxy.ts +854 -0
  21. package/src/sap/fe/core/Synchronization.js +41 -35
  22. package/src/sap/fe/core/Synchronization.ts +29 -0
  23. package/src/sap/fe/core/TemplateComponent.js +248 -164
  24. package/src/sap/fe/core/TemplateComponent.ts +161 -0
  25. package/src/sap/fe/core/TemplateModel.js +77 -54
  26. package/src/sap/fe/core/TemplateModel.ts +63 -0
  27. package/src/sap/fe/core/TransactionHelper.js +1575 -1664
  28. package/src/sap/fe/core/TransactionHelper.ts +1736 -0
  29. package/src/sap/fe/core/actions/collaboration/ActivitySync.js +406 -0
  30. package/src/sap/fe/core/actions/collaboration/ActivitySync.ts +362 -0
  31. package/src/sap/fe/core/actions/collaboration/CollaborationCommon.js +146 -0
  32. package/src/sap/fe/core/actions/collaboration/CollaborationCommon.ts +129 -0
  33. package/src/sap/fe/core/actions/collaboration/Manage.js +264 -0
  34. package/src/sap/fe/core/actions/collaboration/Manage.ts +246 -0
  35. package/src/sap/fe/core/actions/collaboration/ManageDialog.fragment.xml +100 -0
  36. package/src/sap/fe/core/actions/collaboration/UserDetails.fragment.xml +13 -0
  37. package/src/sap/fe/core/actions/draft.js +663 -608
  38. package/src/sap/fe/core/actions/draft.ts +669 -0
  39. package/src/sap/fe/core/actions/messageHandling.js +576 -514
  40. package/src/sap/fe/core/actions/messageHandling.ts +562 -0
  41. package/src/sap/fe/core/actions/nonDraft.js +17 -19
  42. package/src/sap/fe/core/actions/nonDraft.ts +12 -0
  43. package/src/sap/fe/core/actions/operations.js +1093 -1215
  44. package/src/sap/fe/core/actions/operations.ts +1193 -0
  45. package/src/sap/fe/core/actions/sticky.js +114 -104
  46. package/src/sap/fe/core/actions/sticky.ts +119 -0
  47. package/src/sap/fe/core/buildingBlocks/AttributeModel.js +60 -0
  48. package/src/sap/fe/core/buildingBlocks/AttributeModel.ts +37 -0
  49. package/src/sap/fe/core/buildingBlocks/BuildingBlock.js +165 -0
  50. package/src/sap/fe/core/buildingBlocks/BuildingBlock.ts +178 -0
  51. package/src/sap/fe/core/buildingBlocks/BuildingBlockRuntime.js +707 -0
  52. package/src/sap/fe/core/buildingBlocks/BuildingBlockRuntime.ts +628 -0
  53. package/src/sap/fe/core/buildingBlocks/TraceInfo.js +436 -0
  54. package/src/sap/fe/core/buildingBlocks/TraceInfo.ts +431 -0
  55. package/src/sap/fe/core/controllerextensions/EditFlow.js +1855 -1827
  56. package/src/sap/fe/core/controllerextensions/EditFlow.ts +1792 -0
  57. package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.js +80 -54
  58. package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.ts +60 -0
  59. package/src/sap/fe/core/controllerextensions/InternalEditFlow.js +717 -512
  60. package/src/sap/fe/core/controllerextensions/InternalEditFlow.ts +785 -0
  61. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.js +797 -815
  62. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.ts +810 -0
  63. package/src/sap/fe/core/controllerextensions/InternalRouting.js +1057 -1004
  64. package/src/sap/fe/core/controllerextensions/InternalRouting.ts +1001 -0
  65. package/src/sap/fe/core/controllerextensions/KPIManagement.js +498 -533
  66. package/src/sap/fe/core/controllerextensions/KPIManagement.ts +36 -32
  67. package/src/sap/fe/core/controllerextensions/MassEdit.js +142 -77
  68. package/src/sap/fe/core/controllerextensions/MassEdit.ts +155 -0
  69. package/src/sap/fe/core/controllerextensions/MessageHandler.js +222 -236
  70. package/src/sap/fe/core/controllerextensions/MessageHandler.ts +215 -0
  71. package/src/sap/fe/core/controllerextensions/PageReady.js +312 -345
  72. package/src/sap/fe/core/controllerextensions/PageReady.ts +63 -55
  73. package/src/sap/fe/core/controllerextensions/Paginator.js +189 -175
  74. package/src/sap/fe/core/controllerextensions/Paginator.ts +169 -0
  75. package/src/sap/fe/core/controllerextensions/Placeholder.js +158 -149
  76. package/src/sap/fe/core/controllerextensions/Placeholder.ts +149 -0
  77. package/src/sap/fe/core/controllerextensions/Routing.js +145 -121
  78. package/src/sap/fe/core/controllerextensions/Routing.ts +131 -0
  79. package/src/sap/fe/core/controllerextensions/RoutingListener.js +8 -6
  80. package/src/sap/fe/core/controllerextensions/RoutingListener.ts +3 -0
  81. package/src/sap/fe/core/controllerextensions/Share.js +231 -268
  82. package/src/sap/fe/core/controllerextensions/Share.ts +231 -0
  83. package/src/sap/fe/core/controllerextensions/SideEffects.js +603 -644
  84. package/src/sap/fe/core/controllerextensions/SideEffects.ts +79 -79
  85. package/src/sap/fe/core/controllerextensions/ViewState.js +775 -806
  86. package/src/sap/fe/core/controllerextensions/ViewState.ts +796 -0
  87. package/src/sap/fe/core/controls/ActionParameterDialog.fragment.xml +2 -2
  88. package/src/sap/fe/core/controls/ActionPartial.fragment.xml +2 -2
  89. package/src/sap/fe/core/controls/Any.js +28 -0
  90. package/src/sap/fe/core/controls/Any.ts +30 -0
  91. package/src/sap/fe/core/controls/CommandExecution.js +93 -68
  92. package/src/sap/fe/core/controls/CommandExecution.ts +72 -0
  93. package/src/sap/fe/core/controls/ConditionalWrapper.js +166 -79
  94. package/src/sap/fe/core/controls/ConditionalWrapper.ts +74 -0
  95. package/src/sap/fe/core/controls/CustomFilterFieldContentWrapper.js +366 -0
  96. package/src/sap/fe/core/controls/CustomFilterFieldContentWrapper.ts +278 -0
  97. package/src/sap/fe/core/controls/CustomQuickViewPage.js +168 -125
  98. package/src/sap/fe/core/controls/CustomQuickViewPage.ts +116 -0
  99. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossDraft.fragment.xml +44 -5
  100. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossOrDraftDiscardHandler.js +164 -122
  101. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossOrDraftDiscardHandler.ts +155 -0
  102. package/src/sap/fe/core/controls/FieldWrapper.js +213 -153
  103. package/src/sap/fe/core/controls/FieldWrapper.ts +104 -0
  104. package/src/sap/fe/core/controls/FileWrapper.js +313 -0
  105. package/src/sap/fe/core/controls/FileWrapper.ts +169 -0
  106. package/src/sap/fe/core/controls/FilterBar.js +198 -159
  107. package/src/sap/fe/core/controls/FilterBar.ts +148 -0
  108. package/src/sap/fe/core/controls/FormElementWrapper.js +101 -39
  109. package/src/sap/fe/core/controls/FormElementWrapper.ts +37 -0
  110. package/src/sap/fe/core/controls/MultiValueParameterDelegate.js +38 -42
  111. package/src/sap/fe/core/controls/MultiValueParameterDelegate.ts +31 -0
  112. package/src/sap/fe/core/controls/NonComputedVisibleKeyFieldsDialog.fragment.xml +1 -0
  113. package/src/sap/fe/core/controls/filterbar/FilterContainer.js +148 -115
  114. package/src/sap/fe/core/controls/filterbar/FilterContainer.ts +102 -0
  115. package/src/sap/fe/core/controls/filterbar/VisualFilter.js +301 -265
  116. package/src/sap/fe/core/controls/filterbar/VisualFilter.ts +252 -0
  117. package/src/sap/fe/core/controls/filterbar/VisualFilterContainer.js +186 -140
  118. package/src/sap/fe/core/controls/filterbar/VisualFilterContainer.ts +125 -0
  119. package/src/sap/fe/core/controls/filterbar/utils/VisualFilterUtils.js +336 -322
  120. package/src/sap/fe/core/controls/filterbar/utils/VisualFilterUtils.ts +337 -0
  121. package/src/sap/fe/core/controls/massEdit/MassEditDialog.fragment.xml +37 -42
  122. package/src/sap/fe/core/controls/massEdit/MassEditHandlers.js +76 -74
  123. package/src/sap/fe/core/controls/massEdit/MassEditHandlers.ts +71 -0
  124. package/src/sap/fe/core/converters/ConverterContext.js +348 -379
  125. package/src/sap/fe/core/converters/ConverterContext.ts +23 -19
  126. package/src/sap/fe/core/converters/ManifestSettings.js +13 -1
  127. package/src/sap/fe/core/converters/ManifestSettings.ts +18 -2
  128. package/src/sap/fe/core/converters/ManifestWrapper.js +354 -365
  129. package/src/sap/fe/core/converters/ManifestWrapper.ts +19 -0
  130. package/src/sap/fe/core/converters/MetaModelConverter.js +16 -11
  131. package/src/sap/fe/core/converters/MetaModelConverter.ts +21 -18
  132. package/src/sap/fe/core/converters/TemplateConverter.js +1 -1
  133. package/src/sap/fe/core/converters/TemplateConverter.ts +4 -3
  134. package/src/sap/fe/core/converters/annotations/DataField.js +26 -13
  135. package/src/sap/fe/core/converters/annotations/DataField.ts +40 -17
  136. package/src/sap/fe/core/converters/common/AnnotationConverter.js +17 -13
  137. package/src/sap/fe/core/converters/controls/Common/Action.js +11 -11
  138. package/src/sap/fe/core/converters/controls/Common/Action.ts +22 -21
  139. package/src/sap/fe/core/converters/controls/Common/Chart.js +12 -10
  140. package/src/sap/fe/core/converters/controls/Common/Chart.ts +23 -14
  141. package/src/sap/fe/core/converters/controls/Common/DataVisualization.js +3 -3
  142. package/src/sap/fe/core/converters/controls/Common/DataVisualization.ts +2 -2
  143. package/src/sap/fe/core/converters/controls/Common/Form.js +9 -7
  144. package/src/sap/fe/core/converters/controls/Common/Form.ts +23 -5
  145. package/src/sap/fe/core/converters/controls/Common/KPI.js +1 -1
  146. package/src/sap/fe/core/converters/controls/Common/KPI.ts +2 -2
  147. package/src/sap/fe/core/converters/controls/Common/Table.js +562 -218
  148. package/src/sap/fe/core/converters/controls/Common/Table.ts +670 -320
  149. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.js +218 -94
  150. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.ts +265 -159
  151. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.js +495 -77
  152. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.ts +535 -130
  153. package/src/sap/fe/core/converters/controls/ObjectPage/HeaderFacet.js +6 -6
  154. package/src/sap/fe/core/converters/controls/ObjectPage/HeaderFacet.ts +20 -18
  155. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.js +10 -7
  156. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.ts +13 -16
  157. package/src/sap/fe/core/converters/helpers/Aggregation.js +117 -127
  158. package/src/sap/fe/core/converters/helpers/Aggregation.ts +20 -5
  159. package/src/sap/fe/core/converters/helpers/BindingHelper.js +20 -6
  160. package/src/sap/fe/core/converters/helpers/BindingHelper.ts +16 -4
  161. package/src/sap/fe/core/converters/helpers/ConfigurableObject.js +12 -1
  162. package/src/sap/fe/core/converters/helpers/ConfigurableObject.ts +11 -0
  163. package/src/sap/fe/core/converters/helpers/IssueManager.js +4 -1
  164. package/src/sap/fe/core/converters/helpers/IssueManager.ts +3 -0
  165. package/src/sap/fe/core/converters/helpers/Key.js +42 -57
  166. package/src/sap/fe/core/converters/helpers/Key.ts +1 -1
  167. package/src/sap/fe/core/converters/objectPage/FormMenuActions.js +1 -1
  168. package/src/sap/fe/core/converters/objectPage/FormMenuActions.ts +0 -4
  169. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.js +54 -30
  170. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.ts +69 -43
  171. package/src/sap/fe/core/converters/templates/ListReportConverter.js +52 -28
  172. package/src/sap/fe/core/converters/templates/ListReportConverter.ts +111 -74
  173. package/src/sap/fe/core/converters/templates/ObjectPageConverter.js +11 -9
  174. package/src/sap/fe/core/converters/templates/ObjectPageConverter.ts +8 -8
  175. package/src/sap/fe/core/designtime/AppComponent.designtime.js +93 -98
  176. package/src/sap/fe/core/designtime/AppComponent.designtime.ts +91 -0
  177. package/src/sap/fe/core/formatters/CollaborationFormatter.js +104 -0
  178. package/src/sap/fe/core/formatters/CollaborationFormatter.ts +60 -0
  179. package/src/sap/fe/core/formatters/CriticalityFormatter.js +1 -1
  180. package/src/sap/fe/core/formatters/CriticalityFormatter.ts +1 -1
  181. package/src/sap/fe/core/formatters/FPMFormatter.js +1 -1
  182. package/src/sap/fe/core/formatters/FPMFormatter.ts +4 -10
  183. package/src/sap/fe/core/formatters/KPIFormatter.js +3 -12
  184. package/src/sap/fe/core/formatters/KPIFormatter.ts +4 -1
  185. package/src/sap/fe/core/formatters/TableFormatter.js +91 -29
  186. package/src/sap/fe/core/formatters/TableFormatter.ts +94 -28
  187. package/src/sap/fe/core/formatters/ValueFormatter.js +4 -4
  188. package/src/sap/fe/core/formatters/ValueFormatter.ts +5 -7
  189. package/src/sap/fe/core/fpm/Component.js +81 -55
  190. package/src/sap/fe/core/fpm/Component.ts +43 -0
  191. package/src/sap/fe/core/helpers/AppStartupHelper.js +324 -310
  192. package/src/sap/fe/core/helpers/AppStartupHelper.ts +370 -341
  193. package/src/sap/fe/core/helpers/BindingExpression.js +319 -360
  194. package/src/sap/fe/core/helpers/BindingExpression.ts +323 -397
  195. package/src/sap/fe/core/helpers/ClassSupport.js +321 -168
  196. package/src/sap/fe/core/helpers/ClassSupport.ts +362 -158
  197. package/src/sap/fe/core/helpers/DynamicAnnotationPathHelper.js +64 -59
  198. package/src/sap/fe/core/helpers/DynamicAnnotationPathHelper.ts +52 -0
  199. package/src/sap/fe/core/helpers/EditState.js +81 -84
  200. package/src/sap/fe/core/helpers/EditState.ts +81 -0
  201. package/src/sap/fe/core/helpers/ExcelFormatHelper.js +62 -48
  202. package/src/sap/fe/core/helpers/ExcelFormatHelper.ts +49 -0
  203. package/src/sap/fe/core/helpers/FPMHelper.js +52 -56
  204. package/src/sap/fe/core/helpers/FPMHelper.ts +62 -0
  205. package/src/sap/fe/core/helpers/KeepAliveHelper.js +3 -4
  206. package/src/sap/fe/core/helpers/KeepAliveHelper.ts +9 -9
  207. package/src/sap/fe/core/helpers/MassEditHelper.js +736 -676
  208. package/src/sap/fe/core/helpers/MassEditHelper.ts +803 -0
  209. package/src/sap/fe/core/helpers/ModelHelper.js +281 -225
  210. package/src/sap/fe/core/helpers/ModelHelper.ts +273 -0
  211. package/src/sap/fe/core/helpers/PasteHelper.js +210 -132
  212. package/src/sap/fe/core/helpers/PasteHelper.ts +197 -0
  213. package/src/sap/fe/core/helpers/SemanticDateOperators.js +336 -313
  214. package/src/sap/fe/core/helpers/SemanticDateOperators.ts +336 -0
  215. package/src/sap/fe/core/helpers/SemanticKeyHelper.js +66 -67
  216. package/src/sap/fe/core/helpers/SemanticKeyHelper.ts +73 -0
  217. package/src/sap/fe/core/helpers/StableIdHelper.js +1 -10
  218. package/src/sap/fe/core/helpers/StableIdHelper.ts +2 -10
  219. package/src/sap/fe/core/jsx-runtime/jsx.js +35 -5
  220. package/src/sap/fe/core/jsx-runtime/jsx.ts +23 -9
  221. package/src/sap/fe/core/library.js +426 -451
  222. package/src/sap/fe/core/library.support.js +23 -33
  223. package/src/sap/fe/core/library.support.ts +23 -0
  224. package/src/sap/fe/core/library.ts +420 -0
  225. package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.js +5 -3
  226. package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.ts +5 -5
  227. package/src/sap/fe/core/messagebundle.properties +63 -18
  228. package/src/sap/fe/core/messagebundle_ar.properties +37 -6
  229. package/src/sap/fe/core/messagebundle_bg.properties +37 -6
  230. package/src/sap/fe/core/messagebundle_ca.properties +37 -6
  231. package/src/sap/fe/core/messagebundle_cs.properties +38 -7
  232. package/src/sap/fe/core/messagebundle_cy.properties +37 -6
  233. package/src/sap/fe/core/messagebundle_da.properties +37 -6
  234. package/src/sap/fe/core/messagebundle_de.properties +37 -6
  235. package/src/sap/fe/core/messagebundle_el.properties +37 -6
  236. package/src/sap/fe/core/messagebundle_en.properties +37 -6
  237. package/src/sap/fe/core/messagebundle_en_GB.properties +37 -6
  238. package/src/sap/fe/core/messagebundle_en_US_sappsd.properties +37 -6
  239. package/src/sap/fe/core/messagebundle_en_US_saprigi.properties +37 -6
  240. package/src/sap/fe/core/messagebundle_en_US_saptrc.properties +37 -6
  241. package/src/sap/fe/core/messagebundle_es.properties +37 -6
  242. package/src/sap/fe/core/messagebundle_es_MX.properties +37 -6
  243. package/src/sap/fe/core/messagebundle_et.properties +37 -6
  244. package/src/sap/fe/core/messagebundle_fi.properties +38 -7
  245. package/src/sap/fe/core/messagebundle_fr.properties +43 -12
  246. package/src/sap/fe/core/messagebundle_fr_CA.properties +45 -14
  247. package/src/sap/fe/core/messagebundle_hi.properties +43 -12
  248. package/src/sap/fe/core/messagebundle_hr.properties +43 -12
  249. package/src/sap/fe/core/messagebundle_hu.properties +37 -6
  250. package/src/sap/fe/core/messagebundle_id.properties +38 -7
  251. package/src/sap/fe/core/messagebundle_it.properties +37 -6
  252. package/src/sap/fe/core/messagebundle_iw.properties +37 -6
  253. package/src/sap/fe/core/messagebundle_ja.properties +36 -5
  254. package/src/sap/fe/core/messagebundle_kk.properties +43 -12
  255. package/src/sap/fe/core/messagebundle_ko.properties +37 -6
  256. package/src/sap/fe/core/messagebundle_lt.properties +37 -6
  257. package/src/sap/fe/core/messagebundle_lv.properties +44 -13
  258. package/src/sap/fe/core/messagebundle_ms.properties +42 -11
  259. package/src/sap/fe/core/messagebundle_nl.properties +37 -6
  260. package/src/sap/fe/core/messagebundle_no.properties +37 -6
  261. package/src/sap/fe/core/messagebundle_pl.properties +37 -6
  262. package/src/sap/fe/core/messagebundle_pt.properties +38 -7
  263. package/src/sap/fe/core/messagebundle_pt_PT.properties +37 -6
  264. package/src/sap/fe/core/messagebundle_ro.properties +37 -6
  265. package/src/sap/fe/core/messagebundle_ru.properties +37 -6
  266. package/src/sap/fe/core/messagebundle_sh.properties +39 -8
  267. package/src/sap/fe/core/messagebundle_sk.properties +37 -6
  268. package/src/sap/fe/core/messagebundle_sl.properties +43 -12
  269. package/src/sap/fe/core/messagebundle_sv.properties +38 -7
  270. package/src/sap/fe/core/messagebundle_th.properties +36 -5
  271. package/src/sap/fe/core/messagebundle_tr.properties +39 -8
  272. package/src/sap/fe/core/messagebundle_uk.properties +37 -6
  273. package/src/sap/fe/core/messagebundle_vi.properties +37 -6
  274. package/src/sap/fe/core/messagebundle_zh_CN.properties +37 -6
  275. package/src/sap/fe/core/messagebundle_zh_TW.properties +43 -12
  276. package/src/sap/fe/core/services/AsyncComponentServiceFactory.js +47 -73
  277. package/src/sap/fe/core/services/AsyncComponentServiceFactory.ts +3 -1
  278. package/src/sap/fe/core/services/CacheHandlerServiceFactory.js +231 -202
  279. package/src/sap/fe/core/services/CacheHandlerServiceFactory.ts +211 -0
  280. package/src/sap/fe/core/services/EnvironmentServiceFactory.js +70 -96
  281. package/src/sap/fe/core/services/EnvironmentServiceFactory.ts +10 -8
  282. package/src/sap/fe/core/services/NavigationServiceFactory.js +351 -300
  283. package/src/sap/fe/core/services/NavigationServiceFactory.ts +313 -0
  284. package/src/sap/fe/core/services/ResourceModelServiceFactory.js +114 -81
  285. package/src/sap/fe/core/services/ResourceModelServiceFactory.ts +83 -0
  286. package/src/sap/fe/core/services/RoutingServiceFactory.js +963 -899
  287. package/src/sap/fe/core/services/RoutingServiceFactory.ts +907 -0
  288. package/src/sap/fe/core/services/ShellServicesFactory.js +694 -741
  289. package/src/sap/fe/core/services/ShellServicesFactory.ts +45 -40
  290. package/src/sap/fe/core/services/SideEffectsServiceFactory.js +572 -643
  291. package/src/sap/fe/core/services/SideEffectsServiceFactory.ts +67 -96
  292. package/src/sap/fe/core/services/TemplatedViewServiceFactory.js +429 -487
  293. package/src/sap/fe/core/services/TemplatedViewServiceFactory.ts +449 -0
  294. package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.js +48 -8
  295. package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.ts +11 -0
  296. package/src/sap/fe/core/support/AnnotationIssue.support.js +15 -3
  297. package/src/sap/fe/core/support/AnnotationIssue.support.ts +16 -2
  298. package/src/sap/fe/core/support/CollectionFacetUnsupportedLevel.support.js +2 -2
  299. package/src/sap/fe/core/support/CollectionFacetUnsupportedLevel.support.ts +1 -1
  300. package/src/sap/fe/core/support/CommonHelper.js +1 -1
  301. package/src/sap/fe/core/support/CommonHelper.ts +1 -4
  302. package/src/sap/fe/core/support/Diagnostics.js +36 -48
  303. package/src/sap/fe/core/templating/DataModelPathHelper.js +91 -90
  304. package/src/sap/fe/core/templating/DataModelPathHelper.ts +126 -123
  305. package/src/sap/fe/core/templating/DisplayModeFormatter.js +23 -3
  306. package/src/sap/fe/core/templating/DisplayModeFormatter.ts +26 -5
  307. package/src/sap/fe/core/templating/FieldControlHelper.js +8 -8
  308. package/src/sap/fe/core/templating/FieldControlHelper.ts +25 -7
  309. package/src/sap/fe/core/templating/FilterHelper.js +138 -79
  310. package/src/sap/fe/core/templating/FilterHelper.ts +148 -79
  311. package/src/sap/fe/core/templating/PropertyHelper.js +16 -2
  312. package/src/sap/fe/core/templating/PropertyHelper.ts +31 -24
  313. package/src/sap/fe/core/templating/UIFormatters.js +179 -43
  314. package/src/sap/fe/core/templating/UIFormatters.ts +190 -61
  315. package/src/sap/fe/core/type/Email.js +26 -8
  316. package/src/sap/fe/core/type/Email.ts +10 -11
  317. package/ui5.yaml +0 -3
  318. package/src/sap/fe/core/controllerextensions/ControllerExtensionMetadata.js +0 -74
@@ -1,825 +1,938 @@
1
1
  /*!
2
- * SAPUI5
3
- * (c) Copyright 2009-2022 SAP SE. All rights reserved.
2
+ * SAP UI development toolkit for HTML5 (SAPUI5)
3
+ * (c) Copyright 2009-2021 SAP SE. All rights reserved
4
4
  */
5
- /* eslint-disable no-alert */
6
- sap.ui.define(
7
- ["sap/base/Log", "sap/ui/base/Object", "sap/ui/base/EventProvider", "sap/fe/core/Synchronization", "sap/ui/thirdparty/URI"],
8
- function(Log, BaseObject, EventProvider, Synchronization, URI) {
9
- "use strict";
10
-
11
- var enumState = {
12
- EQUAL: 0,
13
- COMPATIBLE: 1,
14
- ANCESTOR: 2,
15
- DIFFERENT: 3
16
- };
17
-
18
- var enumURLParams = {
19
- LAYOUTPARAM: "layout",
20
- IAPPSTATEPARAM: "sap-iapp-state"
21
- };
22
-
23
- /**
24
- * Creates a HashGuard object.
25
- *
26
- * @param {string} sGuardHash The hash used for the guard
27
- * @returns {object} The created hash guard
28
- */
29
- function createGuardFromHash(sGuardHash) {
30
- return {
31
- _guardHash: sGuardHash.replace(/\?[^\?]*$/, ""), // Remove query part
32
- check: function(sHash) {
33
- return sHash.indexOf(this._guardHash) === 0;
34
- }
35
- };
36
- }
37
-
38
- /**
39
- * Returns the iAppState part from a hash (or null if not found).
40
- *
41
- * @param {string} sHash The hash
42
- * @returns {string} The iAppState part of the hash
43
- */
44
- function findAppStateInHash(sHash) {
45
- var aAppState = sHash.match(new RegExp("\\?.*" + enumURLParams.IAPPSTATEPARAM + "=([^&]*)"));
46
- return aAppState && aAppState.length > 1 ? aAppState[1] : null;
47
- }
48
-
49
- /**
50
- * Returns a hash without its iAppState part.
51
- *
52
- * @param {string} sHash The hash
53
- * @returns {string} The hash without the iAppState
54
- */
55
- function removeAppStateInHash(sHash) {
56
- return sHash.replace(new RegExp("[&?]*" + enumURLParams.IAPPSTATEPARAM + "=[^&]*"), "");
57
- }
58
-
59
- /**
60
- * Adds an iAppState inside a hash (or replaces an existing one).
61
- *
62
- * @param {*} sHash The hash
63
- * @param {*} sAppStateKey The iAppState to add
64
- * @returns {string} The hash with the app state
65
- */
66
- function setAppStateInHash(sHash, sAppStateKey) {
67
- var sNewHash;
68
-
69
- if (sHash.indexOf(enumURLParams.IAPPSTATEPARAM) >= 0) {
70
- // If there's already an iAppState parameter in the hash, replace it
71
- sNewHash = sHash.replace(
72
- new RegExp(enumURLParams.IAPPSTATEPARAM + "=[^&]*"),
73
- enumURLParams.IAPPSTATEPARAM + "=" + sAppStateKey
74
- );
75
- } else {
76
- // Add the iAppState parameter in the hash
77
- if (sHash.indexOf("?") < 0) {
78
- sNewHash = sHash + "?";
79
- } else {
80
- sNewHash = sHash + "&";
81
- }
82
- sNewHash += enumURLParams.IAPPSTATEPARAM + "=" + sAppStateKey;
83
- }
84
-
85
- return sNewHash;
86
- }
87
-
88
- return BaseObject.extend("sap.fe.core.RouterProxy", {
89
- bIsRebuildHistoryRunning: false,
90
- bIsComputingTitleHierachy: false,
91
- bIsGuardCrossAllowed: false,
92
- sIAppStateKey: null,
93
-
94
- init: function(oAppComponent, isfclEnabled) {
95
- // Save the name of the app (including startup parameters) for rebuilding full hashes later
96
- oAppComponent
97
- .getService("shellServices")
98
- .then(
99
- function() {
100
- this._oShellServices = oAppComponent.getShellServices();
101
-
102
- this.initRaw(oAppComponent.getRouter());
103
- // We want to wait until the initial routeMatched is done before doing any navigation
104
- this.waitForRouteMatchBeforeNavigation();
105
-
106
- // Set feLevel=0 for the first Application page in the history
107
- history.replaceState(
108
- Object.assign(
109
- {
110
- feLevel: 0
111
- },
112
- history.state
113
- ),
114
- "",
115
- window.location
116
- );
117
- this.fclEnabled = isfclEnabled;
118
-
119
- this._fnBlockingNavFilter = this._blockingNavigationFilter.bind(this);
120
- this._oShellServices.registerNavigationFilter(this._fnBlockingNavFilter);
121
- }.bind(this)
122
- )
123
- .catch(function(oError) {
124
- Log.error("Cannot retrieve the shell services", oError);
125
- });
126
- this._fnHashGuard = this.hashGuard.bind(this);
127
- window.addEventListener("popstate", this._fnHashGuard);
128
- this._bDisableOnHashChange = false;
129
- this._bIgnoreRestore = false;
130
- this._bCleanedRestore = false;
131
- this._bForceFocus = true; // Trigger the focus mechanism for the first view displayed by the app
132
- },
133
-
134
- destroy: function() {
135
- if (this._oShellServices) {
136
- this._oShellServices.unregisterNavigationFilter(this._fnBlockingNavFilter);
137
- }
138
- window.removeEventListener("popstate", this._fnHashGuard);
139
- },
140
-
141
- /**
142
- * Raw initialization (for unit tests).
143
- *
144
- * @param {sap.ui.core.routing.Router} oRouter The router used by this proxy
145
- */
146
- initRaw: function(oRouter) {
147
- this._oRouter = oRouter;
148
- this._oManagedHistory = [];
149
- this._oNavigationGuard = null;
150
-
151
- var sCurrentAppHash = this.getHash();
152
- this._oManagedHistory.push(this._extractStateFromHash(sCurrentAppHash));
153
-
154
- // Set the iAppState if the initial hash contains one
155
- this.sIAppStateKey = findAppStateInHash(sCurrentAppHash);
156
- },
157
-
158
- getHash: function() {
159
- return this._oRouter.getHashChanger().getHash();
160
- },
161
-
162
- isFocusForced: function() {
163
- return this._bForceFocus;
164
- },
165
-
166
- setFocusForced: function(bForced) {
167
- this._bForceFocus = bForced;
168
- },
169
-
170
- /**
171
- * Resets the internal variable sIAppStateKey.
172
- *
173
- * @function
174
- * @name sap.fe.core.RouterProxy#removeIAppStateKey
175
- *
176
- * @ui5-restricted
177
- */
178
- removeIAppStateKey: function() {
179
- this.sIAppStateKey = null;
180
- },
181
-
182
- /**
183
- * Navigates to a specific hash.
184
- *
185
- * @function
186
- * @name sap.fe.core.RouterProxy#navToHash
187
- * @memberof sap.fe.core.RouterProxy
188
- * @static
189
- * @param {string} sHash Hash to be navigated to
190
- * @param {boolean} bPreserveHistory If set to true, non-ancestor entries in history will be retained
191
- * @param {boolean} bDisablePreservationCache If set to true, cache preservation mechanism is disabled for the current navigation
192
- * @param {boolean} bForceFocus If set to true, the logic to set the focus once the navigation is finalized will be triggered (onPageReady)
193
- * @returns {Promise} Promise (resolved when the navigation is finalized) that returns 'true' if a navigation took place, 'false' if the navigation didn't happen
194
- * @ui5-restricted
195
- */
196
- navToHash: function(sHash, bPreserveHistory, bDisablePreservationCache, bForceFocus) {
197
- var that = this;
198
-
199
- if (this._oRouteMatchSynchronization) {
200
- return this._oRouteMatchSynchronization.waitFor().then(function() {
201
- that._oRouteMatchSynchronization = null;
202
- return that._internalNavToHash(sHash, bPreserveHistory, bDisablePreservationCache, bForceFocus);
203
- });
204
- } else {
205
- if (this._bActivateRouteMatchSynchro) {
206
- this.waitForRouteMatchBeforeNavigation();
207
- }
208
- return that._internalNavToHash(sHash, bPreserveHistory, bDisablePreservationCache, bForceFocus);
209
- }
210
- },
211
-
212
- _internalNavToHash: function(sHash, bPreserveHistory, bDisablePreservationCache, bForceFocus) {
213
- // Add the app state in the hash if needed
214
- if (this.fclEnabled && this.sIAppStateKey && !findAppStateInHash(sHash)) {
215
- sHash = setAppStateInHash(sHash, this.sIAppStateKey);
216
- }
217
-
218
- if (!this.checkHashWithGuard(sHash)) {
219
- if (!this.oResourceBundle) {
220
- this.oResourceBundle = sap.ui.getCore().getLibraryResourceBundle("sap.fe.core");
221
- }
222
-
223
- // We have to use a confirm here for UI consistency reasons, as with some scenarios
224
- // in the EditFlow we rely on a UI5 mechanism that displays a confirm dialog.
225
- if (!confirm(this.oResourceBundle.getText("C_ROUTER_PROXY_SAPFE_EXIT_NOTSAVED_MESSAGE"))) {
226
- // The user clicked on Cancel --> cancel navigation
227
- return Promise.resolve(false);
228
- }
229
- this.bIsGuardCrossAllowed = true;
230
- }
231
-
232
- // In case the navigation will cause a new view to be displayed, we force the focus
233
- // I.e. if the keys for the hash we're navigating to is a superset of the current hash keys.
234
- var oNewState = this._extractStateFromHash(sHash);
235
- if (!this._bForceFocus) {
236
- // If the focus was already forced, keep it
237
- var aCurrentHashKeys = this._extractKeysFromHash(this.getHash());
238
- this._bForceFocus =
239
- bForceFocus ||
240
- (aCurrentHashKeys.length < oNewState.keys.length &&
241
- aCurrentHashKeys.every(function(key, index) {
242
- return key === oNewState.keys[index];
243
- }));
244
- }
245
-
246
- var oHistoryAction = this._pushNewState(oNewState, false, bPreserveHistory, bDisablePreservationCache);
247
-
248
- return this._rebuildBrowserHistory(oHistoryAction, false);
249
- },
250
-
251
- /**
252
- * Clears browser history if entries have been added without using the RouterProxy.
253
- * Updates the internal history accordingly.
254
- *
255
- * @returns {Promise} Promise that is resolved once the history is rebuilt
256
- */
257
- restoreHistory: function() {
258
- if (this._bApplyRestore) {
259
- this._bApplyRestore = false;
260
- var sTargetHash = this.getHash();
261
- sTargetHash = sTargetHash.replace(/(\?|&)restoreHistory=true/, "");
262
- var oNewState = this._extractStateFromHash(sTargetHash);
263
-
264
- var oHistoryAction = this._pushNewState(oNewState, true, false, true);
265
-
266
- return this._rebuildBrowserHistory(oHistoryAction, true);
267
- } else {
268
- return Promise.resolve();
269
- }
270
- },
271
-
272
- /**
273
- * Navigates back in the history.
274
- *
275
- * @returns {Promise} Promise that is resolved when the navigation is finalized
276
- */
277
- navBack: function() {
278
- var sCurrentHash = this.getHash(),
279
- sPreviousHash;
280
-
281
- // Look for the current hash in the managed history
282
- for (var i = this._oManagedHistory.length - 1; i > 0; i--) {
283
- if (this._oManagedHistory[i].hash === sCurrentHash) {
284
- sPreviousHash = this._oManagedHistory[i - 1].hash;
285
- break;
286
- }
287
- }
288
-
289
- if (sPreviousHash) {
290
- return this.navToHash(sPreviousHash);
291
- } else {
292
- // We couldn't find a previous hash in history
293
- // This can happen when navigating from a transient hash in a create app, and
294
- // in that case history.back would go back to the FLP
295
- window.history.back();
296
- return Promise.resolve();
297
- }
298
- },
299
-
300
- /**
301
- * Navigates to a route with parameters.
302
- *
303
- * @param {string} sRouteName The route name to be navigated to
304
- * @param {object} oParameters Parameters for the navigation
305
- * @returns {Promise} Promise that is resolved when the navigation is finalized
306
- * @ui5-restricted
307
- */
308
- navTo: function(sRouteName, oParameters) {
309
- var sHash = this._oRouter.getURL(sRouteName, oParameters);
310
- return this.navToHash(sHash, false, oParameters.noPreservationCache);
311
- },
312
-
313
- /**
314
- * Exits the current app by navigating back
315
- * to the previous app (if any) or the FLP.
316
- *
317
- * @returns {Promise} Promise that is resolved when we exit the app
318
- */
319
- exitFromApp: function() {
320
- return this._oShellServices.backToPreviousApp();
321
- },
322
-
323
- /**
324
- * Checks whether a given hash can have an impact on the current state
325
- * i.e. if the hash is equal, compatible or an ancestor of the current state.
326
- *
327
- * @param {*} sHash `true` if there is an impact
328
- * @returns {boolean} If there is an impact
329
- */
330
- isCurrentStateImpactedBy: function(sHash) {
331
- if (sHash[0] === "/") {
332
- sHash = sHash.substring(1);
333
- }
334
- var oLocalGuard = createGuardFromHash(sHash);
335
- return oLocalGuard.check(this.getHash());
336
- },
337
-
338
- /**
339
- * Checks if a navigation is currently being processed.
340
- *
341
- * @returns {boolean} `false` if a navigation has been triggered in the RouterProxy and is not yet finalized
342
- */
343
- isNavigationFinalized: function() {
344
- return !this.bIsRebuildHistoryRunning && !this._bDelayedRebuild;
345
- },
346
-
347
- /**
348
- * Sets the last state as a guard.
349
- * Each future navigation will be checked against this guard, and a confirmation dialog will
350
- * be displayed before the navigation crosses the guard (i.e. goes to an ancestor of the guard).
351
- */
352
- setNavigationGuard: function() {
353
- this._oNavigationGuard = createGuardFromHash(this.getHash());
354
- this.bIsGuardCrossAllowed = false;
355
- },
356
-
357
- /**
358
- * Disables the navigation guard.
359
- */
360
- discardNavigationGuard: function() {
361
- this._oNavigationGuard = null;
362
- },
363
-
364
- /**
365
- * Checks for the availability of the navigation guard.
366
- *
367
- * @returns {boolean} `true` if navigating guard is available
368
- */
369
- hasNavigationGuard: function() {
370
- return this._oNavigationGuard !== null;
371
- },
372
-
373
- /**
374
- * Tests a hash against the navigation guard.
375
- *
376
- * @param {string} sHash The hash to be tested
377
- * @returns {boolean} `true` if navigating to the hash doesn't cross the guard
378
- */
379
- checkHashWithGuard: function(sHash) {
380
- return this._oNavigationGuard === null || this._oNavigationGuard.check(sHash);
381
- },
382
-
383
- /**
384
- * Checks if the user allowed the navigation guard to be crossed.
385
- *
386
- * @returns {boolean} `true` if crossing the guard has been allowed by the user
387
- */
388
- isGuardCrossAllowedByUser: function() {
389
- return this.bIsGuardCrossAllowed;
390
- },
391
-
392
- /**
393
- * Activates the synchronization for routeMatchedEvent.
394
- * The next NavToHash call will create a Synchronization object that will be resolved
395
- * by the corresponding onRouteMatched event, preventing another NavToHash to happen in parallel.
396
- */
397
- activateRouteMatchSynchronization: function() {
398
- this._bActivateRouteMatchSynchro = true;
399
- },
400
-
401
- /**
402
- * Resolve the routeMatch synchronization object, unlocking potential pending NavToHash calls.
403
- */
404
- resolveRouteMatch: function() {
405
- if (this._oRouteMatchSynchronization) {
406
- this._oRouteMatchSynchronization.resolve();
407
- }
408
- },
409
-
410
- /**
411
- * Makes sure no navigation can happen before a routeMatch happened.
412
- */
413
- waitForRouteMatchBeforeNavigation: function() {
414
- this._oRouteMatchSynchronization = new Synchronization();
415
- this._bActivateRouteMatchSynchro = false;
416
- },
417
-
418
- _extractKeysFromHash: function(sHash) {
419
- if (sHash === undefined) {
420
- sHash = "";
421
- }
422
- var sHashNoParams = sHash.split("?")[0]; // remove params
423
- var aTokens = sHashNoParams.split("/");
424
- var aKeys = [];
425
-
426
- aTokens.forEach(function(sToken) {
427
- var regexKey = /[^\(\)]+\([^\(\)]+\)/; // abc(def)
428
- if (regexKey.test(sToken)) {
429
- aKeys.push(sToken.split("(")[0]);
430
- }
431
- });
432
-
433
- return aKeys;
434
- },
435
-
436
- /**
437
- * Builds a state from a hash.
438
- *
439
- * @param {string} sHash The hash to be used as entry
440
- * @returns {object} The state
441
- *
442
- * @ui5-restricted
443
- */
444
- _extractStateFromHash: function(sHash) {
445
- if (sHash === undefined) {
446
- sHash = "";
447
- }
448
-
449
- var oState = {
450
- keys: this._extractKeysFromHash(sHash)
451
- };
452
-
453
- // Retrieve layout (if any)
454
- var aLayout = sHash.match(new RegExp("\\?.*" + enumURLParams.LAYOUTPARAM + "=([^&]*)"));
455
- oState.sLayout = aLayout && aLayout.length > 1 ? aLayout[1] : null;
456
- if (oState.sLayout === "MidColumnFullScreen") {
457
- oState.screenMode = 1;
458
- } else if (oState.sLayout === "EndColumnFullScreen") {
459
- oState.screenMode = 2;
460
- } else {
461
- oState.screenMode = 0;
462
- }
463
-
464
- oState.hash = sHash;
465
- return oState;
466
- },
467
-
468
- /**
469
- * Adds a new state into the internal history structure.
470
- * Makes sure this new state is added after an ancestor.
471
- * Also sets the iAppState key in the whole history.
472
- *
473
- * @memberof sap.fe.core.RouterProxy
474
- * @param {object} oNewState The new state to be added
475
- * @param {boolean} bRebuildOnly `true` if we're rebuilding the history after a shell menu navigation
476
- * @param {boolean} bPreserveHistory If set to true, non-ancestor entries in history will be retained
477
- * @param {boolean} bDisableHistoryPreservation Disable the mechanism to retained marked entries in cache
478
- * @returns {object} The new state
479
- * @ui5-restricted
480
- * @final
481
- */
482
- _pushNewState: function(oNewState, bRebuildOnly, bPreserveHistory, bDisableHistoryPreservation) {
483
- var sCurrentHash = this.getHash(),
484
- lastIndex = this._oManagedHistory.length - 1,
485
- iPopCount = bRebuildOnly ? 1 : 0,
486
- that = this;
487
-
488
- // 1. Do some cleanup in the managed history : in case the user has navigated back in the browser history, we need to remove
489
- // the states ahead in history and make sure the top state corresponds to the current page
490
- // We don't do that when restoring the history, as the current state has been added on top of the browser history
491
- // and is not reflected in the managed history
492
- if (!bRebuildOnly) {
493
- while (lastIndex >= 0 && this._oManagedHistory[lastIndex].hash !== sCurrentHash) {
494
- this._oManagedHistory.pop();
495
- lastIndex--;
496
- }
497
-
498
- if (this._oManagedHistory.length === 0) {
499
- // We couldn't find the current location in the history. This can happen if a browser reload
500
- // happened, causing a reinitialization of the managed history.
501
- // In that case, we use the current location as the new starting point in the managed history
502
- this._oManagedHistory.push(this._extractStateFromHash(sCurrentHash));
503
- history.replaceState(Object.assign({ feLevel: 0 }, history.state), "");
504
- }
505
- }
506
-
507
- // 2. Mark the top state as preserved if required
508
- if (bPreserveHistory && !bDisableHistoryPreservation) {
509
- this._oManagedHistory[this._oManagedHistory.length - 1].preserved = true;
510
- }
511
-
512
- // 3. Then pop all states until we find an ancestor of the new state, or we find a state that need to be preserved
513
- var oLastRemovedItem;
514
- while (this._oManagedHistory.length > 0) {
515
- var oTopState = this._oManagedHistory[this._oManagedHistory.length - 1];
516
- if (
517
- (bDisableHistoryPreservation || !oTopState.preserved) &&
518
- this._compareCacheStates(oTopState, oNewState) !== enumState.ANCESTOR
519
- ) {
520
- // The top state is not an ancestor of oNewState and is not preserved --> we can pop it
521
- oLastRemovedItem = this._oManagedHistory.pop();
522
- iPopCount++;
523
- } else if (oTopState.preserved && removeAppStateInHash(oTopState.hash) === removeAppStateInHash(oNewState.hash)) {
524
- // We try to add a state that is already in cache (due to preserved flag) but with a different iapp-state
525
- // --> we should delete the previous entry (it will be later replaced by the new one) and stop popping
526
- oLastRemovedItem = this._oManagedHistory.pop();
527
- iPopCount++;
528
- oNewState.preserved = true;
529
- break;
530
- } else {
531
- break; // Ancestor or preserved state found --> we stop popping out states
532
- }
533
- }
534
-
535
- // 4. iAppState management
536
- this.sIAppStateKey = findAppStateInHash(oNewState.hash);
537
- if (this.fclEnabled && this.sIAppStateKey) {
538
- // In case of FCL, the new app state needs to be applied to the whole history
539
- this._oManagedHistory.forEach(function(oManagedState) {
540
- oManagedState.hash = setAppStateInHash(oManagedState.hash, that.sIAppStateKey);
541
- });
542
- } else if (!this.fclEnabled && oLastRemovedItem) {
543
- var sPreviousIAppStateKey = findAppStateInHash(oLastRemovedItem.hash);
544
- var oComparisonStateResult = this._compareCacheStates(oLastRemovedItem, oNewState);
545
- // if current state doesn't contain a i-appstate and this state should replace a state containing a iAppState
546
- // then the previous iAppState is preserved
547
- if (
548
- !this.sIAppStateKey &&
549
- sPreviousIAppStateKey &&
550
- (oComparisonStateResult === enumState.EQUAL || oComparisonStateResult === enumState.COMPATIBLE)
551
- ) {
552
- oNewState.hash = setAppStateInHash(oNewState.hash, sPreviousIAppStateKey);
553
- }
554
- }
555
-
556
- // 5. Now we can push the state at the top of the internal history
557
- var bHasSameHash = oLastRemovedItem && oNewState.hash === oLastRemovedItem.hash;
558
- if (this._oManagedHistory.length === 0 || this._oManagedHistory[this._oManagedHistory.length - 1].hash !== oNewState.hash) {
559
- this._oManagedHistory.push(oNewState);
560
- }
561
-
562
- // 6. Determine which actions to do on the history
563
- if (iPopCount === 0) {
564
- // No state was popped --> append
565
- return { type: "append" };
566
- } else if (iPopCount === 1) {
567
- // Only 1 state was popped --> replace current hash unless hash is the same (then nothing to do)
568
- return bHasSameHash ? { type: "none" } : { type: "replace" };
569
- } else {
570
- // More than 1 state was popped --> go bakc in history and replace hash if necessary
571
- return bHasSameHash ? { type: "back", steps: iPopCount - 1 } : { type: "back-replace", steps: iPopCount - 1 };
572
- }
573
- },
574
-
575
- _blockingNavigationFilter: function() {
576
- return this._bDisableOnHashChange ? "Custom" : "Continue";
577
- },
578
-
579
- /**
580
- * Disable the routing by calling the router stop method.
581
- *
582
- * @function
583
- * @memberof sap.fe.core.RouterProxy
584
- *
585
- * @ui5-restricted
586
- * @final
587
- */
588
- _disableEventOnHashChange: function() {
589
- this._bDisableOnHashChange = true;
590
- this._oRouter.stop();
591
- },
592
-
593
- /**
594
- * Enable the routing by calling the router initialize method.
595
- *
596
- * @function
597
- * @name sap.fe.core.RouterProxy#_enableEventOnHashChange
598
- * @memberof sap.fe.core.RouterProxy
599
- * @param {Array} [bIgnoreCurrentHash] Ignore the last hash event triggered before the router has initialized
600
- *
601
- * @ui5-restricted
602
- * @final
603
- */
604
- _enableEventOnHashChange: function(bIgnoreCurrentHash) {
605
- this._bDisableOnHashChange = false;
606
- this._oRouter.initialize(bIgnoreCurrentHash);
607
- },
608
-
609
- /**
610
- * Synchronizes the browser history with the internal history of the routerProxy, and triggers a navigation if needed.
611
- *
612
- * @memberof sap.fe.core.RouterProxy
613
- * @param {object} oHistoryAction Specifies the navigation action to be performed
614
- * @param {boolean} bRebuildOnly `true` if internal history is currently being rebuilt
615
- * @returns {Promise} Promise (resolved when the navigation is finalized) that returns 'true' if a navigation took place, 'false' if the navigation didn't happen
616
- * @ui5-restricted
617
- * @final
618
- */
619
- _rebuildBrowserHistory: function(oHistoryAction, bRebuildOnly) {
620
- var that = this;
621
- return new Promise(function(resolve, reject) {
622
- that.bIsRebuildHistoryRunning = true;
623
- var oTargetState = that._oManagedHistory[that._oManagedHistory.length - 1],
624
- newLevel = that._oManagedHistory.length - 1;
625
-
626
- function replaceAsync() {
627
- if (!bRebuildOnly) {
628
- that._enableEventOnHashChange(true);
629
- }
630
-
631
- that._oRouter.getHashChanger().replaceHash(oTargetState.hash);
632
- history.replaceState(Object.assign({ feLevel: newLevel }, history.state), "");
633
-
634
- if (bRebuildOnly) {
635
- setTimeout(function() {
636
- // Timeout to let 'hashchange' event be processed before by the HashChanger, so that
637
- // onRouteMatched notification isn't raised
638
- that._enableEventOnHashChange(true);
639
- }, 0);
640
- }
641
-
642
- that.bIsRebuildHistoryRunning = false;
643
- resolve(true); // a navigation occurred
644
- }
645
-
646
- // Async callbacks when navigating back, in order to let all notifications and events get processed
647
- function backReplaceAsync() {
648
- window.removeEventListener("popstate", backReplaceAsync);
649
- setTimeout(function() {
650
- // Timeout to let 'hashchange' event be processed before by the HashChanger
651
- replaceAsync();
652
- }, 0);
653
- }
654
-
655
- function backAsync() {
656
- window.removeEventListener("popstate", backAsync);
657
- that.bIsRebuildHistoryRunning = false;
658
- resolve(true); // a navigation occurred
659
- }
660
-
661
- that._bIgnoreRestore = true;
662
-
663
- switch (oHistoryAction.type) {
664
- case "replace":
665
- that._oRouter.getHashChanger().replaceHash(oTargetState.hash);
666
- history.replaceState(Object.assign({ feLevel: newLevel }, history.state), "");
667
- that.bIsRebuildHistoryRunning = false;
668
- resolve(true); // a navigation occurred
669
- break;
670
-
671
- case "append":
672
- that._oRouter.getHashChanger().setHash(oTargetState.hash);
673
- history.replaceState(Object.assign({ feLevel: newLevel }, history.state), "");
674
- that.bIsRebuildHistoryRunning = false;
675
- resolve(true); // a navigation occurred
676
- break;
677
-
678
- case "back":
679
- window.addEventListener("popstate", backAsync);
680
- history.go(-oHistoryAction.steps);
681
- break;
682
-
683
- case "back-replace":
684
- that._disableEventOnHashChange();
685
- window.addEventListener("popstate", backReplaceAsync);
686
- history.go(-oHistoryAction.steps);
687
- break;
688
-
689
- default:
690
- // No navigation
691
- that.bIsRebuildHistoryRunning = false;
692
- resolve(false); // no navigation --> resolve to false
693
- }
694
- });
695
- },
696
-
697
- getLastHistoryEntry: function() {
698
- return this._oManagedHistory[this._oManagedHistory.length - 1];
699
- },
700
-
701
- hashGuard: function(oEvent) {
702
- if (this._bCleanedRestore) {
703
- this._bCleanedRestore = false;
704
- return;
705
- }
706
- var sHash = window.location.hash;
707
- if (sHash.indexOf("restoreHistory=true") !== -1) {
708
- this._bApplyRestore = true;
709
- } else if (!this.bIsRebuildHistoryRunning) {
710
- var aHashSplit = sHash.split("&/");
711
- var sAppHash = aHashSplit[1] ? aHashSplit[1] : "";
712
- if (this.checkHashWithGuard(sAppHash)) {
713
- this._bDelayedRebuild = true;
714
- var oNewState = this._extractStateFromHash(sAppHash);
715
- this._pushNewState(oNewState, false, false, true);
716
-
717
- var that = this;
718
- setTimeout(function() {
719
- that._bDelayedRebuild = false;
720
- }, 0);
721
- }
722
- }
723
- },
724
-
725
- /**
726
- * Compares 2 states.
727
- *
728
- * @param {object} oState1
729
- * @param {object} oState2
730
- * @returns {number} The result of the comparison:
731
- * - enumState.EQUAL if oState1 and oState2 are equal
732
- * - enumState.COMPATIBLE if oState1 and oState2 are compatible
733
- * - enumState.ANCESTOR if oState1 is an ancestor of oState2
734
- * - enumState.DIFFERENT if the 2 states are different
735
- */
736
-
737
- _compareCacheStates: function(oState1, oState2) {
738
- // First compare object keys
739
- if (oState1.keys.length > oState2.keys.length) {
740
- return enumState.DIFFERENT;
741
- }
742
- var equal = true;
743
- var index;
744
- for (index = 0; equal && index < oState1.keys.length; index++) {
745
- if (oState1.keys[index] !== oState2.keys[index]) {
746
- equal = false;
747
- }
748
- }
749
- if (!equal) {
750
- // Some objects keys are different
751
- return enumState.DIFFERENT;
752
- }
753
-
754
- // All keys from oState1 are in oState2 --> check if ancestor
755
- if (oState1.keys.length < oState2.keys.length || oState1.screenMode < oState2.screenMode) {
756
- return enumState.ANCESTOR;
757
- }
758
- if (oState1.screenMode > oState2.screenMode) {
759
- return enumState.DIFFERENT; // Not sure this case can happen...
760
- }
761
-
762
- // At this stage, the 2 states have the same object keys (in the same order) and same screenmode
763
- // They can be either compatible or equal
764
- return oState1.sLayout === oState2.sLayout ? enumState.EQUAL : enumState.COMPATIBLE;
765
- },
766
-
767
- /**
768
- * Checks if back exits the present guard set.
769
- *
770
- * @param {string} sPresentHash The current hash. Only used for unit tests.
771
- * @returns {boolean} `true` if back exits there is a guard exit on back
772
- */
773
- checkIfBackIsOutOfGuard: function(sPresentHash) {
774
- var that = this,
775
- sPrevHash;
776
-
777
- if (sPresentHash === undefined) {
778
- // We use window.location.hash instead of HashChanger.getInstance().getHash() because the latter
779
- // replaces characters in the URL (e.g. %24 replaced by $) and it causes issues when comparing
780
- // with the URLs in the managed history
781
- var oSplitHash = this._oShellServices.splitHash(window.location.hash);
782
- if (oSplitHash && oSplitHash.appSpecificRoute) {
783
- sPresentHash = oSplitHash.appSpecificRoute;
784
- if (sPresentHash.indexOf("&/") === 0) {
785
- sPresentHash = sPresentHash.substring(2);
786
- }
787
- } else {
788
- sPresentHash = window.location.hash.substring(1); // To remove the '#'
789
- if (sPresentHash[0] === "/") {
790
- sPresentHash = sPresentHash.substring(1);
791
- }
792
- }
793
- }
794
- sPresentHash = URI.decode(sPresentHash);
795
- if (that._oNavigationGuard) {
796
- for (var i = that._oManagedHistory.length - 1; i > 0; i--) {
797
- if (that._oManagedHistory[i].hash === sPresentHash) {
798
- sPrevHash = that._oManagedHistory[i - 1].hash;
799
- break;
800
- }
801
- }
802
-
803
- return !sPrevHash || !that.checkHashWithGuard(sPrevHash);
804
- }
805
- return false;
806
- },
807
-
808
- /**
809
- * Checks if the last 2 entries in the history share the same context.
810
- *
811
- * @returns {boolean} `true` if they share the same context.
812
- */
813
- checkIfBackHasSameContext: function() {
814
- if (this._oManagedHistory.length < 2) {
815
- return false;
816
- }
817
-
818
- var oCurrentState = this._oManagedHistory[this._oManagedHistory.length - 1];
819
- var oPreviousState = this._oManagedHistory[this._oManagedHistory.length - 2];
820
-
821
- return oCurrentState.hash.split("?")[0] === oPreviousState.hash.split("?")[0];
822
- }
823
- });
824
- }
825
- );
5
+ sap.ui.define(["sap/base/Log", "sap/ui/base/Object", "sap/fe/core/Synchronization", "sap/ui/thirdparty/URI", "sap/fe/core/helpers/ClassSupport", "sap/ui/core/Core"], function (Log, BaseObject, Synchronization, URI, ClassSupport, Core) {
6
+ "use strict";
7
+
8
+ var _dec, _class;
9
+
10
+ var defineUI5Class = ClassSupport.defineUI5Class;
11
+
12
+ function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
13
+
14
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
15
+
16
+ var enumState = {
17
+ EQUAL: 0,
18
+ COMPATIBLE: 1,
19
+ ANCESTOR: 2,
20
+ DIFFERENT: 3
21
+ };
22
+ var enumURLParams = {
23
+ LAYOUTPARAM: "layout",
24
+ IAPPSTATEPARAM: "sap-iapp-state"
25
+ };
26
+ /**
27
+ * Creates a HashGuard object.
28
+ *
29
+ * @param {string} sGuardHash The hash used for the guard
30
+ * @returns {object} The created hash guard
31
+ */
32
+
33
+ function createGuardFromHash(sGuardHash) {
34
+ return {
35
+ _guardHash: sGuardHash.replace(/\?[^\?]*$/, ""),
36
+ // Remove query part
37
+ check: function (sHash) {
38
+ return sHash.indexOf(this._guardHash) === 0;
39
+ }
40
+ };
41
+ }
42
+ /**
43
+ * Returns the iAppState part from a hash (or null if not found).
44
+ *
45
+ * @param {string} sHash The hash
46
+ * @returns {string} The iAppState part of the hash
47
+ */
48
+
49
+
50
+ function findAppStateInHash(sHash) {
51
+ var aAppState = sHash.match(new RegExp("\\?.*" + enumURLParams.IAPPSTATEPARAM + "=([^&]*)"));
52
+ return aAppState && aAppState.length > 1 ? aAppState[1] : null;
53
+ }
54
+ /**
55
+ * Returns a hash without its iAppState part.
56
+ *
57
+ * @param {string} sHash The hash
58
+ * @returns {string} The hash without the iAppState
59
+ */
60
+
61
+
62
+ function removeAppStateInHash(sHash) {
63
+ return sHash.replace(new RegExp("[&?]*" + enumURLParams.IAPPSTATEPARAM + "=[^&]*"), "");
64
+ }
65
+ /**
66
+ * Adds an iAppState inside a hash (or replaces an existing one).
67
+ *
68
+ * @param {*} sHash The hash
69
+ * @param {*} sAppStateKey The iAppState to add
70
+ * @returns {string} The hash with the app state
71
+ */
72
+
73
+
74
+ function setAppStateInHash(sHash, sAppStateKey) {
75
+ var sNewHash;
76
+
77
+ if (sHash.indexOf(enumURLParams.IAPPSTATEPARAM) >= 0) {
78
+ // If there's already an iAppState parameter in the hash, replace it
79
+ sNewHash = sHash.replace(new RegExp(enumURLParams.IAPPSTATEPARAM + "=[^&]*"), enumURLParams.IAPPSTATEPARAM + "=" + sAppStateKey);
80
+ } else {
81
+ // Add the iAppState parameter in the hash
82
+ if (sHash.indexOf("?") < 0) {
83
+ sNewHash = sHash + "?";
84
+ } else {
85
+ sNewHash = sHash + "&";
86
+ }
87
+
88
+ sNewHash += enumURLParams.IAPPSTATEPARAM + "=" + sAppStateKey;
89
+ }
90
+
91
+ return sNewHash;
92
+ }
93
+
94
+ var RouterProxy = (_dec = defineUI5Class("sap.fe.core.RouterProxy"), _dec(_class = /*#__PURE__*/function (_BaseObject) {
95
+ _inheritsLoose(RouterProxy, _BaseObject);
96
+
97
+ function RouterProxy() {
98
+ var _this;
99
+
100
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
101
+ args[_key] = arguments[_key];
102
+ }
103
+
104
+ _this = _BaseObject.call.apply(_BaseObject, [this].concat(args)) || this;
105
+ _this.bIsRebuildHistoryRunning = false;
106
+ _this.bIsComputingTitleHierachy = false;
107
+ _this.bIsGuardCrossAllowed = false;
108
+ _this.sIAppStateKey = null;
109
+ _this._bActivateRouteMatchSynchro = false;
110
+ _this._bApplyRestore = false;
111
+ _this._bDelayedRebuild = false;
112
+ _this._pathMappings = [];
113
+ return _this;
114
+ }
115
+
116
+ var _proto = RouterProxy.prototype;
117
+
118
+ _proto.init = function init(oAppComponent, isfclEnabled) {
119
+ var _this2 = this;
120
+
121
+ // Save the name of the app (including startup parameters) for rebuilding full hashes later
122
+ oAppComponent.getService("shellServices").then(function () {
123
+ _this2._oShellServices = oAppComponent.getShellServices();
124
+
125
+ _this2.initRaw(oAppComponent.getRouter()); // We want to wait until the initial routeMatched is done before doing any navigation
126
+
127
+
128
+ _this2.waitForRouteMatchBeforeNavigation(); // Set feLevel=0 for the first Application page in the history
129
+
130
+
131
+ history.replaceState(Object.assign({
132
+ feLevel: 0
133
+ }, history.state), "", window.location);
134
+ _this2.fclEnabled = isfclEnabled;
135
+ _this2._fnBlockingNavFilter = _this2._blockingNavigationFilter.bind(_this2);
136
+
137
+ _this2._oShellServices.registerNavigationFilter(_this2._fnBlockingNavFilter);
138
+ }).catch(function (oError) {
139
+ Log.error("Cannot retrieve the shell services", oError);
140
+ });
141
+ this._fnHashGuard = this.hashGuard.bind(this);
142
+ window.addEventListener("popstate", this._fnHashGuard);
143
+ this._bDisableOnHashChange = false;
144
+ this._bIgnoreRestore = false;
145
+ this._bForceFocus = true; // Trigger the focus mechanism for the first view displayed by the app
146
+ };
147
+
148
+ _proto.destroy = function destroy() {
149
+ if (this._oShellServices) {
150
+ this._oShellServices.unregisterNavigationFilter(this._fnBlockingNavFilter);
151
+ }
152
+
153
+ window.removeEventListener("popstate", this._fnHashGuard);
154
+ }
155
+ /**
156
+ * Raw initialization (for unit tests).
157
+ *
158
+ * @param {sap.ui.core.routing.Router} oRouter The router used by this proxy
159
+ */
160
+ ;
161
+
162
+ _proto.initRaw = function initRaw(oRouter) {
163
+ this._oRouter = oRouter;
164
+ this._oManagedHistory = [];
165
+ this._oNavigationGuard = null;
166
+ var sCurrentAppHash = this.getHash();
167
+
168
+ this._oManagedHistory.push(this._extractStateFromHash(sCurrentAppHash)); // Set the iAppState if the initial hash contains one
169
+
170
+
171
+ this.sIAppStateKey = findAppStateInHash(sCurrentAppHash);
172
+ };
173
+
174
+ _proto.getHash = function getHash() {
175
+ return this._oRouter.getHashChanger().getHash();
176
+ };
177
+
178
+ _proto.isFocusForced = function isFocusForced() {
179
+ return this._bForceFocus;
180
+ };
181
+
182
+ _proto.setFocusForced = function setFocusForced(bForced) {
183
+ this._bForceFocus = bForced;
184
+ }
185
+ /**
186
+ * Resets the internal variable sIAppStateKey.
187
+ *
188
+ * @function
189
+ * @name sap.fe.core.RouterProxy#removeIAppStateKey
190
+ *
191
+ * @ui5-restricted
192
+ */
193
+ ;
194
+
195
+ _proto.removeIAppStateKey = function removeIAppStateKey() {
196
+ this.sIAppStateKey = null;
197
+ }
198
+ /**
199
+ * Navigates to a specific hash.
200
+ *
201
+ * @function
202
+ * @name sap.fe.core.RouterProxy#navToHash
203
+ * @memberof sap.fe.core.RouterProxy
204
+ * @static
205
+ * @param {string} sHash Hash to be navigated to
206
+ * @param {boolean} bPreserveHistory If set to true, non-ancestor entries in history will be retained
207
+ * @param {boolean} bDisablePreservationCache If set to true, cache preservation mechanism is disabled for the current navigation
208
+ * @param {boolean} bForceFocus If set to true, the logic to set the focus once the navigation is finalized will be triggered (onPageReady)
209
+ * @param {boolean} bPreserveShellBackNavigationHandler If not set to false, the back navigation is set to undefined
210
+ * @returns {Promise} Promise (resolved when the navigation is finalized) that returns 'true' if a navigation took place, 'false' if the navigation didn't happen
211
+ * @ui5-restricted
212
+ */
213
+ ;
214
+
215
+ _proto.navToHash = function navToHash(sHash, bPreserveHistory, bDisablePreservationCache, bForceFocus, bPreserveShellBackNavigationHandler) {
216
+ var _this3 = this;
217
+
218
+ if (bPreserveShellBackNavigationHandler !== false) {
219
+ this._oShellServices.setBackNavigation();
220
+ }
221
+
222
+ if (this._oRouteMatchSynchronization) {
223
+ return this._oRouteMatchSynchronization.waitFor().then(function () {
224
+ _this3._oRouteMatchSynchronization = undefined;
225
+ return _this3._internalNavToHash(sHash, bPreserveHistory, bDisablePreservationCache, bForceFocus);
226
+ });
227
+ } else {
228
+ if (this._bActivateRouteMatchSynchro) {
229
+ this.waitForRouteMatchBeforeNavigation();
230
+ }
231
+
232
+ return this._internalNavToHash(sHash, bPreserveHistory, bDisablePreservationCache, bForceFocus);
233
+ }
234
+ };
235
+
236
+ _proto._internalNavToHash = function _internalNavToHash(sHash, bPreserveHistory, bDisablePreservationCache, bForceFocus) {
237
+ // Add the app state in the hash if needed
238
+ if (this.fclEnabled && this.sIAppStateKey && !findAppStateInHash(sHash)) {
239
+ sHash = setAppStateInHash(sHash, this.sIAppStateKey);
240
+ }
241
+
242
+ if (!this.checkHashWithGuard(sHash)) {
243
+ if (!this.oResourceBundle) {
244
+ this.oResourceBundle = Core.getLibraryResourceBundle("sap.fe.core");
245
+ } // We have to use a confirm here for UI consistency reasons, as with some scenarios
246
+ // in the EditFlow we rely on a UI5 mechanism that displays a confirm dialog.
247
+ // eslint-disable-next-line no-alert
248
+
249
+
250
+ if (!confirm(this.oResourceBundle.getText("C_ROUTER_PROXY_SAPFE_EXIT_NOTSAVED_MESSAGE"))) {
251
+ // The user clicked on Cancel --> cancel navigation
252
+ return Promise.resolve(false);
253
+ }
254
+
255
+ this.bIsGuardCrossAllowed = true;
256
+ } // In case the navigation will cause a new view to be displayed, we force the focus
257
+ // I.e. if the keys for the hash we're navigating to is a superset of the current hash keys.
258
+
259
+
260
+ var oNewState = this._extractStateFromHash(sHash);
261
+
262
+ if (!this._bForceFocus) {
263
+ // If the focus was already forced, keep it
264
+ var aCurrentHashKeys = this._extractKeysFromHash(this.getHash());
265
+
266
+ this._bForceFocus = bForceFocus || aCurrentHashKeys.length < oNewState.keys.length && aCurrentHashKeys.every(function (key, index) {
267
+ return key === oNewState.keys[index];
268
+ });
269
+ }
270
+
271
+ var oHistoryAction = this._pushNewState(oNewState, false, bPreserveHistory, bDisablePreservationCache);
272
+
273
+ return this._rebuildBrowserHistory(oHistoryAction, false);
274
+ }
275
+ /**
276
+ * Clears browser history if entries have been added without using the RouterProxy.
277
+ * Updates the internal history accordingly.
278
+ *
279
+ * @returns {Promise} Promise that is resolved once the history is rebuilt
280
+ */
281
+ ;
282
+
283
+ _proto.restoreHistory = function restoreHistory() {
284
+ if (this._bApplyRestore) {
285
+ this._bApplyRestore = false;
286
+ var sTargetHash = this.getHash();
287
+ sTargetHash = sTargetHash.replace(/(\?|&)restoreHistory=true/, "");
288
+
289
+ var oNewState = this._extractStateFromHash(sTargetHash);
290
+
291
+ var oHistoryAction = this._pushNewState(oNewState, true, false, true);
292
+
293
+ return this._rebuildBrowserHistory(oHistoryAction, true);
294
+ } else {
295
+ return Promise.resolve();
296
+ }
297
+ }
298
+ /**
299
+ * Navigates back in the history.
300
+ *
301
+ * @returns {Promise} Promise that is resolved when the navigation is finalized
302
+ */
303
+ ;
304
+
305
+ _proto.navBack = function navBack() {
306
+ var sCurrentHash = this.getHash();
307
+ var sPreviousHash; // Look for the current hash in the managed history
308
+
309
+ for (var i = this._oManagedHistory.length - 1; i > 0; i--) {
310
+ if (this._oManagedHistory[i].hash === sCurrentHash) {
311
+ sPreviousHash = this._oManagedHistory[i - 1].hash;
312
+ break;
313
+ }
314
+ }
315
+
316
+ if (sPreviousHash) {
317
+ return this.navToHash(sPreviousHash);
318
+ } else {
319
+ // We couldn't find a previous hash in history
320
+ // This can happen when navigating from a transient hash in a create app, and
321
+ // in that case history.back would go back to the FLP
322
+ window.history.back();
323
+ return Promise.resolve();
324
+ }
325
+ }
326
+ /**
327
+ * Navigates to a route with parameters.
328
+ * @param {string} sRouteName The route name to be navigated to
329
+ * @param {object} oParameters Parameters for the navigation
330
+ * @returns {Promise} Promise that is resolved when the navigation is finalized
331
+ * @ui5-restricted
332
+ */
333
+ ;
334
+
335
+ _proto.navTo = function navTo(sRouteName, oParameters) {
336
+ var sHash = this._oRouter.getURL(sRouteName, oParameters);
337
+
338
+ return this.navToHash(sHash, false, oParameters.noPreservationCache, false, !oParameters.bIsStickyMode);
339
+ }
340
+ /**
341
+ * Exits the current app by navigating back
342
+ * to the previous app (if any) or the FLP.
343
+ *
344
+ * @returns {Promise} Promise that is resolved when we exit the app
345
+ */
346
+ ;
347
+
348
+ _proto.exitFromApp = function exitFromApp() {
349
+ return this._oShellServices.backToPreviousApp();
350
+ }
351
+ /**
352
+ * Checks whether a given hash can have an impact on the current state
353
+ * i.e. if the hash is equal, compatible or an ancestor of the current state.
354
+ *
355
+ * @param {*} sHash `true` if there is an impact
356
+ * @returns {boolean} If there is an impact
357
+ */
358
+ ;
359
+
360
+ _proto.isCurrentStateImpactedBy = function isCurrentStateImpactedBy(sHash) {
361
+ if (sHash[0] === "/") {
362
+ sHash = sHash.substring(1);
363
+ }
364
+
365
+ var oLocalGuard = createGuardFromHash(sHash);
366
+ return oLocalGuard.check(this.getHash());
367
+ }
368
+ /**
369
+ * Checks if a navigation is currently being processed.
370
+ *
371
+ * @returns {boolean} `false` if a navigation has been triggered in the RouterProxy and is not yet finalized
372
+ */
373
+ ;
374
+
375
+ _proto.isNavigationFinalized = function isNavigationFinalized() {
376
+ return !this.bIsRebuildHistoryRunning && !this._bDelayedRebuild;
377
+ }
378
+ /**
379
+ * Sets the last state as a guard.
380
+ * Each future navigation will be checked against this guard, and a confirmation dialog will
381
+ * be displayed before the navigation crosses the guard (i.e. goes to an ancestor of the guard).
382
+ *
383
+ * @param sHash The hash for the guard
384
+ */
385
+ ;
386
+
387
+ _proto.setNavigationGuard = function setNavigationGuard(sHash) {
388
+ this._oNavigationGuard = createGuardFromHash(sHash);
389
+ this.bIsGuardCrossAllowed = false;
390
+ }
391
+ /**
392
+ * Disables the navigation guard.
393
+ */
394
+ ;
395
+
396
+ _proto.discardNavigationGuard = function discardNavigationGuard() {
397
+ this._oNavigationGuard = null;
398
+ }
399
+ /**
400
+ * Checks for the availability of the navigation guard.
401
+ *
402
+ * @returns {boolean} `true` if navigating guard is available
403
+ */
404
+ ;
405
+
406
+ _proto.hasNavigationGuard = function hasNavigationGuard() {
407
+ return this._oNavigationGuard !== null;
408
+ }
409
+ /**
410
+ * Tests a hash against the navigation guard.
411
+ *
412
+ * @param {string} sHash The hash to be tested
413
+ * @returns {boolean} `true` if navigating to the hash doesn't cross the guard
414
+ */
415
+ ;
416
+
417
+ _proto.checkHashWithGuard = function checkHashWithGuard(sHash) {
418
+ return this._oNavigationGuard === null || this._oNavigationGuard.check(sHash);
419
+ }
420
+ /**
421
+ * Checks if the user allowed the navigation guard to be crossed.
422
+ *
423
+ * @returns {boolean} `true` if crossing the guard has been allowed by the user
424
+ */
425
+ ;
426
+
427
+ _proto.isGuardCrossAllowedByUser = function isGuardCrossAllowedByUser() {
428
+ return this.bIsGuardCrossAllowed;
429
+ }
430
+ /**
431
+ * Activates the synchronization for routeMatchedEvent.
432
+ * The next NavToHash call will create a Synchronization object that will be resolved
433
+ * by the corresponding onRouteMatched event, preventing another NavToHash to happen in parallel.
434
+ */
435
+ ;
436
+
437
+ _proto.activateRouteMatchSynchronization = function activateRouteMatchSynchronization() {
438
+ this._bActivateRouteMatchSynchro = true;
439
+ }
440
+ /**
441
+ * Resolve the routeMatch synchronization object, unlocking potential pending NavToHash calls.
442
+ */
443
+ ;
444
+
445
+ _proto.resolveRouteMatch = function resolveRouteMatch() {
446
+ if (this._oRouteMatchSynchronization) {
447
+ this._oRouteMatchSynchronization.resolve();
448
+ }
449
+ }
450
+ /**
451
+ * Makes sure no navigation can happen before a routeMatch happened.
452
+ */
453
+ ;
454
+
455
+ _proto.waitForRouteMatchBeforeNavigation = function waitForRouteMatchBeforeNavigation() {
456
+ this._oRouteMatchSynchronization = new Synchronization();
457
+ this._bActivateRouteMatchSynchro = false;
458
+ };
459
+
460
+ _proto._extractKeysFromHash = function _extractKeysFromHash(sHash) {
461
+ if (sHash === undefined) {
462
+ sHash = "";
463
+ }
464
+
465
+ var sHashNoParams = sHash.split("?")[0]; // remove params
466
+
467
+ var aTokens = sHashNoParams.split("/");
468
+ var aKeys = [];
469
+ aTokens.forEach(function (sToken) {
470
+ var regexKey = /[^\(\)]+\([^\(\)]+\)/; // abc(def)
471
+
472
+ if (regexKey.test(sToken)) {
473
+ aKeys.push(sToken.split("(")[0]);
474
+ }
475
+ });
476
+ return aKeys;
477
+ }
478
+ /**
479
+ * Builds a state from a hash.
480
+ *
481
+ * @param {string} sHash The hash to be used as entry
482
+ * @returns {object} The state
483
+ *
484
+ * @ui5-restricted
485
+ */
486
+ ;
487
+
488
+ _proto._extractStateFromHash = function _extractStateFromHash(sHash) {
489
+ if (sHash === undefined) {
490
+ sHash = "";
491
+ }
492
+
493
+ var oState = {
494
+ keys: this._extractKeysFromHash(sHash)
495
+ }; // Retrieve layout (if any)
496
+
497
+ var aLayout = sHash.match(new RegExp("\\?.*" + enumURLParams.LAYOUTPARAM + "=([^&]*)"));
498
+ oState.sLayout = aLayout && aLayout.length > 1 ? aLayout[1] : null;
499
+
500
+ if (oState.sLayout === "MidColumnFullScreen") {
501
+ oState.screenMode = 1;
502
+ } else if (oState.sLayout === "EndColumnFullScreen") {
503
+ oState.screenMode = 2;
504
+ } else {
505
+ oState.screenMode = 0;
506
+ }
507
+
508
+ oState.hash = sHash;
509
+ return oState;
510
+ }
511
+ /**
512
+ * Adds a new state into the internal history structure.
513
+ * Makes sure this new state is added after an ancestor.
514
+ * Also sets the iAppState key in the whole history.
515
+ *
516
+ * @memberof sap.fe.core.RouterProxy
517
+ * @param {object} oNewState The new state to be added
518
+ * @param {boolean} bRebuildOnly `true` if we're rebuilding the history after a shell menu navigation
519
+ * @param {boolean} bPreserveHistory If set to true, non-ancestor entries in history will be retained
520
+ * @param {boolean} bDisableHistoryPreservation Disable the mechanism to retained marked entries in cache
521
+ * @returns {object} The new state
522
+ * @ui5-restricted
523
+ * @final
524
+ */
525
+ ;
526
+
527
+ _proto._pushNewState = function _pushNewState(oNewState, bRebuildOnly, bPreserveHistory, bDisableHistoryPreservation) {
528
+ var _this4 = this;
529
+
530
+ var sCurrentHash = this.getHash();
531
+ var lastIndex = this._oManagedHistory.length - 1;
532
+ var iPopCount = bRebuildOnly ? 1 : 0; // 1. Do some cleanup in the managed history : in case the user has navigated back in the browser history, we need to remove
533
+ // the states ahead in history and make sure the top state corresponds to the current page
534
+ // We don't do that when restoring the history, as the current state has been added on top of the browser history
535
+ // and is not reflected in the managed history
536
+
537
+ if (!bRebuildOnly) {
538
+ while (lastIndex >= 0 && this._oManagedHistory[lastIndex].hash !== sCurrentHash) {
539
+ this._oManagedHistory.pop();
540
+
541
+ lastIndex--;
542
+ }
543
+
544
+ if (this._oManagedHistory.length === 0) {
545
+ // We couldn't find the current location in the history. This can happen if a browser reload
546
+ // happened, causing a reinitialization of the managed history.
547
+ // In that case, we use the current location as the new starting point in the managed history
548
+ this._oManagedHistory.push(this._extractStateFromHash(sCurrentHash));
549
+
550
+ history.replaceState(Object.assign({
551
+ feLevel: 0
552
+ }, history.state), "");
553
+ }
554
+ } // 2. Mark the top state as preserved if required
555
+
556
+
557
+ if (bPreserveHistory && !bDisableHistoryPreservation) {
558
+ this._oManagedHistory[this._oManagedHistory.length - 1].preserved = true;
559
+ } // 3. Then pop all states until we find an ancestor of the new state, or we find a state that need to be preserved
560
+
561
+
562
+ var oLastRemovedItem;
563
+
564
+ while (this._oManagedHistory.length > 0) {
565
+ var oTopState = this._oManagedHistory[this._oManagedHistory.length - 1];
566
+
567
+ if ((bDisableHistoryPreservation || !oTopState.preserved) && this._compareCacheStates(oTopState, oNewState) !== enumState.ANCESTOR) {
568
+ // The top state is not an ancestor of oNewState and is not preserved --> we can pop it
569
+ oLastRemovedItem = this._oManagedHistory.pop();
570
+ iPopCount++;
571
+ } else if (oTopState.preserved && removeAppStateInHash(oTopState.hash) === removeAppStateInHash(oNewState.hash)) {
572
+ // We try to add a state that is already in cache (due to preserved flag) but with a different iapp-state
573
+ // --> we should delete the previous entry (it will be later replaced by the new one) and stop popping
574
+ oLastRemovedItem = this._oManagedHistory.pop();
575
+ iPopCount++;
576
+ oNewState.preserved = true;
577
+ break;
578
+ } else {
579
+ break; // Ancestor or preserved state found --> we stop popping out states
580
+ }
581
+ } // 4. iAppState management
582
+
583
+
584
+ this.sIAppStateKey = findAppStateInHash(oNewState.hash);
585
+
586
+ if (this.fclEnabled && this.sIAppStateKey) {
587
+ // In case of FCL, the new app state needs to be applied to the whole history
588
+ this._oManagedHistory.forEach(function (oManagedState) {
589
+ oManagedState.hash = setAppStateInHash(oManagedState.hash, _this4.sIAppStateKey);
590
+ });
591
+ } else if (!this.fclEnabled && oLastRemovedItem) {
592
+ var sPreviousIAppStateKey = findAppStateInHash(oLastRemovedItem.hash);
593
+
594
+ var oComparisonStateResult = this._compareCacheStates(oLastRemovedItem, oNewState); // if current state doesn't contain a i-appstate and this state should replace a state containing a iAppState
595
+ // then the previous iAppState is preserved
596
+
597
+
598
+ if (!this.sIAppStateKey && sPreviousIAppStateKey && (oComparisonStateResult === enumState.EQUAL || oComparisonStateResult === enumState.COMPATIBLE)) {
599
+ oNewState.hash = setAppStateInHash(oNewState.hash, sPreviousIAppStateKey);
600
+ }
601
+ } // 5. Now we can push the state at the top of the internal history
602
+
603
+
604
+ var bHasSameHash = oLastRemovedItem && oNewState.hash === oLastRemovedItem.hash;
605
+
606
+ if (this._oManagedHistory.length === 0 || this._oManagedHistory[this._oManagedHistory.length - 1].hash !== oNewState.hash) {
607
+ this._oManagedHistory.push(oNewState);
608
+ } // 6. Determine which actions to do on the history
609
+
610
+
611
+ if (iPopCount === 0) {
612
+ // No state was popped --> append
613
+ return {
614
+ type: "append"
615
+ };
616
+ } else if (iPopCount === 1) {
617
+ // Only 1 state was popped --> replace current hash unless hash is the same (then nothing to do)
618
+ return bHasSameHash ? {
619
+ type: "none"
620
+ } : {
621
+ type: "replace"
622
+ };
623
+ } else {
624
+ // More than 1 state was popped --> go bakc in history and replace hash if necessary
625
+ return bHasSameHash ? {
626
+ type: "back",
627
+ steps: iPopCount - 1
628
+ } : {
629
+ type: "back-replace",
630
+ steps: iPopCount - 1
631
+ };
632
+ }
633
+ };
634
+
635
+ _proto._blockingNavigationFilter = function _blockingNavigationFilter() {
636
+ return this._bDisableOnHashChange ? "Custom" : "Continue";
637
+ }
638
+ /**
639
+ * Disable the routing by calling the router stop method.
640
+ *
641
+ * @function
642
+ * @memberof sap.fe.core.RouterProxy
643
+ *
644
+ * @ui5-restricted
645
+ * @final
646
+ */
647
+ ;
648
+
649
+ _proto._disableEventOnHashChange = function _disableEventOnHashChange() {
650
+ this._bDisableOnHashChange = true;
651
+
652
+ this._oRouter.stop();
653
+ }
654
+ /**
655
+ * Enable the routing by calling the router initialize method.
656
+ *
657
+ * @function
658
+ * @name sap.fe.core.RouterProxy#_enableEventOnHashChange
659
+ * @memberof sap.fe.core.RouterProxy
660
+ * @param {boolean} [bIgnoreCurrentHash] Ignore the last hash event triggered before the router has initialized
661
+ *
662
+ * @ui5-restricted
663
+ * @final
664
+ */
665
+ ;
666
+
667
+ _proto._enableEventOnHashChange = function _enableEventOnHashChange(bIgnoreCurrentHash) {
668
+ this._bDisableOnHashChange = false;
669
+
670
+ this._oRouter.initialize(bIgnoreCurrentHash);
671
+ }
672
+ /**
673
+ * Synchronizes the browser history with the internal history of the routerProxy, and triggers a navigation if needed.
674
+ *
675
+ * @memberof sap.fe.core.RouterProxy
676
+ * @param {object} oHistoryAction Specifies the navigation action to be performed
677
+ * @param {boolean} bRebuildOnly `true` if internal history is currently being rebuilt
678
+ * @returns {Promise} Promise (resolved when the navigation is finalized) that returns 'true' if a navigation took place, 'false' if the navigation didn't happen
679
+ * @ui5-restricted
680
+ * @final
681
+ */
682
+ ;
683
+
684
+ _proto._rebuildBrowserHistory = function _rebuildBrowserHistory(oHistoryAction, bRebuildOnly) {
685
+ var _this5 = this;
686
+
687
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
688
+ var that = this;
689
+ return new Promise(function (resolve) {
690
+ _this5.bIsRebuildHistoryRunning = true;
691
+ var oTargetState = _this5._oManagedHistory[_this5._oManagedHistory.length - 1],
692
+ newLevel = _this5._oManagedHistory.length - 1;
693
+
694
+ function replaceAsync() {
695
+ if (!bRebuildOnly) {
696
+ that._enableEventOnHashChange(true);
697
+ }
698
+
699
+ that._oRouter.getHashChanger().replaceHash(oTargetState.hash);
700
+
701
+ history.replaceState(Object.assign({
702
+ feLevel: newLevel
703
+ }, history.state), "");
704
+
705
+ if (bRebuildOnly) {
706
+ setTimeout(function () {
707
+ // Timeout to let 'hashchange' event be processed before by the HashChanger, so that
708
+ // onRouteMatched notification isn't raised
709
+ that._enableEventOnHashChange(true);
710
+ }, 0);
711
+ }
712
+
713
+ that.bIsRebuildHistoryRunning = false;
714
+ resolve(true); // a navigation occurred
715
+ } // Async callbacks when navigating back, in order to let all notifications and events get processed
716
+
717
+
718
+ function backReplaceAsync() {
719
+ window.removeEventListener("popstate", backReplaceAsync);
720
+ setTimeout(function () {
721
+ // Timeout to let 'hashchange' event be processed before by the HashChanger
722
+ replaceAsync();
723
+ }, 0);
724
+ }
725
+
726
+ function backAsync() {
727
+ window.removeEventListener("popstate", backAsync);
728
+ that.bIsRebuildHistoryRunning = false;
729
+ resolve(true); // a navigation occurred
730
+ }
731
+
732
+ that._bIgnoreRestore = true;
733
+
734
+ switch (oHistoryAction.type) {
735
+ case "replace":
736
+ that._oRouter.getHashChanger().replaceHash(oTargetState.hash);
737
+
738
+ history.replaceState(Object.assign({
739
+ feLevel: newLevel
740
+ }, history.state), "");
741
+ that.bIsRebuildHistoryRunning = false;
742
+ resolve(true); // a navigation occurred
743
+
744
+ break;
745
+
746
+ case "append":
747
+ that._oRouter.getHashChanger().setHash(oTargetState.hash);
748
+
749
+ history.replaceState(Object.assign({
750
+ feLevel: newLevel
751
+ }, history.state), "");
752
+ that.bIsRebuildHistoryRunning = false;
753
+ resolve(true); // a navigation occurred
754
+
755
+ break;
756
+
757
+ case "back":
758
+ window.addEventListener("popstate", backAsync);
759
+ history.go(-oHistoryAction.steps);
760
+ break;
761
+
762
+ case "back-replace":
763
+ _this5._disableEventOnHashChange();
764
+
765
+ window.addEventListener("popstate", backReplaceAsync);
766
+ history.go(-oHistoryAction.steps);
767
+ break;
768
+
769
+ default:
770
+ // No navigation
771
+ _this5.bIsRebuildHistoryRunning = false;
772
+ resolve(false);
773
+ // no navigation --> resolve to false
774
+ }
775
+ });
776
+ };
777
+
778
+ _proto.getLastHistoryEntry = function getLastHistoryEntry() {
779
+ return this._oManagedHistory[this._oManagedHistory.length - 1];
780
+ };
781
+
782
+ _proto.setPathMapping = function setPathMapping(mappings) {
783
+ this._pathMappings = mappings;
784
+ };
785
+
786
+ _proto.hashGuard = function hashGuard() {
787
+ var _this6 = this;
788
+
789
+ var sHash = window.location.hash;
790
+
791
+ if (sHash.indexOf("restoreHistory=true") !== -1) {
792
+ this._bApplyRestore = true;
793
+ } else if (!this.bIsRebuildHistoryRunning) {
794
+ // Check if the hash needs to be changed (this happens in FCL when switching b/w edit and read-only with 3 columns open)
795
+ var mapping = this._pathMappings.find(function (m) {
796
+ return sHash.indexOf(m.oldPath) >= 0;
797
+ });
798
+
799
+ if (mapping) {
800
+ // Replace the current hash
801
+ sHash = sHash.replace(mapping.oldPath, mapping.newPath);
802
+ history.replaceState(Object.assign({}, history.state), "", sHash);
803
+ } else {
804
+ var aHashSplit = sHash.split("&/");
805
+ var sAppHash = aHashSplit[1] ? aHashSplit[1] : "";
806
+
807
+ if (this.checkHashWithGuard(sAppHash)) {
808
+ this._bDelayedRebuild = true;
809
+
810
+ var oNewState = this._extractStateFromHash(sAppHash);
811
+
812
+ this._pushNewState(oNewState, false, false, true);
813
+
814
+ setTimeout(function () {
815
+ _this6._bDelayedRebuild = false;
816
+ }, 0);
817
+ }
818
+ }
819
+ }
820
+ }
821
+ /**
822
+ * Compares 2 states.
823
+ *
824
+ * @param {object} oState1
825
+ * @param {object} oState2
826
+ * @returns {number} The result of the comparison:
827
+ * - enumState.EQUAL if oState1 and oState2 are equal
828
+ * - enumState.COMPATIBLE if oState1 and oState2 are compatible
829
+ * - enumState.ANCESTOR if oState1 is an ancestor of oState2
830
+ * - enumState.DIFFERENT if the 2 states are different
831
+ */
832
+ ;
833
+
834
+ _proto._compareCacheStates = function _compareCacheStates(oState1, oState2) {
835
+ // First compare object keys
836
+ if (oState1.keys.length > oState2.keys.length) {
837
+ return enumState.DIFFERENT;
838
+ }
839
+
840
+ var equal = true;
841
+ var index;
842
+
843
+ for (index = 0; equal && index < oState1.keys.length; index++) {
844
+ if (oState1.keys[index] !== oState2.keys[index]) {
845
+ equal = false;
846
+ }
847
+ }
848
+
849
+ if (!equal) {
850
+ // Some objects keys are different
851
+ return enumState.DIFFERENT;
852
+ } // All keys from oState1 are in oState2 --> check if ancestor
853
+
854
+
855
+ if (oState1.keys.length < oState2.keys.length || oState1.screenMode < oState2.screenMode) {
856
+ return enumState.ANCESTOR;
857
+ }
858
+
859
+ if (oState1.screenMode > oState2.screenMode) {
860
+ return enumState.DIFFERENT; // Not sure this case can happen...
861
+ } // At this stage, the 2 states have the same object keys (in the same order) and same screenmode
862
+ // They can be either compatible or equal
863
+
864
+
865
+ return oState1.sLayout === oState2.sLayout ? enumState.EQUAL : enumState.COMPATIBLE;
866
+ }
867
+ /**
868
+ * Checks if back exits the present guard set.
869
+ *
870
+ * @param {string} sPresentHash The current hash. Only used for unit tests.
871
+ * @returns {boolean} `true` if back exits there is a guard exit on back
872
+ */
873
+ ;
874
+
875
+ _proto.checkIfBackIsOutOfGuard = function checkIfBackIsOutOfGuard(sPresentHash) {
876
+ var sPrevHash;
877
+ var sCurrentHash;
878
+
879
+ if (sPresentHash === undefined) {
880
+ // We use window.location.hash instead of HashChanger.getInstance().getHash() because the latter
881
+ // replaces characters in the URL (e.g. %24 replaced by $) and it causes issues when comparing
882
+ // with the URLs in the managed history
883
+ var oSplitHash = this._oShellServices.splitHash(window.location.hash);
884
+
885
+ if (oSplitHash && oSplitHash.appSpecificRoute) {
886
+ sCurrentHash = oSplitHash.appSpecificRoute;
887
+
888
+ if (sCurrentHash.indexOf("&/") === 0) {
889
+ sCurrentHash = sCurrentHash.substring(2);
890
+ }
891
+ } else {
892
+ sCurrentHash = window.location.hash.substring(1); // To remove the '#'
893
+
894
+ if (sCurrentHash[0] === "/") {
895
+ sCurrentHash = sCurrentHash.substring(1);
896
+ }
897
+ }
898
+ } else {
899
+ sCurrentHash = sPresentHash;
900
+ }
901
+
902
+ sPresentHash = URI.decode(sCurrentHash);
903
+
904
+ if (this._oNavigationGuard) {
905
+ for (var i = this._oManagedHistory.length - 1; i > 0; i--) {
906
+ if (this._oManagedHistory[i].hash === sPresentHash) {
907
+ sPrevHash = this._oManagedHistory[i - 1].hash;
908
+ break;
909
+ }
910
+ }
911
+
912
+ return !sPrevHash || !this.checkHashWithGuard(sPrevHash);
913
+ }
914
+
915
+ return false;
916
+ }
917
+ /**
918
+ * Checks if the last 2 entries in the history share the same context.
919
+ *
920
+ * @returns {boolean} `true` if they share the same context.
921
+ */
922
+ ;
923
+
924
+ _proto.checkIfBackHasSameContext = function checkIfBackHasSameContext() {
925
+ if (this._oManagedHistory.length < 2) {
926
+ return false;
927
+ }
928
+
929
+ var oCurrentState = this._oManagedHistory[this._oManagedHistory.length - 1];
930
+ var oPreviousState = this._oManagedHistory[this._oManagedHistory.length - 2];
931
+ return oCurrentState.hash.split("?")[0] === oPreviousState.hash.split("?")[0];
932
+ };
933
+
934
+ return RouterProxy;
935
+ }(BaseObject)) || _class);
936
+ return RouterProxy;
937
+ }, false);
938
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIlJvdXRlclByb3h5LnRzIl0sIm5hbWVzIjpbImVudW1TdGF0ZSIsIkVRVUFMIiwiQ09NUEFUSUJMRSIsIkFOQ0VTVE9SIiwiRElGRkVSRU5UIiwiZW51bVVSTFBhcmFtcyIsIkxBWU9VVFBBUkFNIiwiSUFQUFNUQVRFUEFSQU0iLCJjcmVhdGVHdWFyZEZyb21IYXNoIiwic0d1YXJkSGFzaCIsIl9ndWFyZEhhc2giLCJyZXBsYWNlIiwiY2hlY2siLCJzSGFzaCIsImluZGV4T2YiLCJmaW5kQXBwU3RhdGVJbkhhc2giLCJhQXBwU3RhdGUiLCJtYXRjaCIsIlJlZ0V4cCIsImxlbmd0aCIsInJlbW92ZUFwcFN0YXRlSW5IYXNoIiwic2V0QXBwU3RhdGVJbkhhc2giLCJzQXBwU3RhdGVLZXkiLCJzTmV3SGFzaCIsIlJvdXRlclByb3h5IiwiZGVmaW5lVUk1Q2xhc3MiLCJiSXNSZWJ1aWxkSGlzdG9yeVJ1bm5pbmciLCJiSXNDb21wdXRpbmdUaXRsZUhpZXJhY2h5IiwiYklzR3VhcmRDcm9zc0FsbG93ZWQiLCJzSUFwcFN0YXRlS2V5IiwiX2JBY3RpdmF0ZVJvdXRlTWF0Y2hTeW5jaHJvIiwiX2JBcHBseVJlc3RvcmUiLCJfYkRlbGF5ZWRSZWJ1aWxkIiwiX3BhdGhNYXBwaW5ncyIsImluaXQiLCJvQXBwQ29tcG9uZW50IiwiaXNmY2xFbmFibGVkIiwiZ2V0U2VydmljZSIsInRoZW4iLCJfb1NoZWxsU2VydmljZXMiLCJnZXRTaGVsbFNlcnZpY2VzIiwiaW5pdFJhdyIsImdldFJvdXRlciIsIndhaXRGb3JSb3V0ZU1hdGNoQmVmb3JlTmF2aWdhdGlvbiIsImhpc3RvcnkiLCJyZXBsYWNlU3RhdGUiLCJPYmplY3QiLCJhc3NpZ24iLCJmZUxldmVsIiwic3RhdGUiLCJ3aW5kb3ciLCJsb2NhdGlvbiIsImZjbEVuYWJsZWQiLCJfZm5CbG9ja2luZ05hdkZpbHRlciIsIl9ibG9ja2luZ05hdmlnYXRpb25GaWx0ZXIiLCJiaW5kIiwicmVnaXN0ZXJOYXZpZ2F0aW9uRmlsdGVyIiwiY2F0Y2giLCJvRXJyb3IiLCJMb2ciLCJlcnJvciIsIl9mbkhhc2hHdWFyZCIsImhhc2hHdWFyZCIsImFkZEV2ZW50TGlzdGVuZXIiLCJfYkRpc2FibGVPbkhhc2hDaGFuZ2UiLCJfYklnbm9yZVJlc3RvcmUiLCJfYkZvcmNlRm9jdXMiLCJkZXN0cm95IiwidW5yZWdpc3Rlck5hdmlnYXRpb25GaWx0ZXIiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwib1JvdXRlciIsIl9vUm91dGVyIiwiX29NYW5hZ2VkSGlzdG9yeSIsIl9vTmF2aWdhdGlvbkd1YXJkIiwic0N1cnJlbnRBcHBIYXNoIiwiZ2V0SGFzaCIsInB1c2giLCJfZXh0cmFjdFN0YXRlRnJvbUhhc2giLCJnZXRIYXNoQ2hhbmdlciIsImlzRm9jdXNGb3JjZWQiLCJzZXRGb2N1c0ZvcmNlZCIsImJGb3JjZWQiLCJyZW1vdmVJQXBwU3RhdGVLZXkiLCJuYXZUb0hhc2giLCJiUHJlc2VydmVIaXN0b3J5IiwiYkRpc2FibGVQcmVzZXJ2YXRpb25DYWNoZSIsImJGb3JjZUZvY3VzIiwiYlByZXNlcnZlU2hlbGxCYWNrTmF2aWdhdGlvbkhhbmRsZXIiLCJzZXRCYWNrTmF2aWdhdGlvbiIsIl9vUm91dGVNYXRjaFN5bmNocm9uaXphdGlvbiIsIndhaXRGb3IiLCJ1bmRlZmluZWQiLCJfaW50ZXJuYWxOYXZUb0hhc2giLCJjaGVja0hhc2hXaXRoR3VhcmQiLCJvUmVzb3VyY2VCdW5kbGUiLCJDb3JlIiwiZ2V0TGlicmFyeVJlc291cmNlQnVuZGxlIiwiY29uZmlybSIsImdldFRleHQiLCJQcm9taXNlIiwicmVzb2x2ZSIsIm9OZXdTdGF0ZSIsImFDdXJyZW50SGFzaEtleXMiLCJfZXh0cmFjdEtleXNGcm9tSGFzaCIsImtleXMiLCJldmVyeSIsImtleSIsImluZGV4Iiwib0hpc3RvcnlBY3Rpb24iLCJfcHVzaE5ld1N0YXRlIiwiX3JlYnVpbGRCcm93c2VySGlzdG9yeSIsInJlc3RvcmVIaXN0b3J5Iiwic1RhcmdldEhhc2giLCJuYXZCYWNrIiwic0N1cnJlbnRIYXNoIiwic1ByZXZpb3VzSGFzaCIsImkiLCJoYXNoIiwiYmFjayIsIm5hdlRvIiwic1JvdXRlTmFtZSIsIm9QYXJhbWV0ZXJzIiwiZ2V0VVJMIiwibm9QcmVzZXJ2YXRpb25DYWNoZSIsImJJc1N0aWNreU1vZGUiLCJleGl0RnJvbUFwcCIsImJhY2tUb1ByZXZpb3VzQXBwIiwiaXNDdXJyZW50U3RhdGVJbXBhY3RlZEJ5Iiwic3Vic3RyaW5nIiwib0xvY2FsR3VhcmQiLCJpc05hdmlnYXRpb25GaW5hbGl6ZWQiLCJzZXROYXZpZ2F0aW9uR3VhcmQiLCJkaXNjYXJkTmF2aWdhdGlvbkd1YXJkIiwiaGFzTmF2aWdhdGlvbkd1YXJkIiwiaXNHdWFyZENyb3NzQWxsb3dlZEJ5VXNlciIsImFjdGl2YXRlUm91dGVNYXRjaFN5bmNocm9uaXphdGlvbiIsInJlc29sdmVSb3V0ZU1hdGNoIiwiU3luY2hyb25pemF0aW9uIiwic0hhc2hOb1BhcmFtcyIsInNwbGl0IiwiYVRva2VucyIsImFLZXlzIiwiZm9yRWFjaCIsInNUb2tlbiIsInJlZ2V4S2V5IiwidGVzdCIsIm9TdGF0ZSIsImFMYXlvdXQiLCJzTGF5b3V0Iiwic2NyZWVuTW9kZSIsImJSZWJ1aWxkT25seSIsImJEaXNhYmxlSGlzdG9yeVByZXNlcnZhdGlvbiIsImxhc3RJbmRleCIsImlQb3BDb3VudCIsInBvcCIsInByZXNlcnZlZCIsIm9MYXN0UmVtb3ZlZEl0ZW0iLCJvVG9wU3RhdGUiLCJfY29tcGFyZUNhY2hlU3RhdGVzIiwib01hbmFnZWRTdGF0ZSIsInNQcmV2aW91c0lBcHBTdGF0ZUtleSIsIm9Db21wYXJpc29uU3RhdGVSZXN1bHQiLCJiSGFzU2FtZUhhc2giLCJ0eXBlIiwic3RlcHMiLCJfZGlzYWJsZUV2ZW50T25IYXNoQ2hhbmdlIiwic3RvcCIsIl9lbmFibGVFdmVudE9uSGFzaENoYW5nZSIsImJJZ25vcmVDdXJyZW50SGFzaCIsImluaXRpYWxpemUiLCJ0aGF0Iiwib1RhcmdldFN0YXRlIiwibmV3TGV2ZWwiLCJyZXBsYWNlQXN5bmMiLCJyZXBsYWNlSGFzaCIsInNldFRpbWVvdXQiLCJiYWNrUmVwbGFjZUFzeW5jIiwiYmFja0FzeW5jIiwic2V0SGFzaCIsImdvIiwiZ2V0TGFzdEhpc3RvcnlFbnRyeSIsInNldFBhdGhNYXBwaW5nIiwibWFwcGluZ3MiLCJtYXBwaW5nIiwiZmluZCIsIm0iLCJvbGRQYXRoIiwibmV3UGF0aCIsImFIYXNoU3BsaXQiLCJzQXBwSGFzaCIsIm9TdGF0ZTEiLCJvU3RhdGUyIiwiZXF1YWwiLCJjaGVja0lmQmFja0lzT3V0T2ZHdWFyZCIsInNQcmVzZW50SGFzaCIsInNQcmV2SGFzaCIsIm9TcGxpdEhhc2giLCJzcGxpdEhhc2giLCJhcHBTcGVjaWZpY1JvdXRlIiwiVVJJIiwiZGVjb2RlIiwiY2hlY2tJZkJhY2tIYXNTYW1lQ29udGV4dCIsIm9DdXJyZW50U3RhdGUiLCJvUHJldmlvdXNTdGF0ZSIsIkJhc2VPYmplY3QiXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7OztBQVNBLE1BQU1BLFNBQVMsR0FBRztBQUNqQkMsSUFBQUEsS0FBSyxFQUFFLENBRFU7QUFFakJDLElBQUFBLFVBQVUsRUFBRSxDQUZLO0FBR2pCQyxJQUFBQSxRQUFRLEVBQUUsQ0FITztBQUlqQkMsSUFBQUEsU0FBUyxFQUFFO0FBSk0sR0FBbEI7QUFNQSxNQUFNQyxhQUFhLEdBQUc7QUFDckJDLElBQUFBLFdBQVcsRUFBRSxRQURRO0FBRXJCQyxJQUFBQSxjQUFjLEVBQUU7QUFGSyxHQUF0QjtBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFDQSxXQUFTQyxtQkFBVCxDQUE2QkMsVUFBN0IsRUFBaUQ7QUFDaEQsV0FBTztBQUNOQyxNQUFBQSxVQUFVLEVBQUVELFVBQVUsQ0FBQ0UsT0FBWCxDQUFtQixXQUFuQixFQUFnQyxFQUFoQyxDQUROO0FBQzJDO0FBQ2pEQyxNQUFBQSxLQUFLLEVBQUUsVUFBU0MsS0FBVCxFQUFxQjtBQUMzQixlQUFPQSxLQUFLLENBQUNDLE9BQU4sQ0FBYyxL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RSxZQUF0QyxFQUFvRDtBQUNuREMsWUFBQUEsU0FBUyxHQUFHLEtBQUszSCxnQkFBTCxDQUFzQjRDLENBQUMsR0FBRyxDQUExQixFQUE2QkMsSUFBekM7QUFDQTtBQUNBO0FBQ0Q7O0FBRUQsZUFBTyxDQUFDOEUsU0FBRCxJQUFjLENBQUMsS0FBS3RHLGtCQUFMLENBQXdCc0csU0FBeEIsQ0FBdEI7QUFDQTs7QUFDRCxhQUFPLEtBQVA7QUFDQTtBQUVEO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7OztXQUNDTSx5QixHQUFBLHFDQUE0QjtBQUMzQixVQUFJLEtBQUtqSSxnQkFBTCxDQUFzQnJELE1BQXRCLEdBQStCLENBQW5DLEVBQXNDO0FBQ3JDLGVBQU8sS0FBUDtBQUNBOztBQUVELFVBQU11TCxhQUFhLEdBQUcsS0FBS2xJLGdCQUFMLENBQXNCLEtBQUtBLGdCQUFMLENBQXNCckQsTUFBdEIsR0FBK0IsQ0FBckQsQ0FBdEI7QUFDQSxVQUFNd0wsY0FBYyxHQUFHLEtBQUtuSSxnQkFBTCxDQUFzQixLQUFLQSxnQkFBTCxDQUFzQnJELE1BQXRCLEdBQStCLENBQXJELENBQXZCO0FBRUEsYUFBT3VMLGFBQWEsQ0FBQ3JGLElBQWQsQ0FBbUJzQixLQUFuQixDQUF5QixHQUF6QixFQUE4QixDQUE5QixNQUFxQ2dFLGNBQWMsQ0FBQ3RGLElBQWYsQ0FBb0JzQixLQUFwQixDQUEwQixHQUExQixFQUErQixDQUEvQixDQUE1QztBQUNBLEs7OztJQWh3QndCaUUsVTtTQW13QlhwTCxXIiwic291cmNlUm9vdCI6Ii4iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgTG9nIGZyb20gXCJzYXAvYmFzZS9Mb2dcIjtcbmltcG9ydCBCYXNlT2JqZWN0IGZyb20gXCJzYXAvdWkvYmFzZS9PYmplY3RcIjtcbmltcG9ydCBTeW5jaHJvbml6YXRpb24gZnJvbSBcInNhcC9mZS9jb3JlL1N5bmNocm9uaXphdGlvblwiO1xuaW1wb3J0IFVSSSBmcm9tIFwic2FwL3VpL3RoaXJkcGFydHkvVVJJXCI7XG5pbXBvcnQgeyBJU2hlbGxTZXJ2aWNlcyB9IGZyb20gXCJzYXAvZmUvY29yZS9zZXJ2aWNlcy9TaGVsbFNlcnZpY2VzRmFjdG9yeVwiO1xuaW1wb3J0IFJvdXRlciBmcm9tIFwic2FwL3VpL2NvcmUvcm91dGluZy9Sb3V0ZXJcIjtcbmltcG9ydCB7IGRlZmluZVVJNUNsYXNzIH0gZnJvbSBcInNhcC9mZS9jb3JlL2hlbHBlcnMvQ2xhc3NTdXBwb3J0XCI7XG5pbXBvcnQgUmVzb3VyY2VCdW5kbGUgZnJvbSBcInNhcC9iYXNlL2kxOG4vUmVzb3VyY2VCdW5kbGVcIjtcbmltcG9ydCB7IENvcmVFeCB9IGZyb20gXCJ0eXBlcy9leHRlbnNpb25fdHlwZXNcIjtcbmltcG9ydCBDb3JlIGZyb20gXCJzYXAvdWkvY29yZS9Db3JlXCI7XG5cbmNvbnN0IGVudW1TdGF0ZSA9IHtcblx0RVFVQUw6IDAsXG5cdENPTVBBVElCTEU6IDEsXG5cdEFOQ0VTVE9SOiAyLFxuXHRESUZGRVJFTlQ6IDNcbn07XG5jb25zdCBlbnVtVVJMUGFyYW1zID0ge1xuXHRMQVlPVVRQQVJBTTogXCJsYXlvdXRcIixcblx0SUFQUFNUQVRFUEFSQU06IFwic2FwLWlhcHAtc3RhdGVcIlxufTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgSGFzaEd1YXJkIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc0d1YXJkSGFzaCBUaGUgaGFzaCB1c2VkIGZvciB0aGUgZ3VhcmRcbiAqIEByZXR1cm5zIHtvYmplY3R9IFRoZSBjcmVhdGVkIGhhc2ggZ3VhcmRcbiAqL1xuZnVuY3Rpb24gY3JlYXRlR3VhcmRGcm9tSGFzaChzR3VhcmRIYXNoOiBzdHJpbmcpIHtcblx0cmV0dXJuIHtcblx0XHRfZ3VhcmRIYXNoOiBzR3VhcmRIYXNoLnJlcGxhY2UoL1xcP1teXFw/XSokLywgXCJcIiksIC8vIFJlbW92ZSBxdWVyeSBwYXJ0XG5cdFx0Y2hlY2s6IGZ1bmN0aW9uKHNIYXNoOiBhbnkpIHtcblx0XHRcdHJldHVybiBzSGFzaC5pbmRleE9mKHRoaXMuX2d1YXJkSGFzaCkgPT09IDA7XG5cdFx0fVxuXHR9O1xufVxuLyoqXG4gKiBSZXR1cm5zIHRoZSBpQXBwU3RhdGUgcGFydCBmcm9tIGEgaGFzaCAob3IgbnVsbCBpZiBub3QgZm91bmQpLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzSGFzaCBUaGUgaGFzaFxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGlBcHBTdGF0ZSBwYXJ0IG9mIHRoZSBoYXNoXG4gKi9cbmZ1bmN0aW9uIGZpbmRBcHBTdGF0ZUluSGFzaChzSGFzaDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG5cdGNvbnN0IGFBcHBTdGF0ZSA9IHNIYXNoLm1hdGNoKG5ldyBSZWdFeHAoXCJcXFxcPy4qXCIgKyBlbnVtVVJMUGFyYW1zLklBUFBTVEFURVBBUkFNICsgXCI9KFteJl0qKVwiKSk7XG5cdHJldHVybiBhQXBwU3RhdGUgJiYgYUFwcFN0YXRlLmxlbmd0aCA+IDEgPyBhQXBwU3RhdGVbMV0gOiBudWxsO1xufVxuLyoqXG4gKiBSZXR1cm5zIGEgaGFzaCB3aXRob3V0IGl0cyBpQXBwU3RhdGUgcGFydC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc0hhc2ggVGhlIGhhc2hcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBoYXNoIHdpdGhvdXQgdGhlIGlBcHBTdGF0ZVxuICovXG5mdW5jdGlvbiByZW1vdmVBcHBTdGF0ZUluSGFzaChzSGFzaDogc3RyaW5nKSB7XG5cdHJldHVybiBzSGFzaC5yZXBsYWNlKG5ldyBSZWdFeHAoXCJbJj9dKlwiICsgZW51bVVSTFBhcmFtcy5JQVBQU1RBVEVQQVJBTSArIFwiPVteJl0qXCIpLCBcIlwiKTtcbn1cbi8qKlxuICogQWRkcyBhbiBpQXBwU3RhdGUgaW5zaWRlIGEgaGFzaCAob3IgcmVwbGFjZXMgYW4gZXhpc3Rpbmcgb25lKS5cbiAqXG4gKiBAcGFyYW0geyp9IHNIYXNoIFRoZSBoYXNoXG4gKiBAcGFyYW0geyp9IHNBcHBTdGF0ZUtleSBUaGUgaUFwcFN0YXRlIHRvIGFkZFxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGhhc2ggd2l0aCB0aGUgYXBwIHN0YXRlXG4gKi9cbmZ1bmN0aW9uIHNldEFwcFN0YXRlSW5IYXNoKHNIYXNoOiBhbnksIHNBcHBTdGF0ZUtleTogYW55KSB7XG5cdGxldCBzTmV3SGFzaDtcblxuXHRpZiAoc0hhc2guaW5kZXhPZihlbnVtVVJMUGFyYW1zLklBUFBTVEFURVBBUkFNKSA+PSAwKSB7XG5cdFx0Ly8gSWYgdGhlcmUncyBhbHJlYWR5IGFuIGlBcHBTdGF0ZSBwYXJhbWV0ZXIgaW4gdGhlIGhhc2gsIHJlcGxhY2UgaXRcblx0XHRzTmV3SGFzaCA9IHNIYXNoLnJlcGxhY2UobmV3IFJlZ0V4cChlbnVtVVJMUGFyYW1zLklBUFBTVEFURVBBUkFNICsgXCI9W14mXSpcIiksIGVudW1VUkxQYXJhbXMuSUFQUFNUQVRFUEFSQU0gKyBcIj1cIiArIHNBcHBTdGF0ZUtleSk7XG5cdH0gZWxzZSB7XG5cdFx0Ly8gQWRkIHRoZSBpQXBwU3RhdGUgcGFyYW1ldGVyIGluIHRoZSBoYXNoXG5cdFx0aWYgKHNIYXNoLmluZGV4T2YoXCI/XCIpIDwgMCkge1xuXHRcdFx0c05ld0hhc2ggPSBzSGFzaCArIFwiP1wiO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRzTmV3SGFzaCA9IHNIYXNoICsgXCImXCI7XG5cdFx0fVxuXHRcdHNOZXdIYXNoICs9IGVudW1VUkxQYXJhbXMuSUFQUFNUQVRFUEFSQU0gKyBcIj1cIiArIHNBcHBTdGF0ZUtleTtcblx0fVxuXG5cdHJldHVybiBzTmV3SGFzaDtcbn1cblxuQGRlZmluZVVJNUNsYXNzKFwic2FwLmZlLmNvcmUuUm91dGVyUHJveHlcIilcbmNsYXNzIFJvdXRlclByb3h5IGV4dGVuZHMgQmFzZU9iamVjdCB7XG5cdGJJc1JlYnVpbGRIaXN0b3J5UnVubmluZyA9IGZhbHNlO1xuXHRiSXNDb21wdXRpbmdUaXRsZUhpZXJhY2h5ID0gZmFsc2U7XG5cdGJJc0d1YXJkQ3Jvc3NBbGxvd2VkID0gZmFsc2U7XG5cdHNJQXBwU3RhdGVLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXHRfb1NoZWxsU2VydmljZXMhOiBJU2hlbGxTZXJ2aWNlcztcblx0ZmNsRW5hYmxlZCE6IGJvb2xlYW47XG5cdF9mbkJsb2NraW5nTmF2RmlsdGVyITogRnVuY3Rpb247XG5cdF9mbkhhc2hHdWFyZCE6IEZ1bmN0aW9uO1xuXHRfYkRpc2FibGVPbkhhc2hDaGFuZ2UhOiBib29sZWFuO1xuXHRfYklnbm9yZVJlc3RvcmUhOiBib29sZWFuO1xuXHRfYkZvcmNlRm9jdXMhOiBib29sZWFuO1xuXHRfb1JvdXRlciE6IFJvdXRlcjtcblx0X29NYW5hZ2VkSGlzdG9yeSE6IGFueVtdO1xuXHRfb05hdmlnYXRpb25HdWFyZDogYW55O1xuXHRvUmVzb3VyY2VCdW5kbGU/OiBSZXNvdXJjZUJ1bmRsZTtcblx0X29Sb3V0ZU1hdGNoU3luY2hyb25pemF0aW9uPzogU3luY2hyb25pemF0aW9uO1xuXHRfYkFjdGl2YXRlUm91dGVNYXRjaFN5bmNocm86IGJvb2xlYW4gPSBmYWxzZTtcblx0X2JBcHBseVJlc3RvcmU6IGJvb2xlYW4gPSBmYWxzZTtcblx0X2JEZWxheWVkUmVidWlsZDogYm9vbGVhbiA9IGZhbHNlO1xuXHRfcGF0aE1hcHBpbmdzOiB7IG9sZFBhdGg6IHN0cmluZzsgbmV3UGF0aDogc3RyaW5nIH1bXSA9IFtdO1xuXG5cdGluaXQob0FwcENvbXBvbmVudDogYW55LCBpc2ZjbEVuYWJsZWQ6IGJvb2xlYW4pIHtcblx0XHQvLyBTYXZlIHRoZSBuYW1lIG9mIHRoZSBhcHAgKGluY2x1ZGluZyBzdGFydHVwIHBhcmFtZXRlcnMpIGZvciByZWJ1aWxkaW5nIGZ1bGwgaGFzaGVzIGxhdGVyXG5cdFx0b0FwcENvbXBvbmVudFxuXHRcdFx0LmdldFNlcnZpY2UoXCJzaGVsbFNlcnZpY2VzXCIpXG5cdFx0XHQudGhlbigoKSA9PiB7XG5cdFx0XHRcdHRoaXMuX29TaGVsbFNlcnZpY2VzID0gb0FwcENvbXBvbmVudC5nZXRTaGVsbFNlcnZpY2VzKCk7XG5cblx0XHRcdFx0dGhpcy5pbml0UmF3KG9BcHBDb21wb25lbnQuZ2V0Um91dGVyKCkpO1xuXHRcdFx0XHQvLyBXZSB3YW50IHRvIHdhaXQgdW50aWwgdGhlIGluaXRpYWwgcm91dGVNYXRjaGVkIGlzIGRvbmUgYmVmb3JlIGRvaW5nIGFueSBuYXZpZ2F0aW9uXG5cdFx0XHRcdHRoaXMud2FpdEZvclJvdXRlTWF0Y2hCZWZvcmVOYXZpZ2F0aW9uKCk7XG5cblx0XHRcdFx0Ly8gU2V0IGZlTGV2ZWw9MCBmb3IgdGhlIGZpcnN0IEFwcGxpY2F0aW9uIHBhZ2UgaW4gdGhlIGhpc3Rvcnlcblx0XHRcdFx0aGlzdG9yeS5yZXBsYWNlU3RhdGUoXG5cdFx0XHRcdFx0T2JqZWN0LmFzc2lnbihcblx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0ZmVMZXZlbDogMFxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdGhpc3Rvcnkuc3RhdGVcblx0XHRcdFx0XHQpLFxuXHRcdFx0XHRcdFwiXCIsXG5cdFx0XHRcdFx0d2luZG93LmxvY2F0aW9uIGFzIGFueVxuXHRcdFx0XHQpO1xuXHRcdFx0XHR0aGlzLmZjbEVuYWJsZWQgPSBpc2ZjbEVuYWJsZWQ7XG5cblx0XHRcdFx0dGhpcy5fZm5CbG9ja2luZ05hdkZpbHRlciA9IHRoaXMuX2Jsb2NraW5nTmF2aWdhdGlvbkZpbHRlci5iaW5kKHRoaXMpO1xuXHRcdFx0XHR0aGlzLl9vU2hlbGxTZXJ2aWNlcy5yZWdpc3Rlck5hdmlnYXRpb25GaWx0ZXIodGhpcy5fZm5CbG9ja2luZ05hdkZpbHRlcik7XG5cdFx0XHR9KVxuXHRcdFx0LmNhdGNoKGZ1bmN0aW9uKG9FcnJvcjogYW55KSB7XG5cdFx0XHRcdExvZy5lcnJvcihcIkNhbm5vdCByZXRyaWV2ZSB0aGUgc2hlbGwgc2VydmljZXNcIiwgb0Vycm9yKTtcblx0XHRcdH0pO1xuXHRcdHRoaXMuX2ZuSGFzaEd1YXJkID0gdGhpcy5oYXNoR3VhcmQuYmluZCh0aGlzKTtcblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInBvcHN0YXRlXCIsIHRoaXMuX2ZuSGFzaEd1YXJkIGFzIGFueSk7XG5cdFx0dGhpcy5fYkRpc2FibGVPbkhhc2hDaGFuZ2UgPSBmYWxzZTtcblx0XHR0aGlzLl9iSWdub3JlUmVzdG9yZSA9IGZhbHNlO1xuXHRcdHRoaXMuX2JGb3JjZUZvY3VzID0gdHJ1ZTsgLy8gVHJpZ2dlciB0aGUgZm9jdXMgbWVjaGFuaXNtIGZvciB0aGUgZmlyc3QgdmlldyBkaXNwbGF5ZWQgYnkgdGhlIGFwcFxuXHR9XG5cblx0ZGVzdHJveSgpIHtcblx0XHRpZiAodGhpcy5fb1NoZWxsU2VydmljZXMpIHtcblx0XHRcdHRoaXMuX29TaGVsbFNlcnZpY2VzLnVucmVnaXN0ZXJOYXZpZ2F0aW9uRmlsdGVyKHRoaXMuX2ZuQmxvY2tpbmdOYXZGaWx0ZXIpO1xuXHRcdH1cblx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihcInBvcHN0YXRlXCIsIHRoaXMuX2ZuSGFzaEd1YXJkIGFzIGFueSk7XG5cdH1cblxuXHQvKipcblx0ICogUmF3IGluaXRpYWxpemF0aW9uIChmb3IgdW5pdCB0ZXN0cykuXG5cdCAqXG5cdCAqIEBwYXJhbSB7c2FwLnVpLmNvcmUucm91dGluZy5Sb3V0ZXJ9IG9Sb3V0ZXIgVGhlIHJvdXRlciB1c2VkIGJ5IHRoaXMgcHJveHlcblx0ICovXG5cdGluaXRSYXcob1JvdXRlcjogUm91dGVyKSB7XG5cdFx0dGhpcy5fb1JvdXRlciA9IG9Sb3V0ZXI7XG5cdFx0dGhpcy5fb01hbmFnZWRIaXN0b3J5ID0gW107XG5cdFx0dGhpcy5fb05hdmlnYXRpb25HdWFyZCA9IG51bGw7XG5cblx0XHRjb25zdCBzQ3VycmVudEFwcEhhc2ggPSB0aGlzLmdldEhhc2goKTtcblx0XHR0aGlzLl9vTWFuYWdlZEhpc3RvcnkucHVzaCh0aGlzLl9leHRyYWN0U3RhdGVGcm9tSGFzaChzQ3VycmVudEFwcEhhc2gpKTtcblxuXHRcdC8vIFNldCB0aGUgaUFwcFN0YXRlIGlmIHRoZSBpbml0aWFsIGhhc2ggY29udGFpbnMgb25lXG5cdFx0dGhpcy5zSUFwcFN0YXRlS2V5ID0gZmluZEFwcFN0YXRlSW5IYXNoKHNDdXJyZW50QXBwSGFzaCk7XG5cdH1cblxuXHRnZXRIYXNoKCkge1xuXHRcdHJldHVybiB0aGlzLl9vUm91dGVyLmdldEhhc2hDaGFuZ2VyKCkuZ2V0SGFzaCgpO1xuXHR9XG5cblx0aXNGb2N1c0ZvcmNlZCgpIHtcblx0XHRyZXR1cm4gdGhpcy5fYkZvcmNlRm9jdXM7XG5cdH1cblxuXHRzZXRGb2N1c0ZvcmNlZChiRm9yY2VkOiBib29sZWFuKSB7XG5cdFx0dGhpcy5fYkZvcmNlRm9jdXMgPSBiRm9yY2VkO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJlc2V0cyB0aGUgaW50ZXJuYWwgdmFyaWFibGUgc0lBcHBTdGF0ZUtleS5cblx0ICpcblx0ICogQGZ1bmN0aW9uXG5cdCAqIEBuYW1lIHNhcC5mZS5jb3JlLlJvdXRlclByb3h5I3JlbW92ZUlBcHBTdGF0ZUtleVxuXHQgKlxuXHQgKiBAdWk1LXJlc3RyaWN0ZWRcblx0ICovXG5cdHJlbW92ZUlBcHBTdGF0ZUtleSgpIHtcblx0XHR0aGlzLnNJQXBwU3RhdGVLZXkgPSBudWxsO1xuXHR9XG5cblx0LyoqXG5cdCAqIE5hdmlnYXRlcyB0byBhIHNwZWNpZmljIGhhc2guXG5cdCAqXG5cdCAqIEBmdW5jdGlvblxuXHQgKiBAbmFtZSBzYXAuZmUuY29yZS5Sb3V0ZXJQcm94eSNuYXZUb0hhc2hcblx0ICogQG1lbWJlcm9mIHNhcC5mZS5jb3JlLlJvdXRlclByb3h5XG5cdCAqIEBzdGF0aWNcblx0ICogQHBhcmFtIHtzdHJpbmd9IHNIYXNoIEhhc2ggdG8gYmUgbmF2aWdhdGVkIHRvXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gYlByZXNlcnZlSGlzdG9yeSBJZiBzZXQgdG8gdHJ1ZSwgbm9uLWFuY2VzdG9yIGVudHJpZXMgaW4gaGlzdG9yeSB3aWxsIGJlIHJldGFpbmVkXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gYkRpc2FibGVQcmVzZXJ2YXRpb25DYWNoZSBJZiBzZXQgdG8gdHJ1ZSwgY2FjaGUgcHJlc2VydmF0aW9uIG1lY2hhbmlzbSBpcyBkaXNhYmxlZCBmb3IgdGhlIGN1cnJlbnQgbmF2aWdhdGlvblxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IGJGb3JjZUZvY3VzIElmIHNldCB0byB0cnVlLCB0aGUgbG9naWMgdG8gc2V0IHRoZSBmb2N1cyBvbmNlIHRoZSBuYXZpZ2F0aW9uIGlzIGZpbmFsaXplZCB3aWxsIGJlIHRyaWdnZXJlZCAob25QYWdlUmVhZHkpXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gYlByZXNlcnZlU2hlbGxCYWNrTmF2aWdhdGlvbkhhbmRsZXIgSWYgbm90IHNldCB0byBmYWxzZSwgdGhlIGJhY2sgbmF2aWdhdGlvbiBpcyBzZXQgdG8gdW5kZWZpbmVkXG5cdCAqIEByZXR1cm5zIHtQcm9taXNlfSBQcm9taXNlIChyZXNvbHZlZCB3aGVuIHRoZSBuYXZpZ2F0aW9uIGlzIGZpbmFsaXplZCkgdGhhdCByZXR1cm5zICd0cnVlJyBpZiBhIG5hdmlnYXRpb24gdG9vayBwbGFjZSwgJ2ZhbHNlJyBpZiB0aGUgbmF2aWdhdGlvbiBkaWRuJ3QgaGFwcGVuXG5cdCAqIEB1aTUtcmVzdHJpY3RlZFxuXHQgKi9cblx0bmF2VG9IYXNoKFxuXHRcdHNIYXNoOiBzdHJpbmcgfCB1bmRlZmluZWQsXG5cdFx0YlByZXNlcnZlSGlzdG9yeT86IGJvb2xlYW4sXG5cdFx0YkRpc2FibGVQcmVzZXJ2YXRpb25DYWNoZT86IGJvb2xlYW4sXG5cdFx0YkZvcmNlRm9jdXM/OiBib29sZWFuLFxuXHRcdGJQcmVzZXJ2ZVNoZWxsQmFja05hdmlnYXRpb25IYW5kbGVyPzogYm9vbGVhblxuXHQpIHtcblx0XHRpZiAoYlByZXNlcnZlU2hlbGxCYWNrTmF2aWdhdGlvbkhhbmRsZXIgIT09IGZhbHNlKSB7XG5cdFx0XHR0aGlzLl9vU2hlbGxTZXJ2aWNlcy5zZXRCYWNrTmF2aWdhdGlvbigpO1xuXHRcdH1cblx0XHRpZiAodGhpcy5fb1JvdXRlTWF0Y2hTeW5jaHJvbml6YXRpb24pIHtcblx0XHRcdHJldHVybiB0aGlzLl9vUm91dGVNYXRjaFN5bmNocm9uaXphdGlvbi53YWl0Rm9yKCkudGhlbigoKSA9PiB7XG5cdFx0XHRcdHRoaXMuX29Sb3V0ZU1hdGNoU3luY2hyb25pemF0aW9uID0gdW5kZWZpbmVkO1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5faW50ZXJuYWxOYXZUb0hhc2goc0hhc2gsIGJQcmVzZXJ2ZUhpc3RvcnksIGJEaXNhYmxlUHJlc2VydmF0aW9uQ2FjaGUsIGJGb3JjZUZvY3VzKTtcblx0XHRcdH0pO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRpZiAodGhpcy5fYkFjdGl2YXRlUm91dGVNYXRjaFN5bmNocm8pIHtcblx0XHRcdFx0dGhpcy53YWl0Rm9yUm91dGVNYXRjaEJlZm9yZU5hdmlnYXRpb24oKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiB0aGlzLl9pbnRlcm5hbE5hdlRvSGFzaChzSGFzaCwgYlByZXNlcnZlSGlzdG9yeSwgYkRpc2FibGVQcmVzZXJ2YXRpb25DYWNoZSwgYkZvcmNlRm9jdXMpO1xuXHRcdH1cblx0fVxuXG5cdF9pbnRlcm5hbE5hdlRvSGFzaChzSGFzaDogYW55LCBiUHJlc2VydmVIaXN0b3J5OiBhbnksIGJEaXNhYmxlUHJlc2VydmF0aW9uQ2FjaGU6IGFueSwgYkZvcmNlRm9jdXM/OiBib29sZWFuKSB7XG5cdFx0Ly8gQWRkIHRoZSBhcHAgc3RhdGUgaW4gdGhlIGhhc2ggaWYgbmVlZGVkXG5cdFx0aWYgKHRoaXMuZmNsRW5hYmxlZCAmJiB0aGlzLnNJQXBwU3RhdGVLZXkgJiYgIWZpbmRBcHBTdGF0ZUluSGFzaChzSGFzaCkpIHtcblx0XHRcdHNIYXNoID0gc2V0QXBwU3RhdGVJbkhhc2goc0hhc2gsIHRoaXMuc0lBcHBTdGF0ZUtleSk7XG5cdFx0fVxuXG5cdFx0aWYgKCF0aGlzLmNoZWNrSGFzaFdpdGhHdWFyZChzSGFzaCkpIHtcblx0XHRcdGlmICghdGhpcy5vUmVzb3VyY2VCdW5kbGUpIHtcblx0XHRcdFx0dGhpcy5vUmVzb3VyY2VCdW5kbGUgPSAoQ29yZSBhcyBDb3JlRXgpLmdldExpYnJhcnlSZXNvdXJjZUJ1bmRsZShcInNhcC5mZS5jb3JlXCIpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBXZSBoYXZlIHRvIHVzZSBhIGNvbmZpcm0gaGVyZSBmb3IgVUkgY29uc2lzdGVuY3kgcmVhc29ucywgYXMgd2l0aCBzb21lIHNjZW5hcmlvc1xuXHRcdFx0Ly8gaW4gdGhlIEVkaXRGbG93IHdlIHJlbHkgb24gYSBVSTUgbWVjaGFuaXNtIHRoYXQgZGlzcGxheXMgYSBjb25maXJtIGRpYWxvZy5cblx0XHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1hbGVydFxuXHRcdFx0aWYgKCFjb25maXJtKHRoaXMub1Jlc291cmNlQnVuZGxlLmdldFRleHQoXCJDX1JPVVRFUl9QUk9YWV9TQVBGRV9FWElUX05PVFNBVkVEX01FU1NBR0VcIikpKSB7XG5cdFx0XHRcdC8vIFRoZSB1c2VyIGNsaWNrZWQgb24gQ2FuY2VsIC0tPiBjYW5jZWwgbmF2aWdhdGlvblxuXHRcdFx0XHRyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuYklzR3VhcmRDcm9zc0FsbG93ZWQgPSB0cnVlO1xuXHRcdH1cblxuXHRcdC8vIEluIGNhc2UgdGhlIG5hdmlnYXRpb24gd2lsbCBjYXVzZSBhIG5ldyB2aWV3IHRvIGJlIGRpc3BsYXllZCwgd2UgZm9yY2UgdGhlIGZvY3VzXG5cdFx0Ly8gSS5lLiBpZiB0aGUga2V5cyBmb3IgdGhlIGhhc2ggd2UncmUgbmF2aWdhdGluZyB0byBpcyBhIHN1cGVyc2V0IG9mIHRoZSBjdXJyZW50IGhhc2gga2V5cy5cblx0XHRjb25zdCBvTmV3U3RhdGUgPSB0aGlzLl9leHRyYWN0U3RhdGVGcm9tSGFzaChzSGFzaCk7XG5cdFx0aWYgKCF0aGlzLl9iRm9yY2VGb2N1cykge1xuXHRcdFx0Ly8gSWYgdGhlIGZvY3VzIHdhcyBhbHJlYWR5IGZvcmNlZCwga2VlcCBpdFxuXHRcdFx0Y29uc3QgYUN1cnJlbnRIYXNoS2V5cyA9IHRoaXMuX2V4dHJhY3RLZXlzRnJvbUhhc2godGhpcy5nZXRIYXNoKCkpO1xuXHRcdFx0dGhpcy5fYkZvcmNlRm9jdXMgPVxuXHRcdFx0XHRiRm9yY2VGb2N1cyB8fFxuXHRcdFx0XHQoYUN1cnJlbnRIYXNoS2V5cy5sZW5ndGggPCBvTmV3U3RhdGUua2V5cy5sZW5ndGggJiZcblx0XHRcdFx0XHRhQ3VycmVudEhhc2hLZXlzLmV2ZXJ5KGZ1bmN0aW9uKGtleTogYW55LCBpbmRleDogYW55KSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4ga2V5ID09PSBvTmV3U3RhdGUua2V5c1tpbmRleF07XG5cdFx0XHRcdFx0fSkpO1xuXHRcdH1cblxuXHRcdGNvbnN0IG9IaXN0b3J5QWN0aW9uID0gdGhpcy5fcHVzaE5ld1N0YXRlKG9OZXdTdGF0ZSwgZmFsc2UsIGJQcmVzZXJ2ZUhpc3RvcnksIGJEaXNhYmxlUHJlc2VydmF0aW9uQ2FjaGUpO1xuXG5cdFx0cmV0dXJuIHRoaXMuX3JlYnVpbGRCcm93c2VySGlzdG9yeShvSGlzdG9yeUFjdGlvbiwgZmFsc2UpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENsZWFycyBicm93c2VyIGhpc3RvcnkgaWYgZW50cmllcyBoYXZlIGJlZW4gYWRkZWQgd2l0aG91dCB1c2luZyB0aGUgUm91dGVyUHJveHkuXG5cdCAqIFVwZGF0ZXMgdGhlIGludGVybmFsIGhpc3RvcnkgYWNjb3JkaW5nbHkuXG5cdCAqXG5cdCAqIEByZXR1cm5zIHtQcm9taXNlfSBQcm9taXNlIHRoYXQgaXMgcmVzb2x2ZWQgb25jZSB0aGUgaGlzdG9yeSBpcyByZWJ1aWx0XG5cdCAqL1xuXHRyZXN0b3JlSGlzdG9yeSgpIHtcblx0XHRpZiAodGhpcy5fYkFwcGx5UmVzdG9yZSkge1xuXHRcdFx0dGhpcy5fYkFwcGx5UmVzdG9yZSA9IGZhbHNlO1xuXHRcdFx0bGV0IHNUYXJnZXRIYXNoID0gdGhpcy5nZXRIYXNoKCk7XG5cdFx0XHRzVGFyZ2V0SGFzaCA9IHNUYXJnZXRIYXNoLnJlcGxhY2UoLyhcXD98JilyZXN0b3JlSGlzdG9yeT10cnVlLywgXCJcIik7XG5cdFx0XHRjb25zdCBvTmV3U3RhdGUgPSB0aGlzLl9leHRyYWN0U3RhdGVGcm9tSGFzaChzVGFyZ2V0SGFzaCk7XG5cblx0XHRcdGNvbnN0IG9IaXN0b3J5QWN0aW9uID0gdGhpcy5fcHVzaE5ld1N0YXRlKG9OZXdTdGF0ZSwgdHJ1ZSwgZmFsc2UsIHRydWUpO1xuXG5cdFx0XHRyZXR1cm4gdGhpcy5fcmVidWlsZEJyb3dzZXJIaXN0b3J5KG9IaXN0b3J5QWN0aW9uLCB0cnVlKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBOYXZpZ2F0ZXMgYmFjayBpbiB0aGUgaGlzdG9yeS5cblx0ICpcblx0ICogQHJldHVybnMge1Byb21pc2V9IFByb21pc2UgdGhhdCBpcyByZXNvbHZlZCB3aGVuIHRoZSBuYXZpZ2F0aW9uIGlzIGZpbmFsaXplZFxuXHQgKi9cblx0bmF2QmFjaygpIHtcblx0XHRjb25zdCBzQ3VycmVudEhhc2ggPSB0aGlzLmdldEhhc2goKTtcblx0XHRsZXQgc1ByZXZpb3VzSGFzaDtcblxuXHRcdC8vIExvb2sgZm9yIHRoZSBjdXJyZW50IGhhc2ggaW4gdGhlIG1hbmFnZWQgaGlzdG9yeVxuXHRcdGZvciAobGV0IGkgPSB0aGlzLl9vTWFuYWdlZEhpc3RvcnkubGVuZ3RoIC0gMTsgaSA+IDA7IGktLSkge1xuXHRcdFx0aWYgKHRoaXMuX29NYW5hZ2VkSGlzdG9yeVtpXS5oYXNoID09PSBzQ3VycmVudEhhc2gpIHtcblx0XHRcdFx0c1ByZXZpb3VzSGFzaCA9IHRoaXMuX29NYW5hZ2VkSGlzdG9yeVtpIC0gMV0uaGFzaDtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKHNQcmV2aW91c0hhc2gpIHtcblx0XHRcdHJldHVybiB0aGlzLm5hdlRvSGFzaChzUHJldmlvdXNIYXNoKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gV2UgY291bGRuJ3QgZmluZCBhIHByZXZpb3VzIGhhc2ggaW4gaGlzdG9yeVxuXHRcdFx0Ly8gVGhpcyBjYW4gaGFwcGVuIHdoZW4gbmF2aWdhdGluZyBmcm9tIGEgdHJhbnNpZW50IGhhc2ggaW4gYSBjcmVhdGUgYXBwLCBhbmRcblx0XHRcdC8vIGluIHRoYXQgY2FzZSBoaXN0b3J5LmJhY2sgd291bGQgZ28gYmFjayB0byB0aGUgRkxQXG5cdFx0XHR3aW5kb3cuaGlzdG9yeS5iYWNrKCk7XG5cdFx0XHRyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIE5hdmlnYXRlcyB0byBhIHJvdXRlIHdpdGggcGFyYW1ldGVycy5cblx0ICogQHBhcmFtIHtzdHJpbmd9IHNSb3V0ZU5hbWUgVGhlIHJvdXRlIG5hbWUgdG8gYmUgbmF2aWdhdGVkIHRvXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBvUGFyYW1ldGVycyBQYXJhbWV0ZXJzIGZvciB0aGUgbmF2aWdhdGlvblxuXHQgKiBAcmV0dXJucyB7UHJvbWlzZX0gUHJvbWlzZSB0aGF0IGlzIHJlc29sdmVkIHdoZW4gdGhlIG5hdmlnYXRpb24gaXMgZmluYWxpemVkXG5cdCAqIEB1aTUtcmVzdHJpY3RlZFxuXHQgKi9cblx0bmF2VG8oc1JvdXRlTmFtZTogc3RyaW5nLCBvUGFyYW1ldGVyczogYW55KSB7XG5cdFx0Y29uc3Qgc0hhc2ggPSB0aGlzLl9vUm91dGVyLmdldFVSTChzUm91dGVOYW1lLCBvUGFyYW1ldGVycyk7XG5cdFx0cmV0dXJuIHRoaXMubmF2VG9IYXNoKHNIYXNoLCBmYWxzZSwgb1BhcmFtZXRlcnMubm9QcmVzZXJ2YXRpb25DYWNoZSwgZmFsc2UsICFvUGFyYW1ldGVycy5iSXNTdGlja3lNb2RlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBFeGl0cyB0aGUgY3VycmVudCBhcHAgYnkgbmF2aWdhdGluZyBiYWNrXG5cdCAqIHRvIHRoZSBwcmV2aW91cyBhcHAgKGlmIGFueSkgb3IgdGhlIEZMUC5cblx0ICpcblx0ICogQHJldHVybnMge1Byb21pc2V9IFByb21pc2UgdGhhdCBpcyByZXNvbHZlZCB3aGVuIHdlIGV4aXQgdGhlIGFwcFxuXHQgKi9cblx0ZXhpdEZyb21BcHAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX29TaGVsbFNlcnZpY2VzLmJhY2tUb1ByZXZpb3VzQXBwKCk7XG5cdH1cblxuXHQvKipcblx0ICogQ2hlY2tzIHdoZXRoZXIgYSBnaXZlbiBoYXNoIGNhbiBoYXZlIGFuIGltcGFjdCBvbiB0aGUgY3VycmVudCBzdGF0ZVxuXHQgKiBpLmUuIGlmIHRoZSBoYXNoIGlzIGVxdWFsLCBjb21wYXRpYmxlIG9yIGFuIGFuY2VzdG9yIG9mIHRoZSBjdXJyZW50IHN0YXRlLlxuXHQgKlxuXHQgKiBAcGFyYW0geyp9IHNIYXNoIGB0cnVlYCBpZiB0aGVyZSBpcyBhbiBpbXBhY3Rcblx0ICogQHJldHVybnMge2Jvb2xlYW59IElmIHRoZXJlIGlzIGFuIGltcGFjdFxuXHQgKi9cblx0aXNDdXJyZW50U3RhdGVJbXBhY3RlZEJ5KHNIYXNoOiBhbnkpIHtcblx0XHRpZiAoc0hhc2hbMF0gPT09IFwiL1wiKSB7XG5cdFx0XHRzSGFzaCA9IHNIYXNoLnN1YnN0cmluZygxKTtcblx0XHR9XG5cdFx0Y29uc3Qgb0xvY2FsR3VhcmQgPSBjcmVhdGVHdWFyZEZyb21IYXNoKHNIYXNoKTtcblx0XHRyZXR1cm4gb0xvY2FsR3VhcmQuY2hlY2sodGhpcy5nZXRIYXNoKCkpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENoZWNrcyBpZiBhIG5hdmlnYXRpb24gaXMgY3VycmVudGx5IGJlaW5nIHByb2Nlc3NlZC5cblx0ICpcblx0ICogQHJldHVybnMge2Jvb2xlYW59IGBmYWxzZWAgaWYgYSBuYXZpZ2F0aW9uIGhhcyBiZWVuIHRyaWdnZXJlZCBpbiB0aGUgUm91dGVyUHJveHkgYW5kIGlzIG5vdCB5ZXQgZmluYWxpemVkXG5cdCAqL1xuXHRpc05hdmlnYXRpb25GaW5hbGl6ZWQoKSB7XG5cdFx0cmV0dXJuICF0aGlzLmJJc1JlYnVpbGRIaXN0b3J5UnVubmluZyAmJiAhdGhpcy5fYkRlbGF5ZWRSZWJ1aWxkO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgdGhlIGxhc3Qgc3RhdGUgYXMgYSBndWFyZC5cblx0ICogRWFjaCBmdXR1cmUgbmF2aWdhdGlvbiB3aWxsIGJlIGNoZWNrZWQgYWdhaW5zdCB0aGlzIGd1YXJkLCBhbmQgYSBjb25maXJtYXRpb24gZGlhbG9nIHdpbGxcblx0ICogYmUgZGlzcGxheWVkIGJlZm9yZSB0aGUgbmF2aWdhdGlvbiBjcm9zc2VzIHRoZSBndWFyZCAoaS5lLiBnb2VzIHRvIGFuIGFuY2VzdG9yIG9mIHRoZSBndWFyZCkuXG5cdCAqXG5cdCAqIEBwYXJhbSBzSGFzaCBUaGUgaGFzaCBmb3IgdGhlIGd1YXJkXG5cdCAqL1xuXHRzZXROYXZpZ2F0aW9uR3VhcmQoc0hhc2g6IHN0cmluZykge1xuXHRcdHRoaXMuX29OYXZpZ2F0aW9uR3VhcmQgPSBjcmVhdGVHdWFyZEZyb21IYXNoKHNIYXNoKTtcblx0XHR0aGlzLmJJc0d1YXJkQ3Jvc3NBbGxvd2VkID0gZmFsc2U7XG5cdH1cblxuXHQvKipcblx0ICogRGlzYWJsZXMgdGhlIG5hdmlnYXRpb24gZ3VhcmQuXG5cdCAqL1xuXHRkaXNjYXJkTmF2aWdhdGlvbkd1YXJkKCkge1xuXHRcdHRoaXMuX29OYXZpZ2F0aW9uR3VhcmQgPSBudWxsO1xuXHR9XG5cblx0LyoqXG5cdCAqIENoZWNrcyBmb3IgdGhlIGF2YWlsYWJpbGl0eSBvZiB0aGUgbmF2aWdhdGlvbiBndWFyZC5cblx0ICpcblx0ICogQHJldHVybnMge2Jvb2xlYW59IGB0cnVlYCBpZiBuYXZpZ2F0aW5nIGd1YXJkIGlzIGF2YWlsYWJsZVxuXHQgKi9cblx0aGFzTmF2aWdhdGlvbkd1YXJkKCkge1xuXHRcdHJldHVybiB0aGlzLl9vTmF2aWdhdGlvbkd1YXJkICE9PSBudWxsO1xuXHR9XG5cblx0LyoqXG5cdCAqIFRlc3RzIGEgaGFzaCBhZ2FpbnN0IHRoZSBuYXZpZ2F0aW9uIGd1YXJkLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc0hhc2ggVGhlIGhhc2ggdG8gYmUgdGVzdGVkXG5cdCAqIEByZXR1cm5zIHtib29sZWFufSBgdHJ1ZWAgaWYgbmF2aWdhdGluZyB0byB0aGUgaGFzaCBkb2Vzbid0IGNyb3NzIHRoZSBndWFyZFxuXHQgKi9cblx0Y2hlY2tIYXNoV2l0aEd1YXJkKHNIYXNoOiBzdHJpbmcpIHtcblx0XHRyZXR1cm4gdGhpcy5fb05hdmlnYXRpb25HdWFyZCA9PT0gbnVsbCB8fCB0aGlzLl9vTmF2aWdhdGlvbkd1YXJkLmNoZWNrKHNIYXNoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDaGVja3MgaWYgdGhlIHVzZXIgYWxsb3dlZCB0aGUgbmF2aWdhdGlvbiBndWFyZCB0byBiZSBjcm9zc2VkLlxuXHQgKlxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn0gYHRydWVgIGlmIGNyb3NzaW5nIHRoZSBndWFyZCBoYXMgYmVlbiBhbGxvd2VkIGJ5IHRoZSB1c2VyXG5cdCAqL1xuXHRpc0d1YXJkQ3Jvc3NBbGxvd2VkQnlVc2VyKCkge1xuXHRcdHJldHVybiB0aGlzLmJJc0d1YXJkQ3Jvc3NBbGxvd2VkO1xuXHR9XG5cblx0LyoqXG5cdCAqIEFjdGl2YXRlcyB0aGUgc3luY2hyb25pemF0aW9uIGZvciByb3V0ZU1hdGNoZWRFdmVudC5cblx0ICogVGhlIG5leHQgTmF2VG9IYXNoIGNhbGwgd2lsbCBjcmVhdGUgYSBTeW5jaHJvbml6YXRpb24gb2JqZWN0IHRoYXQgd2lsbCBiZSByZXNvbHZlZFxuXHQgKiBieSB0aGUgY29ycmVzcG9uZGluZyBvblJvdXRlTWF0Y2hlZCBldmVudCwgcHJldmVudGluZyBhbm90aGVyIE5hdlRvSGFzaCB0byBoYXBwZW4gaW4gcGFyYWxsZWwuXG5cdCAqL1xuXHRhY3RpdmF0ZVJvdXRlTWF0Y2hTeW5jaHJvbml6YXRpb24oKSB7XG5cdFx0dGhpcy5fYkFjdGl2YXRlUm91dGVNYXRjaFN5bmNocm8gPSB0cnVlO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJlc29sdmUgdGhlIHJvdXRlTWF0Y2ggc3luY2hyb25pemF0aW9uIG9iamVjdCwgdW5sb2NraW5nIHBvdGVudGlhbCBwZW5kaW5nIE5hdlRvSGFzaCBjYWxscy5cblx0ICovXG5cdHJlc29sdmVSb3V0ZU1hdGNoKCkge1xuXHRcdGlmICh0aGlzLl9vUm91dGVNYXRjaFN5bmNocm9uaXphdGlvbikge1xuXHRcdFx0dGhpcy5fb1JvdXRlTWF0Y2hTeW5jaHJvbml6YXRpb24ucmVzb2x2ZSgpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBNYWtlcyBzdXJlIG5vIG5hdmlnYXRpb24gY2FuIGhhcHBlbiBiZWZvcmUgYSByb3V0ZU1hdGNoIGhhcHBlbmVkLlxuXHQgKi9cblx0d2FpdEZvclJvdXRlTWF0Y2hCZWZvcmVOYXZpZ2F0aW9uKCkge1xuXHRcdHRoaXMuX29Sb3V0ZU1hdGNoU3luY2hyb25pemF0aW9uID0gbmV3IFN5bmNocm9uaXphdGlvbigpO1xuXHRcdHRoaXMuX2JBY3RpdmF0ZVJvdXRlTWF0Y2hTeW5jaHJvID0gZmFsc2U7XG5cdH1cblxuXHRfZXh0cmFjdEtleXNGcm9tSGFzaChzSGFzaDogYW55KSB7XG5cdFx0aWYgKHNIYXNoID09PSB1bmRlZmluZWQpIHtcblx0XHRcdHNIYXNoID0gXCJcIjtcblx0XHR9XG5cdFx0Y29uc3Qgc0hhc2hOb1BhcmFtcyA9IHNIYXNoLnNwbGl0KFwiP1wiKVswXTsgLy8gcmVtb3ZlIHBhcmFtc1xuXHRcdGNvbnN0IGFUb2tlbnMgPSBzSGFzaE5vUGFyYW1zLnNwbGl0KFwiL1wiKTtcblx0XHRjb25zdCBhS2V5czogYW55W10gPSBbXTtcblxuXHRcdGFUb2tlbnMuZm9yRWFjaChmdW5jdGlvbihzVG9rZW46IGFueSkge1xuXHRcdFx0Y29uc3QgcmVnZXhLZXkgPSAvW15cXChcXCldK1xcKFteXFwoXFwpXStcXCkvOyAvLyBhYmMoZGVmKVxuXHRcdFx0aWYgKHJlZ2V4S2V5LnRlc3Qoc1Rva2VuKSkge1xuXHRcdFx0XHRhS2V5cy5wdXNoKHNUb2tlbi5zcGxpdChcIihcIilbMF0pO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0cmV0dXJuIGFLZXlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIEJ1aWxkcyBhIHN0YXRlIGZyb20gYSBoYXNoLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc0hhc2ggVGhlIGhhc2ggdG8gYmUgdXNlZCBhcyBlbnRyeVxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fSBUaGUgc3RhdGVcblx0ICpcblx0ICogQHVpNS1yZXN0cmljdGVkXG5cdCAqL1xuXHRfZXh0cmFjdFN0YXRlRnJvbUhhc2goc0hhc2g6IHN0cmluZykge1xuXHRcdGlmIChzSGFzaCA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRzSGFzaCA9IFwiXCI7XG5cdFx0fVxuXG5cdFx0Y29uc3Qgb1N0YXRlOiBhbnkgPSB7XG5cdFx0XHRrZXlzOiB0aGlzLl9leHRyYWN0S2V5c0Zyb21IYXNoKHNIYXNoKVxuXHRcdH07XG5cblx0XHQvLyBSZXRyaWV2ZSBsYXlvdXQgKGlmIGFueSlcblx0XHRjb25zdCBhTGF5b3V0ID0gc0hhc2gubWF0Y2gobmV3IFJlZ0V4cChcIlxcXFw/LipcIiArIGVudW1VUkxQYXJhbXMuTEFZT1VUUEFSQU0gKyBcIj0oW14mXSopXCIpKTtcblx0XHRvU3RhdGUuc0xheW91dCA9IGFMYXlvdXQgJiYgYUxheW91dC5sZW5ndGggPiAxID8gYUxheW91dFsxXSA6IG51bGw7XG5cdFx0aWYgKG9TdGF0ZS5zTGF5b3V0ID09PSBcIk1pZENvbHVtbkZ1bGxTY3JlZW5cIikge1xuXHRcdFx0b1N0YXRlLnNjcmVlbk1vZGUgPSAxO1xuXHRcdH0gZWxzZSBpZiAob1N0YXRlLnNMYXlvdXQgPT09IFwiRW5kQ29sdW1uRnVsbFNjcmVlblwiKSB7XG5cdFx0XHRvU3RhdGUuc2NyZWVuTW9kZSA9IDI7XG5cdFx0fSBlbHNlIHtcblx0XHRcdG9TdGF0ZS5zY3JlZW5Nb2RlID0gMDtcblx0XHR9XG5cblx0XHRvU3RhdGUuaGFzaCA9IHNIYXNoO1xuXHRcdHJldHVybiBvU3RhdGU7XG5cdH1cblxuXHQvKipcblx0ICogQWRkcyBhIG5ldyBzdGF0ZSBpbnRvIHRoZSBpbnRlcm5hbCBoaXN0b3J5IHN0cnVjdHVyZS5cblx0ICogTWFrZXMgc3VyZSB0aGlzIG5ldyBzdGF0ZSBpcyBhZGRlZCBhZnRlciBhbiBhbmNlc3Rvci5cblx0ICogQWxzbyBzZXRzIHRoZSBpQXBwU3RhdGUga2V5IGluIHRoZSB3aG9sZSBoaXN0b3J5LlxuXHQgKlxuXHQgKiBAbWVtYmVyb2Ygc2FwLmZlLmNvcmUuUm91dGVyUHJveHlcblx0ICogQHBhcmFtIHtvYmplY3R9IG9OZXdTdGF0ZSBUaGUgbmV3IHN0YXRlIHRvIGJlIGFkZGVkXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gYlJlYnVpbGRPbmx5IGB0cnVlYCBpZiB3ZSdyZSByZWJ1aWxkaW5nIHRoZSBoaXN0b3J5IGFmdGVyIGEgc2hlbGwgbWVudSBuYXZpZ2F0aW9uXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gYlByZXNlcnZlSGlzdG9yeSBJZiBzZXQgdG8gdHJ1ZSwgbm9uLWFuY2VzdG9yIGVudHJpZXMgaW4gaGlzdG9yeSB3aWxsIGJlIHJldGFpbmVkXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gYkRpc2FibGVIaXN0b3J5UHJlc2VydmF0aW9uIERpc2FibGUgdGhlIG1lY2hhbmlzbSB0byByZXRhaW5lZCBtYXJrZWQgZW50cmllcyBpbiBjYWNoZVxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fSBUaGUgbmV3IHN0YXRlXG5cdCAqIEB1aTUtcmVzdHJpY3RlZFxuXHQgKiBAZmluYWxcblx0ICovXG5cdF9wdXNoTmV3U3RhdGUob05ld1N0YXRlOiBhbnksIGJSZWJ1aWxkT25seTogYm9vbGVhbiwgYlByZXNlcnZlSGlzdG9yeTogYm9vbGVhbiwgYkRpc2FibGVIaXN0b3J5UHJlc2VydmF0aW9uOiBib29sZWFuKSB7XG5cdFx0Y29uc3Qgc0N1cnJlbnRIYXNoID0gdGhpcy5nZXRIYXNoKCk7XG5cdFx0bGV0IGxhc3RJbmRleCA9IHRoaXMuX29NYW5hZ2VkSGlzdG9yeS5sZW5ndGggLSAxO1xuXHRcdGxldCBpUG9wQ291bnQgPSBiUmVidWlsZE9ubHkgPyAxIDogMDtcblxuXHRcdC8vIDEuIERvIHNvbWUgY2xlYW51cCBpbiB0aGUgbWFuYWdlZCBoaXN0b3J5IDogaW4gY2FzZSB0aGUgdXNlciBoYXMgbmF2aWdhdGVkIGJhY2sgaW4gdGhlIGJyb3dzZXIgaGlzdG9yeSwgd2UgbmVlZCB0byByZW1vdmVcblx0XHQvLyB0aGUgc3RhdGVzIGFoZWFkIGluIGhpc3RvcnkgYW5kIG1ha2Ugc3VyZSB0aGUgdG9wIHN0YXRlIGNvcnJlc3BvbmRzIHRvIHRoZSBjdXJyZW50IHBhZ2Vcblx0XHQvLyBXZSBkb24ndCBkbyB0aGF0IHdoZW4gcmVzdG9yaW5nIHRoZSBoaXN0b3J5LCBhcyB0aGUgY3VycmVudCBzdGF0ZSBoYXMgYmVlbiBhZGRlZCBvbiB0b3Agb2YgdGhlIGJyb3dzZXIgaGlzdG9yeVxuXHRcdC8vIGFuZCBpcyBub3QgcmVmbGVjdGVkIGluIHRoZSBtYW5hZ2VkIGhpc3Rvcnlcblx0XHRpZiAoIWJSZWJ1aWxkT25seSkge1xuXHRcdFx0d2hpbGUgKGxhc3RJbmRleCA+PSAwICYmIHRoaXMuX29NYW5hZ2VkSGlzdG9yeVtsYXN0SW5kZXhdLmhhc2ggIT09IHNDdXJyZW50SGFzaCkge1xuXHRcdFx0XHR0aGlzLl9vTWFuYWdlZEhpc3RvcnkucG9wKCk7XG5cdFx0XHRcdGxhc3RJbmRleC0tO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAodGhpcy5fb01hbmFnZWRIaXN0b3J5Lmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0XHQvLyBXZSBjb3VsZG4ndCBmaW5kIHRoZSBjdXJyZW50IGxvY2F0aW9uIGluIHRoZSBoaXN0b3J5LiBUaGlzIGNhbiBoYXBwZW4gaWYgYSBicm93c2VyIHJlbG9hZFxuXHRcdFx0XHQvLyBoYXBwZW5lZCwgY2F1c2luZyBhIHJlaW5pdGlhbGl6YXRpb24gb2YgdGhlIG1hbmFnZWQgaGlzdG9yeS5cblx0XHRcdFx0Ly8gSW4gdGhhdCBjYXNlLCB3ZSB1c2UgdGhlIGN1cnJlbnQgbG9jYXRpb24gYXMgdGhlIG5ldyBzdGFydGluZyBwb2ludCBpbiB0aGUgbWFuYWdlZCBoaXN0b3J5XG5cdFx0XHRcdHRoaXMuX29NYW5hZ2VkSGlzdG9yeS5wdXNoKHRoaXMuX2V4dHJhY3RTdGF0ZUZyb21IYXNoKHNDdXJyZW50SGFzaCkpO1xuXHRcdFx0XHRoaXN0b3J5LnJlcGxhY2VTdGF0ZShPYmplY3QuYXNzaWduKHsgZmVMZXZlbDogMCB9LCBoaXN0b3J5LnN0YXRlKSwgXCJcIik7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gMi4gTWFyayB0aGUgdG9wIHN0YXRlIGFzIHByZXNlcnZlZCBpZiByZXF1aXJlZFxuXHRcdGlmIChiUHJlc2VydmVIaXN0b3J5ICYmICFiRGlzYWJsZUhpc3RvcnlQcmVzZXJ2YXRpb24pIHtcblx0XHRcdHRoaXMuX29NYW5hZ2VkSGlzdG9yeVt0aGlzLl9vTWFuYWdlZEhpc3RvcnkubGVuZ3RoIC0gMV0ucHJlc2VydmVkID0gdHJ1ZTtcblx0XHR9XG5cblx0XHQvLyAzLiBUaGVuIHBvcCBhbGwgc3RhdGVzIHVudGlsIHdlIGZpbmQgYW4gYW5jZXN0b3Igb2YgdGhlIG5ldyBzdGF0ZSwgb3Igd2UgZmluZCBhIHN0YXRlIHRoYXQgbmVlZCB0byBiZSBwcmVzZXJ2ZWRcblx0XHRsZXQgb0xhc3RSZW1vdmVkSXRlbTtcblx0XHR3aGlsZSAodGhpcy5fb01hbmFnZWRIaXN0b3J5Lmxlbmd0aCA+IDApIHtcblx0XHRcdGNvbnN0IG9Ub3BTdGF0ZSA9IHRoaXMuX29NYW5hZ2VkSGlzdG9yeVt0aGlzLl9vTWFuYWdlZEhpc3RvcnkubGVuZ3RoIC0gMV07XG5cdFx0XHRpZiAoXG5cdFx0XHRcdChiRGlzYWJsZUhpc3RvcnlQcmVzZXJ2YXRpb24gfHwgIW9Ub3BTdGF0ZS5wcmVzZXJ2ZWQpICYmXG5cdFx0XHRcdHRoaXMuX2NvbXBhcmVDYWNoZVN0YXRlcyhvVG9wU3RhdGUsIG9OZXdTdGF0ZSkgIT09IGVudW1TdGF0ZS5BTkNFU1RPUlxuXHRcdFx0KSB7XG5cdFx0XHRcdC8vIFRoZSB0b3Agc3RhdGUgaXMgbm90IGFuIGFuY2VzdG9yIG9mIG9OZXdTdGF0ZSBhbmQgaXMgbm90IHByZXNlcnZlZCAtLT4gd2UgY2FuIHBvcCBpdFxuXHRcdFx0XHRvTGFzdFJlbW92ZWRJdGVtID0gdGhpcy5fb01hbmFnZWRIaXN0b3J5LnBvcCgpO1xuXHRcdFx0XHRpUG9wQ291bnQrKztcblx0XHRcdH0gZWxzZSBpZiAob1RvcFN0YXRlLnByZXNlcnZlZCAmJiByZW1vdmVBcHBTdGF0ZUluSGFzaChvVG9wU3RhdGUuaGFzaCkgPT09IHJlbW92ZUFwcFN0YXRlSW5IYXNoKG9OZXdTdGF0ZS5oYXNoKSkge1xuXHRcdFx0XHQvLyBXZSB0cnkgdG8gYWRkIGEgc3RhdGUgdGhhdCBpcyBhbHJlYWR5IGluIGNhY2hlIChkdWUgdG8gcHJlc2VydmVkIGZsYWcpIGJ1dCB3aXRoIGEgZGlmZmVyZW50IGlhcHAtc3RhdGVcblx0XHRcdFx0Ly8gLS0+IHdlIHNob3VsZCBkZWxldGUgdGhlIHByZXZpb3VzIGVudHJ5IChpdCB3aWxsIGJlIGxhdGVyIHJlcGxhY2VkIGJ5IHRoZSBuZXcgb25lKSBhbmQgc3RvcCBwb3BwaW5nXG5cdFx0XHRcdG9MYXN0UmVtb3ZlZEl0ZW0gPSB0aGlzLl9vTWFuYWdlZEhpc3RvcnkucG9wKCk7XG5cdFx0XHRcdGlQb3BDb3VudCsrO1xuXHRcdFx0XHRvTmV3U3RhdGUucHJlc2VydmVkID0gdHJ1ZTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRicmVhazsgLy8gQW5jZXN0b3Igb3IgcHJlc2VydmVkIHN0YXRlIGZvdW5kIC0tPiB3ZSBzdG9wIHBvcHBpbmcgb3V0IHN0YXRlc1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIDQuIGlBcHBTdGF0ZSBtYW5hZ2VtZW50XG5cdFx0dGhpcy5zSUFwcFN0YXRlS2V5ID0gZmluZEFwcFN0YXRlSW5IYXNoKG9OZXdTdGF0ZS5oYXNoKTtcblx0XHRpZiAodGhpcy5mY2xFbmFibGVkICYmIHRoaXMuc0lBcHBTdGF0ZUtleSkge1xuXHRcdFx0Ly8gSW4gY2FzZSBvZiBGQ0wsIHRoZSBuZXcgYXBwIHN0YXRlIG5lZWRzIHRvIGJlIGFwcGxpZWQgdG8gdGhlIHdob2xlIGhpc3Rvcnlcblx0XHRcdHRoaXMuX29NYW5hZ2VkSGlzdG9yeS5mb3JFYWNoKChvTWFuYWdlZFN0YXRlOiBhbnkpID0+IHtcblx0XHRcdFx0b01hbmFnZWRTdGF0ZS5oYXNoID0gc2V0QXBwU3RhdGVJbkhhc2gob01hbmFnZWRTdGF0ZS5oYXNoLCB0aGlzLnNJQXBwU3RhdGVLZXkpO1xuXHRcdFx0fSk7XG5cdFx0fSBlbHNlIGlmICghdGhpcy5mY2xFbmFibGVkICYmIG9MYXN0UmVtb3ZlZEl0ZW0pIHtcblx0XHRcdGNvbnN0IHNQcmV2aW91c0lBcHBTdGF0ZUtleSA9IGZpbmRBcHBTdGF0ZUluSGFzaChvTGFzdFJlbW92ZWRJdGVtLmhhc2gpO1xuXHRcdFx0Y29uc3Qgb0NvbXBhcmlzb25TdGF0ZVJlc3VsdCA9IHRoaXMuX2NvbXBhcmVDYWNoZVN0YXRlcyhvTGFzdFJlbW92ZWRJdGVtLCBvTmV3U3RhdGUpO1xuXHRcdFx0Ly8gaWYgY3VycmVudCBzdGF0ZSBkb2Vzbid0IGNvbnRhaW4gYSBpLWFwcHN0YXRlIGFuZCB0aGlzIHN0YXRlIHNob3VsZCByZXBsYWNlIGEgc3RhdGUgY29udGFpbmluZyBhIGlBcHBTdGF0ZVxuXHRcdFx0Ly8gdGhlbiB0aGUgcHJldmlvdXMgaUFwcFN0YXRlIGlzIHByZXNlcnZlZFxuXHRcdFx0aWYgKFxuXHRcdFx0XHQhdGhpcy5zSUFwcFN0YXRlS2V5ICYmXG5cdFx0XHRcdHNQcmV2aW91c0lBcHBTdGF0ZUtleSAmJlxuXHRcdFx0XHQob0NvbXBhcmlzb25TdGF0ZVJlc3VsdCA9PT0gZW51bVN0YXRlLkVRVUFMIHx8IG9Db21wYXJpc29uU3RhdGVSZXN1bHQgPT09IGVudW1TdGF0ZS5DT01QQVRJQkxFKVxuXHRcdFx0KSB7XG5cdFx0XHRcdG9OZXdTdGF0ZS5oYXNoID0gc2V0QXBwU3RhdGVJbkhhc2gob05ld1N0YXRlLmhhc2gsIHNQcmV2aW91c0lBcHBTdGF0ZUtleSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gNS4gTm93IHdlIGNhbiBwdXNoIHRoZSBzdGF0ZSBhdCB0aGUgdG9wIG9mIHRoZSBpbnRlcm5hbCBoaXN0b3J5XG5cdFx0Y29uc3QgYkhhc1NhbWVIYXNoID0gb0xhc3RSZW1vdmVkSXRlbSAmJiBvTmV3U3RhdGUuaGFzaCA9PT0gb0xhc3RSZW1vdmVkSXRlbS5oYXNoO1xuXHRcdGlmICh0aGlzLl9vTWFuYWdlZEhpc3RvcnkubGVuZ3RoID09PSAwIHx8IHRoaXMuX29NYW5hZ2VkSGlzdG9yeVt0aGlzLl9vTWFuYWdlZEhpc3RvcnkubGVuZ3RoIC0gMV0uaGFzaCAhPT0gb05ld1N0YXRlLmhhc2gpIHtcblx0XHRcdHRoaXMuX29NYW5hZ2VkSGlzdG9yeS5wdXNoKG9OZXdTdGF0ZSk7XG5cdFx0fVxuXG5cdFx0Ly8gNi4gRGV0ZXJtaW5lIHdoaWNoIGFjdGlvbnMgdG8gZG8gb24gdGhlIGhpc3Rvcnlcblx0XHRpZiAoaVBvcENvdW50ID09PSAwKSB7XG5cdFx0XHQvLyBObyBzdGF0ZSB3YXMgcG9wcGVkIC0tPiBhcHBlbmRcblx0XHRcdHJldHVybiB7IHR5cGU6IFwiYXBwZW5kXCIgfTtcblx0XHR9IGVsc2UgaWYgKGlQb3BDb3VudCA9PT0gMSkge1xuXHRcdFx0Ly8gT25seSAxIHN0YXRlIHdhcyBwb3BwZWQgLS0+IHJlcGxhY2UgY3VycmVudCBoYXNoIHVubGVzcyBoYXNoIGlzIHRoZSBzYW1lICh0aGVuIG5vdGhpbmcgdG8gZG8pXG5cdFx0XHRyZXR1cm4gYkhhc1NhbWVIYXNoID8geyB0eXBlOiBcIm5vbmVcIiB9IDogeyB0eXBlOiBcInJlcGxhY2VcIiB9O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBNb3JlIHRoYW4gMSBzdGF0ZSB3YXMgcG9wcGVkIC0tPiBnbyBiYWtjIGluIGhpc3RvcnkgYW5kIHJlcGxhY2UgaGFzaCBpZiBuZWNlc3Nhcnlcblx0XHRcdHJldHVybiBiSGFzU2FtZUhhc2ggPyB7IHR5cGU6IFwiYmFja1wiLCBzdGVwczogaVBvcENvdW50IC0gMSB9IDogeyB0eXBlOiBcImJhY2stcmVwbGFjZVwiLCBzdGVwczogaVBvcENvdW50IC0gMSB9O1xuXHRcdH1cblx0fVxuXG5cdF9ibG9ja2luZ05hdmlnYXRpb25GaWx0ZXIoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2JEaXNhYmxlT25IYXNoQ2hhbmdlID8gXCJDdXN0b21cIiA6IFwiQ29udGludWVcIjtcblx0fVxuXG5cdC8qKlxuXHQgKiBEaXNhYmxlIHRoZSByb3V0aW5nIGJ5IGNhbGxpbmcgdGhlIHJvdXRlciBzdG9wIG1ldGhvZC5cblx0ICpcblx0ICogQGZ1bmN0aW9uXG5cdCAqIEBtZW1iZXJvZiBzYXAuZmUuY29yZS5Sb3V0ZXJQcm94eVxuXHQgKlxuXHQgKiBAdWk1LXJlc3RyaWN0ZWRcblx0ICogQGZpbmFsXG5cdCAqL1xuXHRfZGlzYWJsZUV2ZW50T25IYXNoQ2hhbmdlKCkge1xuXHRcdHRoaXMuX2JEaXNhYmxlT25IYXNoQ2hhbmdlID0gdHJ1ZTtcblx0XHR0aGlzLl9vUm91dGVyLnN0b3AoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBFbmFibGUgdGhlIHJvdXRpbmcgYnkgY2FsbGluZyB0aGUgcm91dGVyIGluaXRpYWxpemUgbWV0aG9kLlxuXHQgKlxuXHQgKiBAZnVuY3Rpb25cblx0ICogQG5hbWUgc2FwLmZlLmNvcmUuUm91dGVyUHJveHkjX2VuYWJsZUV2ZW50T25IYXNoQ2hhbmdlXG5cdCAqIEBtZW1iZXJvZiBzYXAuZmUuY29yZS5Sb3V0ZXJQcm94eVxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtiSWdub3JlQ3VycmVudEhhc2hdIElnbm9yZSB0aGUgbGFzdCBoYXNoIGV2ZW50IHRyaWdnZXJlZCBiZWZvcmUgdGhlIHJvdXRlciBoYXMgaW5pdGlhbGl6ZWRcblx0ICpcblx0ICogQHVpNS1yZXN0cmljdGVkXG5cdCAqIEBmaW5hbFxuXHQgKi9cblx0X2VuYWJsZUV2ZW50T25IYXNoQ2hhbmdlKGJJZ25vcmVDdXJyZW50SGFzaDogYm9vbGVhbiB8IHVuZGVmaW5lZCkge1xuXHRcdHRoaXMuX2JEaXNhYmxlT25IYXNoQ2hhbmdlID0gZmFsc2U7XG5cdFx0dGhpcy5fb1JvdXRlci5pbml0aWFsaXplKGJJZ25vcmVDdXJyZW50SGFzaCk7XG5cdH1cblxuXHQvKipcblx0ICogU3luY2hyb25pemVzIHRoZSBicm93c2VyIGhpc3Rvcnkgd2l0aCB0aGUgaW50ZXJuYWwgaGlzdG9yeSBvZiB0aGUgcm91dGVyUHJveHksIGFuZCB0cmlnZ2VycyBhIG5hdmlnYXRpb24gaWYgbmVlZGVkLlxuXHQgKlxuXHQgKiBAbWVtYmVyb2Ygc2FwLmZlLmNvcmUuUm91dGVyUHJveHlcblx0ICogQHBhcmFtIHtvYmplY3R9IG9IaXN0b3J5QWN0aW9uIFNwZWNpZmllcyB0aGUgbmF2aWdhdGlvbiBhY3Rpb24gdG8gYmUgcGVyZm9ybWVkXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gYlJlYnVpbGRPbmx5IGB0cnVlYCBpZiBpbnRlcm5hbCBoaXN0b3J5IGlzIGN1cnJlbnRseSBiZWluZyByZWJ1aWx0XG5cdCAqIEByZXR1cm5zIHtQcm9taXNlfSBQcm9taXNlIChyZXNvbHZlZCB3aGVuIHRoZSBuYXZpZ2F0aW9uIGlzIGZpbmFsaXplZCkgdGhhdCByZXR1cm5zICd0cnVlJyBpZiBhIG5hdmlnYXRpb24gdG9vayBwbGFjZSwgJ2ZhbHNlJyBpZiB0aGUgbmF2aWdhdGlvbiBkaWRuJ3QgaGFwcGVuXG5cdCAqIEB1aTUtcmVzdHJpY3RlZFxuXHQgKiBAZmluYWxcblx0ICovXG5cdF9yZWJ1aWxkQnJvd3Nlckhpc3Rvcnkob0hpc3RvcnlBY3Rpb246IGFueSwgYlJlYnVpbGRPbmx5OiBib29sZWFuKSB7XG5cdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby10aGlzLWFsaWFzXG5cdFx0Y29uc3QgdGhhdCA9IHRoaXM7XG5cdFx0cmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuXHRcdFx0dGhpcy5iSXNSZWJ1aWxkSGlzdG9yeVJ1bm5pbmcgPSB0cnVlO1xuXHRcdFx0Y29uc3Qgb1RhcmdldFN0YXRlID0gdGhpcy5fb01hbmFnZWRIaXN0b3J5W3RoaXMuX29NYW5hZ2VkSGlzdG9yeS5sZW5ndGggLSAxXSxcblx0XHRcdFx0bmV3TGV2ZWwgPSB0aGlzLl9vTWFuYWdlZEhpc3RvcnkubGVuZ3RoIC0gMTtcblxuXHRcdFx0ZnVuY3Rpb24gcmVwbGFjZUFzeW5jKCkge1xuXHRcdFx0XHRpZiAoIWJSZWJ1aWxkT25seSkge1xuXHRcdFx0XHRcdHRoYXQuX2VuYWJsZUV2ZW50T25IYXNoQ2hhbmdlKHRydWUpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0KHRoYXQuX29Sb3V0ZXIuZ2V0SGFzaENoYW5nZXIoKS5yZXBsYWNlSGFzaCBhcyBhbnkpKG9UYXJnZXRTdGF0ZS5oYXNoKTtcblx0XHRcdFx0aGlzdG9yeS5yZXBsYWNlU3RhdGUoT2JqZWN0LmFzc2lnbih7IGZlTGV2ZWw6IG5ld0xldmVsIH0sIGhpc3Rvcnkuc3RhdGUpLCBcIlwiKTtcblxuXHRcdFx0XHRpZiAoYlJlYnVpbGRPbmx5KSB7XG5cdFx0XHRcdFx0c2V0VGltZW91dChmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdC8vIFRpbWVvdXQgdG8gbGV0ICdoYXNoY2hhbmdlJyBldmVudCBiZSBwcm9jZXNzZWQgYmVmb3JlIGJ5IHRoZSBIYXNoQ2hhbmdlciwgc28gdGhhdFxuXHRcdFx0XHRcdFx0Ly8gb25Sb3V0ZU1hdGNoZWQgbm90aWZpY2F0aW9uIGlzbid0IHJhaXNlZFxuXHRcdFx0XHRcdFx0dGhhdC5fZW5hYmxlRXZlbnRPbkhhc2hDaGFuZ2UodHJ1ZSk7XG5cdFx0XHRcdFx0fSwgMCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR0aGF0LmJJc1JlYnVpbGRIaXN0b3J5UnVubmluZyA9IGZhbHNlO1xuXHRcdFx0XHRyZXNvbHZlKHRydWUpOyAvLyBhIG5hdmlnYXRpb24gb2NjdXJyZWRcblx0XHRcdH1cblxuXHRcdFx0Ly8gQXN5bmMgY2FsbGJhY2tzIHdoZW4gbmF2aWdhdGluZyBiYWNrLCBpbiBvcmRlciB0byBsZXQgYWxsIG5vdGlmaWNhdGlvbnMgYW5kIGV2ZW50cyBnZXQgcHJvY2Vzc2VkXG5cdFx0XHRmdW5jdGlvbiBiYWNrUmVwbGFjZUFzeW5jKCkge1xuXHRcdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihcInBvcHN0YXRlXCIsIGJhY2tSZXBsYWNlQXN5bmMpO1xuXHRcdFx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdC8vIFRpbWVvdXQgdG8gbGV0ICdoYXNoY2hhbmdlJyBldmVudCBiZSBwcm9jZXNzZWQgYmVmb3JlIGJ5IHRoZSBIYXNoQ2hhbmdlclxuXHRcdFx0XHRcdHJlcGxhY2VBc3luYygpO1xuXHRcdFx0XHR9LCAwKTtcblx0XHRcdH1cblxuXHRcdFx0ZnVuY3Rpb24gYmFja0FzeW5jKCkge1xuXHRcdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihcInBvcHN0YXRlXCIsIGJhY2tBc3luYyk7XG5cdFx0XHRcdHRoYXQuYklzUmVidWlsZEhpc3RvcnlSdW5uaW5nID0gZmFsc2U7XG5cdFx0XHRcdHJlc29sdmUodHJ1ZSk7IC8vIGEgbmF2aWdhdGlvbiBvY2N1cnJlZFxuXHRcdFx0fVxuXG5cdFx0XHR0aGF0Ll9iSWdub3JlUmVzdG9yZSA9IHRydWU7XG5cblx0XHRcdHN3aXRjaCAob0hpc3RvcnlBY3Rpb24udHlwZSkge1xuXHRcdFx0XHRjYXNlIFwicmVwbGFjZVwiOlxuXHRcdFx0XHRcdCh0aGF0Ll9vUm91dGVyLmdldEhhc2hDaGFuZ2VyKCkucmVwbGFjZUhhc2ggYXMgYW55KShvVGFyZ2V0U3RhdGUuaGFzaCk7XG5cdFx0XHRcdFx0aGlzdG9yeS5yZXBsYWNlU3RhdGUoT2JqZWN0LmFzc2lnbih7IGZlTGV2ZWw6IG5ld0xldmVsIH0sIGhpc3Rvcnkuc3RhdGUpLCBcIlwiKTtcblx0XHRcdFx0XHR0aGF0LmJJc1JlYnVpbGRIaXN0b3J5UnVubmluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdHJlc29sdmUodHJ1ZSk7IC8vIGEgbmF2aWdhdGlvbiBvY2N1cnJlZFxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgXCJhcHBlbmRcIjpcblx0XHRcdFx0XHR0aGF0Ll9vUm91dGVyLmdldEhhc2hDaGFuZ2VyKCkuc2V0SGFzaChvVGFyZ2V0U3RhdGUuaGFzaCk7XG5cdFx0XHRcdFx0aGlzdG9yeS5yZXBsYWNlU3RhdGUoT2JqZWN0LmFzc2lnbih7IGZlTGV2ZWw6IG5ld0xldmVsIH0sIGhpc3Rvcnkuc3RhdGUpLCBcIlwiKTtcblx0XHRcdFx0XHR0aGF0LmJJc1JlYnVpbGRIaXN0b3J5UnVubmluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdHJlc29sdmUodHJ1ZSk7IC8vIGEgbmF2aWdhdGlvbiBvY2N1cnJlZFxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgXCJiYWNrXCI6XG5cdFx0XHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJwb3BzdGF0ZVwiLCBiYWNrQXN5bmMpO1xuXHRcdFx0XHRcdGhpc3RvcnkuZ28oLW9IaXN0b3J5QWN0aW9uLnN0ZXBzKTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlIFwiYmFjay1yZXBsYWNlXCI6XG5cdFx0XHRcdFx0dGhpcy5fZGlzYWJsZUV2ZW50T25IYXNoQ2hhbmdlKCk7XG5cdFx0XHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJwb3BzdGF0ZVwiLCBiYWNrUmVwbGFjZUFzeW5jKTtcblx0XHRcdFx0XHRoaXN0b3J5LmdvKC1vSGlzdG9yeUFjdGlvbi5zdGVwcyk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHQvLyBObyBuYXZpZ2F0aW9uXG5cdFx0XHRcdFx0dGhpcy5iSXNSZWJ1aWxkSGlzdG9yeVJ1bm5pbmcgPSBmYWxzZTtcblx0XHRcdFx0XHRyZXNvbHZlKGZhbHNlKTsgLy8gbm8gbmF2aWdhdGlvbiAtLT4gcmVzb2x2ZSB0byBmYWxzZVxuXHRcdFx0fVxuXHRcdH0pO1xuXHR9XG5cblx0Z2V0TGFzdEhpc3RvcnlFbnRyeSgpIHtcblx0XHRyZXR1cm4gdGhpcy5fb01hbmFnZWRIaXN0b3J5W3RoaXMuX29NYW5hZ2VkSGlzdG9yeS5sZW5ndGggLSAxXTtcblx0fVxuXG5cdHNldFBhdGhNYXBwaW5nKG1hcHBpbmdzOiB7IG9sZFBhdGg6IHN0cmluZzsgbmV3UGF0aDogc3RyaW5nIH1bXSkge1xuXHRcdHRoaXMuX3BhdGhNYXBwaW5ncyA9IG1hcHBpbmdzO1xuXHR9XG5cblx0aGFzaEd1YXJkKCkge1xuXHRcdGxldCBzSGFzaCA9IHdpbmRvdy5sb2NhdGlvbi5oYXNoO1xuXG5cdFx0aWYgKHNIYXNoLmluZGV4T2YoXCJyZXN0b3JlSGlzdG9yeT10cnVlXCIpICE9PSAtMSkge1xuXHRcdFx0dGhpcy5fYkFwcGx5UmVzdG9yZSA9IHRydWU7XG5cdFx0fSBlbHNlIGlmICghdGhpcy5iSXNSZWJ1aWxkSGlzdG9yeVJ1bm5pbmcpIHtcblx0XHRcdC8vIENoZWNrIGlmIHRoZSBoYXNoIG5lZWRzIHRvIGJlIGNoYW5nZWQgKHRoaXMgaGFwcGVucyBpbiBGQ0wgd2hlbiBzd2l0Y2hpbmcgYi93IGVkaXQgYW5kIHJlYWQtb25seSB3aXRoIDMgY29sdW1ucyBvcGVuKVxuXHRcdFx0Y29uc3QgbWFwcGluZyA9IHRoaXMuX3BhdGhNYXBwaW5ncy5maW5kKG0gPT4ge1xuXHRcdFx0XHRyZXR1cm4gc0hhc2guaW5kZXhPZihtLm9sZFBhdGgpID49IDA7XG5cdFx0XHR9KTtcblx0XHRcdGlmIChtYXBwaW5nKSB7XG5cdFx0XHRcdC8vIFJlcGxhY2UgdGhlIGN1cnJlbnQgaGFzaFxuXHRcdFx0XHRzSGFzaCA9IHNIYXNoLnJlcGxhY2UobWFwcGluZy5vbGRQYXRoLCBtYXBwaW5nLm5ld1BhdGgpO1xuXHRcdFx0XHRoaXN0b3J5LnJlcGxhY2VTdGF0ZShPYmplY3QuYXNzaWduKHt9LCBoaXN0b3J5LnN0YXRlKSwgXCJcIiwgc0hhc2gpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y29uc3QgYUhhc2hTcGxpdCA9IHNIYXNoLnNwbGl0KFwiJi9cIik7XG5cdFx0XHRcdGNvbnN0IHNBcHBIYXNoID0gYUhhc2hTcGxpdFsxXSA/IGFIYXNoU3BsaXRbMV0gOiBcIlwiO1xuXHRcdFx0XHRpZiAodGhpcy5jaGVja0hhc2hXaXRoR3VhcmQoc0FwcEhhc2gpKSB7XG5cdFx0XHRcdFx0dGhpcy5fYkRlbGF5ZWRSZWJ1aWxkID0gdHJ1ZTtcblx0XHRcdFx0XHRjb25zdCBvTmV3U3RhdGUgPSB0aGlzLl9leHRyYWN0U3RhdGVGcm9tSGFzaChzQXBwSGFzaCk7XG5cdFx0XHRcdFx0dGhpcy5fcHVzaE5ld1N0YXRlKG9OZXdTdGF0ZSwgZmFsc2UsIGZhbHNlLCB0cnVlKTtcblxuXHRcdFx0XHRcdHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0XHRcdFx0dGhpcy5fYkRlbGF5ZWRSZWJ1aWxkID0gZmFsc2U7XG5cdFx0XHRcdFx0fSwgMCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogQ29tcGFyZXMgMiBzdGF0ZXMuXG5cdCAqXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBvU3RhdGUxXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBvU3RhdGUyXG5cdCAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSByZXN1bHQgb2YgdGhlIGNvbXBhcmlzb246XG5cdCAqICAgICAgICAtIGVudW1TdGF0ZS5FUVVBTCBpZiBvU3RhdGUxIGFuZCBvU3RhdGUyIGFyZSBlcXVhbFxuXHQgKiAgICAgICAgLSBlbnVtU3RhdGUuQ09NUEFUSUJMRSBpZiBvU3RhdGUxIGFuZCBvU3RhdGUyIGFyZSBjb21wYXRpYmxlXG5cdCAqICAgICAgICAtIGVudW1TdGF0ZS5BTkNFU1RPUiBpZiBvU3RhdGUxIGlzIGFuIGFuY2VzdG9yIG9mIG9TdGF0ZTJcblx0ICogICAgICAgIC0gZW51bVN0YXRlLkRJRkZFUkVOVCBpZiB0aGUgMiBzdGF0ZXMgYXJlIGRpZmZlcmVudFxuXHQgKi9cblxuXHRfY29tcGFyZUNhY2hlU3RhdGVzKG9TdGF0ZTE6IGFueSwgb1N0YXRlMjogYW55KSB7XG5cdFx0Ly8gRmlyc3QgY29tcGFyZSBvYmplY3Qga2V5c1xuXHRcdGlmIChvU3RhdGUxLmtleXMubGVuZ3RoID4gb1N0YXRlMi5rZXlzLmxlbmd0aCkge1xuXHRcdFx0cmV0dXJuIGVudW1TdGF0ZS5ESUZGRVJFTlQ7XG5cdFx0fVxuXHRcdGxldCBlcXVhbCA9IHRydWU7XG5cdFx0bGV0IGluZGV4O1xuXHRcdGZvciAoaW5kZXggPSAwOyBlcXVhbCAmJiBpbmRleCA8IG9TdGF0ZTEua2V5cy5sZW5ndGg7IGluZGV4KyspIHtcblx0XHRcdGlmIChvU3RhdGUxLmtleXNbaW5kZXhdICE9PSBvU3RhdGUyLmtleXNbaW5kZXhdKSB7XG5cdFx0XHRcdGVxdWFsID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmICghZXF1YWwpIHtcblx0XHRcdC8vIFNvbWUgb2JqZWN0cyBrZXlzIGFyZSBkaWZmZXJlbnRcblx0XHRcdHJldHVybiBlbnVtU3RhdGUuRElGRkVSRU5UO1xuXHRcdH1cblxuXHRcdC8vIEFsbCBrZXlzIGZyb20gb1N0YXRlMSBhcmUgaW4gb1N0YXRlMiAtLT4gY2hlY2sgaWYgYW5jZXN0b3Jcblx0XHRpZiAob1N0YXRlMS5rZXlzLmxlbmd0aCA8IG9TdGF0ZTIua2V5cy5sZW5ndGggfHwgb1N0YXRlMS5zY3JlZW5Nb2RlIDwgb1N0YXRlMi5zY3JlZW5Nb2RlKSB7XG5cdFx0XHRyZXR1cm4gZW51bVN0YXRlLkFOQ0VTVE9SO1xuXHRcdH1cblx0XHRpZiAob1N0YXRlMS5zY3JlZW5Nb2RlID4gb1N0YXRlMi5zY3JlZW5Nb2RlKSB7XG5cdFx0XHRyZXR1cm4gZW51bVN0YXRlLkRJRkZFUkVOVDsgLy8gTm90IHN1cmUgdGhpcyBjYXNlIGNhbiBoYXBwZW4uLi5cblx0XHR9XG5cblx0XHQvLyBBdCB0aGlzIHN0YWdlLCB0aGUgMiBzdGF0ZXMgaGF2ZSB0aGUgc2FtZSBvYmplY3Qga2V5cyAoaW4gdGhlIHNhbWUgb3JkZXIpIGFuZCBzYW1lIHNjcmVlbm1vZGVcblx0XHQvLyBUaGV5IGNhbiBiZSBlaXRoZXIgY29tcGF0aWJsZSBvciBlcXVhbFxuXHRcdHJldHVybiBvU3RhdGUxLnNMYXlvdXQgPT09IG9TdGF0ZTIuc0xheW91dCA/IGVudW1TdGF0ZS5FUVVBTCA6IGVudW1TdGF0ZS5DT01QQVRJQkxFO1xuXHR9XG5cblx0LyoqXG5cdCAqIENoZWNrcyBpZiBiYWNrIGV4aXRzIHRoZSBwcmVzZW50IGd1YXJkIHNldC5cblx0ICpcblx0ICogQHBhcmFtIHtzdHJpbmd9IHNQcmVzZW50SGFzaCBUaGUgY3VycmVudCBoYXNoLiBPbmx5IHVzZWQgZm9yIHVuaXQgdGVzdHMuXG5cdCAqIEByZXR1cm5zIHtib29sZWFufSBgdHJ1ZWAgaWYgYmFjayBleGl0cyB0aGVyZSBpcyBhIGd1YXJkIGV4aXQgb24gYmFja1xuXHQgKi9cblx0Y2hlY2tJZkJhY2tJc091dE9mR3VhcmQoc1ByZXNlbnRIYXNoPzogc3RyaW5nKSB7XG5cdFx0bGV0IHNQcmV2SGFzaDtcblx0XHRsZXQgc0N1cnJlbnRIYXNoOiBzdHJpbmc7XG5cdFx0aWYgKHNQcmVzZW50SGFzaCA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHQvLyBXZSB1c2Ugd2luZG93LmxvY2F0aW9uLmhhc2ggaW5zdGVhZCBvZiBIYXNoQ2hhbmdlci5nZXRJbnN0YW5jZSgpLmdldEhhc2goKSBiZWNhdXNlIHRoZSBsYXR0ZXJcblx0XHRcdC8vIHJlcGxhY2VzIGNoYXJhY3RlcnMgaW4gdGhlIFVSTCAoZS5nLiAlMjQgcmVwbGFjZWQgYnkgJCkgYW5kIGl0IGNhdXNlcyBpc3N1ZXMgd2hlbiBjb21wYXJpbmdcblx0XHRcdC8vIHdpdGggdGhlIFVSTHMgaW4gdGhlIG1hbmFnZWQgaGlzdG9yeVxuXHRcdFx0Y29uc3Qgb1NwbGl0SGFzaCA9IHRoaXMuX29TaGVsbFNlcnZpY2VzLnNwbGl0SGFzaCh3aW5kb3cubG9jYXRpb24uaGFzaCkgYXMgYW55O1xuXHRcdFx0aWYgKG9TcGxpdEhhc2ggJiYgb1NwbGl0SGFzaC5hcHBTcGVjaWZpY1JvdXRlKSB7XG5cdFx0XHRcdHNDdXJyZW50SGFzaCA9IG9TcGxpdEhhc2guYXBwU3BlY2lmaWNSb3V0ZTtcblx0XHRcdFx0aWYgKHNDdXJyZW50SGFzaC5pbmRleE9mKFwiJi9cIikgPT09IDApIHtcblx0XHRcdFx0XHRzQ3VycmVudEhhc2ggPSBzQ3VycmVudEhhc2guc3Vic3RyaW5nKDIpO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRzQ3VycmVudEhhc2ggPSB3aW5kb3cubG9jYXRpb24uaGFzaC5zdWJzdHJpbmcoMSk7IC8vIFRvIHJlbW92ZSB0aGUgJyMnXG5cdFx0XHRcdGlmIChzQ3VycmVudEhhc2hbMF0gPT09IFwiL1wiKSB7XG5cdFx0XHRcdFx0c0N1cnJlbnRIYXNoID0gc0N1cnJlbnRIYXNoLnN1YnN0cmluZygxKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRzQ3VycmVudEhhc2ggPSBzUHJlc2VudEhhc2g7XG5cdFx0fVxuXHRcdHNQcmVzZW50SGFzaCA9IFVSSS5kZWNvZGUoc0N1cnJlbnRIYXNoKTtcblx0XHRpZiAodGhpcy5fb05hdmlnYXRpb25HdWFyZCkge1xuXHRcdFx0Zm9yIChsZXQgaSA9IHRoaXMuX29NYW5hZ2VkSGlzdG9yeS5sZW5ndGggLSAxOyBpID4gMDsgaS0tKSB7XG5cdFx0XHRcdGlmICh0aGlzLl9vTWFuYWdlZEhpc3RvcnlbaV0uaGFzaCA9PT0gc1ByZXNlbnRIYXNoKSB7XG5cdFx0XHRcdFx0c1ByZXZIYXNoID0gdGhpcy5fb01hbmFnZWRIaXN0b3J5W2kgLSAxXS5oYXNoO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiAhc1ByZXZIYXNoIHx8ICF0aGlzLmNoZWNrSGFzaFdpdGhHdWFyZChzUHJldkhhc2gpO1xuXHRcdH1cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHQvKipcblx0ICogQ2hlY2tzIGlmIHRoZSBsYXN0IDIgZW50cmllcyBpbiB0aGUgaGlzdG9yeSBzaGFyZSB0aGUgc2FtZSBjb250ZXh0LlxuXHQgKlxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn0gYHRydWVgIGlmIHRoZXkgc2hhcmUgdGhlIHNhbWUgY29udGV4dC5cblx0ICovXG5cdGNoZWNrSWZCYWNrSGFzU2FtZUNvbnRleHQoKSB7XG5cdFx0aWYgKHRoaXMuX29NYW5hZ2VkSGlzdG9yeS5sZW5ndGggPCAyKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Y29uc3Qgb0N1cnJlbnRTdGF0ZSA9IHRoaXMuX29NYW5hZ2VkSGlzdG9yeVt0aGlzLl9vTWFuYWdlZEhpc3RvcnkubGVuZ3RoIC0gMV07XG5cdFx0Y29uc3Qgb1ByZXZpb3VzU3RhdGUgPSB0aGlzLl9vTWFuYWdlZEhpc3RvcnlbdGhpcy5fb01hbmFnZWRIaXN0b3J5Lmxlbmd0aCAtIDJdO1xuXG5cdFx0cmV0dXJuIG9DdXJyZW50U3RhdGUuaGFzaC5zcGxpdChcIj9cIilbMF0gPT09IG9QcmV2aW91c1N0YXRlLmhhc2guc3BsaXQoXCI/XCIpWzBdO1xuXHR9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFJvdXRlclByb3h5O1xuIl19