@ifsworld/granite-components 4.4.0 → 5.0.1

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 (291) hide show
  1. package/README.md +117 -4
  2. package/esm2020/ifsworld-granite-components.mjs +5 -0
  3. package/esm2020/index.mjs +48 -0
  4. package/esm2020/lib/arrange-grid/arrange-grid-item.component.mjs +44 -0
  5. package/esm2020/lib/arrange-grid/arrange-grid.component.mjs +125 -0
  6. package/esm2020/lib/arrange-grid/arrange-grid.module.mjs +19 -0
  7. package/esm2020/lib/badge/badge.component.mjs +39 -0
  8. package/esm2020/lib/badge/badge.module.mjs +18 -0
  9. package/esm2020/lib/badge/testing/badge.harness.mjs +25 -0
  10. package/esm2020/lib/button/button.component.mjs +89 -0
  11. package/esm2020/lib/button/button.module.mjs +16 -0
  12. package/esm2020/lib/checkbox/checkbox-group.component.mjs +17 -0
  13. package/esm2020/lib/checkbox/checkbox.component.mjs +96 -0
  14. package/esm2020/lib/checkbox/checkbox.module.mjs +17 -0
  15. package/esm2020/lib/core/animation.mjs +34 -0
  16. package/esm2020/lib/core/client-environment.mjs +20 -0
  17. package/esm2020/lib/core/common-behaviors/disabled.mjs +27 -0
  18. package/esm2020/lib/core/core.module.mjs +36 -0
  19. package/esm2020/lib/core/devices/client-input-desktop.directive.mjs +29 -0
  20. package/esm2020/lib/core/devices/client-input-touch.directive.mjs +29 -0
  21. package/esm2020/lib/core/devices/client-output-desktop.directive.mjs +29 -0
  22. package/esm2020/lib/core/devices/client-output-touch.directive.mjs +29 -0
  23. package/esm2020/lib/core/pipes/pure-pipes.module.mjs +16 -0
  24. package/esm2020/lib/core/pipes/title.pipe.mjs +21 -0
  25. package/esm2020/lib/core/radio-checkbox-base.mjs +19 -0
  26. package/esm2020/lib/core/theme.library.mjs +59 -0
  27. package/esm2020/lib/core/types.mjs +2 -0
  28. package/esm2020/lib/grid/grid.component.mjs +128 -0
  29. package/esm2020/lib/grid/grid.module.mjs +18 -0
  30. package/esm2020/lib/icon/icon.component.mjs +43 -0
  31. package/esm2020/lib/icon/icon.module.mjs +16 -0
  32. package/esm2020/lib/input-field/input-field.component.mjs +160 -0
  33. package/esm2020/lib/input-field/input-field.module.mjs +20 -0
  34. package/esm2020/lib/menu/divider.directive.mjs +23 -0
  35. package/esm2020/lib/menu/menu-base.mjs +347 -0
  36. package/esm2020/lib/menu/menu-desktop-animations.mjs +23 -0
  37. package/esm2020/lib/menu/menu-errors.mjs +37 -0
  38. package/esm2020/lib/menu/menu-item.component.mjs +91 -0
  39. package/esm2020/lib/menu/menu-panel.mjs +7 -0
  40. package/esm2020/lib/menu/menu-positions.mjs +9 -0
  41. package/esm2020/lib/menu/menu-touch-animations.mjs +137 -0
  42. package/esm2020/lib/menu/menu-touch-close.component.mjs +13 -0
  43. package/esm2020/lib/menu/menu-touch-title.component.mjs +59 -0
  44. package/esm2020/lib/menu/menu-trigger-for.directive.mjs +702 -0
  45. package/esm2020/lib/menu/menu.component.mjs +30 -0
  46. package/esm2020/lib/menu/menu.module.mjs +55 -0
  47. package/esm2020/lib/menu/testing/menu.harness.mjs +109 -0
  48. package/esm2020/lib/menu/title.directive.mjs +17 -0
  49. package/esm2020/lib/radio-button/radio-button.component.mjs +118 -0
  50. package/esm2020/lib/radio-button/radio-button.module.mjs +17 -0
  51. package/esm2020/lib/radio-button/radio-group.component.mjs +17 -0
  52. package/esm2020/lib/table/cell/cell.mjs +15 -0
  53. package/esm2020/lib/table/cell/table-data-cell.component.mjs +26 -0
  54. package/esm2020/lib/table/cell/table-header-cell.component.mjs +12 -0
  55. package/esm2020/lib/table/column/table-column.directive.mjs +23 -0
  56. package/esm2020/lib/table/table-constants.library.mjs +4 -0
  57. package/esm2020/lib/table/table.component.mjs +36 -0
  58. package/esm2020/lib/table/table.module.mjs +32 -0
  59. package/esm2020/lib/toggle-switch/toggle-switch.component.mjs +96 -0
  60. package/esm2020/lib/toggle-switch/toggle-switch.module.mjs +16 -0
  61. package/fesm2015/ifsworld-granite-components.mjs +3145 -0
  62. package/fesm2015/ifsworld-granite-components.mjs.map +1 -0
  63. package/fesm2020/ifsworld-granite-components.mjs +3103 -0
  64. package/fesm2020/ifsworld-granite-components.mjs.map +1 -0
  65. package/ifsworld-granite-components.d.ts +1 -8
  66. package/lib/arrange-grid/arrange-grid-item.component.d.ts +3 -0
  67. package/lib/arrange-grid/arrange-grid.component.d.ts +3 -0
  68. package/lib/arrange-grid/arrange-grid.module.d.ts +7 -0
  69. package/lib/badge/badge.component.d.ts +3 -0
  70. package/lib/badge/badge.module.d.ts +6 -0
  71. package/lib/button/button.component.d.ts +5 -0
  72. package/lib/button/button.module.d.ts +5 -0
  73. package/lib/checkbox/checkbox-group.component.d.ts +3 -0
  74. package/lib/checkbox/checkbox.component.d.ts +3 -0
  75. package/lib/checkbox/checkbox.module.d.ts +6 -0
  76. package/lib/core/core.module.d.ts +8 -0
  77. package/lib/core/devices/client-input-desktop.directive.d.ts +3 -0
  78. package/lib/core/devices/client-input-touch.directive.d.ts +3 -0
  79. package/lib/core/devices/client-output-desktop.directive.d.ts +3 -0
  80. package/lib/core/devices/client-output-touch.directive.d.ts +3 -0
  81. package/lib/core/pipes/pure-pipes.module.d.ts +5 -0
  82. package/lib/core/pipes/title.pipe.d.ts +3 -0
  83. package/lib/core/radio-checkbox-base.d.ts +3 -0
  84. package/lib/grid/grid.component.d.ts +5 -0
  85. package/lib/grid/grid.module.d.ts +6 -0
  86. package/lib/icon/icon.component.d.ts +3 -0
  87. package/lib/icon/icon.module.d.ts +5 -0
  88. package/lib/input-field/input-field.component.d.ts +3 -0
  89. package/lib/input-field/input-field.module.d.ts +8 -0
  90. package/lib/menu/divider.directive.d.ts +3 -0
  91. package/lib/menu/menu-base.d.ts +190 -0
  92. package/lib/menu/menu-item.component.d.ts +3 -0
  93. package/lib/menu/menu-touch-close.component.d.ts +3 -0
  94. package/lib/menu/menu-touch-title.component.d.ts +4 -1
  95. package/lib/menu/menu-trigger-for.directive.d.ts +4 -1
  96. package/lib/menu/menu.component.d.ts +4 -187
  97. package/lib/menu/menu.module.d.ts +15 -0
  98. package/lib/menu/title.directive.d.ts +3 -0
  99. package/lib/radio-button/radio-button.component.d.ts +4 -1
  100. package/lib/radio-button/radio-button.module.d.ts +6 -0
  101. package/lib/radio-button/radio-group.component.d.ts +3 -0
  102. package/lib/table/cell/cell.d.ts +3 -0
  103. package/lib/table/cell/table-data-cell.component.d.ts +3 -0
  104. package/lib/table/cell/table-header-cell.component.d.ts +3 -0
  105. package/lib/table/column/table-column.directive.d.ts +3 -0
  106. package/lib/table/table.component.d.ts +3 -0
  107. package/lib/table/table.module.d.ts +12 -0
  108. package/lib/toggle-switch/toggle-switch.component.d.ts +3 -0
  109. package/lib/toggle-switch/toggle-switch.module.d.ts +5 -0
  110. package/package.json +26 -13
  111. package/bundles/ifsworld-granite-components.umd.js +0 -3649
  112. package/bundles/ifsworld-granite-components.umd.js.map +0 -1
  113. package/bundles/ifsworld-granite-components.umd.min.js +0 -10
  114. package/bundles/ifsworld-granite-components.umd.min.js.map +0 -1
  115. package/esm2015/ifsworld-granite-components.js +0 -13
  116. package/esm2015/ifsworld-granite-components.js.map +0 -1
  117. package/esm2015/ifsworld-granite-components.metadata.json +0 -1
  118. package/esm2015/index.js +0 -48
  119. package/esm2015/index.js.map +0 -1
  120. package/esm2015/index.metadata.json +0 -1
  121. package/esm2015/lib/arrange-grid/arrange-grid-item.component.js +0 -48
  122. package/esm2015/lib/arrange-grid/arrange-grid-item.component.js.map +0 -1
  123. package/esm2015/lib/arrange-grid/arrange-grid-item.component.metadata.json +0 -1
  124. package/esm2015/lib/arrange-grid/arrange-grid.component.js +0 -123
  125. package/esm2015/lib/arrange-grid/arrange-grid.component.js.map +0 -1
  126. package/esm2015/lib/arrange-grid/arrange-grid.component.metadata.json +0 -1
  127. package/esm2015/lib/arrange-grid/arrange-grid.module.js +0 -14
  128. package/esm2015/lib/arrange-grid/arrange-grid.module.js.map +0 -1
  129. package/esm2015/lib/arrange-grid/arrange-grid.module.metadata.json +0 -1
  130. package/esm2015/lib/badge/badge.component.js +0 -44
  131. package/esm2015/lib/badge/badge.component.js.map +0 -1
  132. package/esm2015/lib/badge/badge.component.metadata.json +0 -1
  133. package/esm2015/lib/badge/badge.module.js +0 -13
  134. package/esm2015/lib/badge/badge.module.js.map +0 -1
  135. package/esm2015/lib/badge/badge.module.metadata.json +0 -1
  136. package/esm2015/lib/badge/testing/badge.harness.js +0 -30
  137. package/esm2015/lib/badge/testing/badge.harness.js.map +0 -1
  138. package/esm2015/lib/badge/testing/badge.harness.metadata.json +0 -1
  139. package/esm2015/lib/button/button.component.js +0 -108
  140. package/esm2015/lib/button/button.component.js.map +0 -1
  141. package/esm2015/lib/button/button.component.metadata.json +0 -1
  142. package/esm2015/lib/button/button.module.js +0 -11
  143. package/esm2015/lib/button/button.module.js.map +0 -1
  144. package/esm2015/lib/button/button.module.metadata.json +0 -1
  145. package/esm2015/lib/checkbox/checkbox-group.component.js +0 -19
  146. package/esm2015/lib/checkbox/checkbox-group.component.js.map +0 -1
  147. package/esm2015/lib/checkbox/checkbox-group.component.metadata.json +0 -1
  148. package/esm2015/lib/checkbox/checkbox.component.js +0 -89
  149. package/esm2015/lib/checkbox/checkbox.component.js.map +0 -1
  150. package/esm2015/lib/checkbox/checkbox.component.metadata.json +0 -1
  151. package/esm2015/lib/checkbox/checkbox.module.js +0 -12
  152. package/esm2015/lib/checkbox/checkbox.module.js.map +0 -1
  153. package/esm2015/lib/checkbox/checkbox.module.metadata.json +0 -1
  154. package/esm2015/lib/core/animation.js +0 -34
  155. package/esm2015/lib/core/animation.js.map +0 -1
  156. package/esm2015/lib/core/animation.metadata.json +0 -1
  157. package/esm2015/lib/core/client-environment.js +0 -20
  158. package/esm2015/lib/core/client-environment.js.map +0 -1
  159. package/esm2015/lib/core/client-environment.metadata.json +0 -1
  160. package/esm2015/lib/core/common-behaviors/disabled.js +0 -25
  161. package/esm2015/lib/core/common-behaviors/disabled.js.map +0 -1
  162. package/esm2015/lib/core/common-behaviors/disabled.metadata.json +0 -1
  163. package/esm2015/lib/core/core.module.js +0 -25
  164. package/esm2015/lib/core/core.module.js.map +0 -1
  165. package/esm2015/lib/core/core.module.metadata.json +0 -1
  166. package/esm2015/lib/core/devices/client-input-desktop.directive.js +0 -22
  167. package/esm2015/lib/core/devices/client-input-desktop.directive.js.map +0 -1
  168. package/esm2015/lib/core/devices/client-input-desktop.directive.metadata.json +0 -1
  169. package/esm2015/lib/core/devices/client-input-touch.directive.js +0 -22
  170. package/esm2015/lib/core/devices/client-input-touch.directive.js.map +0 -1
  171. package/esm2015/lib/core/devices/client-input-touch.directive.metadata.json +0 -1
  172. package/esm2015/lib/core/devices/client-output-desktop.directive.js +0 -22
  173. package/esm2015/lib/core/devices/client-output-desktop.directive.js.map +0 -1
  174. package/esm2015/lib/core/devices/client-output-desktop.directive.metadata.json +0 -1
  175. package/esm2015/lib/core/devices/client-output-touch.directive.js +0 -22
  176. package/esm2015/lib/core/devices/client-output-touch.directive.js.map +0 -1
  177. package/esm2015/lib/core/devices/client-output-touch.directive.metadata.json +0 -1
  178. package/esm2015/lib/core/pipes/pure-pipes.module.js +0 -11
  179. package/esm2015/lib/core/pipes/pure-pipes.module.js.map +0 -1
  180. package/esm2015/lib/core/pipes/pure-pipes.module.metadata.json +0 -1
  181. package/esm2015/lib/core/pipes/title.pipe.js +0 -17
  182. package/esm2015/lib/core/pipes/title.pipe.js.map +0 -1
  183. package/esm2015/lib/core/pipes/title.pipe.metadata.json +0 -1
  184. package/esm2015/lib/core/radio-checkbox-base.js +0 -15
  185. package/esm2015/lib/core/radio-checkbox-base.js.map +0 -1
  186. package/esm2015/lib/core/radio-checkbox-base.metadata.json +0 -1
  187. package/esm2015/lib/core/theme.library.js +0 -59
  188. package/esm2015/lib/core/theme.library.js.map +0 -1
  189. package/esm2015/lib/core/theme.library.metadata.json +0 -1
  190. package/esm2015/lib/core/types.js +0 -2
  191. package/esm2015/lib/core/types.js.map +0 -1
  192. package/esm2015/lib/core/types.metadata.json +0 -1
  193. package/esm2015/lib/grid/grid.component.js +0 -131
  194. package/esm2015/lib/grid/grid.component.js.map +0 -1
  195. package/esm2015/lib/grid/grid.component.metadata.json +0 -1
  196. package/esm2015/lib/grid/grid.module.js +0 -13
  197. package/esm2015/lib/grid/grid.module.js.map +0 -1
  198. package/esm2015/lib/grid/grid.module.metadata.json +0 -1
  199. package/esm2015/lib/icon/icon.component.js +0 -48
  200. package/esm2015/lib/icon/icon.component.js.map +0 -1
  201. package/esm2015/lib/icon/icon.component.metadata.json +0 -1
  202. package/esm2015/lib/icon/icon.module.js +0 -11
  203. package/esm2015/lib/icon/icon.module.js.map +0 -1
  204. package/esm2015/lib/icon/icon.module.metadata.json +0 -1
  205. package/esm2015/lib/input-field/input-field.component.js +0 -144
  206. package/esm2015/lib/input-field/input-field.component.js.map +0 -1
  207. package/esm2015/lib/input-field/input-field.component.metadata.json +0 -1
  208. package/esm2015/lib/input-field/input-field.module.js +0 -15
  209. package/esm2015/lib/input-field/input-field.module.js.map +0 -1
  210. package/esm2015/lib/input-field/input-field.module.metadata.json +0 -1
  211. package/esm2015/lib/menu/divider.directive.js +0 -20
  212. package/esm2015/lib/menu/divider.directive.js.map +0 -1
  213. package/esm2015/lib/menu/divider.directive.metadata.json +0 -1
  214. package/esm2015/lib/menu/menu-desktop-animations.js +0 -23
  215. package/esm2015/lib/menu/menu-desktop-animations.js.map +0 -1
  216. package/esm2015/lib/menu/menu-desktop-animations.metadata.json +0 -1
  217. package/esm2015/lib/menu/menu-errors.js +0 -37
  218. package/esm2015/lib/menu/menu-errors.js.map +0 -1
  219. package/esm2015/lib/menu/menu-errors.metadata.json +0 -1
  220. package/esm2015/lib/menu/menu-item.component.js +0 -82
  221. package/esm2015/lib/menu/menu-item.component.js.map +0 -1
  222. package/esm2015/lib/menu/menu-item.component.metadata.json +0 -1
  223. package/esm2015/lib/menu/menu-panel.js +0 -7
  224. package/esm2015/lib/menu/menu-panel.js.map +0 -1
  225. package/esm2015/lib/menu/menu-panel.metadata.json +0 -1
  226. package/esm2015/lib/menu/menu-positions.js +0 -9
  227. package/esm2015/lib/menu/menu-positions.js.map +0 -1
  228. package/esm2015/lib/menu/menu-positions.metadata.json +0 -1
  229. package/esm2015/lib/menu/menu-touch-animations.js +0 -137
  230. package/esm2015/lib/menu/menu-touch-animations.js.map +0 -1
  231. package/esm2015/lib/menu/menu-touch-animations.metadata.json +0 -1
  232. package/esm2015/lib/menu/menu-touch-close.component.js +0 -16
  233. package/esm2015/lib/menu/menu-touch-close.component.js.map +0 -1
  234. package/esm2015/lib/menu/menu-touch-close.component.metadata.json +0 -1
  235. package/esm2015/lib/menu/menu-touch-title.component.js +0 -45
  236. package/esm2015/lib/menu/menu-touch-title.component.js.map +0 -1
  237. package/esm2015/lib/menu/menu-touch-title.component.metadata.json +0 -1
  238. package/esm2015/lib/menu/menu-trigger-for.directive.js +0 -684
  239. package/esm2015/lib/menu/menu-trigger-for.directive.js.map +0 -1
  240. package/esm2015/lib/menu/menu-trigger-for.directive.metadata.json +0 -1
  241. package/esm2015/lib/menu/menu.component.js +0 -362
  242. package/esm2015/lib/menu/menu.component.js.map +0 -1
  243. package/esm2015/lib/menu/menu.component.metadata.json +0 -1
  244. package/esm2015/lib/menu/menu.module.js +0 -38
  245. package/esm2015/lib/menu/menu.module.js.map +0 -1
  246. package/esm2015/lib/menu/menu.module.metadata.json +0 -1
  247. package/esm2015/lib/menu/testing/menu.harness.js +0 -133
  248. package/esm2015/lib/menu/testing/menu.harness.js.map +0 -1
  249. package/esm2015/lib/menu/testing/menu.harness.metadata.json +0 -1
  250. package/esm2015/lib/menu/title.directive.js +0 -13
  251. package/esm2015/lib/menu/title.directive.js.map +0 -1
  252. package/esm2015/lib/menu/title.directive.metadata.json +0 -1
  253. package/esm2015/lib/radio-button/radio-button.component.js +0 -110
  254. package/esm2015/lib/radio-button/radio-button.component.js.map +0 -1
  255. package/esm2015/lib/radio-button/radio-button.component.metadata.json +0 -1
  256. package/esm2015/lib/radio-button/radio-button.module.js +0 -12
  257. package/esm2015/lib/radio-button/radio-button.module.js.map +0 -1
  258. package/esm2015/lib/radio-button/radio-button.module.metadata.json +0 -1
  259. package/esm2015/lib/radio-button/radio-group.component.js +0 -19
  260. package/esm2015/lib/radio-button/radio-group.component.js.map +0 -1
  261. package/esm2015/lib/radio-button/radio-group.component.metadata.json +0 -1
  262. package/esm2015/lib/table/cell/cell.js +0 -12
  263. package/esm2015/lib/table/cell/cell.js.map +0 -1
  264. package/esm2015/lib/table/cell/cell.metadata.json +0 -1
  265. package/esm2015/lib/table/cell/table-data-cell.component.js +0 -21
  266. package/esm2015/lib/table/cell/table-data-cell.component.js.map +0 -1
  267. package/esm2015/lib/table/cell/table-data-cell.component.metadata.json +0 -1
  268. package/esm2015/lib/table/cell/table-header-cell.component.js +0 -13
  269. package/esm2015/lib/table/cell/table-header-cell.component.js.map +0 -1
  270. package/esm2015/lib/table/cell/table-header-cell.component.metadata.json +0 -1
  271. package/esm2015/lib/table/column/table-column.directive.js +0 -16
  272. package/esm2015/lib/table/column/table-column.directive.js.map +0 -1
  273. package/esm2015/lib/table/column/table-column.directive.metadata.json +0 -1
  274. package/esm2015/lib/table/table-constants.library.js +0 -4
  275. package/esm2015/lib/table/table-constants.library.js.map +0 -1
  276. package/esm2015/lib/table/table-constants.library.metadata.json +0 -1
  277. package/esm2015/lib/table/table.component.js +0 -28
  278. package/esm2015/lib/table/table.component.js.map +0 -1
  279. package/esm2015/lib/table/table.component.metadata.json +0 -1
  280. package/esm2015/lib/table/table.module.js +0 -24
  281. package/esm2015/lib/table/table.module.js.map +0 -1
  282. package/esm2015/lib/table/table.module.metadata.json +0 -1
  283. package/esm2015/lib/toggle-switch/toggle-switch.component.js +0 -89
  284. package/esm2015/lib/toggle-switch/toggle-switch.component.js.map +0 -1
  285. package/esm2015/lib/toggle-switch/toggle-switch.component.metadata.json +0 -1
  286. package/esm2015/lib/toggle-switch/toggle-switch.module.js +0 -11
  287. package/esm2015/lib/toggle-switch/toggle-switch.module.js.map +0 -1
  288. package/esm2015/lib/toggle-switch/toggle-switch.module.metadata.json +0 -1
  289. package/fesm2015/ifsworld-granite-components.js +0 -2992
  290. package/fesm2015/ifsworld-granite-components.js.map +0 -1
  291. package/ifsworld-granite-components.metadata.json +0 -1
