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