@@ -0,0 +1,702 @@
1
+ import { Directive, ElementRef, Inject, Input, Optional, Self, ViewContainerRef, } from '@angular/core';
2
+ import { DOCUMENT } from '@angular/common';
3
+ import { FocusMonitor, isFakeMousedownFromScreenReader, } from '@angular/cdk/a11y';
4
+ import { Directionality } from '@angular/cdk/bidi';
5
+ import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
6
+ import { Overlay, OverlayConfig, } from '@angular/cdk/overlay';
7
+ import { TemplatePortal } from '@angular/cdk/portal';
8
+ import { asapScheduler, fromEvent, merge, of as observableOf, Subscription, } from 'rxjs';
9
+ import { delay, filter, take, takeUntil } from 'rxjs/operators';
10
+ import { _MenuBaseComponent } from './menu-base';
11
+ import { GraniteMenuItemComponent } from './menu-item.component';
12
+ import { GRANITE_MENU_PANEL } from './menu-panel';
13
+ //#region --- Touch device customizations ---
14
+ import { GRANITE_CLIENT_INPUT, GRANITE_CLIENT_OUTPUT, } from '../core/client-environment';
15
+ import { throwGraniteMenuMissingError } from './menu-errors';
16
+ import * as i0 from "@angular/core";
17
+ import * as i1 from "@angular/cdk/overlay";
18
+ import * as i2 from "./menu-item.component";
19
+ import * as i3 from "@angular/cdk/bidi";
20
+ import * as i4 from "@angular/cdk/a11y";
21
+ import * as i5 from "./menu-base";
22
+ /** Options for binding a passive event listener. */
23
+ const passiveEventListenerOptions = normalizePassiveListenerOptions({
24
+ passive: true,
25
+ });
26
+ //#endregion --- Touch device customizations ---
27
+ /**
28
+ * Directive used to turn a button element into a (popup) menu trigger
29
+ *
30
+ * Stripped-down version of Angular Material's menu trigger directive (.../menu/menu-trigger.ts)
31
+ */
32
+ export class GraniteMenuTriggerForDirective {
33
+ constructor(_overlay, _element, _viewContainerRef,
34
+ /** If this is a _submenu_ trigger, it will have a parent menu */
35
+ _parentMenu,
36
+ //#region --- Touch device customizations ---
37
+ /** Client input device information */
38
+ _clientInput,
39
+ /** Client output device information */
40
+ _clientOutput,
41
+ //#endregion --- Touch device customizations ---
42
+ /**
43
+ * If this is a _submenu_ trigger, there should be a corresponding menu
44
+ * item directive present as well:
45
+ *
46
+ * <button graniteMenuItem [graniteMenuTriggerFor]="...">
47
+ * ^-- This one
48
+ */
49
+ _menuItemInstance, _dir, _focusMonitor,
50
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
51
+ document) {
52
+ this._overlay = _overlay;
53
+ this._element = _element;
54
+ this._viewContainerRef = _viewContainerRef;
55
+ this._parentMenu = _parentMenu;
56
+ this._clientInput = _clientInput;
57
+ this._clientOutput = _clientOutput;
58
+ this._menuItemInstance = _menuItemInstance;
59
+ this._dir = _dir;
60
+ this._focusMonitor = _focusMonitor;
61
+ /** Whether the associated menu is open */
62
+ this._isMenuOpen = false;
63
+ // Tracking input type is necessary so it's possible to only auto-focus
64
+ // the first item of the list when the menu is opened via the keyboard
65
+ this._openedBy = null;
66
+ this._hoverSubscription = Subscription.EMPTY;
67
+ this._menuCloseSubscription = Subscription.EMPTY;
68
+ this._closingActionsSubscription = Subscription.EMPTY;
69
+ this._portal = null;
70
+ this._overlayRef = null;
71
+ this._touchTouchingElement = false;
72
+ /**
73
+ * Handles touch start events on the trigger.
74
+ * Needs to be an arrow function so we can easily use addEventListener and removeEventListener.
75
+ */
76
+ this._handleTouchStart = () => {
77
+ this._openedBy = 'touch';
78
+ };
79
+ // ----------------------------------------- //
80
+ // --- Here be poor man's touch gestures --- //
81
+ // ----------------------------------------- //
82
+ // TODO: Replace with Hammer or other gesture library
83
+ /**
84
+ * Handles touch start events on the overlay host element (wrapper).
85
+ * Needs to be an arrow function so we can easily use addEventListener and removeEventListener.
86
+ */
87
+ this._handleOverlayTouchStart = (event) => {
88
+ if (this.menu._isAnimating) {
89
+ return;
90
+ }
91
+ this._touchStartTime = new Date().getTime();
92
+ this._touchStartX = event.changedTouches[0].clientX;
93
+ this._touchStartY = event.changedTouches[0].clientY;
94
+ this._touchCurrentX = this._touchStartX;
95
+ this._touchCurrentY = this._touchStartY;
96
+ this._touchTranslateX = 0;
97
+ this._touchMaxX =
98
+ this._overlayRef.hostElement.getBoundingClientRect().width;
99
+ this._touchLockedX = null;
100
+ this._touchTouchingElement = true;
101
+ };
102
+ this._handleOverlayTouchMove = (event) => {
103
+ if (!this._touchTouchingElement || this.menu._isAnimating) {
104
+ return;
105
+ }
106
+ if (this._touchLockedX) {
107
+ return;
108
+ }
109
+ this._touchCurrentX = event.changedTouches[0].clientX;
110
+ this._touchCurrentY = event.changedTouches[0].clientY;
111
+ // Lock X-axis pan if initiating pan on Y-axis
112
+ if (this._touchLockedX === null) {
113
+ const dy = Math.abs(this._touchCurrentY - this._touchStartY);
114
+ const dx = Math.abs(this._touchCurrentX - this._touchStartX);
115
+ if (dx > 10 || dy > 10) {
116
+ this._touchLockedX = dy > dx;
117
+ return;
118
+ }
119
+ }
120
+ // Restrict to right pan/swipe and make menu movement extremely slow when
121
+ // moved past allowed limits.
122
+ const menuMargin = 16;
123
+ this._touchTranslateX = this._touchCurrentX - this._touchStartX;
124
+ if (this._touchTranslateX < 0) {
125
+ this._touchTranslateX = this.easeOutExpo(this._touchTranslateX, 0, -menuMargin / 2, this._touchMaxX * -4);
126
+ }
127
+ else if (!this._parentMenu) {
128
+ this._touchTranslateX = this.easeOutExpo(this._touchTranslateX, 0, menuMargin / 2, this._touchMaxX * 4);
129
+ }
130
+ else if (this._touchTranslateX > this._touchMaxX) {
131
+ this._touchTranslateX = this.easeOutExpo(this._touchTranslateX - this._touchMaxX, this._touchMaxX, menuMargin / 2, this._touchMaxX * 4);
132
+ }
133
+ // Set new sub menu position and tell any parent to follow;
134
+ this.animateSetMenuPosition(this._touchTranslateX);
135
+ };
136
+ this._handleOverlayTouchEnd = () => {
137
+ if (!this._touchTouchingElement || this.menu._isAnimating) {
138
+ return;
139
+ }
140
+ this._touchTranslateX = this._touchCurrentX - this._touchStartX;
141
+ if (this._touchTranslateX === 0) {
142
+ return;
143
+ }
144
+ this._touchTouchingElement = false;
145
+ this._touchTimeTaken = new Date().getTime() - this._touchStartTime;
146
+ const swipeMinDistance = 10;
147
+ const swipeMinTime = 50;
148
+ const swipeMaxTime = 300;
149
+ const pannedHalfwayRight = this._touchTranslateX > this._touchMaxX / 2;
150
+ const swipedRight = this._touchTranslateX > this._touchMaxX / swipeMinDistance &&
151
+ this._touchTimeTaken > swipeMinTime &&
152
+ this._touchTimeTaken < swipeMaxTime;
153
+ if (!!this._parentMenu && (swipedRight || pannedHalfwayRight)) {
154
+ // Close submenu keydown-style: close only this menu and leave parents open
155
+ this.menu.closed.emit('keydown');
156
+ }
157
+ else {
158
+ // Pan ended but the menu was not moved far enough. Reset menus to
159
+ // where they were before panning stared.
160
+ this.animateOpenMenu();
161
+ }
162
+ };
163
+ _element.nativeElement.addEventListener('touchstart', this._handleTouchStart, passiveEventListenerOptions);
164
+ if (_menuItemInstance) {
165
+ _menuItemInstance._triggersSubmenu = this.triggersSubmenu();
166
+ }
167
+ this._document = document;
168
+ }
169
+ ngOnChanges(changes) {
170
+ if (changes.menu) {
171
+ this._handleMenuChange();
172
+ }
173
+ }
174
+ ngAfterContentInit() {
175
+ // removed checkMenu here to avoid errors in dynamically genarated menus
176
+ // menu is checked when opening the menu
177
+ // this._checkMenu();
178
+ this._handleHover();
179
+ }
180
+ ngOnDestroy() {
181
+ if (this._overlayRef) {
182
+ //#region --- Touch device customizations ---
183
+ this.removeOverlayListeners();
184
+ //#endregion --- Touch device customizations ---
185
+ this._overlayRef.dispose();
186
+ this._overlayRef = null;
187
+ }
188
+ this._element.nativeElement.removeEventListener('touchstart', this._handleTouchStart, passiveEventListenerOptions);
189
+ this._hoverSubscription.unsubscribe();
190
+ this._menuCloseSubscription.unsubscribe();
191
+ this._closingActionsSubscription.unsubscribe();
192
+ }
193
+ /** Handles change of associated menu */
194
+ _handleMenuChange() {
195
+ this._menuCloseSubscription.unsubscribe();
196
+ // Close the menu overlay when the menu itself says it wants to be closed
197
+ if (this.menu) {
198
+ const closed = this.menu.closed;
199
+ this._menuCloseSubscription = closed.subscribe((reason) => {
200
+ //#region --- Touch device customizations ---
201
+ if (this.menu._isClosing) {
202
+ return;
203
+ }
204
+ this.menu._isClosing = true;
205
+ // Get rid of the menu and tell any parent to restore its position
206
+ if (this._clientOutput.device === 'touch') {
207
+ // First we wait for any running animation to complete
208
+ const runningAnimationDone = this.menu._isAnimating
209
+ ? this.menu._animationDone
210
+ : observableOf([null]);
211
+ runningAnimationDone
212
+ .pipe(take(1), delay(0, asapScheduler))
213
+ // eslint-disable-next-line rxjs/no-nested-subscribe
214
+ .subscribe(() => {
215
+ this.animateCloseMenu(reason !== 'keydown', reason === 'click');
216
+ this.menu._animationDone
217
+ .pipe(take(1), delay(0, asapScheduler))
218
+ // eslint-disable-next-line rxjs/no-nested-subscribe
219
+ .subscribe(() => this._destroyMenu());
220
+ });
221
+ }
222
+ else {
223
+ //#endregion --- Touch device customizations ---
224
+ this._destroyMenu();
225
+ }
226
+ // If a click closed the menu, we should close the entire chain of nested menus.
227
+ if ((reason === 'click' || reason === 'tab') && this._parentMenu) {
228
+ this._parentMenu.closed.emit(reason);
229
+ }
230
+ });
231
+ }
232
+ }
233
+ isOpen() {
234
+ return this._isMenuOpen;
235
+ }
236
+ /** Open the associated menu */
237
+ openMenu() {
238
+ if (this._isMenuOpen) {
239
+ return;
240
+ }
241
+ this._checkMenu();
242
+ this.menu.parentMenu = this.triggersSubmenu()
243
+ ? this._parentMenu
244
+ : undefined;
245
+ this.menu.direction = this._dir.value === 'rtl' ? 'rtl' : 'ltr';
246
+ if (this._parentMenu) {
247
+ // Menu triggers inherit target device types from their parent.
248
+ // Ultimately it is the root trigger that determines device types for
249
+ // the whole menu hierarchy.
250
+ this._clientInput = this._parentMenu._clientInput;
251
+ this._clientOutput = this._parentMenu._clientOutput;
252
+ }
253
+ //#region --- Touch device customizations ---
254
+ // Make the menu we're about to open use the same devices as the trigger
255
+ this.menu._setDevice(this._clientInput, this._clientOutput);
256
+ if (this._clientOutput.device === 'touch') {
257
+ this.menu.showBackButton = !!this._parentMenu;
258
+ this.menu._updateShowTitle();
259
+ if (!this.menu.closeLabel) {
260
+ this.menu.closeLabel = this._parentMenu?.closeLabel;
261
+ }
262
+ this.menu.showCloseButton = !!this.menu.closeLabel;
263
+ }
264
+ this.menu._isClosing = false;
265
+ const panelClass = [];
266
+ if (this._clientOutput.device === 'touch') {
267
+ panelClass.push('granite-overlay-pane-fill-width-bottom');
268
+ }
269
+ const scrollStrategy = this._clientOutput.device !== 'touch'
270
+ ? this._overlay.scrollStrategies.reposition()
271
+ : undefined;
272
+ const hasBackdrop = this._clientOutput.device === 'touch' && !this.triggersSubmenu();
273
+ //#endregion --- Touch device customizations ---
274
+ // Create an overlay to stuff the menu (portal) into below
275
+ if (!this._overlayRef) {
276
+ const config = new OverlayConfig({
277
+ positionStrategy: this._positionStrategy(),
278
+ backdropClass: 'granite-overlay-dark-glass-backdrop',
279
+ scrollStrategy,
280
+ direction: this._dir,
281
+ panelClass,
282
+ hasBackdrop,
283
+ });
284
+ this._overlayRef = this._overlay.create(config);
285
+ //#region --- Touch device customizations ---
286
+ // Add touch listener for submenu back pan/swipe
287
+ if (this._clientOutput.device === 'touch') {
288
+ this.addOverlayListeners();
289
+ }
290
+ //#endregion --- Touch device customizations ---
291
+ }
292
+ else {
293
+ // Reset animation state for reused overlays
294
+ if (this._clientOutput.device === 'touch') {
295
+ this.menu._panelAnimationState = 'void';
296
+ }
297
+ }
298
+ // Create portal from associated menu's template
299
+ if (!this._portal || this._portal.templateRef !== this.menu.templateRef) {
300
+ this._portal = new TemplatePortal(this.menu.templateRef, this._viewContainerRef);
301
+ }
302
+ // Attach menu portal to overlay ref (which is a portal outlet)
303
+ this._overlayRef.attach(this._portal);
304
+ // Subscribe to stream that emits whenever an action that should close the menu occurs
305
+ this._closingActionsSubscription = this._menuClosingActions().subscribe(() => this.closeMenu());
306
+ this.animateOpenMenu();
307
+ this._setIsMenuOpen(true);
308
+ this.menu.focusFirstItem(this._openedBy || 'program');
309
+ }
310
+ /** Whether the menu triggers a sub-menu or a top-level one. */
311
+ triggersSubmenu() {
312
+ return !!(this._menuItemInstance && this._parentMenu);
313
+ }
314
+ /** Toggles the menu between the open and closed states. */
315
+ toggleMenu() {
316
+ if (this._isMenuOpen) {
317
+ this.closeMenu();
318
+ }
319
+ else {
320
+ this.openMenu();
321
+ }
322
+ }
323
+ /** Close the associated menu */
324
+ closeMenu() {
325
+ this.menu.closed.emit();
326
+ }
327
+ /**
328
+ * Focuses the menu trigger.
329
+ * @param origin Source of the menu trigger's focus.
330
+ */
331
+ focus(origin = 'program', options) {
332
+ if (this._focusMonitor) {
333
+ this._focusMonitor.focusVia(this._element, origin, options);
334
+ }
335
+ else {
336
+ this._element.nativeElement.focus(options);
337
+ }
338
+ }
339
+ /** Detach menu portal from overlay and update open state */
340
+ _destroyMenu() {
341
+ if (!this._overlayRef || !this._isMenuOpen) {
342
+ return;
343
+ }
344
+ this._closingActionsSubscription.unsubscribe();
345
+ this._overlayRef.detach();
346
+ this._restoreFocus();
347
+ this.menu._resetAnimation();
348
+ this._setIsMenuOpen(false);
349
+ }
350
+ /** Handles mouse presses on the trigger. */
351
+ _handleMousedown(event) {
352
+ if (!isFakeMousedownFromScreenReader(event)) {
353
+ if (this._openedBy !== 'touch') {
354
+ // Since right or middle button clicks won't trigger the `click` event,
355
+ // we shouldn't consider the menu as opened by mouse in those cases.
356
+ this._openedBy = event.button === 0 ? 'mouse' : null;
357
+ }
358
+ // Since clicking on the trigger won't close the menu if it opens a sub-menu,
359
+ // we should prevent focus from moving onto it via click to avoid the
360
+ // highlight from lingering on the menu item.
361
+ if (this.triggersSubmenu() && !this._toggleOnSubmenuClick()) {
362
+ event.preventDefault();
363
+ }
364
+ }
365
+ }
366
+ /** Handles key presses on the trigger. */
367
+ _handleKeydown(event) {
368
+ const key = event.key;
369
+ if (this.triggersSubmenu() &&
370
+ ((key === 'ArrowRight' && this._dir.value === 'ltr') ||
371
+ (key === 'ArrowLeft' && this._dir.value === 'rtl'))) {
372
+ this.openMenu();
373
+ }
374
+ }
375
+ /** Handles click events on the trigger. */
376
+ _handleClick(event) {
377
+ if (this.triggersSubmenu()) {
378
+ // Stop event propagation to avoid closing the parent menu.
379
+ event.stopPropagation();
380
+ this._toggleOnSubmenuClick() ? this.toggleMenu() : this.openMenu();
381
+ }
382
+ else {
383
+ this.toggleMenu();
384
+ }
385
+ }
386
+ /** Handles the cases where the user hovers over the trigger. */
387
+ _handleHover() {
388
+ // Subscribe to changes in the hovered item in order to toggle the panel.
389
+ if (!this.triggersSubmenu() || !this._parentMenu) {
390
+ return;
391
+ }
392
+ this._hoverSubscription = this._parentMenu
393
+ ._hovered()
394
+ .pipe(filter(() => this._openOnHover()),
395
+ // Since we might have multiple competing triggers for the same menu (e.g. a sub-menu
396
+ // with different data and triggers), we have to delay it by a tick to ensure that
397
+ // it won't be closed immediately after it is opened.
398
+ filter((active) => active === this._menuItemInstance /*&& !active.disabled*/), delay(0, asapScheduler))
399
+ .subscribe(() => {
400
+ this._openedBy = 'mouse';
401
+ // If the same menu is used between multiple triggers, it might still be animating
402
+ // while the new trigger tries to re-open it. Wait for the animation to finish
403
+ // before doing so. Also interrupt if the user moves to another item.
404
+ if (this.menu instanceof _MenuBaseComponent && this.menu._isAnimating) {
405
+ // We need the `delay(0)` here in order to avoid
406
+ // 'changed after checked' errors in some cases. See Angular Material #12194.
407
+ this.menu._animationDone
408
+ .pipe(take(1), delay(0, asapScheduler), takeUntil(this._parentMenu._hovered()))
409
+ // eslint-disable-next-line rxjs/no-nested-subscribe
410
+ .subscribe(() => this.openMenu());
411
+ }
412
+ else {
413
+ this.openMenu();
414
+ }
415
+ });
416
+ }
417
+ /**
418
+ * Restores focus to the element that was focused before the menu was open.
419
+ * Could be the root trigger button or a submenu trigger item
420
+ */
421
+ _restoreFocus() {
422
+ // We should reset focus if the user is navigating using a keyboard or
423
+ // if we have a top-level trigger which might cause focus to be lost
424
+ // when clicking outside of the menu.
425
+ if (!this._openedBy) {
426
+ // Note that the focus style will show up both for `program` and
427
+ // `keyboard` so we don't have to specify which one it is.
428
+ this.focus();
429
+ }
430
+ else if (!this.triggersSubmenu()) {
431
+ this.focus(this._openedBy);
432
+ }
433
+ this._openedBy = null;
434
+ }
435
+ // Set state rather than toggle to support triggers sharing a menu
436
+ _setIsMenuOpen(isOpen) {
437
+ this._isMenuOpen = isOpen;
438
+ if (this.triggersSubmenu()) {
439
+ this._menuItemInstance._highlighted =
440
+ isOpen && this._clientOutput.device !== 'touch';
441
+ }
442
+ }
443
+ /**
444
+ * This method checks that a valid instance of MenuComponent has been passed into
445
+ * graniteMenuTriggerFor. If not, an exception is thrown.
446
+ */
447
+ _checkMenu() {
448
+ if (!this.menu) {
449
+ throwGraniteMenuMissingError();
450
+ }
451
+ }
452
+ /**
453
+ * Returns strategy for positioning the overlay for desktop devices:
454
+ * Place adjacent to the trigger button (preferably immediately below)
455
+ * in order to show as much of the menu as possible.
456
+ */
457
+ _desktopPositionStrategy() {
458
+ const positionStrategy = this._overlay
459
+ .position()
460
+ .flexibleConnectedTo(this._element)
461
+ .withLockedPosition()
462
+ .withTransformOriginOn('.granite-menu')
463
+ .withPush(false);
464
+ this._setPosition(positionStrategy);
465
+ return positionStrategy;
466
+ }
467
+ /**
468
+ * Sets the appropriate positions on a position strategy
469
+ * so the overlay connects with the trigger correctly.
470
+ * @param positionStrategy Strategy whose position to update.
471
+ */
472
+ _setPosition(positionStrategy) {
473
+ const MENU_PANEL_TOP_PADDING = 0;
474
+ let [originX, originFallbackX] = this.menu.xPosition === 'before' ? ['end', 'start'] : ['start', 'end'];
475
+ const [overlayY, overlayFallbackY] = this.menu.yPosition === 'above' ? ['bottom', 'top'] : ['top', 'bottom'];
476
+ let [originY, originFallbackY] = [overlayY, overlayFallbackY];
477
+ let [overlayX, overlayFallbackX] = [originX, originFallbackX];
478
+ let offsetY = 0;
479
+ if (this.triggersSubmenu()) {
480
+ // When the menu is a sub-menu, it should always align itself
481
+ // to the edges of the trigger, instead of overlapping it.
482
+ overlayFallbackX = originX =
483
+ this.menu.xPosition === 'before' ? 'start' : 'end';
484
+ originFallbackX = overlayX = originX === 'end' ? 'start' : 'end';
485
+ offsetY =
486
+ overlayY === 'bottom'
487
+ ? MENU_PANEL_TOP_PADDING
488
+ : -MENU_PANEL_TOP_PADDING;
489
+ }
490
+ else {
491
+ originY = overlayY === 'top' ? 'bottom' : 'top';
492
+ originFallbackY = overlayFallbackY === 'top' ? 'bottom' : 'top';
493
+ }
494
+ positionStrategy.withPositions([
495
+ { originX, originY, overlayX, overlayY, offsetY },
496
+ {
497
+ originX: originFallbackX,
498
+ originY,
499
+ overlayX: overlayFallbackX,
500
+ overlayY,
501
+ offsetY,
502
+ },
503
+ {
504
+ originX,
505
+ originY: originFallbackY,
506
+ overlayX,
507
+ overlayY: overlayFallbackY,
508
+ offsetY: -offsetY,
509
+ },
510
+ {
511
+ originX: originFallbackX,
512
+ originY: originFallbackY,
513
+ overlayX: overlayFallbackX,
514
+ overlayY: overlayFallbackY,
515
+ offsetY: -offsetY,
516
+ },
517
+ ]);
518
+ }
519
+ /** Returns a stream that emits whenever an action that should close the menu occurs. */
520
+ _menuClosingActions() {
521
+ const detachments = this._overlayRef?.detachments();
522
+ const parentClose = this._parentMenu
523
+ ? this._parentMenu.closed
524
+ : observableOf();
525
+ const hover = this._clientOutput.device === 'desktop' && this._parentMenu
526
+ ? this._parentMenu._hovered().pipe(filter((item) => item !== this._menuItemInstance), filter(() => this._isMenuOpen))
527
+ : observableOf();
528
+ // Note: Quick fix. Feature reportedly exists in CDK for Angular 10
529
+ // Filter to prevent closing when animating added though. Applied to
530
+ // root menu only.
531
+ const outsideClick = !this._parentMenu
532
+ ? fromEvent(this._document, 'click').pipe(filter((e) => e.target !== this._element.nativeElement &&
533
+ e.target.closest('.granite-menu') === null), filter(() => !this.menu._isAnimating))
534
+ : observableOf();
535
+ return merge(detachments, hover, parentClose, outsideClick);
536
+ }
537
+ /**
538
+ * Whether to automatically open submenus on hover. This is true when showing
539
+ * desktop menus and having mouse support.
540
+ */
541
+ _openOnHover() {
542
+ return ((this.triggersSubmenu()
543
+ ? this._parentMenu.openOnHover
544
+ : this.menu.openOnHover) &&
545
+ this._parentMenu._clientOutput?.device === 'desktop' &&
546
+ this._parentMenu._clientInput?.devices.includes('mouse'));
547
+ }
548
+ /**
549
+ * Whether to toggle submenus on click. This is true when showing desktop menus
550
+ * without mouse support. Which, by the way, is not a great idea to begin with.
551
+ */
552
+ _toggleOnSubmenuClick() {
553
+ return (!(this.triggersSubmenu()
554
+ ? this._parentMenu.openOnHover
555
+ : this.menu.openOnHover) ||
556
+ (this._parentMenu._clientOutput?.device === 'desktop' &&
557
+ !this._parentMenu._clientInput?.devices.includes('mouse')));
558
+ }
559
+ // ------------------------------------------- //
560
+ // --- Here be touch device customizations --- //
561
+ // ------------------------------------------- //
562
+ /** Set animation state to bring a newly opened menu into view */
563
+ animateOpenMenu() {
564
+ this._clientOutput.device === 'touch'
565
+ ? this.animateTouchOpenMenu()
566
+ : this.menu._startAnimation();
567
+ }
568
+ animateTouchOpenMenu() {
569
+ if (this.triggersSubmenu()) {
570
+ // Slide newly opened sub menu into view from the side,
571
+ // pushing any parent menu out of view on the other side
572
+ this.menu._startTouchSubmenuEnterAnimation();
573
+ this._parentMenu._startTouchHideAnimation();
574
+ }
575
+ else {
576
+ // Slide root menu into view from below
577
+ this.menu._startTouchRootEnterAnimation();
578
+ }
579
+ }
580
+ /** Set animation state to close the active menu */
581
+ animateCloseMenu(toBelow, withDelay) {
582
+ this._clientOutput.device === 'touch'
583
+ ? this._animateTouchCloseMenu(toBelow, withDelay)
584
+ : this._parentMenu._resetAnimation();
585
+ }
586
+ _animateTouchCloseMenu(toBelow, withDelay) {
587
+ if (toBelow) {
588
+ // Slide menu out of view below the viewport
589
+ withDelay
590
+ ? this.menu._startTouchCloseDownAnimationWithDelay()
591
+ : this.menu._startTouchCloseDownAnimation();
592
+ }
593
+ else {
594
+ // Slide the closed menu out of view to the side
595
+ // and slide any parent menu back into view
596
+ this.menu._startTouchCloseSideAnimation();
597
+ this._parentMenu?._startTouchSubmenuEnterAnimation();
598
+ }
599
+ }
600
+ /**
601
+ * Set animation state to place the menu and any parent at the given
602
+ * horizontal position, i.e. following touch pan movement.
603
+ *
604
+ * @param xOffset Horizontal offset
605
+ */
606
+ animateSetMenuPosition(xOffset) {
607
+ this.menu._startTouchPanAnimation(xOffset);
608
+ if (this._parentMenu) {
609
+ this._parentMenu._startTouchHidePanAnimation(xOffset);
610
+ }
611
+ }
612
+ /**
613
+ * Returns strategy for positioning the overlay depending on what type of
614
+ * device the menu is being shown on
615
+ */
616
+ _positionStrategy() {
617
+ return this._clientOutput.device === 'touch'
618
+ ? this._touchPositionStrategy()
619
+ : this._desktopPositionStrategy();
620
+ }
621
+ /**
622
+ * Returns strategy for positioning the overlay for touch devices:
623
+ * Place centered at the bottom of the screen.
624
+ */
625
+ _touchPositionStrategy() {
626
+ return this._overlay.position().global();
627
+ }
628
+ /**
629
+ * Remove touch device pan/swipe listeners from overlay host element
630
+ */
631
+ addOverlayListeners() {
632
+ this._overlayRef.hostElement.addEventListener('touchstart', this._handleOverlayTouchStart, passiveEventListenerOptions);
633
+ this._overlayRef.hostElement.addEventListener('touchmove', this._handleOverlayTouchMove, passiveEventListenerOptions);
634
+ this._overlayRef.hostElement.addEventListener('touchend', this._handleOverlayTouchEnd, passiveEventListenerOptions);
635
+ }
636
+ /**
637
+ * Remove touch device pan/swipe listeners from overlay host element
638
+ */
639
+ removeOverlayListeners() {
640
+ this._overlayRef.hostElement.removeEventListener('touchstart', this._handleOverlayTouchStart, passiveEventListenerOptions);
641
+ this._overlayRef.hostElement.removeEventListener('touchmove', this._handleOverlayTouchMove, passiveEventListenerOptions);
642
+ this._overlayRef.hostElement.removeEventListener('touchend', this._handleOverlayTouchEnd, passiveEventListenerOptions);
643
+ }
644
+ /**
645
+ * Standard exponential ease out function
646
+ *
647
+ * @param current Current value
648
+ * @param offset Offset value, to which calculated value will be added
649
+ * @param target The target value
650
+ * @param end Value to which current value is compared
651
+ */
652
+ easeOutExpo(current, offset, target, end) {
653
+ return current === end
654
+ ? offset + target
655
+ : target * (-Math.pow(2, (-10 * current) / end) + 1) + offset;
656
+ }
657
+ }
658
+ GraniteMenuTriggerForDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteMenuTriggerForDirective, deps: [{ token: i1.Overlay }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: GRANITE_MENU_PANEL, optional: true }, { token: GRANITE_CLIENT_INPUT, optional: true }, { token: GRANITE_CLIENT_OUTPUT, optional: true }, { token: i2.GraniteMenuItemComponent, optional: true, self: true }, { token: i3.Directionality, optional: true }, { token: i4.FocusMonitor }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive });
659
+ GraniteMenuTriggerForDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.11", type: GraniteMenuTriggerForDirective, selector: "[graniteMenuTriggerFor]", inputs: { menu: ["graniteMenuTriggerFor", "menu"] }, host: { attributes: { "aria-haspopup": "true" }, listeners: { "mousedown": "_handleMousedown($event)", "keydown": "_handleKeydown($event)", "click": "_handleClick($event)" }, properties: { "attr.aria-expanded": "_isMenuOpen || null", "attr.aria-controls": "_isMenuOpen ? menu.panelId : null" }, classAttribute: "granite-menu-trigger" }, usesOnChanges: true, ngImport: i0 });
660
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteMenuTriggerForDirective, decorators: [{
661
+ type: Directive,
662
+ args: [{
663
+ selector: `[graniteMenuTriggerFor]`,
664
+ host: {
665
+ class: 'granite-menu-trigger',
666
+ 'aria-haspopup': 'true',
667
+ '[attr.aria-expanded]': '_isMenuOpen || null',
668
+ '[attr.aria-controls]': '_isMenuOpen ? menu.panelId : null',
669
+ '(mousedown)': '_handleMousedown($event)',
670
+ '(keydown)': '_handleKeydown($event)',
671
+ '(click)': '_handleClick($event)',
672
+ },
673
+ }]
674
+ }], ctorParameters: function () { return [{ type: i1.Overlay }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i5._MenuBaseComponent, decorators: [{
675
+ type: Inject,
676
+ args: [GRANITE_MENU_PANEL]
677
+ }, {
678
+ type: Optional
679
+ }] }, { type: undefined, decorators: [{
680
+ type: Inject,
681
+ args: [GRANITE_CLIENT_INPUT]
682
+ }, {
683
+ type: Optional
684
+ }] }, { type: undefined, decorators: [{
685
+ type: Inject,
686
+ args: [GRANITE_CLIENT_OUTPUT]
687
+ }, {
688
+ type: Optional
689
+ }] }, { type: i2.GraniteMenuItemComponent, decorators: [{
690
+ type: Optional
691
+ }, {
692
+ type: Self
693
+ }] }, { type: i3.Directionality, decorators: [{
694
+ type: Optional
695
+ }] }, { type: i4.FocusMonitor }, { type: undefined, decorators: [{
696
+ type: Inject,
697
+ args: [DOCUMENT]
698
+ }] }]; }, propDecorators: { menu: [{
699
+ type: Input,
700
+ args: ['graniteMenuTriggerFor']
701
+ }] } });
702
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVudS10cmlnZ2VyLWZvci5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL2dyYW5pdGUtY29tcG9uZW50cy9zcmMvbGliL21lbnUvbWVudS10cmlnZ2VyLWZvci5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsTUFBTSxFQUNOLEtBQUssRUFHTCxRQUFRLEVBQ1IsSUFBSSxFQUVKLGdCQUFnQixHQUNqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFM0MsT0FBTyxFQUNMLFlBQVksRUFFWiwrQkFBK0IsR0FDaEMsTUFBTSxtQkFBbUIsQ0FBQztBQUMzQixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbkQsT0FBTyxFQUFFLCtCQUErQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEUsT0FBTyxFQUdMLE9BQU8sRUFDUCxhQUFhLEdBSWQsTUFBTSxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFckQsT0FBTyxFQUNMLGFBQWEsRUFDYixTQUFTLEVBQ1QsS0FBSyxFQUVMLEVBQUUsSUFBSSxZQUFZLEVBQ2xCLFlBQVksR0FDYixNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVoRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDakQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDakUsT0FBTyxFQUFtQixrQkFBa0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUVuRSw2Q0FBNkM7QUFDN0MsT0FBTyxFQUdM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Qjs0RkFBOUIsOEJBQThCO2tCQVoxQyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSx5QkFBeUI7b0JBQ25DLElBQUksRUFBRTt3QkFDSixLQUFLLEVBQUUsc0JBQXNCO3dCQUM3QixlQUFlLEVBQUUsTUFBTTt3QkFDdkIsc0JBQXNCLEVBQUUscUJBQXFCO3dCQUM3QyxzQkFBc0IsRUFBRSxtQ0FBbUM7d0JBQzNELGFBQWEsRUFBRSwwQkFBMEI7d0JBQ3pDLFdBQVcsRUFBRSx3QkFBd0I7d0JBQ3JDLFNBQVMsRUFBRSxzQkFBc0I7cUJBQ2xDO2lCQUNGOzswQkErQ0ksTUFBTTsyQkFBQyxrQkFBa0I7OzBCQUN6QixRQUFROzswQkFLUixNQUFNOzJCQUFDLG9CQUFvQjs7MEJBQzNCLFFBQVE7OzBCQUlSLE1BQU07MkJBQUMscUJBQXFCOzswQkFDNUIsUUFBUTs7MEJBV1IsUUFBUTs7MEJBQUksSUFBSTs7MEJBRWhCLFFBQVE7OzBCQUdSLE1BQU07MkJBQUMsUUFBUTs0Q0FwRWxCLElBQUk7c0JBREgsS0FBSzt1QkFBQyx1QkFBdUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlckNvbnRlbnRJbml0LFxuICBEaXJlY3RpdmUsXG4gIEVsZW1lbnRSZWYsXG4gIEluamVjdCxcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT25EZXN0cm95LFxuICBPcHRpb25hbCxcbiAgU2VsZixcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVmlld0NvbnRhaW5lclJlZixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5cbmltcG9ydCB7XG4gIEZvY3VzTW9uaXRvcixcbiAgRm9jdXNPcmlnaW4sXG4gIGlzRmFrZU1vdXNlZG93bkZyb21TY3JlZW5SZWFkZXIsXG59IGZyb20gJ0Bhbmd1bGFyL2Nkay9hMTF5JztcbmltcG9ydCB7IERpcmVjdGlvbmFsaXR5IH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2JpZGknO1xuaW1wb3J0IHsgbm9ybWFsaXplUGFzc2l2ZUxpc3RlbmVyT3B0aW9ucyB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9wbGF0Zm9ybSc7XG5pbXBvcnQge1xuICBGbGV4aWJsZUNvbm5lY3RlZFBvc2l0aW9uU3RyYXRlZ3ksXG4gIEhvcml6b250YWxDb25uZWN0aW9uUG9zLFxuICBPdmVybGF5LFxuICBPdmVybGF5Q29uZmlnLFxuICBPdmVybGF5UmVmLFxuICBQb3NpdGlvblN0cmF0ZWd5LFxuICBWZXJ0aWNhbENvbm5lY3Rpb25Qb3MsXG59IGZyb20gJ0Bhbmd1bGFyL2Nkay9vdmVybGF5JztcbmltcG9ydCB7IFRlbXBsYXRlUG9ydGFsIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3BvcnRhbCc7XG5cbmltcG9ydCB7XG4gIGFzYXBTY2hlZHVsZXIsXG4gIGZyb21FdmVudCxcbiAgbWVyZ2UsXG4gIE9ic2VydmFibGUsXG4gIG9mIGFzIG9ic2VydmFibGVPZixcbiAgU3Vic2NyaXB0aW9uLFxufSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRlbGF5LCBmaWx0ZXIsIHRha2UsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgX01lbnVCYXNlQ29tcG9uZW50IH0gZnJvbSAnLi9tZW51LWJhc2UnO1xuaW1wb3J0IHsgR3Jhbml0ZU1lbnVJdGVtQ29tcG9uZW50IH0gZnJvbSAnLi9tZW51LWl0ZW0uY29tcG9uZW50JztcbmltcG9ydCB7IENsb3NlZEV2ZW50VHlwZSwgR1JBTklURV9NRU5VX1BBTkVMIH0gZnJvbSAnLi9tZW51LXBhbmVsJztcblxuLy8jcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG5pbXBvcnQge1xuICBDbGllbnRJbnB1dEludGVyZmFjZSxcbiAgQ2xpZW50T3V0cHV0SW50ZXJmYWNlLFxuICBHUkFOSVRFX0NMSUVOVF9JTlBVVCxcbiAgR1JBTklURV9DTElFTlRfT1VUUFVULFxufSBmcm9tICcuLi9jb3JlL2NsaWVudC1lbnZpcm9ubWVudCc7XG5pbXBvcnQgeyB0aHJvd0dyYW5pdGVNZW51TWlzc2luZ0Vycm9yIH0gZnJvbSAnLi9tZW51LWVycm9ycyc7XG5cbi8qKiBPcHRpb25zIGZvciBiaW5kaW5nIGEgcGFzc2l2ZSBldmVudCBsaXN0ZW5lci4gKi9cbmNvbnN0IHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9ucyA9IG5vcm1hbGl6ZVBhc3NpdmVMaXN0ZW5lck9wdGlvbnMoe1xuICBwYXNzaXZlOiB0cnVlLFxufSk7XG4vLyNlbmRyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cblxuLyoqXG4gKiBEaXJlY3RpdmUgdXNlZCB0byB0dXJuIGEgYnV0dG9uIGVsZW1lbnQgaW50byBhIChwb3B1cCkgbWVudSB0cmlnZ2VyXG4gKlxuICogU3RyaXBwZWQtZG93biB2ZXJzaW9uIG9mIEFuZ3VsYXIgTWF0ZXJpYWwncyBtZW51IHRyaWdnZXIgZGlyZWN0aXZlICguLi4vbWVudS9tZW51LXRyaWdnZXIudHMpXG4gKi9cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogYFtncmFuaXRlTWVudVRyaWdnZXJGb3JdYCxcbiAgaG9zdDoge1xuICAgIGNsYXNzOiAnZ3Jhbml0ZS1tZW51LXRyaWdnZXInLCAvLyBSZXF1aXJlZCBmb3IgdGVzdCBoYXJuZXNzIGhvc3Qgc2VsZWN0b3JcbiAgICAnYXJpYS1oYXNwb3B1cCc6ICd0cnVlJyxcbiAgICAnW2F0dHIuYXJpYS1leHBhbmRlZF0nOiAnX2lzTWVudU9wZW4gfHwgbnVsbCcsXG4gICAgJ1thdHRyLmFyaWEtY29udHJvbHNdJzogJ19pc01lbnVPcGVuID8gbWVudS5wYW5lbElkIDogbnVsbCcsXG4gICAgJyhtb3VzZWRvd24pJzogJ19oYW5kbGVNb3VzZWRvd24oJGV2ZW50KScsXG4gICAgJyhrZXlkb3duKSc6ICdfaGFuZGxlS2V5ZG93bigkZXZlbnQpJyxcbiAgICAnKGNsaWNrKSc6ICdfaGFuZGxlQ2xpY2soJGV2ZW50KScsXG4gIH0sXG59KVxuZXhwb3J0IGNsYXNzIEdyYW5pdGVNZW51VHJpZ2dlckZvckRpcmVjdGl2ZVxuICBpbXBsZW1lbnRzIEFmdGVyQ29udGVudEluaXQsIE9uRGVzdHJveSwgT25DaGFuZ2VzXG57XG4gIC8qKiBSZWZlcmVuY2VzIHRoZSBtZW51IGluc3RhbmNlIHRoYXQgdGhlIHRyaWdnZXIgaXMgYXNzb2NpYXRlZCB3aXRoLiAqL1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L25vLWlucHV0LXJlbmFtZVxuICBASW5wdXQoJ2dyYW5pdGVNZW51VHJpZ2dlckZvcicpXG4gIG1lbnU6IF9NZW51QmFzZUNvbXBvbmVudDtcblxuICAvKiogV2hldGhlciB0aGUgYXNzb2NpYXRlZCBtZW51IGlzIG9wZW4gKi9cbiAgX2lzTWVudU9wZW46IGJvb2xlYW4gPSBmYWxzZTtcblxuICAvLyBUcmFja2luZyBpbnB1dCB0eXBlIGlzIG5lY2Vzc2FyeSBzbyBpdCdzIHBvc3NpYmxlIHRvIG9ubHkgYXV0by1mb2N1c1xuICAvLyB0aGUgZmlyc3QgaXRlbSBvZiB0aGUgbGlzdCB3aGVuIHRoZSBtZW51IGlzIG9wZW5lZCB2aWEgdGhlIGtleWJvYXJkXG4gIF9vcGVuZWRCeTogJ21vdXNlJyB8ICd0b3VjaCcgfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIF9ob3ZlclN1YnNjcmlwdGlvbiA9IFN1YnNjcmlwdGlvbi5FTVBUWTtcbiAgcHJpdmF0ZSBfbWVudUNsb3NlU3Vic2NyaXB0aW9uID0gU3Vic2NyaXB0aW9uLkVNUFRZO1xuICBwcml2YXRlIF9jbG9zaW5nQWN0aW9uc1N1YnNjcmlwdGlvbiA9IFN1YnNjcmlwdGlvbi5FTVBUWTtcblxuICBwcml2YXRlIF9wb3J0YWw6IFRlbXBsYXRlUG9ydGFsIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgX292ZXJsYXlSZWY6IE92ZXJsYXlSZWYgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBfZG9jdW1lbnQ/OiBEb2N1bWVudDtcblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAvL1xuICAvLyAtLS0gSGVyZSBiZSBwb29yIG1hbidzIHRvdWNoIGdlc3R1cmVzIC0tLSAvL1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAvL1xuXG4gIC8vIFRPRE86IFJlcGxhY2Ugd2l0aCBIYW1tZXIgb3Igb3RoZXIgZ2VzdHVyZSBsaWJyYXJ5XG5cbiAgcHJpdmF0ZSBfdG91Y2hTdGFydFRpbWU6IG51bWJlcjtcbiAgcHJpdmF0ZSBfdG91Y2hUaW1lVGFrZW46IG51bWJlcjtcbiAgcHJpdmF0ZSBfdG91Y2hTdGFydFg6IG51bWJlcjtcbiAgcHJpdmF0ZSBfdG91Y2hTdGFydFk6IG51bWJlcjtcbiAgcHJpdmF0ZSBfdG91Y2hDdXJyZW50WDogbnVtYmVyO1xuICBwcml2YXRlIF90b3VjaEN1cnJlbnRZOiBudW1iZXI7XG4gIHByaXZhdGUgX3RvdWNoVHJhbnNsYXRlWDogbnVtYmVyO1xuICBwcml2YXRlIF90b3VjaExvY2tlZFg6IGJvb2xlYW4gfCBudWxsO1xuICBwcml2YXRlIF90b3VjaE1heFg6IG51bWJlcjtcbiAgcHJpdmF0ZSBfdG91Y2hUb3VjaGluZ0VsZW1lbnQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIF9vdmVybGF5OiBPdmVybGF5LFxuICAgIHByaXZhdGUgX2VsZW1lbnQ6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+LFxuICAgIHByaXZhdGUgX3ZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYsXG5cbiAgICAvKiogSWYgdGhpcyBpcyBhIF9zdWJtZW51XyB0cmlnZ2VyLCBpdCB3aWxsIGhhdmUgYSBwYXJlbnQgbWVudSAqL1xuICAgIEBJbmplY3QoR1JBTklURV9NRU5VX1BBTkVMKVxuICAgIEBPcHRpb25hbCgpXG4gICAgcHJpdmF0ZSBfcGFyZW50TWVudTogX01lbnVCYXNlQ29tcG9uZW50LFxuXG4gICAgLy8jcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG4gICAgLyoqIENsaWVudCBpbnB1dCBkZXZpY2UgaW5mb3JtYXRpb24gKi9cbiAgICBASW5qZWN0KEdSQU5JVEVfQ0xJRU5UX0lOUFVUKVxuICAgIEBPcHRpb25hbCgpXG4gICAgcHVibGljIF9jbGllbnRJbnB1dDogQ2xpZW50SW5wdXRJbnRlcmZhY2UsXG5cbiAgICAvKiogQ2xpZW50IG91dHB1dCBkZXZpY2UgaW5mb3JtYXRpb24gKi9cbiAgICBASW5qZWN0KEdSQU5JVEVfQ0xJRU5UX09VVFBVVClcbiAgICBAT3B0aW9uYWwoKVxuICAgIHB1YmxpYyBfY2xpZW50T3V0cHV0OiBDbGllbnRPdXRwdXRJbnRlcmZhY2UsXG4gICAgLy8jZW5kcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG5cbiAgICAvKipcbiAgICAgKiBJZiB0aGlzIGlzIGEgX3N1Ym1lbnVfIHRyaWdnZXIsIHRoZXJlIHNob3VsZCBiZSBhIGNvcnJlc3BvbmRpbmcgbWVudVxuICAgICAqIGl0ZW0gZGlyZWN0aXZlIHByZXNlbnQgYXMgd2VsbDpcbiAgICAgKlxuICAgICAqICAgICA8YnV0dG9uIGdyYW5pdGVNZW51SXRlbSBbZ3Jhbml0ZU1lbnVUcmlnZ2VyRm9yXT1cIi4uLlwiPlxuICAgICAqICAgICAgICAgICAgICAgICAgIF4tLSBUaGlzIG9uZVxuICAgICAqL1xuICAgIEBPcHRpb25hbCgpIEBTZWxmKCkgcHJpdmF0ZSBfbWVudUl0ZW1JbnN0YW5jZTogR3Jhbml0ZU1lbnVJdGVtQ29tcG9uZW50LFxuXG4gICAgQE9wdGlvbmFsKCkgcHJpdmF0ZSBfZGlyOiBEaXJlY3Rpb25hbGl0eSxcbiAgICBwcml2YXRlIF9mb2N1c01vbml0b3I6IEZvY3VzTW9uaXRvcixcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2V4cGxpY2l0LW1vZHVsZS1ib3VuZGFyeS10eXBlc1xuICAgIEBJbmplY3QoRE9DVU1FTlQpIGRvY3VtZW50PzogYW55XG4gICkge1xuICAgIF9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaHN0YXJ0JyxcbiAgICAgIHRoaXMuX2hhbmRsZVRvdWNoU3RhcnQsXG4gICAgICBwYXNzaXZlRXZlbnRMaXN0ZW5lck9wdGlvbnNcbiAgICApO1xuXG4gICAgaWYgKF9tZW51SXRlbUluc3RhbmNlKSB7XG4gICAgICBfbWVudUl0ZW1JbnN0YW5jZS5fdHJpZ2dlcnNTdWJtZW51ID0gdGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKTtcbiAgICB9XG5cbiAgICB0aGlzLl9kb2N1bWVudCA9IGRvY3VtZW50IGFzIERvY3VtZW50O1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzLm1lbnUpIHtcbiAgICAgIHRoaXMuX2hhbmRsZU1lbnVDaGFuZ2UoKTtcbiAgICB9XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudEluaXQoKTogdm9pZCB7XG4gICAgLy8gcmVtb3ZlZCBjaGVja01lbnUgaGVyZSB0byBhdm9pZCBlcnJvcnMgaW4gZHluYW1pY2FsbHkgZ2VuYXJhdGVkIG1lbnVzXG4gICAgLy8gbWVudSBpcyBjaGVja2VkIHdoZW4gb3BlbmluZyB0aGUgbWVudVxuICAgIC8vIHRoaXMuX2NoZWNrTWVudSgpO1xuICAgIHRoaXMuX2hhbmRsZUhvdmVyKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fb3ZlcmxheVJlZikge1xuICAgICAgLy8jcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG4gICAgICB0aGlzLnJlbW92ZU92ZXJsYXlMaXN0ZW5lcnMoKTtcbiAgICAgIC8vI2VuZHJlZ2lvbiAtLS0gVG91Y2ggZGV2aWNlIGN1c3RvbWl6YXRpb25zIC0tLVxuICAgICAgdGhpcy5fb3ZlcmxheVJlZi5kaXNwb3NlKCk7XG4gICAgICB0aGlzLl9vdmVybGF5UmVmID0gbnVsbDtcbiAgICB9XG5cbiAgICB0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaHN0YXJ0JyxcbiAgICAgIHRoaXMuX2hhbmRsZVRvdWNoU3RhcnQsXG4gICAgICBwYXNzaXZlRXZlbnRMaXN0ZW5lck9wdGlvbnNcbiAgICApO1xuXG4gICAgdGhpcy5faG92ZXJTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLl9tZW51Q2xvc2VTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLl9jbG9zaW5nQWN0aW9uc1N1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICB9XG5cbiAgLyoqIEhhbmRsZXMgY2hhbmdlIG9mIGFzc29jaWF0ZWQgbWVudSAqL1xuICBfaGFuZGxlTWVudUNoYW5nZSgpOiB2b2lkIHtcbiAgICB0aGlzLl9tZW51Q2xvc2VTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcblxuICAgIC8vIENsb3NlIHRoZSBtZW51IG92ZXJsYXkgd2hlbiB0aGUgbWVudSBpdHNlbGYgc2F5cyBpdCB3YW50cyB0byBiZSBjbG9zZWRcbiAgICBpZiAodGhpcy5tZW51KSB7XG4gICAgICBjb25zdCBjbG9zZWQgPSB0aGlzLm1lbnUuY2xvc2VkIGFzIE9ic2VydmFibGU8Q2xvc2VkRXZlbnRUeXBlPjtcblxuICAgICAgdGhpcy5fbWVudUNsb3NlU3Vic2NyaXB0aW9uID0gY2xvc2VkLnN1YnNjcmliZSgocmVhc29uKSA9PiB7XG4gICAgICAgIC8vI3JlZ2lvbiAtLS0gVG91Y2ggZGV2aWNlIGN1c3RvbWl6YXRpb25zIC0tLVxuICAgICAgICBpZiAodGhpcy5tZW51Ll9pc0Nsb3NpbmcpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tZW51Ll9pc0Nsb3NpbmcgPSB0cnVlO1xuXG4gICAgICAgIC8vIEdldCByaWQgb2YgdGhlIG1lbnUgYW5kIHRlbGwgYW55IHBhcmVudCB0byByZXN0b3JlIGl0cyBwb3NpdGlvblxuICAgICAgICBpZiAodGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJykge1xuICAgICAgICAgIC8vIEZpcnN0IHdlIHdhaXQgZm9yIGFueSBydW5uaW5nIGFuaW1hdGlvbiB0byBjb21wbGV0ZVxuICAgICAgICAgIGNvbnN0IHJ1bm5pbmdBbmltYXRpb25Eb25lOiBPYnNlcnZhYmxlPGFueT4gPSB0aGlzLm1lbnUuX2lzQW5pbWF0aW5nXG4gICAgICAgICAgICA/IHRoaXMubWVudS5fYW5pbWF0aW9uRG9uZVxuICAgICAgICAgICAgOiBvYnNlcnZhYmxlT2YoW251bGxdKTtcblxuICAgICAgICAgIHJ1bm5pbmdBbmltYXRpb25Eb25lXG4gICAgICAgICAgICAucGlwZSh0YWtlKDEpLCBkZWxheSgwLCBhc2FwU2NoZWR1bGVyKSlcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSByeGpzL25vLW5lc3RlZC1zdWJzY3JpYmVcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICAgICAgICB0aGlzLmFuaW1hdGVDbG9zZU1lbnUocmVhc29uICE9PSAna2V5ZG93bicsIHJlYXNvbiA9PT0gJ2NsaWNrJyk7XG4gICAgICAgICAgICAgIHRoaXMubWVudS5fYW5pbWF0aW9uRG9uZVxuICAgICAgICAgICAgICAgIC5waXBlKHRha2UoMSksIGRlbGF5KDAsIGFzYXBTY2hlZHVsZXIpKVxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSByeGpzL25vLW5lc3RlZC1zdWJzY3JpYmVcbiAgICAgICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuX2Rlc3Ryb3lNZW51KCkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8jZW5kcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG4gICAgICAgICAgdGhpcy5fZGVzdHJveU1lbnUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIGEgY2xpY2sgY2xvc2VkIHRoZSBtZW51LCB3ZSBzaG91bGQgY2xvc2UgdGhlIGVudGlyZSBjaGFpbiBvZiBuZXN0ZWQgbWVudXMuXG4gICAgICAgIGlmICgocmVhc29uID09PSAnY2xpY2snIHx8IHJlYXNvbiA9PT0gJ3RhYicpICYmIHRoaXMuX3BhcmVudE1lbnUpIHtcbiAgICAgICAgICB0aGlzLl9wYXJlbnRNZW51LmNsb3NlZC5lbWl0KHJlYXNvbik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGlzT3BlbigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5faXNNZW51T3BlbjtcbiAgfVxuXG4gIC8qKiBPcGVuIHRoZSBhc3NvY2lhdGVkIG1lbnUgKi9cbiAgb3Blbk1lbnUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2lzTWVudU9wZW4pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl9jaGVja01lbnUoKTtcblxuICAgIHRoaXMubWVudS5wYXJlbnRNZW51ID0gdGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKVxuICAgICAgPyB0aGlzLl9wYXJlbnRNZW51XG4gICAgICA6IHVuZGVmaW5lZDtcbiAgICB0aGlzLm1lbnUuZGlyZWN0aW9uID0gdGhpcy5fZGlyLnZhbHVlID09PSAncnRsJyA/ICdydGwnIDogJ2x0cic7XG5cbiAgICBpZiAodGhpcy5fcGFyZW50TWVudSkge1xuICAgICAgLy8gTWVudSB0cmlnZ2VycyBpbmhlcml0IHRhcmdldCBkZXZpY2UgdHlwZXMgZnJvbSB0aGVpciBwYXJlbnQuXG4gICAgICAvLyBVbHRpbWF0ZWx5IGl0IGlzIHRoZSByb290IHRyaWdnZXIgdGhhdCBkZXRlcm1pbmVzIGRldmljZSB0eXBlcyBmb3JcbiAgICAgIC8vIHRoZSB3aG9sZSBtZW51IGhpZXJhcmNoeS5cbiAgICAgIHRoaXMuX2NsaWVudElucHV0ID0gdGhpcy5fcGFyZW50TWVudS5fY2xpZW50SW5wdXQ7XG4gICAgICB0aGlzLl9jbGllbnRPdXRwdXQgPSB0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRPdXRwdXQ7XG4gICAgfVxuXG4gICAgLy8jcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG4gICAgLy8gTWFrZSB0aGUgbWVudSB3ZSdyZSBhYm91dCB0byBvcGVuIHVzZSB0aGUgc2FtZSBkZXZpY2VzIGFzIHRoZSB0cmlnZ2VyXG4gICAgdGhpcy5tZW51Ll9zZXREZXZpY2UodGhpcy5fY2xpZW50SW5wdXQsIHRoaXMuX2NsaWVudE91dHB1dCk7XG5cbiAgICBpZiAodGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJykge1xuICAgICAgdGhpcy5tZW51LnNob3dCYWNrQnV0dG9uID0gISF0aGlzLl9wYXJlbnRNZW51O1xuICAgICAgdGhpcy5tZW51Ll91cGRhdGVTaG93VGl0bGUoKTtcblxuICAgICAgaWYgKCF0aGlzLm1lbnUuY2xvc2VMYWJlbCkge1xuICAgICAgICB0aGlzLm1lbnUuY2xvc2VMYWJlbCA9IHRoaXMuX3BhcmVudE1lbnU/LmNsb3NlTGFiZWw7XG4gICAgICB9XG5cbiAgICAgIHRoaXMubWVudS5zaG93Q2xvc2VCdXR0b24gPSAhIXRoaXMubWVudS5jbG9zZUxhYmVsO1xuICAgIH1cbiAgICB0aGlzLm1lbnUuX2lzQ2xvc2luZyA9IGZhbHNlO1xuXG4gICAgY29uc3QgcGFuZWxDbGFzczogc3RyaW5nW10gPSBbXTtcbiAgICBpZiAodGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJykge1xuICAgICAgcGFuZWxDbGFzcy5wdXNoKCdncmFuaXRlLW92ZXJsYXktcGFuZS1maWxsLXdpZHRoLWJvdHRvbScpO1xuICAgIH1cblxuICAgIGNvbnN0IHNjcm9sbFN0cmF0ZWd5ID1cbiAgICAgIHRoaXMuX2NsaWVudE91dHB1dC5kZXZpY2UgIT09ICd0b3VjaCdcbiAgICAgICAgPyB0aGlzLl9vdmVybGF5LnNjcm9sbFN0cmF0ZWdpZXMucmVwb3NpdGlvbigpXG4gICAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgY29uc3QgaGFzQmFja2Ryb3AgPVxuICAgICAgdGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJyAmJiAhdGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKTtcbiAgICAvLyNlbmRyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cblxuICAgIC8vIENyZWF0ZSBhbiBvdmVybGF5IHRvIHN0dWZmIHRoZSBtZW51IChwb3J0YWwpIGludG8gYmVsb3dcbiAgICBpZiAoIXRoaXMuX292ZXJsYXlSZWYpIHtcbiAgICAgIGNvbnN0IGNvbmZpZyA9IG5ldyBPdmVybGF5Q29uZmlnKHtcbiAgICAgICAgcG9zaXRpb25TdHJhdGVneTogdGhpcy5fcG9zaXRpb25TdHJhdGVneSgpLFxuICAgICAgICBiYWNrZHJvcENsYXNzOiAnZ3Jhbml0ZS1vdmVybGF5LWRhcmstZ2xhc3MtYmFja2Ryb3AnLFxuICAgICAgICBzY3JvbGxTdHJhdGVneSxcbiAgICAgICAgZGlyZWN0aW9uOiB0aGlzLl9kaXIsXG4gICAgICAgIHBhbmVsQ2xhc3MsXG4gICAgICAgIGhhc0JhY2tkcm9wLFxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuX292ZXJsYXlSZWYgPSB0aGlzLl9vdmVybGF5LmNyZWF0ZShjb25maWcpO1xuXG4gICAgICAvLyNyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cbiAgICAgIC8vIEFkZCB0b3VjaCBsaXN0ZW5lciBmb3Igc3VibWVudSBiYWNrIHBhbi9zd2lwZVxuICAgICAgaWYgKHRoaXMuX2NsaWVudE91dHB1dC5kZXZpY2UgPT09ICd0b3VjaCcpIHtcbiAgICAgICAgdGhpcy5hZGRPdmVybGF5TGlzdGVuZXJzKCk7XG4gICAgICB9XG4gICAgICAvLyNlbmRyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUmVzZXQgYW5pbWF0aW9uIHN0YXRlIGZvciByZXVzZWQgb3ZlcmxheXNcbiAgICAgIGlmICh0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAndG91Y2gnKSB7XG4gICAgICAgIHRoaXMubWVudS5fcGFuZWxBbmltYXRpb25TdGF0ZSA9ICd2b2lkJztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgcG9ydGFsIGZyb20gYXNzb2NpYXRlZCBtZW51J3MgdGVtcGxhdGVcbiAgICBpZiAoIXRoaXMuX3BvcnRhbCB8fCB0aGlzLl9wb3J0YWwudGVtcGxhdGVSZWYgIT09IHRoaXMubWVudS50ZW1wbGF0ZVJlZikge1xuICAgICAgdGhpcy5fcG9ydGFsID0gbmV3IFRlbXBsYXRlUG9ydGFsKFxuICAgICAgICB0aGlzLm1lbnUudGVtcGxhdGVSZWYsXG4gICAgICAgIHRoaXMuX3ZpZXdDb250YWluZXJSZWZcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQXR0YWNoIG1lbnUgcG9ydGFsIHRvIG92ZXJsYXkgcmVmICh3aGljaCBpcyBhIHBvcnRhbCBvdXRsZXQpXG4gICAgdGhpcy5fb3ZlcmxheVJlZi5hdHRhY2godGhpcy5fcG9ydGFsKTtcblxuICAgIC8vIFN1YnNjcmliZSB0byBzdHJlYW0gdGhhdCBlbWl0cyB3aGVuZXZlciBhbiBhY3Rpb24gdGhhdCBzaG91bGQgY2xvc2UgdGhlIG1lbnUgb2NjdXJzXG4gICAgdGhpcy5fY2xvc2luZ0FjdGlvbnNTdWJzY3JpcHRpb24gPSB0aGlzLl9tZW51Q2xvc2luZ0FjdGlvbnMoKS5zdWJzY3JpYmUoXG4gICAgICAoKSA9PiB0aGlzLmNsb3NlTWVudSgpXG4gICAgKTtcblxuICAgIHRoaXMuYW5pbWF0ZU9wZW5NZW51KCk7XG5cbiAgICB0aGlzLl9zZXRJc01lbnVPcGVuKHRydWUpO1xuICAgIHRoaXMubWVudS5mb2N1c0ZpcnN0SXRlbSh0aGlzLl9vcGVuZWRCeSB8fCAncHJvZ3JhbScpO1xuICB9XG5cbiAgLyoqIFdoZXRoZXIgdGhlIG1lbnUgdHJpZ2dlcnMgYSBzdWItbWVudSBvciBhIHRvcC1sZXZlbCBvbmUuICovXG4gIHRyaWdnZXJzU3VibWVudSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISEodGhpcy5fbWVudUl0ZW1JbnN0YW5jZSAmJiB0aGlzLl9wYXJlbnRNZW51KTtcbiAgfVxuXG4gIC8qKiBUb2dnbGVzIHRoZSBtZW51IGJldHdlZW4gdGhlIG9wZW4gYW5kIGNsb3NlZCBzdGF0ZXMuICovXG4gIHRvZ2dsZU1lbnUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2lzTWVudU9wZW4pIHtcbiAgICAgIHRoaXMuY2xvc2VNZW51KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMub3Blbk1lbnUoKTtcbiAgICB9XG4gIH1cblxuICAvKiogQ2xvc2UgdGhlIGFzc29jaWF0ZWQgbWVudSAqL1xuICBjbG9zZU1lbnUoKTogdm9pZCB7XG4gICAgdGhpcy5tZW51LmNsb3NlZC5lbWl0KCk7XG4gIH1cblxuICAvKipcbiAgICogRm9jdXNlcyB0aGUgbWVudSB0cmlnZ2VyLlxuICAgKiBAcGFyYW0gb3JpZ2luIFNvdXJjZSBvZiB0aGUgbWVudSB0cmlnZ2VyJ3MgZm9jdXMuXG4gICAqL1xuICBmb2N1cyhvcmlnaW46IEZvY3VzT3JpZ2luID0gJ3Byb2dyYW0nLCBvcHRpb25zPzogRm9jdXNPcHRpb25zKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2ZvY3VzTW9uaXRvcikge1xuICAgICAgdGhpcy5fZm9jdXNNb25pdG9yLmZvY3VzVmlhKHRoaXMuX2VsZW1lbnQsIG9yaWdpbiwgb3B0aW9ucyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudC5mb2N1cyhvcHRpb25zKTtcbiAgICB9XG4gIH1cblxuICAvKiogRGV0YWNoIG1lbnUgcG9ydGFsIGZyb20gb3ZlcmxheSBhbmQgdXBkYXRlIG9wZW4gc3RhdGUgKi9cbiAgX2Rlc3Ryb3lNZW51KCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5fb3ZlcmxheVJlZiB8fCAhdGhpcy5faXNNZW51T3Blbikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX2Nsb3NpbmdBY3Rpb25zU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5fb3ZlcmxheVJlZi5kZXRhY2goKTtcbiAgICB0aGlzLl9yZXN0b3JlRm9jdXMoKTtcbiAgICB0aGlzLm1lbnUuX3Jlc2V0QW5pbWF0aW9uKCk7XG5cbiAgICB0aGlzLl9zZXRJc01lbnVPcGVuKGZhbHNlKTtcbiAgfVxuXG4gIC8qKiBIYW5kbGVzIG1vdXNlIHByZXNzZXMgb24gdGhlIHRyaWdnZXIuICovXG4gIF9oYW5kbGVNb3VzZWRvd24oZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIWlzRmFrZU1vdXNlZG93bkZyb21TY3JlZW5SZWFkZXIoZXZlbnQpKSB7XG4gICAgICBpZiAodGhpcy5fb3BlbmVkQnkgIT09ICd0b3VjaCcpIHtcbiAgICAgICAgLy8gU2luY2UgcmlnaHQgb3IgbWlkZGxlIGJ1dHRvbiBjbGlja3Mgd29uJ3QgdHJpZ2dlciB0aGUgYGNsaWNrYCBldmVudCxcbiAgICAgICAgLy8gd2Ugc2hvdWxkbid0IGNvbnNpZGVyIHRoZSBtZW51IGFzIG9wZW5lZCBieSBtb3VzZSBpbiB0aG9zZSBjYXNlcy5cbiAgICAgICAgdGhpcy5fb3BlbmVkQnkgPSBldmVudC5idXR0b24gPT09IDAgPyAnbW91c2UnIDogbnVsbDtcbiAgICAgIH1cblxuICAgICAgLy8gU2luY2UgY2xpY2tpbmcgb24gdGhlIHRyaWdnZXIgd29uJ3QgY2xvc2UgdGhlIG1lbnUgaWYgaXQgb3BlbnMgYSBzdWItbWVudSxcbiAgICAgIC8vIHdlIHNob3VsZCBwcmV2ZW50IGZvY3VzIGZyb20gbW92aW5nIG9udG8gaXQgdmlhIGNsaWNrIHRvIGF2b2lkIHRoZVxuICAgICAgLy8gaGlnaGxpZ2h0IGZyb20gbGluZ2VyaW5nIG9uIHRoZSBtZW51IGl0ZW0uXG4gICAgICBpZiAodGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKSAmJiAhdGhpcy5fdG9nZ2xlT25TdWJtZW51Q2xpY2soKSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBIYW5kbGVzIGtleSBwcmVzc2VzIG9uIHRoZSB0cmlnZ2VyLiAqL1xuICBfaGFuZGxlS2V5ZG93bihldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGtleSA9IGV2ZW50LmtleTtcblxuICAgIGlmIChcbiAgICAgIHRoaXMudHJpZ2dlcnNTdWJtZW51KCkgJiZcbiAgICAgICgoa2V5ID09PSAnQXJyb3dSaWdodCcgJiYgdGhpcy5fZGlyLnZhbHVlID09PSAnbHRyJykgfHxcbiAgICAgICAgKGtleSA9PT0gJ0Fycm93TGVmdCcgJiYgdGhpcy5fZGlyLnZhbHVlID09PSAncnRsJykpXG4gICAgKSB7XG4gICAgICB0aGlzLm9wZW5NZW51KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEhhbmRsZXMgY2xpY2sgZXZlbnRzIG9uIHRoZSB0cmlnZ2VyLiAqL1xuICBfaGFuZGxlQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKSkge1xuICAgICAgLy8gU3RvcCBldmVudCBwcm9wYWdhdGlvbiB0byBhdm9pZCBjbG9zaW5nIHRoZSBwYXJlbnQgbWVudS5cbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXG4gICAgICB0aGlzLl90b2dnbGVPblN1Ym1lbnVDbGljaygpID8gdGhpcy50b2dnbGVNZW51KCkgOiB0aGlzLm9wZW5NZW51KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudG9nZ2xlTWVudSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGVzIHRvdWNoIHN0YXJ0IGV2ZW50cyBvbiB0aGUgdHJpZ2dlci5cbiAgICogTmVlZHMgdG8gYmUgYW4gYXJyb3cgZnVuY3Rpb24gc28gd2UgY2FuIGVhc2lseSB1c2UgYWRkRXZlbnRMaXN0ZW5lciBhbmQgcmVtb3ZlRXZlbnRMaXN0ZW5lci5cbiAgICovXG4gIHByaXZhdGUgX2hhbmRsZVRvdWNoU3RhcnQgPSAoKSA9PiB7XG4gICAgdGhpcy5fb3BlbmVkQnkgPSAndG91Y2gnO1xuICB9O1xuXG4gIC8qKiBIYW5kbGVzIHRoZSBjYXNlcyB3aGVyZSB0aGUgdXNlciBob3ZlcnMgb3ZlciB0aGUgdHJpZ2dlci4gKi9cbiAgcHJpdmF0ZSBfaGFuZGxlSG92ZXIoKSB7XG4gICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgaW4gdGhlIGhvdmVyZWQgaXRlbSBpbiBvcmRlciB0byB0b2dnbGUgdGhlIHBhbmVsLlxuICAgIGlmICghdGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKSB8fCAhdGhpcy5fcGFyZW50TWVudSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX2hvdmVyU3Vic2NyaXB0aW9uID0gdGhpcy5fcGFyZW50TWVudVxuICAgICAgLl9ob3ZlcmVkKClcbiAgICAgIC5waXBlKFxuICAgICAgICBmaWx0ZXIoKCkgPT4gdGhpcy5fb3Blbk9uSG92ZXIoKSksXG4gICAgICAgIC8vIFNpbmNlIHdlIG1pZ2h0IGhhdmUgbXVsdGlwbGUgY29tcGV0aW5nIHRyaWdnZXJzIGZvciB0aGUgc2FtZSBtZW51IChlLmcuIGEgc3ViLW1lbnVcbiAgICAgICAgLy8gd2l0aCBkaWZmZXJlbnQgZGF0YSBhbmQgdHJpZ2dlcnMpLCB3ZSBoYXZlIHRvIGRlbGF5IGl0IGJ5IGEgdGljayB0byBlbnN1cmUgdGhhdFxuICAgICAgICAvLyBpdCB3b24ndCBiZSBjbG9zZWQgaW1tZWRpYXRlbHkgYWZ0ZXIgaXQgaXMgb3BlbmVkLlxuICAgICAgICBmaWx0ZXIoXG4gICAgICAgICAgKGFjdGl2ZSkgPT4gYWN0aXZlID09PSB0aGlzLl9tZW51SXRlbUluc3RhbmNlIC8qJiYgIWFjdGl2ZS5kaXNhYmxlZCovXG4gICAgICAgICksXG4gICAgICAgIGRlbGF5KDAsIGFzYXBTY2hlZHVsZXIpXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5fb3BlbmVkQnkgPSAnbW91c2UnO1xuXG4gICAgICAgIC8vIElmIHRoZSBzYW1lIG1lbnUgaXMgdXNlZCBiZXR3ZWVuIG11bHRpcGxlIHRyaWdnZXJzLCBpdCBtaWdodCBzdGlsbCBiZSBhbmltYXRpbmdcbiAgICAgICAgLy8gd2hpbGUgdGhlIG5ldyB0cmlnZ2VyIHRyaWVzIHRvIHJlLW9wZW4gaXQuIFdhaXQgZm9yIHRoZSBhbmltYXRpb24gdG8gZmluaXNoXG4gICAgICAgIC8vIGJlZm9yZSBkb2luZyBzby4gQWxzbyBpbnRlcnJ1cHQgaWYgdGhlIHVzZXIgbW92ZXMgdG8gYW5vdGhlciBpdGVtLlxuICAgICAgICBpZiAodGhpcy5tZW51IGluc3RhbmNlb2YgX01lbnVCYXNlQ29tcG9uZW50ICYmIHRoaXMubWVudS5faXNBbmltYXRpbmcpIHtcbiAgICAgICAgICAvLyBXZSBuZWVkIHRoZSBgZGVsYXkoMClgIGhlcmUgaW4gb3JkZXIgdG8gYXZvaWRcbiAgICAgICAgICAvLyAnY2hhbmdlZCBhZnRlciBjaGVja2VkJyBlcnJvcnMgaW4gc29tZSBjYXNlcy4gU2VlIEFuZ3VsYXIgTWF0ZXJpYWwgIzEyMTk0LlxuICAgICAgICAgIHRoaXMubWVudS5fYW5pbWF0aW9uRG9uZVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgIHRha2UoMSksXG4gICAgICAgICAgICAgIGRlbGF5KDAsIGFzYXBTY2hlZHVsZXIpLFxuICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5fcGFyZW50TWVudS5faG92ZXJlZCgpKVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHJ4anMvbm8tbmVzdGVkLXN1YnNjcmliZVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLm9wZW5NZW51KCkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMub3Blbk1lbnUoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVzdG9yZXMgZm9jdXMgdG8gdGhlIGVsZW1lbnQgdGhhdCB3YXMgZm9jdXNlZCBiZWZvcmUgdGhlIG1lbnUgd2FzIG9wZW4uXG4gICAqIENvdWxkIGJlIHRoZSByb290IHRyaWdnZXIgYnV0dG9uIG9yIGEgc3VibWVudSB0cmlnZ2VyIGl0ZW1cbiAgICovXG4gIHByaXZhdGUgX3Jlc3RvcmVGb2N1cygpIHtcbiAgICAvLyBXZSBzaG91bGQgcmVzZXQgZm9jdXMgaWYgdGhlIHVzZXIgaXMgbmF2aWdhdGluZyB1c2luZyBhIGtleWJvYXJkIG9yXG4gICAgLy8gaWYgd2UgaGF2ZSBhIHRvcC1sZXZlbCB0cmlnZ2VyIHdoaWNoIG1pZ2h0IGNhdXNlIGZvY3VzIHRvIGJlIGxvc3RcbiAgICAvLyB3aGVuIGNsaWNraW5nIG91dHNpZGUgb2YgdGhlIG1lbnUuXG4gICAgaWYgKCF0aGlzLl9vcGVuZWRCeSkge1xuICAgICAgLy8gTm90ZSB0aGF0IHRoZSBmb2N1cyBzdHlsZSB3aWxsIHNob3cgdXAgYm90aCBmb3IgYHByb2dyYW1gIGFuZFxuICAgICAgLy8gYGtleWJvYXJkYCBzbyB3ZSBkb24ndCBoYXZlIHRvIHNwZWNpZnkgd2hpY2ggb25lIGl0IGlzLlxuICAgICAgdGhpcy5mb2N1cygpO1xuICAgIH0gZWxzZSBpZiAoIXRoaXMudHJpZ2dlcnNTdWJtZW51KCkpIHtcbiAgICAgIHRoaXMuZm9jdXModGhpcy5fb3BlbmVkQnkpO1xuICAgIH1cblxuICAgIHRoaXMuX29wZW5lZEJ5ID0gbnVsbDtcbiAgfVxuXG4gIC8vIFNldCBzdGF0ZSByYXRoZXIgdGhhbiB0b2dnbGUgdG8gc3VwcG9ydCB0cmlnZ2VycyBzaGFyaW5nIGEgbWVudVxuICBwcml2YXRlIF9zZXRJc01lbnVPcGVuKGlzT3BlbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuX2lzTWVudU9wZW4gPSBpc09wZW47XG5cbiAgICBpZiAodGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKSkge1xuICAgICAgdGhpcy5fbWVudUl0ZW1JbnN0YW5jZS5faGlnaGxpZ2h0ZWQgPVxuICAgICAgICBpc09wZW4gJiYgdGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSAhPT0gJ3RvdWNoJztcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBtZXRob2QgY2hlY2tzIHRoYXQgYSB2YWxpZCBpbnN0YW5jZSBvZiBNZW51Q29tcG9uZW50IGhhcyBiZWVuIHBhc3NlZCBpbnRvXG4gICAqIGdyYW5pdGVNZW51VHJpZ2dlckZvci4gSWYgbm90LCBhbiBleGNlcHRpb24gaXMgdGhyb3duLlxuICAgKi9cbiAgcHJpdmF0ZSBfY2hlY2tNZW51KCkge1xuICAgIGlmICghdGhpcy5tZW51KSB7XG4gICAgICB0aHJvd0dyYW5pdGVNZW51TWlzc2luZ0Vycm9yKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3RyYXRlZ3kgZm9yIHBvc2l0aW9uaW5nIHRoZSBvdmVybGF5IGZvciBkZXNrdG9wIGRldmljZXM6XG4gICAqIFBsYWNlIGFkamFjZW50IHRvIHRoZSB0cmlnZ2VyIGJ1dHRvbiAocHJlZmVyYWJseSBpbW1lZGlhdGVseSBiZWxvdylcbiAgICogaW4gb3JkZXIgdG8gc2hvdyBhcyBtdWNoIG9mIHRoZSBtZW51IGFzIHBvc3NpYmxlLlxuICAgKi9cbiAgcHJpdmF0ZSBfZGVza3RvcFBvc2l0aW9uU3RyYXRlZ3koKTogUG9zaXRpb25TdHJhdGVneSB7XG4gICAgY29uc3QgcG9zaXRpb25TdHJhdGVneTogRmxleGlibGVDb25uZWN0ZWRQb3NpdGlvblN0cmF0ZWd5ID0gdGhpcy5fb3ZlcmxheVxuICAgICAgLnBvc2l0aW9uKClcbiAgICAgIC5mbGV4aWJsZUNvbm5lY3RlZFRvKHRoaXMuX2VsZW1lbnQpXG4gICAgICAud2l0aExvY2tlZFBvc2l0aW9uKClcbiAgICAgIC53aXRoVHJhbnNmb3JtT3JpZ2luT24oJy5ncmFuaXRlLW1lbnUnKVxuICAgICAgLndpdGhQdXNoKGZhbHNlKTtcblxuICAgIHRoaXMuX3NldFBvc2l0aW9uKHBvc2l0aW9uU3RyYXRlZ3kpO1xuICAgIHJldHVybiBwb3NpdGlvblN0cmF0ZWd5O1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGFwcHJvcHJpYXRlIHBvc2l0aW9ucyBvbiBhIHBvc2l0aW9uIHN0cmF0ZWd5XG4gICAqIHNvIHRoZSBvdmVybGF5IGNvbm5lY3RzIHdpdGggdGhlIHRyaWdnZXIgY29ycmVjdGx5LlxuICAgKiBAcGFyYW0gcG9zaXRpb25TdHJhdGVneSBTdHJhdGVneSB3aG9zZSBwb3NpdGlvbiB0byB1cGRhdGUuXG4gICAqL1xuICBwcml2YXRlIF9zZXRQb3NpdGlvbihwb3NpdGlvblN0cmF0ZWd5OiBGbGV4aWJsZUNvbm5lY3RlZFBvc2l0aW9uU3RyYXRlZ3kpIHtcbiAgICBjb25zdCBNRU5VX1BBTkVMX1RPUF9QQURESU5HID0gMDtcblxuICAgIGxldCBbb3JpZ2luWCwgb3JpZ2luRmFsbGJhY2tYXTogSG9yaXpvbnRhbENvbm5lY3Rpb25Qb3NbXSA9XG4gICAgICB0aGlzLm1lbnUueFBvc2l0aW9uID09PSAnYmVmb3JlJyA/IFsnZW5kJywgJ3N0YXJ0J10gOiBbJ3N0YXJ0JywgJ2VuZCddO1xuXG4gICAgY29uc3QgW292ZXJsYXlZLCBvdmVybGF5RmFsbGJhY2tZXTogVmVydGljYWxDb25uZWN0aW9uUG9zW10gPVxuICAgICAgdGhpcy5tZW51LnlQb3NpdGlvbiA9PT0gJ2Fib3ZlJyA/IFsnYm90dG9tJywgJ3RvcCddIDogWyd0b3AnLCAnYm90dG9tJ107XG5cbiAgICBsZXQgW29yaWdpblksIG9yaWdpbkZhbGxiYWNrWV0gPSBbb3ZlcmxheVksIG92ZXJsYXlGYWxsYmFja1ldO1xuICAgIGxldCBbb3ZlcmxheVgsIG92ZXJsYXlGYWxsYmFja1hdID0gW29yaWdpblgsIG9yaWdpbkZhbGxiYWNrWF07XG4gICAgbGV0IG9mZnNldFkgPSAwO1xuXG4gICAgaWYgKHRoaXMudHJpZ2dlcnNTdWJtZW51KCkpIHtcbiAgICAgIC8vIFdoZW4gdGhlIG1lbnUgaXMgYSBzdWItbWVudSwgaXQgc2hvdWxkIGFsd2F5cyBhbGlnbiBpdHNlbGZcbiAgICAgIC8vIHRvIHRoZSBlZGdlcyBvZiB0aGUgdHJpZ2dlciwgaW5zdGVhZCBvZiBvdmVybGFwcGluZyBpdC5cbiAgICAgIG92ZXJsYXlGYWxsYmFja1ggPSBvcmlnaW5YID1cbiAgICAgICAgdGhpcy5tZW51LnhQb3NpdGlvbiA9PT0gJ2JlZm9yZScgPyAnc3RhcnQnIDogJ2VuZCc7XG4gICAgICBvcmlnaW5GYWxsYmFja1ggPSBvdmVybGF5WCA9IG9yaWdpblggPT09ICdlbmQnID8gJ3N0YXJ0JyA6ICdlbmQnO1xuICAgICAgb2Zmc2V0WSA9XG4gICAgICAgIG92ZXJsYXlZID09PSAnYm90dG9tJ1xuICAgICAgICAgID8gTUVOVV9QQU5FTF9UT1BfUEFERElOR1xuICAgICAgICAgIDogLU1FTlVfUEFORUxfVE9QX1BBRERJTkc7XG4gICAgfSBlbHNlIHtcbiAgICAgIG9yaWdpblkgPSBvdmVybGF5WSA9PT0gJ3RvcCcgPyAnYm90dG9tJyA6ICd0b3AnO1xuICAgICAgb3JpZ2luRmFsbGJhY2tZID0gb3ZlcmxheUZhbGxiYWNrWSA9PT0gJ3RvcCcgPyAnYm90dG9tJyA6ICd0b3AnO1xuICAgIH1cblxuICAgIHBvc2l0aW9uU3RyYXRlZ3kud2l0aFBvc2l0aW9ucyhbXG4gICAgICB7IG9yaWdpblgsIG9yaWdpblksIG92ZXJsYXlYLCBvdmVybGF5WSwgb2Zmc2V0WSB9LFxuICAgICAge1xuICAgICAgICBvcmlnaW5YOiBvcmlnaW5GYWxsYmFja1gsXG4gICAgICAgIG9yaWdpblksXG4gICAgICAgIG92ZXJsYXlYOiBvdmVybGF5RmFsbGJhY2tYLFxuICAgICAgICBvdmVybGF5WSxcbiAgICAgICAgb2Zmc2V0WSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG9yaWdpblgsXG4gICAgICAgIG9yaWdpblk6IG9yaWdpbkZhbGxiYWNrWSxcbiAgICAgICAgb3ZlcmxheVgsXG4gICAgICAgIG92ZXJsYXlZOiBvdmVybGF5RmFsbGJhY2tZLFxuICAgICAgICBvZmZzZXRZOiAtb2Zmc2V0WSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG9yaWdpblg6IG9yaWdpbkZhbGxiYWNrWCxcbiAgICAgICAgb3JpZ2luWTogb3JpZ2luRmFsbGJhY2tZLFxuICAgICAgICBvdmVybGF5WDogb3ZlcmxheUZhbGxiYWNrWCxcbiAgICAgICAgb3ZlcmxheVk6IG92ZXJsYXlGYWxsYmFja1ksXG4gICAgICAgIG9mZnNldFk6IC1vZmZzZXRZLFxuICAgICAgfSxcbiAgICBdKTtcbiAgfVxuXG4gIC8qKiBSZXR1cm5zIGEgc3RyZWFtIHRoYXQgZW1pdHMgd2hlbmV2ZXIgYW4gYWN0aW9uIHRoYXQgc2hvdWxkIGNsb3NlIHRoZSBtZW51IG9jY3Vycy4gKi9cbiAgcHJpdmF0ZSBfbWVudUNsb3NpbmdBY3Rpb25zKCkge1xuICAgIGNvbnN0IGRldGFjaG1lbnRzID0gdGhpcy5fb3ZlcmxheVJlZj8uZGV0YWNobWVudHMoKTtcbiAgICBjb25zdCBwYXJlbnRDbG9zZSA9IHRoaXMuX3BhcmVudE1lbnVcbiAgICAgID8gdGhpcy5fcGFyZW50TWVudS5jbG9zZWRcbiAgICAgIDogb2JzZXJ2YWJsZU9mKCk7XG5cbiAgICBjb25zdCBob3ZlciA9XG4gICAgICB0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAnZGVza3RvcCcgJiYgdGhpcy5fcGFyZW50TWVudVxuICAgICAgICA/IHRoaXMuX3BhcmVudE1lbnUuX2hvdmVyZWQoKS5waXBlKFxuICAgICAgICAgICAgZmlsdGVyKChpdGVtKSA9PiBpdGVtICE9PSB0aGlzLl9tZW51SXRlbUluc3RhbmNlKSxcbiAgICAgICAgICAgIGZpbHRlcigoKSA9PiB0aGlzLl9pc01lbnVPcGVuKVxuICAgICAgICAgIClcbiAgICAgICAgOiBvYnNlcnZhYmxlT2YoKTtcblxuICAgIC8vIE5vdGU6IFF1aWNrIGZpeC4gRmVhdHVyZSByZXBvcnRlZGx5IGV4aXN0cyBpbiBDREsgZm9yIEFuZ3VsYXIgMTBcbiAgICAvLyBGaWx0ZXIgdG8gcHJldmVudCBjbG9zaW5nIHdoZW4gYW5pbWF0aW5nIGFkZGVkIHRob3VnaC4gQXBwbGllZCB0b1xuICAgIC8vIHJvb3QgbWVudSBvbmx5LlxuICAgIGNvbnN0IG91dHNpZGVDbGljayA9ICF0aGlzLl9wYXJlbnRNZW51XG4gICAgICA/IGZyb21FdmVudDxNb3VzZUV2ZW50Pih0aGlzLl9kb2N1bWVudCwgJ2NsaWNrJykucGlwZShcbiAgICAgICAgICBmaWx0ZXIoXG4gICAgICAgICAgICAoZTogTW91c2VFdmVudCkgPT5cbiAgICAgICAgICAgICAgKGUudGFyZ2V0IGFzIEhUTUxFbGVtZW50KSAhPT0gdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50ICYmXG4gICAgICAgICAgICAgIChlLnRhcmdldCBhcyBIVE1MRWxlbWVudCkuY2xvc2VzdCgnLmdyYW5pdGUtbWVudScpID09PSBudWxsXG4gICAgICAgICAgKSxcbiAgICAgICAgICBmaWx0ZXIoKCkgPT4gIXRoaXMubWVudS5faXNBbmltYXRpbmcpXG4gICAgICAgIClcbiAgICAgIDogb2JzZXJ2YWJsZU9mKCk7XG5cbiAgICByZXR1cm4gbWVyZ2UoZGV0YWNobWVudHMsIGhvdmVyLCBwYXJlbnRDbG9zZSwgb3V0c2lkZUNsaWNrKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGF1dG9tYXRpY2FsbHkgb3BlbiBzdWJtZW51cyBvbiBob3Zlci4gVGhpcyBpcyB0cnVlIHdoZW4gc2hvd2luZ1xuICAgKiBkZXNrdG9wIG1lbnVzIGFuZCBoYXZpbmcgbW91c2Ugc3VwcG9ydC5cbiAgICovXG4gIHByaXZhdGUgX29wZW5PbkhvdmVyKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICAodGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKVxuICAgICAgICA/IHRoaXMuX3BhcmVudE1lbnUub3Blbk9uSG92ZXJcbiAgICAgICAgOiB0aGlzLm1lbnUub3Blbk9uSG92ZXIpICYmXG4gICAgICB0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRPdXRwdXQ/LmRldmljZSA9PT0gJ2Rlc2t0b3AnICYmXG4gICAgICB0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRJbnB1dD8uZGV2aWNlcy5pbmNsdWRlcygnbW91c2UnKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciB0byB0b2dnbGUgc3VibWVudXMgb24gY2xpY2suIFRoaXMgaXMgdHJ1ZSB3aGVuIHNob3dpbmcgZGVza3RvcCBtZW51c1xuICAgKiB3aXRob3V0IG1vdXNlIHN1cHBvcnQuIFdoaWNoLCBieSB0aGUgd2F5LCBpcyBub3QgYSBncmVhdCBpZGVhIHRvIGJlZ2luIHdpdGguXG4gICAqL1xuICBwcml2YXRlIF90b2dnbGVPblN1Ym1lbnVDbGljaygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgISh0aGlzLnRyaWdnZXJzU3VibWVudSgpXG4gICAgICAgID8gdGhpcy5fcGFyZW50TWVudS5vcGVuT25Ib3ZlclxuICAgICAgICA6IHRoaXMubWVudS5vcGVuT25Ib3ZlcikgfHxcbiAgICAgICh0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRPdXRwdXQ/LmRldmljZSA9PT0gJ2Rlc2t0b3AnICYmXG4gICAgICAgICF0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRJbnB1dD8uZGV2aWNlcy5pbmNsdWRlcygnbW91c2UnKSlcbiAgICApO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAvL1xuICAvLyAtLS0gSGVyZSBiZSB0b3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tIC8vXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gLy9cblxuICAvKiogU2V0IGFuaW1hdGlvbiBzdGF0ZSB0byBicmluZyBhIG5ld2x5IG9wZW5lZCBtZW51IGludG8gdmlldyAqL1xuICBwcml2YXRlIGFuaW1hdGVPcGVuTWVudSgpIHtcbiAgICB0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAndG91Y2gnXG4gICAgICA/IHRoaXMuYW5pbWF0ZVRvdWNoT3Blbk1lbnUoKVxuICAgICAgOiB0aGlzLm1lbnUuX3N0YXJ0QW5pbWF0aW9uKCk7XG4gIH1cblxuICBwcml2YXRlIGFuaW1hdGVUb3VjaE9wZW5NZW51KCkge1xuICAgIGlmICh0aGlzLnRyaWdnZXJzU3VibWVudSgpKSB7XG4gICAgICAvLyBTbGlkZSBuZXdseSBvcGVuZWQgc3ViIG1lbnUgaW50byB2aWV3IGZyb20gdGhlIHNpZGUsXG4gICAgICAvLyBwdXNoaW5nIGFueSBwYXJlbnQgbWVudSBvdXQgb2YgdmlldyBvbiB0aGUgb3RoZXIgc2lkZVxuICAgICAgdGhpcy5tZW51Ll9zdGFydFRvdWNoU3VibWVudUVudGVyQW5pbWF0aW9uKCk7XG4gICAgICB0aGlzLl9wYXJlbnRNZW51Ll9zdGFydFRvdWNoSGlkZUFuaW1hdGlvbigpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBTbGlkZSByb290IG1lbnUgaW50byB2aWV3IGZyb20gYmVsb3dcbiAgICAgIHRoaXMubWVudS5fc3RhcnRUb3VjaFJvb3RFbnRlckFuaW1hdGlvbigpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBTZXQgYW5pbWF0aW9uIHN0YXRlIHRvIGNsb3NlIHRoZSBhY3RpdmUgbWVudSAqL1xuICBwcml2YXRlIGFuaW1hdGVDbG9zZU1lbnUodG9CZWxvdzogYm9vbGVhbiwgd2l0aERlbGF5OiBib29sZWFuKSB7XG4gICAgdGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJ1xuICAgICAgPyB0aGlzLl9hbmltYXRlVG91Y2hDbG9zZU1lbnUodG9CZWxvdywgd2l0aERlbGF5KVxuICAgICAgOiB0aGlzLl9wYXJlbnRNZW51Ll9yZXNldEFuaW1hdGlvbigpO1xuICB9XG5cbiAgcHJpdmF0ZSBfYW5pbWF0ZVRvdWNoQ2xvc2VNZW51KHRvQmVsb3c6IGJvb2xlYW4sIHdpdGhEZWxheTogYm9vbGVhbikge1xuICAgIGlmICh0b0JlbG93KSB7XG4gICAgICAvLyBTbGlkZSBtZW51IG91dCBvZiB2aWV3IGJlbG93IHRoZSB2aWV3cG9ydFxuICAgICAgd2l0aERlbGF5XG4gICAgICAgID8gdGhpcy5tZW51Ll9zdGFydFRvdWNoQ2xvc2VEb3duQW5pbWF0aW9uV2l0aERlbGF5KClcbiAgICAgICAgOiB0aGlzLm1lbnUuX3N0YXJ0VG91Y2hDbG9zZURvd25BbmltYXRpb24oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gU2xpZGUgdGhlIGNsb3NlZCBtZW51IG91dCBvZiB2aWV3IHRvIHRoZSBzaWRlXG4gICAgICAvLyBhbmQgc2xpZGUgYW55IHBhcmVudCBtZW51IGJhY2sgaW50byB2aWV3XG4gICAgICB0aGlzLm1lbnUuX3N0YXJ0VG91Y2hDbG9zZVNpZGVBbmltYXRpb24oKTtcbiAgICAgIHRoaXMuX3BhcmVudE1lbnU/Ll9zdGFydFRvdWNoU3VibWVudUVudGVyQW5pbWF0aW9uKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNldCBhbmltYXRpb24gc3RhdGUgdG8gcGxhY2UgdGhlIG1lbnUgYW5kIGFueSBwYXJlbnQgYXQgdGhlIGdpdmVuXG4gICAqIGhvcml6b250YWwgcG9zaXRpb24sIGkuZS4gZm9sbG93aW5nIHRvdWNoIHBhbiBtb3ZlbWVudC5cbiAgICpcbiAgICogQHBhcmFtIHhPZmZzZXQgSG9yaXpvbnRhbCBvZmZzZXRcbiAgICovXG4gIHByaXZhdGUgYW5pbWF0ZVNldE1lbnVQb3NpdGlvbih4T2Zmc2V0OiBudW1iZXIpIHtcbiAgICB0aGlzLm1lbnUuX3N0YXJ0VG91Y2hQYW5BbmltYXRpb24oeE9mZnNldCk7XG4gICAgaWYgKHRoaXMuX3BhcmVudE1lbnUpIHtcbiAgICAgIHRoaXMuX3BhcmVudE1lbnUuX3N0YXJ0VG91Y2hIaWRlUGFuQW5pbWF0aW9uKHhPZmZzZXQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHN0cmF0ZWd5IGZvciBwb3NpdGlvbmluZyB0aGUgb3ZlcmxheSBkZXBlbmRpbmcgb24gd2hhdCB0eXBlIG9mXG4gICAqIGRldmljZSB0aGUgbWVudSBpcyBiZWluZyBzaG93biBvblxuICAgKi9cbiAgcHJpdmF0ZSBfcG9zaXRpb25TdHJhdGVneSgpOiBQb3NpdGlvblN0cmF0ZWd5IHtcbiAgICByZXR1cm4gdGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJ1xuICAgICAgPyB0aGlzLl90b3VjaFBvc2l0aW9uU3RyYXRlZ3koKVxuICAgICAgOiB0aGlzLl9kZXNrdG9wUG9zaXRpb25TdHJhdGVneSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3RyYXRlZ3kgZm9yIHBvc2l0aW9uaW5nIHRoZSBvdmVybGF5IGZvciB0b3VjaCBkZXZpY2VzOlxuICAgKiBQbGFjZSBjZW50ZXJlZCBhdCB0aGUgYm90dG9tIG9mIHRoZSBzY3JlZW4uXG4gICAqL1xuICBwcml2YXRlIF90b3VjaFBvc2l0aW9uU3RyYXRlZ3koKTogUG9zaXRpb25TdHJhdGVneSB7XG4gICAgcmV0dXJuIHRoaXMuX292ZXJsYXkucG9zaXRpb24oKS5nbG9iYWwoKTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vXG4gIC8vIC0tLSBIZXJlIGJlIHBvb3IgbWFuJ3MgdG91Y2ggZ2VzdHVyZXMgLS0tIC8vXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vXG5cbiAgLy8gVE9ETzogUmVwbGFjZSB3aXRoIEhhbW1lciBvciBvdGhlciBnZXN0dXJlIGxpYnJhcnlcblxuICAvKipcbiAgICogSGFuZGxlcyB0b3VjaCBzdGFydCBldmVudHMgb24gdGhlIG92ZXJsYXkgaG9zdCBlbGVtZW50ICh3cmFwcGVyKS5cbiAgICogTmVlZHMgdG8gYmUgYW4gYXJyb3cgZnVuY3Rpb24gc28gd2UgY2FuIGVhc2lseSB1c2UgYWRkRXZlbnRMaXN0ZW5lciBhbmQgcmVtb3ZlRXZlbnRMaXN0ZW5lci5cbiAgICovXG4gIHByaXZhdGUgX2hhbmRsZU92ZXJsYXlUb3VjaFN0YXJ0ID0gKGV2ZW50OiBUb3VjaEV2ZW50KSA9PiB7XG4gICAgaWYgKHRoaXMubWVudS5faXNBbmltYXRpbmcpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl90b3VjaFN0YXJ0VGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgdGhpcy5fdG91Y2hTdGFydFggPSBldmVudC5jaGFuZ2VkVG91Y2hlc1swXS5jbGllbnRYO1xuICAgIHRoaXMuX3RvdWNoU3RhcnRZID0gZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0uY2xpZW50WTtcbiAgICB0aGlzLl90b3VjaEN1cnJlbnRYID0gdGhpcy5fdG91Y2hTdGFydFg7XG4gICAgdGhpcy5fdG91Y2hDdXJyZW50WSA9IHRoaXMuX3RvdWNoU3RhcnRZO1xuICAgIHRoaXMuX3RvdWNoVHJhbnNsYXRlWCA9IDA7XG4gICAgdGhpcy5fdG91Y2hNYXhYID1cbiAgICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGg7XG4gICAgdGhpcy5fdG91Y2hMb2NrZWRYID0gbnVsbDtcbiAgICB0aGlzLl90b3VjaFRvdWNoaW5nRWxlbWVudCA9IHRydWU7XG4gIH07XG5cbiAgcHJpdmF0ZSBfaGFuZGxlT3ZlcmxheVRvdWNoTW92ZSA9IChldmVudDogVG91Y2hFdmVudCkgPT4ge1xuICAgIGlmICghdGhpcy5fdG91Y2hUb3VjaGluZ0VsZW1lbnQgfHwgdGhpcy5tZW51Ll9pc0FuaW1hdGluZykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl90b3VjaExvY2tlZFgpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl90b3VjaEN1cnJlbnRYID0gZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0uY2xpZW50WDtcbiAgICB0aGlzLl90b3VjaEN1cnJlbnRZID0gZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0uY2xpZW50WTtcblxuICAgIC8vIExvY2sgWC1heGlzIHBhbiBpZiBpbml0aWF0aW5nIHBhbiBvbiBZLWF4aXNcbiAgICBpZiAodGhpcy5fdG91Y2hMb2NrZWRYID09PSBudWxsKSB7XG4gICAgICBjb25zdCBkeSA9IE1hdGguYWJzKHRoaXMuX3RvdWNoQ3VycmVudFkgLSB0aGlzLl90b3VjaFN0YXJ0WSk7XG4gICAgICBjb25zdCBkeCA9IE1hdGguYWJzKHRoaXMuX3RvdWNoQ3VycmVudFggLSB0aGlzLl90b3VjaFN0YXJ0WCk7XG4gICAgICBpZiAoZHggPiAxMCB8fCBkeSA+IDEwKSB7XG4gICAgICAgIHRoaXMuX3RvdWNoTG9ja2VkWCA9IGR5ID4gZHg7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZXN0cmljdCB0byByaWdodCBwYW4vc3dpcGUgYW5kIG1ha2UgbWVudSBtb3ZlbWVudCBleHRyZW1lbHkgc2xvdyB3aGVuXG4gICAgLy8gbW92ZWQgcGFzdCBhbGxvd2VkIGxpbWl0cy5cbiAgICBjb25zdCBtZW51TWFyZ2luID0gMTY7XG4gICAgdGhpcy5fdG91Y2hUcmFuc2xhdGVYID0gdGhpcy5fdG91Y2hDdXJyZW50WCAtIHRoaXMuX3RvdWNoU3RhcnRYO1xuXG4gICAgaWYgKHRoaXMuX3RvdWNoVHJhbnNsYXRlWCA8IDApIHtcbiAgICAgIHRoaXMuX3RvdWNoVHJhbnNsYXRlWCA9IHRoaXMuZWFzZU91dEV4cG8oXG4gICAgICAgIHRoaXMuX3RvdWNoVHJhbnNsYXRlWCxcbiAgICAgICAgMCxcbiAgICAgICAgLW1lbnVNYXJnaW4gLyAyLFxuICAgICAgICB0aGlzLl90b3VjaE1heFggKiAtNFxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKCF0aGlzLl9wYXJlbnRNZW51KSB7XG4gICAgICB0aGlzLl90b3VjaFRyYW5zbGF0ZVggPSB0aGlzLmVhc2VPdXRFeHBvKFxuICAgICAgICB0aGlzLl90b3VjaFRyYW5zbGF0ZVgsXG4gICAgICAgIDAsXG4gICAgICAgIG1lbnVNYXJnaW4gLyAyLFxuICAgICAgICB0aGlzLl90b3VjaE1heFggKiA0XG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAodGhpcy5fdG91Y2hUcmFuc2xhdGVYID4gdGhpcy5fdG91Y2hNYXhYKSB7XG4gICAgICB0aGlzLl90b3VjaFRyYW5zbGF0ZVggPSB0aGlzLmVhc2VPdXRFeHBvKFxuICAgICAgICB0aGlzLl90b3VjaFRyYW5zbGF0ZVggLSB0aGlzLl90b3VjaE1heFgsXG4gICAgICAgIHRoaXMuX3RvdWNoTWF4WCxcbiAgICAgICAgbWVudU1hcmdpbiAvIDIsXG4gICAgICAgIHRoaXMuX3RvdWNoTWF4WCAqIDRcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2V0IG5ldyBzdWIgbWVudSBwb3NpdGlvbiBhbmQgdGVsbCBhbnkgcGFyZW50IHRvIGZvbGxvdztcbiAgICB0aGlzLmFuaW1hdGVTZXRNZW51UG9zaXRpb24odGhpcy5fdG91Y2hUcmFuc2xhdGVYKTtcbiAgfTtcblxuICBwcml2YXRlIF9oYW5kbGVPdmVybGF5VG91Y2hFbmQgPSAoKSA9PiB7XG4gICAgaWYgKCF0aGlzLl90b3VjaFRvdWNoaW5nRWxlbWVudCB8fCB0aGlzLm1lbnUuX2lzQW5pbWF0aW5nKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fdG91Y2hUcmFuc2xhdGVYID0gdGhpcy5fdG91Y2hDdXJyZW50WCAtIHRoaXMuX3RvdWNoU3RhcnRYO1xuICAgIGlmICh0aGlzLl90b3VjaFRyYW5zbGF0ZVggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl90b3VjaFRvdWNoaW5nRWxlbWVudCA9IGZhbHNlO1xuICAgIHRoaXMuX3RvdWNoVGltZVRha2VuID0gbmV3IERhdGUoKS5nZXRUaW1lKCkgLSB0aGlzLl90b3VjaFN0YXJ0VGltZTtcblxuICAgIGNvbnN0IHN3aXBlTWluRGlzdGFuY2UgPSAxMDtcbiAgICBjb25zdCBzd2lwZU1pblRpbWUgPSA1MDtcbiAgICBjb25zdCBzd2lwZU1heFRpbWUgPSAzMDA7XG5cbiAgICBjb25zdCBwYW5uZWRIYWxmd2F5UmlnaHQgPSB0aGlzLl90b3VjaFRyYW5zbGF0ZVggPiB0aGlzLl90b3VjaE1heFggLyAyO1xuICAgIGNvbnN0IHN3aXBlZFJpZ2h0ID1cbiAgICAgIHRoaXMuX3RvdWNoVHJhbnNsYXRlWCA+IHRoaXMuX3RvdWNoTWF4WCAvIHN3aXBlTWluRGlzdGFuY2UgJiZcbiAgICAgIHRoaXMuX3RvdWNoVGltZVRha2VuID4gc3dpcGVNaW5UaW1lICYmXG4gICAgICB0aGlzLl90b3VjaFRpbWVUYWtlbiA8IHN3aXBlTWF4VGltZTtcblxuICAgIGlmICghIXRoaXMuX3BhcmVudE1lbnUgJiYgKHN3aXBlZFJpZ2h0IHx8IHBhbm5lZEhhbGZ3YXlSaWdodCkpIHtcbiAgICAgIC8vIENsb3NlIHN1Ym1lbnUga2V5ZG93bi1zdHlsZTogY2xvc2Ugb25seSB0aGlzIG1lbnUgYW5kIGxlYXZlIHBhcmVudHMgb3BlblxuICAgICAgdGhpcy5tZW51LmNsb3NlZC5lbWl0KCdrZXlkb3duJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFBhbiBlbmRlZCBidXQgdGhlIG1lbnUgd2FzIG5vdCBtb3ZlZCBmYXIgZW5vdWdoLiBSZXNldCBtZW51cyB0b1xuICAgICAgLy8gd2hlcmUgdGhleSB3ZXJlIGJlZm9yZSBwYW5uaW5nIHN0YXJlZC5cbiAgICAgIHRoaXMuYW5pbWF0ZU9wZW5NZW51KCk7XG4gICAgfVxuICB9O1xuXG4gIC8qKlxuICAgKiBSZW1vdmUgdG91Y2ggZGV2aWNlIHBhbi9zd2lwZSBsaXN0ZW5lcnMgZnJvbSBvdmVybGF5IGhvc3QgZWxlbWVudFxuICAgKi9cbiAgcHJpdmF0ZSBhZGRPdmVybGF5TGlzdGVuZXJzKCkge1xuICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaHN0YXJ0JyxcbiAgICAgIHRoaXMuX2hhbmRsZU92ZXJsYXlUb3VjaFN0YXJ0LFxuICAgICAgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zXG4gICAgKTtcblxuICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaG1vdmUnLFxuICAgICAgdGhpcy5faGFuZGxlT3ZlcmxheVRvdWNoTW92ZSxcbiAgICAgIHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9uc1xuICAgICk7XG5cbiAgICB0aGlzLl9vdmVybGF5UmVmLmhvc3RFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICAndG91Y2hlbmQnLFxuICAgICAgdGhpcy5faGFuZGxlT3ZlcmxheVRvdWNoRW5kLFxuICAgICAgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgdG91Y2ggZGV2aWNlIHBhbi9zd2lwZSBsaXN0ZW5lcnMgZnJvbSBvdmVybGF5IGhvc3QgZWxlbWVudFxuICAgKi9cbiAgcHJpdmF0ZSByZW1vdmVPdmVybGF5TGlzdGVuZXJzKCkge1xuICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaHN0YXJ0JyxcbiAgICAgIHRoaXMuX2hhbmRsZU92ZXJsYXlUb3VjaFN0YXJ0LFxuICAgICAgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zXG4gICAgKTtcblxuICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaG1vdmUnLFxuICAgICAgdGhpcy5faGFuZGxlT3ZlcmxheVRvdWNoTW92ZSxcbiAgICAgIHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9uc1xuICAgICk7XG5cbiAgICB0aGlzLl9vdmVybGF5UmVmLmhvc3RFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXG4gICAgICAndG91Y2hlbmQnLFxuICAgICAgdGhpcy5faGFuZGxlT3ZlcmxheVRvdWNoRW5kLFxuICAgICAgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFuZGFyZCBleHBvbmVudGlhbCBlYXNlIG91dCBmdW5jdGlvblxuICAgKlxuICAgKiBAcGFyYW0gY3VycmVudCBDdXJyZW50IHZhbHVlXG4gICAqIEBwYXJhbSBvZmZzZXQgT2Zmc2V0IHZhbHVlLCB0byB3aGljaCBjYWxjdWxhdGVkIHZhbHVlIHdpbGwgYmUgYWRkZWRcbiAgICogQHBhcmFtIHRhcmdldCBUaGUgdGFyZ2V0IHZhbHVlXG4gICAqIEBwYXJhbSBlbmQgVmFsdWUgdG8gd2hpY2ggY3VycmVudCB2YWx1ZSBpcyBjb21wYXJlZFxuICAgKi9cbiAgcHJpdmF0ZSBlYXNlT3V0RXhwbyhcbiAgICBjdXJyZW50OiBudW1iZXIsXG4gICAgb2Zmc2V0OiBudW1iZXIsXG4gICAgdGFyZ2V0OiBudW1iZXIsXG4gICAgZW5kOiBudW1iZXJcbiAgKTogbnVtYmVyIHtcbiAgICByZXR1cm4gY3VycmVudCA9PT0gZW5kXG4gICAgICA/IG9mZnNldCArIHRhcmdldFxuICAgICAgOiB0YXJnZXQgKiAoLU1hdGgucG93KDIsICgtMTAgKiBjdXJyZW50KSAvIGVuZCkgKyAxKSArIG9mZnNldDtcbiAgfVxufVxuIl19