@angular/material 10.0.0-rc.3 → 10.1.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 (627) hide show
  1. package/_theming.scss +17 -17
  2. package/autocomplete/index.metadata.json +1 -1
  3. package/autocomplete/testing/autocomplete-harness.d.ts +2 -0
  4. package/bundles/material-autocomplete-testing.umd.js +11 -0
  5. package/bundles/material-autocomplete-testing.umd.js.map +1 -1
  6. package/bundles/material-autocomplete-testing.umd.min.js +2 -2
  7. package/bundles/material-autocomplete-testing.umd.min.js.map +1 -1
  8. package/bundles/material-autocomplete.umd.js +3 -1
  9. package/bundles/material-autocomplete.umd.js.map +1 -1
  10. package/bundles/material-autocomplete.umd.min.js +5 -5
  11. package/bundles/material-autocomplete.umd.min.js.map +1 -1
  12. package/bundles/material-badge-testing.umd.min.js +1 -1
  13. package/bundles/material-badge-testing.umd.min.js.map +1 -1
  14. package/bundles/material-bottom-sheet-testing.umd.min.js +1 -1
  15. package/bundles/material-bottom-sheet-testing.umd.min.js.map +1 -1
  16. package/bundles/material-button-testing.umd.js +11 -0
  17. package/bundles/material-button-testing.umd.js.map +1 -1
  18. package/bundles/material-button-testing.umd.min.js +2 -2
  19. package/bundles/material-button-testing.umd.min.js.map +1 -1
  20. package/bundles/material-button-toggle-testing.umd.js +11 -0
  21. package/bundles/material-button-toggle-testing.umd.js.map +1 -1
  22. package/bundles/material-button-toggle-testing.umd.min.js +3 -3
  23. package/bundles/material-button-toggle-testing.umd.min.js.map +1 -1
  24. package/bundles/material-button-toggle.umd.js +12 -3
  25. package/bundles/material-button-toggle.umd.js.map +1 -1
  26. package/bundles/material-button-toggle.umd.min.js +2 -2
  27. package/bundles/material-button-toggle.umd.min.js.map +1 -1
  28. package/bundles/material-button.umd.js +7 -2
  29. package/bundles/material-button.umd.js.map +1 -1
  30. package/bundles/material-button.umd.min.js +4 -4
  31. package/bundles/material-button.umd.min.js.map +1 -1
  32. package/bundles/material-card-testing.umd.js +335 -0
  33. package/bundles/material-card-testing.umd.js.map +1 -0
  34. package/bundles/material-card-testing.umd.min.js +44 -0
  35. package/bundles/material-card-testing.umd.min.js.map +1 -0
  36. package/bundles/material-checkbox-testing.umd.js +11 -0
  37. package/bundles/material-checkbox-testing.umd.js.map +1 -1
  38. package/bundles/material-checkbox-testing.umd.min.js +3 -3
  39. package/bundles/material-checkbox-testing.umd.min.js.map +1 -1
  40. package/bundles/material-checkbox.umd.js.map +1 -1
  41. package/bundles/material-chips.umd.js +36 -12
  42. package/bundles/material-chips.umd.js.map +1 -1
  43. package/bundles/material-chips.umd.min.js +4 -4
  44. package/bundles/material-chips.umd.min.js.map +1 -1
  45. package/bundles/material-core-testing.umd.min.js +1 -1
  46. package/bundles/material-core-testing.umd.min.js.map +1 -1
  47. package/bundles/material-core.umd.js +11 -3
  48. package/bundles/material-core.umd.js.map +1 -1
  49. package/bundles/material-core.umd.min.js +11 -11
  50. package/bundles/material-core.umd.min.js.map +1 -1
  51. package/bundles/material-datepicker.umd.js +20 -11
  52. package/bundles/material-datepicker.umd.js.map +1 -1
  53. package/bundles/material-datepicker.umd.min.js +5 -5
  54. package/bundles/material-datepicker.umd.min.js.map +1 -1
  55. package/bundles/material-dialog-testing.umd.min.js +1 -1
  56. package/bundles/material-dialog-testing.umd.min.js.map +1 -1
  57. package/bundles/material-dialog.umd.js +45 -8
  58. package/bundles/material-dialog.umd.js.map +1 -1
  59. package/bundles/material-dialog.umd.min.js +14 -7
  60. package/bundles/material-dialog.umd.min.js.map +1 -1
  61. package/bundles/material-divider-testing.umd.min.js +1 -1
  62. package/bundles/material-divider-testing.umd.min.js.map +1 -1
  63. package/bundles/material-expansion-testing.umd.js +11 -0
  64. package/bundles/material-expansion-testing.umd.js.map +1 -1
  65. package/bundles/material-expansion-testing.umd.min.js +3 -3
  66. package/bundles/material-expansion-testing.umd.min.js.map +1 -1
  67. package/bundles/material-form-field-testing.umd.js +32 -0
  68. package/bundles/material-form-field-testing.umd.js.map +1 -1
  69. package/bundles/material-form-field-testing.umd.min.js +4 -4
  70. package/bundles/material-form-field-testing.umd.min.js.map +1 -1
  71. package/bundles/material-form-field.umd.js +47 -21
  72. package/bundles/material-form-field.umd.js.map +1 -1
  73. package/bundles/material-form-field.umd.min.js +5 -5
  74. package/bundles/material-form-field.umd.min.js.map +1 -1
  75. package/bundles/material-grid-list-testing.umd.min.js +1 -1
  76. package/bundles/material-grid-list-testing.umd.min.js.map +1 -1
  77. package/bundles/material-grid-list.umd.js +2 -2
  78. package/bundles/material-grid-list.umd.js.map +1 -1
  79. package/bundles/material-grid-list.umd.min.js +2 -2
  80. package/bundles/material-grid-list.umd.min.js.map +1 -1
  81. package/bundles/material-input-testing.umd.js +23 -6
  82. package/bundles/material-input-testing.umd.js.map +1 -1
  83. package/bundles/material-input-testing.umd.min.js +3 -3
  84. package/bundles/material-input-testing.umd.min.js.map +1 -1
  85. package/bundles/material-input.umd.js +28 -3
  86. package/bundles/material-input.umd.js.map +1 -1
  87. package/bundles/material-input.umd.min.js +3 -3
  88. package/bundles/material-input.umd.min.js.map +1 -1
  89. package/bundles/material-list-testing.umd.js +33 -0
  90. package/bundles/material-list-testing.umd.js.map +1 -1
  91. package/bundles/material-list-testing.umd.min.js +2 -2
  92. package/bundles/material-list-testing.umd.min.js.map +1 -1
  93. package/bundles/material-list.umd.js +3 -3
  94. package/bundles/material-list.umd.min.js +1 -1
  95. package/bundles/material-list.umd.min.js.map +1 -1
  96. package/bundles/material-menu-testing.umd.js +22 -0
  97. package/bundles/material-menu-testing.umd.js.map +1 -1
  98. package/bundles/material-menu-testing.umd.min.js +2 -2
  99. package/bundles/material-menu-testing.umd.min.js.map +1 -1
  100. package/bundles/material-menu.umd.js +13 -2
  101. package/bundles/material-menu.umd.js.map +1 -1
  102. package/bundles/material-menu.umd.min.js +4 -4
  103. package/bundles/material-menu.umd.min.js.map +1 -1
  104. package/bundles/material-paginator-testing.umd.min.js +1 -1
  105. package/bundles/material-paginator-testing.umd.min.js.map +1 -1
  106. package/bundles/material-progress-bar-testing.umd.min.js +1 -1
  107. package/bundles/material-progress-bar-testing.umd.min.js.map +1 -1
  108. package/bundles/material-progress-spinner-testing.umd.js +1 -1
  109. package/bundles/material-progress-spinner-testing.umd.js.map +1 -1
  110. package/bundles/material-progress-spinner-testing.umd.min.js +2 -2
  111. package/bundles/material-progress-spinner-testing.umd.min.js.map +1 -1
  112. package/bundles/material-progress-spinner.umd.js +2 -2
  113. package/bundles/material-progress-spinner.umd.min.js +3 -3
  114. package/bundles/material-progress-spinner.umd.min.js.map +1 -1
  115. package/bundles/material-radio-testing.umd.js +11 -0
  116. package/bundles/material-radio-testing.umd.js.map +1 -1
  117. package/bundles/material-radio-testing.umd.min.js +3 -3
  118. package/bundles/material-radio-testing.umd.min.js.map +1 -1
  119. package/bundles/material-radio.umd.js +15 -5
  120. package/bundles/material-radio.umd.js.map +1 -1
  121. package/bundles/material-radio.umd.min.js +2 -2
  122. package/bundles/material-radio.umd.min.js.map +1 -1
  123. package/bundles/material-select-testing.umd.js +11 -0
  124. package/bundles/material-select-testing.umd.js.map +1 -1
  125. package/bundles/material-select-testing.umd.min.js +2 -2
  126. package/bundles/material-select-testing.umd.min.js.map +1 -1
  127. package/bundles/material-select.umd.js +11 -3
  128. package/bundles/material-select.umd.js.map +1 -1
  129. package/bundles/material-select.umd.min.js +4 -4
  130. package/bundles/material-select.umd.min.js.map +1 -1
  131. package/bundles/material-sidenav-testing.umd.min.js +1 -1
  132. package/bundles/material-sidenav-testing.umd.min.js.map +1 -1
  133. package/bundles/material-sidenav.umd.js +41 -17
  134. package/bundles/material-sidenav.umd.js.map +1 -1
  135. package/bundles/material-sidenav.umd.min.js +2 -2
  136. package/bundles/material-sidenav.umd.min.js.map +1 -1
  137. package/bundles/material-slide-toggle-testing.umd.js +11 -0
  138. package/bundles/material-slide-toggle-testing.umd.js.map +1 -1
  139. package/bundles/material-slide-toggle-testing.umd.min.js +2 -2
  140. package/bundles/material-slide-toggle-testing.umd.min.js.map +1 -1
  141. package/bundles/material-slide-toggle.umd.js.map +1 -1
  142. package/bundles/material-slider-testing.umd.js +11 -0
  143. package/bundles/material-slider-testing.umd.js.map +1 -1
  144. package/bundles/material-slider-testing.umd.min.js +2 -2
  145. package/bundles/material-slider-testing.umd.min.js.map +1 -1
  146. package/bundles/material-snack-bar-testing.umd.min.js +1 -1
  147. package/bundles/material-snack-bar-testing.umd.min.js.map +1 -1
  148. package/bundles/material-snack-bar.umd.js +47 -39
  149. package/bundles/material-snack-bar.umd.js.map +1 -1
  150. package/bundles/material-snack-bar.umd.min.js +2 -2
  151. package/bundles/material-snack-bar.umd.min.js.map +1 -1
  152. package/bundles/material-sort-testing.umd.js +10 -10
  153. package/bundles/material-sort-testing.umd.js.map +1 -1
  154. package/bundles/material-sort-testing.umd.min.js +3 -3
  155. package/bundles/material-sort-testing.umd.min.js.map +1 -1
  156. package/bundles/material-sort.umd.js +25 -12
  157. package/bundles/material-sort.umd.js.map +1 -1
  158. package/bundles/material-sort.umd.min.js +5 -5
  159. package/bundles/material-sort.umd.min.js.map +1 -1
  160. package/bundles/material-table-testing.umd.min.js +1 -1
  161. package/bundles/material-table-testing.umd.min.js.map +1 -1
  162. package/bundles/material-table.umd.min.js +2 -2
  163. package/bundles/material-table.umd.min.js.map +1 -1
  164. package/bundles/material-tabs-testing.umd.min.js +1 -1
  165. package/bundles/material-tabs-testing.umd.min.js.map +1 -1
  166. package/bundles/material-tabs.umd.js +23 -4
  167. package/bundles/material-tabs.umd.js.map +1 -1
  168. package/bundles/material-tabs.umd.min.js +5 -12
  169. package/bundles/material-tabs.umd.min.js.map +1 -1
  170. package/bundles/material-toolbar-testing.umd.js +330 -0
  171. package/bundles/material-toolbar-testing.umd.js.map +1 -0
  172. package/bundles/material-toolbar-testing.umd.min.js +44 -0
  173. package/bundles/material-toolbar-testing.umd.min.js.map +1 -0
  174. package/bundles/material-tooltip-testing.umd.min.js +1 -1
  175. package/bundles/material-tooltip-testing.umd.min.js.map +1 -1
  176. package/bundles/material-tooltip.umd.js +14 -1
  177. package/bundles/material-tooltip.umd.js.map +1 -1
  178. package/bundles/material-tooltip.umd.min.js +3 -3
  179. package/bundles/material-tooltip.umd.min.js.map +1 -1
  180. package/bundles/material-tree.umd.js.map +1 -1
  181. package/button/_button-base.scss +1 -1
  182. package/button/_button-theme.scss +8 -8
  183. package/button/index.metadata.json +1 -1
  184. package/button/testing/button-harness.d.ts +2 -0
  185. package/button-toggle/button-toggle.d.ts +10 -3
  186. package/button-toggle/index.metadata.json +1 -1
  187. package/button-toggle/testing/button-toggle-harness.d.ts +2 -0
  188. package/card/testing/card-harness-filters.d.ts +17 -0
  189. package/card/testing/card-harness.d.ts +36 -0
  190. package/card/testing/index.d.ts +8 -0
  191. package/card/testing/package.json +9 -0
  192. package/card/testing/public-api.d.ts +9 -0
  193. package/checkbox/index.metadata.json +1 -1
  194. package/checkbox/testing/checkbox-harness.d.ts +2 -0
  195. package/chips/chip.d.ts +19 -1
  196. package/chips/index.metadata.json +1 -1
  197. package/core/focus-indicators/_focus-indicators.scss +6 -6
  198. package/core/index.metadata.json +1 -1
  199. package/core/option/optgroup.d.ts +7 -0
  200. package/core/ripple/ripple-ref.d.ts +21 -2
  201. package/core/ripple/ripple-renderer.d.ts +1 -19
  202. package/core/ripple/ripple.d.ts +2 -2
  203. package/core/style/_list-common.scss +1 -1
  204. package/datepicker/date-range-input-parts.d.ts +2 -4
  205. package/datepicker/date-range-input.d.ts +4 -4
  206. package/datepicker/date-range-picker.d.ts +10 -3
  207. package/datepicker/datepicker.d.ts +2 -3
  208. package/datepicker/index.metadata.json +1 -1
  209. package/datepicker/public-api.d.ts +1 -1
  210. package/dialog/dialog-container.d.ts +9 -2
  211. package/dialog/dialog-content-directives.d.ts +1 -0
  212. package/dialog/dialog-ref.d.ts +7 -0
  213. package/dialog/index.metadata.json +1 -1
  214. package/esm2015/autocomplete/autocomplete-module.js +18 -22
  215. package/esm2015/autocomplete/autocomplete-origin.js +16 -20
  216. package/esm2015/autocomplete/autocomplete-trigger.js +519 -521
  217. package/esm2015/autocomplete/autocomplete.js +126 -130
  218. package/esm2015/autocomplete/testing/autocomplete-harness.js +99 -97
  219. package/esm2015/badge/badge-module.js +13 -17
  220. package/esm2015/badge/badge.js +184 -188
  221. package/esm2015/badge/testing/badge-harness.js +74 -78
  222. package/esm2015/bottom-sheet/bottom-sheet-container.js +161 -165
  223. package/esm2015/bottom-sheet/bottom-sheet-module.js +15 -19
  224. package/esm2015/bottom-sheet/bottom-sheet.js +124 -128
  225. package/esm2015/bottom-sheet/testing/bottom-sheet-harness.js +29 -33
  226. package/esm2015/button/button-module.js +20 -24
  227. package/esm2015/button/button.js +111 -114
  228. package/esm2015/button/testing/button-harness.js +60 -58
  229. package/esm2015/button-toggle/button-toggle-module.js +10 -14
  230. package/esm2015/button-toggle/button-toggle.js +368 -368
  231. package/esm2015/button-toggle/testing/button-toggle-group-harness.js +42 -46
  232. package/esm2015/button-toggle/testing/button-toggle-harness.js +113 -111
  233. package/esm2015/card/card-module.js +30 -34
  234. package/esm2015/card/card.js +147 -203
  235. package/esm2015/card/testing/card-harness-filters.js +8 -0
  236. package/esm2015/card/testing/card-harness.js +52 -0
  237. package/esm2015/card/testing/index.js +9 -0
  238. package/esm2015/card/testing/public-api.js +10 -0
  239. package/esm2015/card/testing/testing.externs.js +0 -0
  240. package/esm2015/checkbox/checkbox-module.js +21 -29
  241. package/esm2015/checkbox/checkbox-required-validator.js +9 -13
  242. package/esm2015/checkbox/checkbox.js +315 -319
  243. package/esm2015/checkbox/testing/checkbox-harness.js +150 -148
  244. package/esm2015/chips/chip-input.js +119 -123
  245. package/esm2015/chips/chip-list.js +572 -576
  246. package/esm2015/chips/chip.js +333 -328
  247. package/esm2015/chips/chips-module.js +16 -20
  248. package/esm2015/core/animation/animation.js +12 -20
  249. package/esm2015/core/common-behaviors/common-module.js +91 -95
  250. package/esm2015/core/datetime/index.js +19 -27
  251. package/esm2015/core/datetime/native-date-adapter.js +202 -206
  252. package/esm2015/core/error/error-options.js +16 -24
  253. package/esm2015/core/line/line.js +18 -26
  254. package/esm2015/core/option/index.js +10 -14
  255. package/esm2015/core/option/optgroup.js +36 -33
  256. package/esm2015/core/option/option.js +181 -185
  257. package/esm2015/core/ripple/index.js +10 -14
  258. package/esm2015/core/ripple/ripple-ref.js +1 -1
  259. package/esm2015/core/ripple/ripple-renderer.js +1 -1
  260. package/esm2015/core/ripple/ripple.js +102 -106
  261. package/esm2015/core/selection/index.js +9 -13
  262. package/esm2015/core/selection/pseudo-checkbox/pseudo-checkbox.js +32 -36
  263. package/esm2015/core/testing/optgroup-harness.js +39 -43
  264. package/esm2015/core/testing/option-harness.js +51 -55
  265. package/esm2015/core/version.js +1 -1
  266. package/esm2015/datepicker/calendar-body.js +214 -218
  267. package/esm2015/datepicker/calendar.js +295 -303
  268. package/esm2015/datepicker/date-range-input-parts.js +214 -229
  269. package/esm2015/datepicker/date-range-input.js +244 -242
  270. package/esm2015/datepicker/date-range-picker.js +19 -23
  271. package/esm2015/datepicker/date-range-selection-strategy.js +31 -35
  272. package/esm2015/datepicker/date-selection-model.js +110 -122
  273. package/esm2015/datepicker/datepicker-base.js +418 -426
  274. package/esm2015/datepicker/datepicker-input-base.js +227 -224
  275. package/esm2015/datepicker/datepicker-input.js +111 -115
  276. package/esm2015/datepicker/datepicker-intl.js +37 -41
  277. package/esm2015/datepicker/datepicker-module.js +62 -66
  278. package/esm2015/datepicker/datepicker-toggle.js +81 -89
  279. package/esm2015/datepicker/datepicker.js +13 -17
  280. package/esm2015/datepicker/month-view.js +283 -287
  281. package/esm2015/datepicker/multi-year-view.js +198 -202
  282. package/esm2015/datepicker/public-api.js +2 -2
  283. package/esm2015/datepicker/year-view.js +220 -224
  284. package/esm2015/dialog/dialog-container.js +175 -164
  285. package/esm2015/dialog/dialog-content-directives.js +105 -114
  286. package/esm2015/dialog/dialog-module.js +32 -36
  287. package/esm2015/dialog/dialog-ref.js +17 -3
  288. package/esm2015/dialog/dialog.js +236 -240
  289. package/esm2015/dialog/testing/dialog-harness.js +58 -62
  290. package/esm2015/divider/divider-module.js +10 -14
  291. package/esm2015/divider/divider.js +33 -37
  292. package/esm2015/divider/testing/divider-harness.js +16 -20
  293. package/esm2015/expansion/accordion.js +73 -77
  294. package/esm2015/expansion/expansion-module.js +26 -30
  295. package/esm2015/expansion/expansion-panel-content.js +13 -17
  296. package/esm2015/expansion/expansion-panel-header.js +168 -180
  297. package/esm2015/expansion/expansion-panel.js +144 -152
  298. package/esm2015/expansion/testing/accordion-harness.js +24 -28
  299. package/esm2015/expansion/testing/expansion-harness.js +136 -134
  300. package/esm2015/form-field/error.js +26 -23
  301. package/esm2015/form-field/form-field-control.js +6 -10
  302. package/esm2015/form-field/form-field-module.js +31 -35
  303. package/esm2015/form-field/form-field.js +407 -409
  304. package/esm2015/form-field/hint.js +35 -29
  305. package/esm2015/form-field/label.js +8 -12
  306. package/esm2015/form-field/placeholder.js +8 -12
  307. package/esm2015/form-field/prefix.js +16 -13
  308. package/esm2015/form-field/suffix.js +16 -13
  309. package/esm2015/form-field/testing/form-field-harness.js +220 -206
  310. package/esm2015/grid-list/grid-list-module.js +26 -30
  311. package/esm2015/grid-list/grid-list.js +108 -112
  312. package/esm2015/grid-list/grid-tile.js +91 -111
  313. package/esm2015/grid-list/testing/grid-list-harness.js +62 -66
  314. package/esm2015/grid-list/testing/grid-tile-harness.js +69 -73
  315. package/esm2015/grid-list/tile-styler.js +1 -1
  316. package/esm2015/icon/icon-module.js +10 -14
  317. package/esm2015/icon/icon-registry.js +406 -410
  318. package/esm2015/icon/icon.js +228 -232
  319. package/esm2015/icon/testing/fake-icon-registry.js +66 -74
  320. package/esm2015/input/autosize.js +30 -34
  321. package/esm2015/input/input-module.js +21 -25
  322. package/esm2015/input/input.js +305 -284
  323. package/esm2015/input/testing/input-harness.js +129 -123
  324. package/esm2015/list/list-module.js +32 -36
  325. package/esm2015/list/list.js +165 -189
  326. package/esm2015/list/selection-list.js +503 -511
  327. package/esm2015/list/testing/action-list-harness.js +55 -57
  328. package/esm2015/list/testing/list-harness.js +31 -39
  329. package/esm2015/list/testing/list-item-harness-base.js +13 -17
  330. package/esm2015/list/testing/nav-list-harness.js +62 -64
  331. package/esm2015/list/testing/selection-list-harness.js +136 -138
  332. package/esm2015/menu/menu-content.js +74 -71
  333. package/esm2015/menu/menu-item.js +119 -123
  334. package/esm2015/menu/menu-module.js +29 -37
  335. package/esm2015/menu/menu-panel.js +1 -1
  336. package/esm2015/menu/menu-trigger.js +402 -405
  337. package/esm2015/menu/menu.js +329 -339
  338. package/esm2015/menu/testing/menu-harness.js +193 -189
  339. package/esm2015/paginator/paginator-intl.js +36 -40
  340. package/esm2015/paginator/paginator-module.js +16 -20
  341. package/esm2015/paginator/paginator.js +205 -209
  342. package/esm2015/paginator/testing/paginator-harness.js +91 -95
  343. package/esm2015/progress-bar/progress-bar-module.js +10 -14
  344. package/esm2015/progress-bar/progress-bar.js +114 -118
  345. package/esm2015/progress-bar/testing/progress-bar-harness.js +27 -31
  346. package/esm2015/progress-spinner/progress-spinner-module.js +17 -21
  347. package/esm2015/progress-spinner/progress-spinner.js +181 -189
  348. package/esm2015/progress-spinner/testing/progress-spinner-harness.js +28 -32
  349. package/esm2015/radio/radio-module.js +10 -14
  350. package/esm2015/radio/radio.js +437 -444
  351. package/esm2015/radio/testing/radio-harness.js +241 -243
  352. package/esm2015/select/select-module.js +23 -27
  353. package/esm2015/select/select.js +917 -918
  354. package/esm2015/select/testing/select-harness.js +138 -136
  355. package/esm2015/sidenav/drawer.js +632 -620
  356. package/esm2015/sidenav/sidenav-module.js +31 -35
  357. package/esm2015/sidenav/sidenav.js +104 -116
  358. package/esm2015/sidenav/testing/drawer-harness.js +40 -44
  359. package/esm2015/sidenav/testing/sidenav-harness.js +20 -24
  360. package/esm2015/slide-toggle/slide-toggle-module.js +27 -35
  361. package/esm2015/slide-toggle/slide-toggle-required-validator.js +9 -13
  362. package/esm2015/slide-toggle/slide-toggle.js +184 -188
  363. package/esm2015/slide-toggle/testing/slide-toggle-harness.js +123 -121
  364. package/esm2015/slider/slider-module.js +10 -14
  365. package/esm2015/slider/slider.js +640 -644
  366. package/esm2015/slider/testing/slider-harness.js +129 -127
  367. package/esm2015/snack-bar/simple-snack-bar.js +32 -36
  368. package/esm2015/snack-bar/snack-bar-container.js +144 -148
  369. package/esm2015/snack-bar/snack-bar-module.js +17 -21
  370. package/esm2015/snack-bar/snack-bar-ref.js +1 -1
  371. package/esm2015/snack-bar/snack-bar.js +208 -205
  372. package/esm2015/snack-bar/testing/snack-bar-harness.js +112 -116
  373. package/esm2015/sort/sort-header-intl.js +21 -21
  374. package/esm2015/sort/sort-header.js +200 -194
  375. package/esm2015/sort/sort-module.js +11 -15
  376. package/esm2015/sort/sort.js +92 -96
  377. package/esm2015/sort/testing/sort-harness.js +28 -32
  378. package/esm2015/sort/testing/sort-header-harness.js +66 -67
  379. package/esm2015/stepper/step-header.js +78 -82
  380. package/esm2015/stepper/step-label.js +8 -12
  381. package/esm2015/stepper/stepper-button.js +23 -31
  382. package/esm2015/stepper/stepper-icon.js +16 -20
  383. package/esm2015/stepper/stepper-intl.js +15 -19
  384. package/esm2015/stepper/stepper-module.js +40 -44
  385. package/esm2015/stepper/stepper.js +139 -155
  386. package/esm2015/table/cell.js +94 -122
  387. package/esm2015/table/row.js +90 -118
  388. package/esm2015/table/table-module.js +13 -17
  389. package/esm2015/table/table.js +26 -30
  390. package/esm2015/table/testing/cell-harness.js +56 -68
  391. package/esm2015/table/testing/row-harness.js +90 -102
  392. package/esm2015/table/testing/table-harness.js +65 -69
  393. package/esm2015/table/text-column.js +17 -21
  394. package/esm2015/tabs/index.js +4 -2
  395. package/esm2015/tabs/ink-bar.js +55 -59
  396. package/esm2015/tabs/paginated-tab-header.js +415 -419
  397. package/esm2015/tabs/tab-body.js +179 -191
  398. package/esm2015/tabs/tab-content.js +21 -16
  399. package/esm2015/tabs/tab-group.js +263 -271
  400. package/esm2015/tabs/tab-header.js +69 -77
  401. package/esm2015/tabs/tab-label-wrapper.js +29 -33
  402. package/esm2015/tabs/tab-label.js +16 -13
  403. package/esm2015/tabs/tab-nav-bar/tab-nav-bar.js +199 -215
  404. package/esm2015/tabs/tab.js +80 -83
  405. package/esm2015/tabs/tabs-module.js +38 -42
  406. package/esm2015/tabs/testing/tab-group-harness.js +52 -56
  407. package/esm2015/tabs/testing/tab-harness.js +78 -82
  408. package/esm2015/toolbar/testing/index.js +9 -0
  409. package/esm2015/toolbar/testing/public-api.js +10 -0
  410. package/esm2015/toolbar/testing/testing.externs.js +0 -0
  411. package/esm2015/toolbar/testing/toolbar-harness-filters.js +8 -0
  412. package/esm2015/toolbar/testing/toolbar-harness.js +47 -0
  413. package/esm2015/toolbar/toolbar-module.js +10 -14
  414. package/esm2015/toolbar/toolbar.js +61 -69
  415. package/esm2015/tooltip/testing/tooltip-harness.js +43 -47
  416. package/esm2015/tooltip/tooltip-module.js +17 -21
  417. package/esm2015/tooltip/tooltip.js +502 -497
  418. package/esm2015/tree/data-source/flat-data-source.js +1 -1
  419. package/esm2015/tree/node.js +99 -111
  420. package/esm2015/tree/outlet.js +19 -23
  421. package/esm2015/tree/padding.js +13 -17
  422. package/esm2015/tree/toggle.js +15 -19
  423. package/esm2015/tree/tree-module.js +10 -14
  424. package/esm2015/tree/tree.js +23 -27
  425. package/expansion/testing/expansion-harness.d.ts +2 -0
  426. package/fesm2015/autocomplete/testing.js +98 -95
  427. package/fesm2015/autocomplete/testing.js.map +1 -1
  428. package/fesm2015/autocomplete.js +677 -687
  429. package/fesm2015/autocomplete.js.map +1 -1
  430. package/fesm2015/badge/testing.js +73 -76
  431. package/fesm2015/badge/testing.js.map +1 -1
  432. package/fesm2015/badge.js +195 -201
  433. package/fesm2015/badge.js.map +1 -1
  434. package/fesm2015/bottom-sheet/testing.js +28 -31
  435. package/fesm2015/bottom-sheet/testing.js.map +1 -1
  436. package/fesm2015/bottom-sheet.js +297 -306
  437. package/fesm2015/bottom-sheet.js.map +1 -1
  438. package/fesm2015/button/testing.js +59 -56
  439. package/fesm2015/button/testing.js.map +1 -1
  440. package/fesm2015/button-toggle/testing.js +155 -155
  441. package/fesm2015/button-toggle/testing.js.map +1 -1
  442. package/fesm2015/button-toggle.js +377 -378
  443. package/fesm2015/button-toggle.js.map +1 -1
  444. package/fesm2015/button.js +129 -133
  445. package/fesm2015/button.js.map +1 -1
  446. package/fesm2015/card/testing.js +79 -0
  447. package/fesm2015/card/testing.js.map +1 -0
  448. package/fesm2015/card.js +175 -220
  449. package/fesm2015/card.js.map +1 -1
  450. package/fesm2015/checkbox/testing.js +149 -146
  451. package/fesm2015/checkbox/testing.js.map +1 -1
  452. package/fesm2015/checkbox.js +342 -354
  453. package/fesm2015/checkbox.js.map +1 -1
  454. package/fesm2015/chips.js +1039 -1039
  455. package/fesm2015/chips.js.map +1 -1
  456. package/fesm2015/core/testing.js +88 -94
  457. package/fesm2015/core/testing.js.map +1 -1
  458. package/fesm2015/core.js +729 -773
  459. package/fesm2015/core.js.map +1 -1
  460. package/fesm2015/datepicker.js +2821 -2884
  461. package/fesm2015/datepicker.js.map +1 -1
  462. package/fesm2015/dialog/testing.js +57 -60
  463. package/fesm2015/dialog/testing.js.map +1 -1
  464. package/fesm2015/dialog.js +564 -549
  465. package/fesm2015/dialog.js.map +1 -1
  466. package/fesm2015/divider/testing.js +15 -18
  467. package/fesm2015/divider/testing.js.map +1 -1
  468. package/fesm2015/divider.js +41 -47
  469. package/fesm2015/divider.js.map +1 -1
  470. package/fesm2015/expansion/testing.js +159 -159
  471. package/fesm2015/expansion/testing.js.map +1 -1
  472. package/fesm2015/expansion.js +422 -446
  473. package/fesm2015/expansion.js.map +1 -1
  474. package/fesm2015/form-field/testing.js +219 -204
  475. package/fesm2015/form-field/testing.js.map +1 -1
  476. package/fesm2015/form-field.js +538 -532
  477. package/fesm2015/form-field.js.map +1 -1
  478. package/fesm2015/grid-list/testing.js +129 -135
  479. package/fesm2015/grid-list/testing.js.map +1 -1
  480. package/fesm2015/grid-list.js +221 -242
  481. package/fesm2015/grid-list.js.map +1 -1
  482. package/fesm2015/icon/testing.js +65 -71
  483. package/fesm2015/icon/testing.js.map +1 -1
  484. package/fesm2015/icon.js +660 -669
  485. package/fesm2015/icon.js.map +1 -1
  486. package/fesm2015/input/testing.js +128 -121
  487. package/fesm2015/input/testing.js.map +1 -1
  488. package/fesm2015/input.js +353 -337
  489. package/fesm2015/input.js.map +1 -1
  490. package/fesm2015/list/testing.js +298 -307
  491. package/fesm2015/list/testing.js.map +1 -1
  492. package/fesm2015/list.js +698 -725
  493. package/fesm2015/list.js.map +1 -1
  494. package/fesm2015/menu/testing.js +192 -186
  495. package/fesm2015/menu/testing.js.map +1 -1
  496. package/fesm2015/menu.js +948 -962
  497. package/fesm2015/menu.js.map +1 -1
  498. package/fesm2015/paginator/testing.js +90 -93
  499. package/fesm2015/paginator/testing.js.map +1 -1
  500. package/fesm2015/paginator.js +247 -256
  501. package/fesm2015/paginator.js.map +1 -1
  502. package/fesm2015/progress-bar/testing.js +26 -29
  503. package/fesm2015/progress-bar/testing.js.map +1 -1
  504. package/fesm2015/progress-bar.js +122 -128
  505. package/fesm2015/progress-bar.js.map +1 -1
  506. package/fesm2015/progress-spinner/testing.js +27 -30
  507. package/fesm2015/progress-spinner/testing.js.map +1 -1
  508. package/fesm2015/progress-spinner.js +196 -205
  509. package/fesm2015/progress-spinner.js.map +1 -1
  510. package/fesm2015/radio/testing.js +240 -240
  511. package/fesm2015/radio/testing.js.map +1 -1
  512. package/fesm2015/radio.js +447 -453
  513. package/fesm2015/radio.js.map +1 -1
  514. package/fesm2015/select/testing.js +137 -134
  515. package/fesm2015/select/testing.js.map +1 -1
  516. package/fesm2015/select.js +939 -941
  517. package/fesm2015/select.js.map +1 -1
  518. package/fesm2015/sidenav/testing.js +58 -64
  519. package/fesm2015/sidenav/testing.js.map +1 -1
  520. package/fesm2015/sidenav.js +765 -762
  521. package/fesm2015/sidenav.js.map +1 -1
  522. package/fesm2015/slide-toggle/testing.js +122 -119
  523. package/fesm2015/slide-toggle/testing.js.map +1 -1
  524. package/fesm2015/slide-toggle.js +217 -229
  525. package/fesm2015/slide-toggle.js.map +1 -1
  526. package/fesm2015/slider/testing.js +128 -125
  527. package/fesm2015/slider/testing.js.map +1 -1
  528. package/fesm2015/slider.js +648 -654
  529. package/fesm2015/slider.js.map +1 -1
  530. package/fesm2015/snack-bar/testing.js +111 -114
  531. package/fesm2015/snack-bar/testing.js.map +1 -1
  532. package/fesm2015/snack-bar.js +426 -431
  533. package/fesm2015/snack-bar.js.map +1 -1
  534. package/fesm2015/sort/testing.js +92 -95
  535. package/fesm2015/sort/testing.js.map +1 -1
  536. package/fesm2015/sort.js +320 -318
  537. package/fesm2015/sort.js.map +1 -1
  538. package/fesm2015/stepper.js +312 -345
  539. package/fesm2015/stepper.js.map +1 -1
  540. package/fesm2015/table/testing.js +208 -229
  541. package/fesm2015/table/testing.js.map +1 -1
  542. package/fesm2015/table.js +235 -286
  543. package/fesm2015/table.js.map +1 -1
  544. package/fesm2015/tabs/testing.js +128 -134
  545. package/fesm2015/tabs/testing.js.map +1 -1
  546. package/fesm2015/tabs.js +1362 -1399
  547. package/fesm2015/tabs.js.map +1 -1
  548. package/fesm2015/toolbar/testing.js +74 -0
  549. package/fesm2015/toolbar/testing.js.map +1 -0
  550. package/fesm2015/toolbar.js +69 -78
  551. package/fesm2015/toolbar.js.map +1 -1
  552. package/fesm2015/tooltip/testing.js +42 -45
  553. package/fesm2015/tooltip/testing.js.map +1 -1
  554. package/fesm2015/tooltip.js +517 -513
  555. package/fesm2015/tooltip.js.map +1 -1
  556. package/fesm2015/tree.js +173 -197
  557. package/fesm2015/tree.js.map +1 -1
  558. package/form-field/error.d.ts +7 -0
  559. package/form-field/hint.d.ts +10 -0
  560. package/form-field/index.metadata.json +1 -1
  561. package/form-field/prefix.d.ts +7 -0
  562. package/form-field/suffix.d.ts +7 -0
  563. package/form-field/testing/form-field-harness.d.ts +8 -0
  564. package/grid-list/grid-list.d.ts +2 -1
  565. package/grid-list/index.metadata.json +1 -1
  566. package/grid-list/tile-styler.d.ts +10 -5
  567. package/input/_input-theme.scss +2 -2
  568. package/input/index.metadata.json +1 -1
  569. package/input/input.d.ts +6 -2
  570. package/input/testing/input-harness.d.ts +2 -0
  571. package/list/index.metadata.json +1 -1
  572. package/list/testing/action-list-harness.d.ts +2 -0
  573. package/list/testing/nav-list-harness.d.ts +2 -0
  574. package/list/testing/selection-list-harness.d.ts +2 -0
  575. package/menu/index.metadata.json +1 -1
  576. package/menu/menu-content.d.ts +7 -1
  577. package/menu/menu-panel.d.ts +1 -0
  578. package/menu/menu.d.ts +4 -0
  579. package/menu/testing/menu-harness.d.ts +4 -0
  580. package/package.json +6 -6
  581. package/prebuilt-themes/deeppurple-amber.css +1 -1
  582. package/prebuilt-themes/indigo-pink.css +1 -1
  583. package/prebuilt-themes/pink-bluegrey.css +1 -1
  584. package/prebuilt-themes/purple-green.css +1 -1
  585. package/progress-spinner/index.metadata.json +1 -1
  586. package/radio/index.metadata.json +1 -1
  587. package/radio/radio.d.ts +6 -0
  588. package/radio/testing/radio-harness.d.ts +2 -0
  589. package/schematics/migration.json +5 -0
  590. package/schematics/ng-add/index.js +2 -2
  591. package/schematics/ng-generate/navigation/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template +3 -3
  592. package/schematics/ng-generate/navigation/schema.json +5 -0
  593. package/schematics/ng-update/data/index.js +1 -1
  594. package/schematics/ng-update/index.d.ts +2 -0
  595. package/schematics/ng-update/index.js +7 -2
  596. package/schematics/ng-update/migrations/hammer-gestures-v9/hammer-gestures-migration.js +639 -639
  597. package/schematics/ng-update/migrations/misc-ripples-v7/ripple-speed-factor-migration.js +1 -1
  598. package/select/index.metadata.json +1 -1
  599. package/select/select.d.ts +6 -0
  600. package/select/testing/select-harness.d.ts +2 -0
  601. package/sidenav/drawer.d.ts +15 -3
  602. package/sidenav/index.metadata.json +1 -1
  603. package/slide-toggle/index.metadata.json +1 -1
  604. package/slide-toggle/testing/slide-toggle-harness.d.ts +2 -0
  605. package/slider/testing/slider-harness.d.ts +2 -0
  606. package/snack-bar/index.metadata.json +1 -1
  607. package/snack-bar/simple-snack-bar.d.ts +13 -1
  608. package/snack-bar/snack-bar-container.d.ts +16 -3
  609. package/snack-bar/snack-bar-ref.d.ts +3 -3
  610. package/snack-bar/snack-bar.d.ts +10 -3
  611. package/sort/index.metadata.json +1 -1
  612. package/sort/sort-header-intl.d.ts +5 -1
  613. package/sort/sort-header.d.ts +3 -1
  614. package/sort/testing/sort-header-harness.d.ts +6 -2
  615. package/tabs/index.d.ts +3 -1
  616. package/tabs/index.metadata.json +1 -1
  617. package/tabs/tab-content.d.ts +7 -1
  618. package/tabs/tab-label.d.ts +7 -0
  619. package/toolbar/testing/index.d.ts +8 -0
  620. package/toolbar/testing/package.json +9 -0
  621. package/toolbar/testing/public-api.d.ts +9 -0
  622. package/toolbar/testing/toolbar-harness-filters.d.ts +13 -0
  623. package/toolbar/testing/toolbar-harness.d.ts +31 -0
  624. package/tooltip/index.metadata.json +1 -1
  625. package/tooltip/tooltip.d.ts +1 -0
  626. package/tree/data-source/flat-data-source.d.ts +4 -4
  627. package/tree/index.metadata.json +1 -1
@@ -12,7 +12,6 @@ const core_1 = require("@angular-devkit/core");
12
12
  const schematics_1 = require("@angular/cdk/schematics");
13
13
  const change_1 = require("@schematics/angular/utility/change");
14
14
  const fs_1 = require("fs");
15
- const path_1 = require("path");
16
15
  const ts = require("typescript");
17
16
  const find_hammer_script_tags_1 = require("./find-hammer-script-tags");
18
17
  const find_main_module_1 = require("./find-main-module");
@@ -29,696 +28,697 @@ const HAMMER_MODULE_NAME = 'HammerModule';
29
28
  const HAMMER_MODULE_IMPORT = '@angular/platform-browser';
30
29
  const HAMMER_MODULE_SPECIFIER = 'hammerjs';
31
30
  const CANNOT_REMOVE_REFERENCE_ERROR = `Cannot remove reference to "GestureConfig". Please remove manually.`;
32
- let HammerGesturesMigration = /** @class */ (() => {
33
- class HammerGesturesMigration extends schematics_1.DevkitMigration {
34
- constructor() {
35
- super(...arguments);
36
- // Only enable this rule if the migration targets v9 or v10 and is running for a non-test
37
- // target. We cannot migrate test targets since they have a limited scope
38
- // (in regards to source files) and therefore the HammerJS usage detection can be incorrect.
39
- this.enabled = (this.targetVersion === schematics_1.TargetVersion.V9 || this.targetVersion === schematics_1.TargetVersion.V10) &&
40
- !this.context.isTestTarget;
41
- this._printer = ts.createPrinter();
42
- this._importManager = new import_manager_1.ImportManager(this.fileSystem, this._printer);
43
- this._nodeFailures = [];
44
- /**
45
- * Whether custom HammerJS events provided by the Material gesture
46
- * config are used in a template.
47
- */
48
- this._customEventsUsedInTemplate = false;
49
- /** Whether standard HammerJS events are used in a template. */
50
- this._standardEventsUsedInTemplate = false;
51
- /** Whether HammerJS is accessed at runtime. */
52
- this._usedInRuntime = false;
53
- /**
54
- * List of imports that make "hammerjs" available globally. We keep track of these
55
- * since we might need to remove them if Hammer is not used.
56
- */
57
- this._installImports = [];
58
- /**
59
- * List of identifiers which resolve to the gesture config from Angular Material.
60
- */
61
- this._gestureConfigReferences = [];
62
- /**
63
- * List of identifiers which resolve to the "HAMMER_GESTURE_CONFIG" token from
64
- * "@angular/platform-browser".
65
- */
66
- this._hammerConfigTokenReferences = [];
67
- /**
68
- * List of identifiers which resolve to the "HammerModule" from
69
- * "@angular/platform-browser".
70
- */
71
- this._hammerModuleReferences = [];
72
- /**
73
- * List of identifiers that have been deleted from source files. This can be
74
- * used to determine if certain imports are still used or not.
75
- */
76
- this._deletedIdentifiers = [];
77
- }
78
- visitTemplate(template) {
79
- if (!this._customEventsUsedInTemplate || !this._standardEventsUsedInTemplate) {
80
- const { standardEvents, customEvents } = hammer_template_check_1.isHammerJsUsedInTemplate(template.content);
81
- this._customEventsUsedInTemplate = this._customEventsUsedInTemplate || customEvents;
82
- this._standardEventsUsedInTemplate = this._standardEventsUsedInTemplate || standardEvents;
83
- }
84
- }
85
- visitNode(node) {
86
- this._checkHammerImports(node);
87
- this._checkForRuntimeHammerUsage(node);
88
- this._checkForMaterialGestureConfig(node);
89
- this._checkForHammerGestureConfigToken(node);
90
- this._checkForHammerModuleReference(node);
91
- }
92
- postAnalysis() {
93
- // Walk through all hammer config token references and check if there
94
- // is a potential custom gesture config setup.
95
- const hasCustomGestureConfigSetup = this._hammerConfigTokenReferences.some(r => this._checkForCustomGestureConfigSetup(r));
96
- const usedInTemplate = this._standardEventsUsedInTemplate || this._customEventsUsedInTemplate;
97
- /*
98
- Possible scenarios and how the migration should change the project:
99
- 1. We detect that a custom HammerJS gesture config is set up:
100
- - Remove references to the Material gesture config if no HammerJS event is used.
101
- - Print a warning about ambiguous configuration that cannot be handled completely
102
- if there are references to the Material gesture config.
103
- 2. We detect that HammerJS is only used programmatically:
104
- - Remove references to GestureConfig of Material.
105
- - Remove references to the "HammerModule" if present.
106
- 3. We detect that standard HammerJS events are used in a template:
107
- - Set up the "HammerModule" from platform-browser.
108
- - Remove all gesture config references.
109
- 4. We detect that custom HammerJS events provided by the Material gesture
110
- config are used.
111
- - Copy the Material gesture config into the app.
112
- - Rewrite all gesture config references to the newly copied one.
113
- - Set up the new gesture config in the root app module.
114
- - Set up the "HammerModule" from platform-browser.
115
- 4. We detect no HammerJS usage at all:
116
- - Remove Hammer imports
117
- - Remove Material gesture config references
118
- - Remove HammerModule setup if present.
119
- - Remove Hammer script imports in "index.html" files.
120
- */
121
- if (hasCustomGestureConfigSetup) {
122
- // If a custom gesture config is provided, we always assume that HammerJS is used.
123
- HammerGesturesMigration.globalUsesHammer = true;
124
- if (!usedInTemplate && this._gestureConfigReferences.length) {
125
- // If the Angular Material gesture events are not used and we found a custom
126
- // gesture config, we can safely remove references to the Material gesture config
127
- // since events provided by the Material gesture config are guaranteed to be unused.
128
- this._removeMaterialGestureConfigSetup();
129
- this.printInfo('The HammerJS v9 migration for Angular Components detected that HammerJS is ' +
130
- 'manually set up in combination with references to the Angular Material gesture ' +
131
- 'config. This target cannot be migrated completely, but all references to the ' +
132
- 'deprecated Angular Material gesture have been removed. Read more here: ' +
133
- 'https://git.io/ng-material-v9-hammer-ambiguous-usage');
134
- }
135
- else if (usedInTemplate && this._gestureConfigReferences.length) {
136
- // Since there is a reference to the Angular Material gesture config, and we detected
137
- // usage of a gesture event that could be provided by Angular Material, we *cannot*
138
- // automatically remove references. This is because we do *not* know whether the
139
- // event is actually provided by the custom config or by the Material config.
140
- this.printInfo('The HammerJS v9 migration for Angular Components detected that HammerJS is ' +
141
- 'manually set up in combination with references to the Angular Material gesture ' +
142
- 'config. This target cannot be migrated completely. Please manually remove ' +
143
- 'references to the deprecated Angular Material gesture config. Read more here: ' +
144
- 'https://git.io/ng-material-v9-hammer-ambiguous-usage');
145
- }
146
- }
147
- else if (this._usedInRuntime || usedInTemplate) {
148
- // We keep track of whether Hammer is used globally. This is necessary because we
149
- // want to only remove Hammer from the "package.json" if it is not used in any project
150
- // target. Just because it isn't used in one target doesn't mean that we can safely
151
- // remove the dependency.
152
- HammerGesturesMigration.globalUsesHammer = true;
153
- // If hammer is only used at runtime, we don't need the gesture config or "HammerModule"
154
- // and can remove it (along with the hammer config token import if no longer needed).
155
- if (!usedInTemplate) {
156
- this._removeMaterialGestureConfigSetup();
157
- this._removeHammerModuleReferences();
158
- }
159
- else if (this._standardEventsUsedInTemplate && !this._customEventsUsedInTemplate) {
160
- this._setupHammerWithStandardEvents();
161
- }
162
- else {
163
- this._setupHammerWithCustomEvents();
164
- }
165
- }
166
- else {
167
- this._removeHammerSetup();
168
- }
169
- // Record the changes collected in the import manager. Changes need to be applied
170
- // once the import manager registered all import modifications. This avoids collisions.
171
- this._importManager.recordChanges();
172
- // Create migration failures that will be printed by the update-tool on migration
173
- // completion. We need special logic for updating failure positions to reflect
174
- // the new source file after modifications from the import manager.
175
- this.failures.push(...this._createMigrationFailures());
176
- // The template check for HammerJS events is not completely reliable as the event
177
- // output could also be from a component having an output named similarly to a known
178
- // hammerjs event (e.g. "@Output() slide"). The usage is therefore somewhat ambiguous
179
- // and we want to print a message that developers might be able to remove Hammer manually.
180
- if (!hasCustomGestureConfigSetup && !this._usedInRuntime && usedInTemplate) {
181
- this.printInfo('The HammerJS v9 migration for Angular Components migrated the ' +
182
- 'project to keep HammerJS installed, but detected ambiguous usage of HammerJS. Please ' +
183
- 'manually check if you can remove HammerJS from your application. More details: ' +
184
- 'https://git.io/ng-material-v9-hammer-ambiguous-usage');
185
- }
186
- }
31
+ class HammerGesturesMigration extends schematics_1.DevkitMigration {
32
+ constructor() {
33
+ super(...arguments);
34
+ // Only enable this rule if the migration targets v9 or v10 and is running for a non-test
35
+ // target. We cannot migrate test targets since they have a limited scope
36
+ // (in regards to source files) and therefore the HammerJS usage detection can be incorrect.
37
+ this.enabled = (this.targetVersion === schematics_1.TargetVersion.V9 || this.targetVersion === schematics_1.TargetVersion.V10) &&
38
+ !this.context.isTestTarget;
39
+ this._printer = ts.createPrinter();
40
+ this._importManager = new import_manager_1.ImportManager(this.fileSystem, this._printer);
41
+ this._nodeFailures = [];
187
42
  /**
188
- * Sets up the hammer gesture config in the current project. To achieve this, the
189
- * following steps are performed:
190
- * 1) Create copy of Angular Material gesture config.
191
- * 2) Rewrite all references to the Angular Material gesture config to the
192
- * new gesture config.
193
- * 3) Setup the HAMMER_GESTURE_CONFIG in the root app module (if not done already).
194
- * 4) Setup the "HammerModule" in the root app module (if not done already).
43
+ * Whether custom HammerJS events provided by the Material gesture
44
+ * config are used in a template.
195
45
  */
196
- _setupHammerWithCustomEvents() {
197
- const project = this.context.project;
198
- const sourceRoot = core_1.normalize(project.sourceRoot || project.root);
199
- const newConfigPath = core_1.join(sourceRoot, this._getAvailableGestureConfigFileName(sourceRoot));
200
- // Copy gesture config template into the CLI project.
201
- this.fileSystem.create(newConfigPath, fs_1.readFileSync(require.resolve(GESTURE_CONFIG_TEMPLATE_PATH), 'utf8'));
202
- // Replace all Material gesture config references to resolve to the
203
- // newly copied gesture config.
204
- this._gestureConfigReferences.forEach(i => this._replaceGestureConfigReference(i, GESTURE_CONFIG_CLASS_NAME, getModuleSpecifier(newConfigPath, i.node.getSourceFile().fileName)));
205
- // Setup the gesture config provider and the "HammerModule" in the root module
206
- // if not done already. The "HammerModule" is needed in v9 since it enables the
207
- // Hammer event plugin that was previously enabled by default in v8.
208
- this._setupNewGestureConfigInRootModule(newConfigPath);
209
- this._setupHammerModuleInRootModule();
210
- }
46
+ this._customEventsUsedInTemplate = false;
47
+ /** Whether standard HammerJS events are used in a template. */
48
+ this._standardEventsUsedInTemplate = false;
49
+ /** Whether HammerJS is accessed at runtime. */
50
+ this._usedInRuntime = false;
211
51
  /**
212
- * Sets up the standard hammer module in the project and removes all
213
- * references to the deprecated Angular Material gesture config.
52
+ * List of imports that make "hammerjs" available globally. We keep track of these
53
+ * since we might need to remove them if Hammer is not used.
214
54
  */
215
- _setupHammerWithStandardEvents() {
216
- // Setup the HammerModule. The HammerModule enables support for
217
- // the standard HammerJS events.
218
- this._setupHammerModuleInRootModule();
219
- this._removeMaterialGestureConfigSetup();
220
- }
55
+ this._installImports = [];
221
56
  /**
222
- * Removes Hammer from the current project. The following steps are performed:
223
- * 1) Delete all TypeScript imports to "hammerjs".
224
- * 2) Remove references to the Angular Material gesture config.
225
- * 3) Remove "hammerjs" from all index HTML files of the current project.
57
+ * List of identifiers which resolve to the gesture config from Angular Material.
226
58
  */
227
- _removeHammerSetup() {
228
- this._installImports.forEach(i => this._importManager.deleteImportByDeclaration(i));
229
- this._removeMaterialGestureConfigSetup();
230
- this._removeHammerModuleReferences();
231
- this._removeHammerFromIndexFile();
232
- }
233
- /**
234
- * Removes the gesture config setup by deleting all found references to the Angular
235
- * Material gesture config. Additionally, unused imports to the hammer gesture config
236
- * token from "@angular/platform-browser" will be removed as well.
237
- */
238
- _removeMaterialGestureConfigSetup() {
239
- this._gestureConfigReferences.forEach(r => this._removeGestureConfigReference(r));
240
- this._hammerConfigTokenReferences.forEach(r => {
241
- if (r.isImport) {
242
- this._removeHammerConfigTokenImportIfUnused(r);
243
- }
244
- });
245
- }
246
- /** Removes all references to the "HammerModule" from "@angular/platform-browser". */
247
- _removeHammerModuleReferences() {
248
- this._hammerModuleReferences.forEach(({ node, isImport, importData }) => {
249
- const sourceFile = node.getSourceFile();
250
- const recorder = this.fileSystem.edit(this.fileSystem.resolve(sourceFile.fileName));
251
- // Only remove the import for the HammerModule if the module has been accessed
252
- // through a non-namespaced identifier access.
253
- if (!isNamespacedIdentifierAccess(node)) {
254
- this._importManager.deleteNamedBindingImport(sourceFile, HAMMER_MODULE_NAME, importData.moduleName);
255
- }
256
- // For references from within an import, we do not need to do anything other than
257
- // removing the import. For other references, we remove the import and the actual
258
- // identifier in the module imports.
259
- if (isImport) {
260
- return;
261
- }
262
- // If the "HammerModule" is referenced within an array literal, we can
263
- // remove the element easily. Otherwise if it's outside of an array literal,
264
- // we need to replace the reference with an empty object literal w/ todo to
265
- // not break the application.
266
- if (ts.isArrayLiteralExpression(node.parent)) {
267
- // Removes the "HammerModule" from the parent array expression. Removes
268
- // the trailing comma token if present.
269
- remove_array_element_1.removeElementFromArrayExpression(node, recorder);
270
- }
271
- else {
272
- recorder.remove(node.getStart(), node.getWidth());
273
- recorder.insertRight(node.getStart(), `/* TODO: remove */ {}`);
274
- this._nodeFailures.push({
275
- node: node,
276
- message: 'Unable to delete reference to "HammerModule".',
277
- });
278
- }
279
- });
280
- }
59
+ this._gestureConfigReferences = [];
281
60
  /**
282
- * Checks if the given node is a reference to the hammer gesture config
283
- * token from platform-browser. If so, keeps track of the reference.
61
+ * List of identifiers which resolve to the "HAMMER_GESTURE_CONFIG" token from
62
+ * "@angular/platform-browser".
284
63
  */
285
- _checkForHammerGestureConfigToken(node) {
286
- if (ts.isIdentifier(node)) {
287
- const importData = schematics_1.getImportOfIdentifier(node, this.typeChecker);
288
- if (importData && importData.symbolName === HAMMER_CONFIG_TOKEN_NAME &&
289
- importData.moduleName === HAMMER_CONFIG_TOKEN_MODULE) {
290
- this._hammerConfigTokenReferences.push({ node, importData, isImport: ts.isImportSpecifier(node.parent) });
291
- }
292
- }
293
- }
64
+ this._hammerConfigTokenReferences = [];
294
65
  /**
295
- * Checks if the given node is a reference to the HammerModule from
296
- * "@angular/platform-browser". If so, keeps track of the reference.
66
+ * List of identifiers which resolve to the "HammerModule" from
67
+ * "@angular/platform-browser".
297
68
  */
298
- _checkForHammerModuleReference(node) {
299
- if (ts.isIdentifier(node)) {
300
- const importData = schematics_1.getImportOfIdentifier(node, this.typeChecker);
301
- if (importData && importData.symbolName === HAMMER_MODULE_NAME &&
302
- importData.moduleName === HAMMER_MODULE_IMPORT) {
303
- this._hammerModuleReferences.push({ node, importData, isImport: ts.isImportSpecifier(node.parent) });
304
- }
305
- }
306
- }
69
+ this._hammerModuleReferences = [];
307
70
  /**
308
- * Checks if the given node is an import to the HammerJS package. Imports to
309
- * HammerJS which load specific symbols from the package are considered as
310
- * runtime usage of Hammer. e.g. `import {Symbol} from "hammerjs";`.
71
+ * List of identifiers that have been deleted from source files. This can be
72
+ * used to determine if certain imports are still used or not.
311
73
  */
312
- _checkHammerImports(node) {
313
- if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) &&
314
- node.moduleSpecifier.text === HAMMER_MODULE_SPECIFIER) {
315
- // If there is an import to HammerJS that imports symbols, or is namespaced
316
- // (e.g. "import {A, B} from ..." or "import * as hammer from ..."), then we
317
- // assume that some exports are used at runtime.
318
- if (node.importClause &&
319
- !(node.importClause.namedBindings && ts.isNamedImports(node.importClause.namedBindings) &&
320
- node.importClause.namedBindings.elements.length === 0)) {
321
- this._usedInRuntime = true;
322
- }
323
- else {
324
- this._installImports.push(node);
325
- }
326
- }
74
+ this._deletedIdentifiers = [];
75
+ }
76
+ visitTemplate(template) {
77
+ if (!this._customEventsUsedInTemplate || !this._standardEventsUsedInTemplate) {
78
+ const { standardEvents, customEvents } = hammer_template_check_1.isHammerJsUsedInTemplate(template.content);
79
+ this._customEventsUsedInTemplate = this._customEventsUsedInTemplate || customEvents;
80
+ this._standardEventsUsedInTemplate = this._standardEventsUsedInTemplate || standardEvents;
327
81
  }
328
- /**
329
- * Checks if the given node accesses the global "Hammer" symbol at runtime. If so,
330
- * the migration rule state will be updated to reflect that Hammer is used at runtime.
331
- */
332
- _checkForRuntimeHammerUsage(node) {
333
- if (this._usedInRuntime) {
334
- return;
335
- }
336
- // Detects usages of "window.Hammer".
337
- if (ts.isPropertyAccessExpression(node) && node.name.text === 'Hammer') {
338
- const originExpr = unwrapExpression(node.expression);
339
- if (ts.isIdentifier(originExpr) && originExpr.text === 'window') {
340
- this._usedInRuntime = true;
341
- }
342
- return;
343
- }
344
- // Detects usages of "window['Hammer']".
345
- if (ts.isElementAccessExpression(node) && ts.isStringLiteral(node.argumentExpression) &&
346
- node.argumentExpression.text === 'Hammer') {
347
- const originExpr = unwrapExpression(node.expression);
348
- if (ts.isIdentifier(originExpr) && originExpr.text === 'window') {
349
- this._usedInRuntime = true;
350
- }
351
- return;
352
- }
353
- // Handles usages of plain identifier with the name "Hammer". These usage
354
- // are valid if they resolve to "@types/hammerjs". e.g. "new Hammer(myElement)".
355
- if (ts.isIdentifier(node) && node.text === 'Hammer' &&
356
- !ts.isPropertyAccessExpression(node.parent) && !ts.isElementAccessExpression(node.parent)) {
357
- const symbol = this._getDeclarationSymbolOfNode(node);
358
- if (symbol && symbol.valueDeclaration &&
359
- symbol.valueDeclaration.getSourceFile().fileName.includes('@types/hammerjs')) {
360
- this._usedInRuntime = true;
361
- }
82
+ }
83
+ visitNode(node) {
84
+ this._checkHammerImports(node);
85
+ this._checkForRuntimeHammerUsage(node);
86
+ this._checkForMaterialGestureConfig(node);
87
+ this._checkForHammerGestureConfigToken(node);
88
+ this._checkForHammerModuleReference(node);
89
+ }
90
+ postAnalysis() {
91
+ // Walk through all hammer config token references and check if there
92
+ // is a potential custom gesture config setup.
93
+ const hasCustomGestureConfigSetup = this._hammerConfigTokenReferences.some(r => this._checkForCustomGestureConfigSetup(r));
94
+ const usedInTemplate = this._standardEventsUsedInTemplate || this._customEventsUsedInTemplate;
95
+ /*
96
+ Possible scenarios and how the migration should change the project:
97
+ 1. We detect that a custom HammerJS gesture config is set up:
98
+ - Remove references to the Material gesture config if no HammerJS event is used.
99
+ - Print a warning about ambiguous configuration that cannot be handled completely
100
+ if there are references to the Material gesture config.
101
+ 2. We detect that HammerJS is only used programmatically:
102
+ - Remove references to GestureConfig of Material.
103
+ - Remove references to the "HammerModule" if present.
104
+ 3. We detect that standard HammerJS events are used in a template:
105
+ - Set up the "HammerModule" from platform-browser.
106
+ - Remove all gesture config references.
107
+ 4. We detect that custom HammerJS events provided by the Material gesture
108
+ config are used.
109
+ - Copy the Material gesture config into the app.
110
+ - Rewrite all gesture config references to the newly copied one.
111
+ - Set up the new gesture config in the root app module.
112
+ - Set up the "HammerModule" from platform-browser.
113
+ 4. We detect no HammerJS usage at all:
114
+ - Remove Hammer imports
115
+ - Remove Material gesture config references
116
+ - Remove HammerModule setup if present.
117
+ - Remove Hammer script imports in "index.html" files.
118
+ */
119
+ if (hasCustomGestureConfigSetup) {
120
+ // If a custom gesture config is provided, we always assume that HammerJS is used.
121
+ HammerGesturesMigration.globalUsesHammer = true;
122
+ if (!usedInTemplate && this._gestureConfigReferences.length) {
123
+ // If the Angular Material gesture events are not used and we found a custom
124
+ // gesture config, we can safely remove references to the Material gesture config
125
+ // since events provided by the Material gesture config are guaranteed to be unused.
126
+ this._removeMaterialGestureConfigSetup();
127
+ this.printInfo('The HammerJS v9 migration for Angular Components detected that HammerJS is ' +
128
+ 'manually set up in combination with references to the Angular Material gesture ' +
129
+ 'config. This target cannot be migrated completely, but all references to the ' +
130
+ 'deprecated Angular Material gesture have been removed. Read more here: ' +
131
+ 'https://git.io/ng-material-v9-hammer-ambiguous-usage');
362
132
  }
363
- }
364
- /**
365
- * Checks if the given node references the gesture config from Angular Material.
366
- * If so, we keep track of the found symbol reference.
367
- */
368
- _checkForMaterialGestureConfig(node) {
369
- if (ts.isIdentifier(node)) {
370
- const importData = schematics_1.getImportOfIdentifier(node, this.typeChecker);
371
- if (importData && importData.symbolName === GESTURE_CONFIG_CLASS_NAME &&
372
- importData.moduleName.startsWith('@angular/material/')) {
373
- this._gestureConfigReferences.push({ node, importData, isImport: ts.isImportSpecifier(node.parent) });
374
- }
133
+ else if (usedInTemplate && this._gestureConfigReferences.length) {
134
+ // Since there is a reference to the Angular Material gesture config, and we detected
135
+ // usage of a gesture event that could be provided by Angular Material, we *cannot*
136
+ // automatically remove references. This is because we do *not* know whether the
137
+ // event is actually provided by the custom config or by the Material config.
138
+ this.printInfo('The HammerJS v9 migration for Angular Components detected that HammerJS is ' +
139
+ 'manually set up in combination with references to the Angular Material gesture ' +
140
+ 'config. This target cannot be migrated completely. Please manually remove ' +
141
+ 'references to the deprecated Angular Material gesture config. Read more here: ' +
142
+ 'https://git.io/ng-material-v9-hammer-ambiguous-usage');
375
143
  }
376
144
  }
377
- /**
378
- * Checks if the given Hammer gesture config token reference is part of an
379
- * Angular provider definition that sets up a custom gesture config.
380
- */
381
- _checkForCustomGestureConfigSetup(tokenRef) {
382
- // Walk up the tree to look for a parent property assignment of the
383
- // reference to the hammer gesture config token.
384
- let propertyAssignment = tokenRef.node;
385
- while (propertyAssignment && !ts.isPropertyAssignment(propertyAssignment)) {
386
- propertyAssignment = propertyAssignment.parent;
145
+ else if (this._usedInRuntime || usedInTemplate) {
146
+ // We keep track of whether Hammer is used globally. This is necessary because we
147
+ // want to only remove Hammer from the "package.json" if it is not used in any project
148
+ // target. Just because it isn't used in one target doesn't mean that we can safely
149
+ // remove the dependency.
150
+ HammerGesturesMigration.globalUsesHammer = true;
151
+ // If hammer is only used at runtime, we don't need the gesture config or "HammerModule"
152
+ // and can remove it (along with the hammer config token import if no longer needed).
153
+ if (!usedInTemplate) {
154
+ this._removeMaterialGestureConfigSetup();
155
+ this._removeHammerModuleReferences();
156
+ }
157
+ else if (this._standardEventsUsedInTemplate && !this._customEventsUsedInTemplate) {
158
+ this._setupHammerWithStandardEvents();
387
159
  }
388
- if (!propertyAssignment || !ts.isPropertyAssignment(propertyAssignment) ||
389
- getPropertyNameText(propertyAssignment.name) !== 'provide') {
390
- return false;
160
+ else {
161
+ this._setupHammerWithCustomEvents();
391
162
  }
392
- const objectLiteralExpr = propertyAssignment.parent;
393
- const matchingIdentifiers = findMatchingChildNodes(objectLiteralExpr, ts.isIdentifier);
394
- // We naively assume that if there is a reference to the "GestureConfig" export
395
- // from Angular Material in the provider literal, that the provider sets up the
396
- // Angular Material gesture config.
397
- return !this._gestureConfigReferences.some(r => matchingIdentifiers.includes(r.node));
398
163
  }
399
- /**
400
- * Determines an available file name for the gesture config which should
401
- * be stored in the specified file path.
402
- */
403
- _getAvailableGestureConfigFileName(sourceRoot) {
404
- if (!this.fileSystem.exists(core_1.join(sourceRoot, `${GESTURE_CONFIG_FILE_NAME}.ts`))) {
405
- return `${GESTURE_CONFIG_FILE_NAME}.ts`;
406
- }
407
- let possibleName = `${GESTURE_CONFIG_FILE_NAME}-`;
408
- let index = 1;
409
- while (this.fileSystem.exists(core_1.join(sourceRoot, `${possibleName}-${index}.ts`))) {
410
- index++;
411
- }
412
- return `${possibleName + index}.ts`;
164
+ else {
165
+ this._removeHammerSetup();
413
166
  }
414
- /** Replaces a given gesture config reference with a new import. */
415
- _replaceGestureConfigReference({ node, importData, isImport }, symbolName, moduleSpecifier) {
416
- const sourceFile = node.getSourceFile();
417
- const recorder = this.fileSystem.edit(this.fileSystem.resolve(sourceFile.fileName));
418
- // List of all identifiers referring to the gesture config in the current file. This
419
- // allows us to add an import for the copied gesture configuration without generating a
420
- // new identifier for the import to avoid collisions. i.e. "GestureConfig_1". The import
421
- // manager checks for possible name collisions, but is able to ignore specific identifiers.
422
- // We use this to ignore all references to the original Angular Material gesture config,
423
- // because these will be replaced and therefore will not interfere.
424
- const gestureIdentifiersInFile = this._getGestureConfigIdentifiersOfFile(sourceFile);
425
- // If the parent of the identifier is accessed through a namespace, we can just
426
- // import the new gesture config without rewriting the import declaration because
427
- // the config has been imported through a namespaced import.
428
- if (isNamespacedIdentifierAccess(node)) {
429
- const newExpression = this._importManager.addImportToSourceFile(sourceFile, symbolName, moduleSpecifier, false, gestureIdentifiersInFile);
430
- recorder.remove(node.parent.getStart(), node.parent.getWidth());
431
- recorder.insertRight(node.parent.getStart(), this._printNode(newExpression, sourceFile));
432
- return;
433
- }
434
- // Delete the old import to the "GestureConfig".
435
- this._importManager.deleteNamedBindingImport(sourceFile, GESTURE_CONFIG_CLASS_NAME, importData.moduleName);
436
- // If the current reference is not from inside of a import, we need to add a new
437
- // import to the copied gesture config and replace the identifier. For references
438
- // within an import, we do nothing but removing the actual import. This allows us
439
- // to remove unused imports to the Material gesture config.
440
- if (!isImport) {
441
- const newExpression = this._importManager.addImportToSourceFile(sourceFile, symbolName, moduleSpecifier, false, gestureIdentifiersInFile);
442
- recorder.remove(node.getStart(), node.getWidth());
443
- recorder.insertRight(node.getStart(), this._printNode(newExpression, sourceFile));
444
- }
167
+ // Record the changes collected in the import manager. Changes need to be applied
168
+ // once the import manager registered all import modifications. This avoids collisions.
169
+ this._importManager.recordChanges();
170
+ // Create migration failures that will be printed by the update-tool on migration
171
+ // completion. We need special logic for updating failure positions to reflect
172
+ // the new source file after modifications from the import manager.
173
+ this.failures.push(...this._createMigrationFailures());
174
+ // The template check for HammerJS events is not completely reliable as the event
175
+ // output could also be from a component having an output named similarly to a known
176
+ // hammerjs event (e.g. "@Output() slide"). The usage is therefore somewhat ambiguous
177
+ // and we want to print a message that developers might be able to remove Hammer manually.
178
+ if (!hasCustomGestureConfigSetup && !this._usedInRuntime && usedInTemplate) {
179
+ this.printInfo('The HammerJS v9 migration for Angular Components migrated the ' +
180
+ 'project to keep HammerJS installed, but detected ambiguous usage of HammerJS. Please ' +
181
+ 'manually check if you can remove HammerJS from your application. More details: ' +
182
+ 'https://git.io/ng-material-v9-hammer-ambiguous-usage');
445
183
  }
446
- /**
447
- * Removes a given gesture config reference and its corresponding import from
448
- * its containing source file. Imports will be always removed, but in some cases,
449
- * where it's not guaranteed that a removal can be performed safely, we just
450
- * create a migration failure (and add a TODO if possible).
451
- */
452
- _removeGestureConfigReference({ node, importData, isImport }) {
184
+ }
185
+ /**
186
+ * Sets up the hammer gesture config in the current project. To achieve this, the
187
+ * following steps are performed:
188
+ * 1) Create copy of Angular Material gesture config.
189
+ * 2) Rewrite all references to the Angular Material gesture config to the
190
+ * new gesture config.
191
+ * 3) Setup the HAMMER_GESTURE_CONFIG in the root app module (if not done already).
192
+ * 4) Setup the "HammerModule" in the root app module (if not done already).
193
+ */
194
+ _setupHammerWithCustomEvents() {
195
+ const project = this.context.project;
196
+ const sourceRoot = this.fileSystem.resolve(project.sourceRoot || project.root);
197
+ const newConfigPath = core_1.join(sourceRoot, this._getAvailableGestureConfigFileName(sourceRoot));
198
+ // Copy gesture config template into the CLI project.
199
+ this.fileSystem.create(newConfigPath, fs_1.readFileSync(require.resolve(GESTURE_CONFIG_TEMPLATE_PATH), 'utf8'));
200
+ // Replace all Material gesture config references to resolve to the
201
+ // newly copied gesture config.
202
+ this._gestureConfigReferences.forEach(i => {
203
+ const filePath = this.fileSystem.resolve(i.node.getSourceFile().fileName);
204
+ return this._replaceGestureConfigReference(i, GESTURE_CONFIG_CLASS_NAME, getModuleSpecifier(newConfigPath, filePath));
205
+ });
206
+ // Setup the gesture config provider and the "HammerModule" in the root module
207
+ // if not done already. The "HammerModule" is needed in v9 since it enables the
208
+ // Hammer event plugin that was previously enabled by default in v8.
209
+ this._setupNewGestureConfigInRootModule(newConfigPath);
210
+ this._setupHammerModuleInRootModule();
211
+ }
212
+ /**
213
+ * Sets up the standard hammer module in the project and removes all
214
+ * references to the deprecated Angular Material gesture config.
215
+ */
216
+ _setupHammerWithStandardEvents() {
217
+ // Setup the HammerModule. The HammerModule enables support for
218
+ // the standard HammerJS events.
219
+ this._setupHammerModuleInRootModule();
220
+ this._removeMaterialGestureConfigSetup();
221
+ }
222
+ /**
223
+ * Removes Hammer from the current project. The following steps are performed:
224
+ * 1) Delete all TypeScript imports to "hammerjs".
225
+ * 2) Remove references to the Angular Material gesture config.
226
+ * 3) Remove "hammerjs" from all index HTML files of the current project.
227
+ */
228
+ _removeHammerSetup() {
229
+ this._installImports.forEach(i => this._importManager.deleteImportByDeclaration(i));
230
+ this._removeMaterialGestureConfigSetup();
231
+ this._removeHammerModuleReferences();
232
+ this._removeHammerFromIndexFile();
233
+ }
234
+ /**
235
+ * Removes the gesture config setup by deleting all found references to the Angular
236
+ * Material gesture config. Additionally, unused imports to the hammer gesture config
237
+ * token from "@angular/platform-browser" will be removed as well.
238
+ */
239
+ _removeMaterialGestureConfigSetup() {
240
+ this._gestureConfigReferences.forEach(r => this._removeGestureConfigReference(r));
241
+ this._hammerConfigTokenReferences.forEach(r => {
242
+ if (r.isImport) {
243
+ this._removeHammerConfigTokenImportIfUnused(r);
244
+ }
245
+ });
246
+ }
247
+ /** Removes all references to the "HammerModule" from "@angular/platform-browser". */
248
+ _removeHammerModuleReferences() {
249
+ this._hammerModuleReferences.forEach(({ node, isImport, importData }) => {
453
250
  const sourceFile = node.getSourceFile();
454
251
  const recorder = this.fileSystem.edit(this.fileSystem.resolve(sourceFile.fileName));
455
- // Only remove the import for the gesture config if the gesture config has
456
- // been accessed through a non-namespaced identifier access.
252
+ // Only remove the import for the HammerModule if the module has been accessed
253
+ // through a non-namespaced identifier access.
457
254
  if (!isNamespacedIdentifierAccess(node)) {
458
- this._importManager.deleteNamedBindingImport(sourceFile, GESTURE_CONFIG_CLASS_NAME, importData.moduleName);
255
+ this._importManager.deleteNamedBindingImport(sourceFile, HAMMER_MODULE_NAME, importData.moduleName);
459
256
  }
460
257
  // For references from within an import, we do not need to do anything other than
461
- // removing the import. For other references, we remove the import and the reference
462
- // identifier if used inside of a provider definition.
258
+ // removing the import. For other references, we remove the import and the actual
259
+ // identifier in the module imports.
463
260
  if (isImport) {
464
261
  return;
465
262
  }
466
- const providerAssignment = node.parent;
467
- // Only remove references to the gesture config which are part of a statically
468
- // analyzable provider definition. We only support the common case of a gesture
469
- // config provider definition where the config is set up through "useClass".
470
- // Otherwise, it's not guaranteed that we can safely remove the provider definition.
471
- if (!ts.isPropertyAssignment(providerAssignment) ||
472
- getPropertyNameText(providerAssignment.name) !== 'useClass') {
473
- this._nodeFailures.push({ node, message: CANNOT_REMOVE_REFERENCE_ERROR });
474
- return;
475
- }
476
- const objectLiteralExpr = providerAssignment.parent;
477
- const provideToken = objectLiteralExpr.properties.find((p) => ts.isPropertyAssignment(p) && getPropertyNameText(p.name) === 'provide');
478
- // Do not remove the reference if the gesture config is not part of a provider definition,
479
- // or if the provided toke is not referring to the known HAMMER_GESTURE_CONFIG token
480
- // from platform-browser.
481
- if (!provideToken || !this._isReferenceToHammerConfigToken(provideToken.initializer)) {
482
- this._nodeFailures.push({ node, message: CANNOT_REMOVE_REFERENCE_ERROR });
483
- return;
263
+ // If the "HammerModule" is referenced within an array literal, we can
264
+ // remove the element easily. Otherwise if it's outside of an array literal,
265
+ // we need to replace the reference with an empty object literal w/ todo to
266
+ // not break the application.
267
+ if (ts.isArrayLiteralExpression(node.parent)) {
268
+ // Removes the "HammerModule" from the parent array expression. Removes
269
+ // the trailing comma token if present.
270
+ remove_array_element_1.removeElementFromArrayExpression(node, recorder);
484
271
  }
485
- // Collect all nested identifiers which will be deleted. This helps us
486
- // determining if we can remove imports for the "HAMMER_GESTURE_CONFIG" token.
487
- this._deletedIdentifiers.push(...findMatchingChildNodes(objectLiteralExpr, ts.isIdentifier));
488
- // In case the found provider definition is not part of an array literal,
489
- // we cannot safely remove the provider. This is because it could be declared
490
- // as a variable. e.g. "const gestureProvider = {provide: .., useClass: GestureConfig}".
491
- // In that case, we just add an empty object literal with TODO and print a failure.
492
- if (!ts.isArrayLiteralExpression(objectLiteralExpr.parent)) {
493
- recorder.remove(objectLiteralExpr.getStart(), objectLiteralExpr.getWidth());
494
- recorder.insertRight(objectLiteralExpr.getStart(), `/* TODO: remove */ {}`);
272
+ else {
273
+ recorder.remove(node.getStart(), node.getWidth());
274
+ recorder.insertRight(node.getStart(), `/* TODO: remove */ {}`);
495
275
  this._nodeFailures.push({
496
- node: objectLiteralExpr,
497
- message: `Unable to delete provider definition for "GestureConfig" completely. ` +
498
- `Please clean up the provider.`
276
+ node: node,
277
+ message: 'Unable to delete reference to "HammerModule".',
499
278
  });
500
- return;
501
279
  }
502
- // Removes the object literal from the parent array expression. Removes
503
- // the trailing comma token if present.
504
- remove_array_element_1.removeElementFromArrayExpression(objectLiteralExpr, recorder);
505
- }
506
- /** Removes the given hammer config token import if it is not used. */
507
- _removeHammerConfigTokenImportIfUnused({ node, importData }) {
508
- const sourceFile = node.getSourceFile();
509
- const isTokenUsed = this._hammerConfigTokenReferences.some(r => !r.isImport && !isNamespacedIdentifierAccess(r.node) &&
510
- r.node.getSourceFile() === sourceFile && !this._deletedIdentifiers.includes(r.node));
511
- // We don't want to remove the import for the token if the token is
512
- // still used somewhere.
513
- if (!isTokenUsed) {
514
- this._importManager.deleteNamedBindingImport(sourceFile, HAMMER_CONFIG_TOKEN_NAME, importData.moduleName);
280
+ });
281
+ }
282
+ /**
283
+ * Checks if the given node is a reference to the hammer gesture config
284
+ * token from platform-browser. If so, keeps track of the reference.
285
+ */
286
+ _checkForHammerGestureConfigToken(node) {
287
+ if (ts.isIdentifier(node)) {
288
+ const importData = schematics_1.getImportOfIdentifier(node, this.typeChecker);
289
+ if (importData && importData.symbolName === HAMMER_CONFIG_TOKEN_NAME &&
290
+ importData.moduleName === HAMMER_CONFIG_TOKEN_MODULE) {
291
+ this._hammerConfigTokenReferences.push({ node, importData, isImport: ts.isImportSpecifier(node.parent) });
515
292
  }
516
293
  }
517
- /** Removes Hammer from all index HTML files of the current project. */
518
- _removeHammerFromIndexFile() {
519
- const indexFilePaths = schematics_1.getProjectIndexFiles(this.context.project);
520
- indexFilePaths.forEach(filePath => {
521
- if (!this.fileSystem.exists(filePath)) {
522
- return;
523
- }
524
- const htmlContent = this.fileSystem.read(filePath);
525
- const recorder = this.fileSystem.edit(filePath);
526
- find_hammer_script_tags_1.findHammerScriptImportElements(htmlContent)
527
- .forEach(el => remove_element_from_html_1.removeElementFromHtml(el, recorder));
528
- });
529
- }
530
- /** Sets up the Hammer gesture config in the root module if needed. */
531
- _setupNewGestureConfigInRootModule(gestureConfigPath) {
532
- const { workspaceFsPath, project } = this.context;
533
- const mainFilePath = schematics_1.getProjectMainFile(project);
534
- const rootModuleSymbol = this._getRootModuleSymbol(mainFilePath);
535
- if (rootModuleSymbol === null) {
536
- this.failures.push({
537
- filePath: mainFilePath,
538
- message: `Could not setup Hammer gestures in module. Please ` +
539
- `manually ensure that the Hammer gesture config is set up.`,
540
- });
541
- return;
542
- }
543
- const sourceFile = rootModuleSymbol.valueDeclaration.getSourceFile();
544
- const relativePath = path_1.relative(workspaceFsPath, sourceFile.fileName);
545
- const metadata = schematics_1.getDecoratorMetadata(sourceFile, 'NgModule', '@angular/core');
546
- // If no "NgModule" definition is found inside the source file, we just do nothing.
547
- if (!metadata.length) {
548
- return;
549
- }
550
- const recorder = this.fileSystem.edit(this.fileSystem.resolve(sourceFile.fileName));
551
- const providersField = schematics_1.getMetadataField(metadata[0], 'providers')[0];
552
- const providerIdentifiers = providersField ? findMatchingChildNodes(providersField, ts.isIdentifier) : null;
553
- const gestureConfigExpr = this._importManager.addImportToSourceFile(sourceFile, GESTURE_CONFIG_CLASS_NAME, getModuleSpecifier(gestureConfigPath, sourceFile.fileName), false, this._getGestureConfigIdentifiersOfFile(sourceFile));
554
- const hammerConfigTokenExpr = this._importManager.addImportToSourceFile(sourceFile, HAMMER_CONFIG_TOKEN_NAME, HAMMER_CONFIG_TOKEN_MODULE);
555
- const newProviderNode = ts.createObjectLiteral([
556
- ts.createPropertyAssignment('provide', hammerConfigTokenExpr),
557
- ts.createPropertyAssignment('useClass', gestureConfigExpr)
558
- ]);
559
- // If the providers field exists and already contains references to the hammer gesture
560
- // config token and the gesture config, we naively assume that the gesture config is
561
- // already set up. We only want to add the gesture config provider if it is not set up.
562
- if (!providerIdentifiers ||
563
- !(this._hammerConfigTokenReferences.some(r => providerIdentifiers.includes(r.node)) &&
564
- this._gestureConfigReferences.some(r => providerIdentifiers.includes(r.node)))) {
565
- schematics_1.addSymbolToNgModuleMetadata(sourceFile, relativePath, 'providers', this._printNode(newProviderNode, sourceFile), null)
566
- .forEach(change => {
567
- if (change instanceof change_1.InsertChange) {
568
- recorder.insertRight(change.pos, change.toAdd);
569
- }
570
- });
294
+ }
295
+ /**
296
+ * Checks if the given node is a reference to the HammerModule from
297
+ * "@angular/platform-browser". If so, keeps track of the reference.
298
+ */
299
+ _checkForHammerModuleReference(node) {
300
+ if (ts.isIdentifier(node)) {
301
+ const importData = schematics_1.getImportOfIdentifier(node, this.typeChecker);
302
+ if (importData && importData.symbolName === HAMMER_MODULE_NAME &&
303
+ importData.moduleName === HAMMER_MODULE_IMPORT) {
304
+ this._hammerModuleReferences.push({ node, importData, isImport: ts.isImportSpecifier(node.parent) });
571
305
  }
572
306
  }
573
- /**
574
- * Gets the TypeScript symbol of the root module by looking for the module
575
- * bootstrap expression in the specified source file.
576
- */
577
- _getRootModuleSymbol(mainFilePath) {
578
- const mainFile = this.program.getSourceFile(path_1.resolve(this.context.workspaceFsPath, mainFilePath));
579
- if (!mainFile) {
580
- return null;
581
- }
582
- const appModuleExpr = find_main_module_1.findMainModuleExpression(mainFile);
583
- if (!appModuleExpr) {
584
- return null;
585
- }
586
- const appModuleSymbol = this._getDeclarationSymbolOfNode(unwrapExpression(appModuleExpr));
587
- if (!appModuleSymbol || !appModuleSymbol.valueDeclaration) {
588
- return null;
589
- }
590
- return appModuleSymbol;
591
- }
592
- /** Sets up the "HammerModule" in the root module of the current project. */
593
- _setupHammerModuleInRootModule() {
594
- const { workspaceFsPath, project } = this.context;
595
- const mainFilePath = schematics_1.getProjectMainFile(project);
596
- const rootModuleSymbol = this._getRootModuleSymbol(mainFilePath);
597
- if (rootModuleSymbol === null) {
598
- this.failures.push({
599
- filePath: mainFilePath,
600
- message: `Could not setup HammerModule. Please manually set up the "HammerModule" ` +
601
- `from "@angular/platform-browser".`,
602
- });
603
- return;
604
- }
605
- const sourceFile = rootModuleSymbol.valueDeclaration.getSourceFile();
606
- const relativePath = path_1.relative(workspaceFsPath, sourceFile.fileName);
607
- const metadata = schematics_1.getDecoratorMetadata(sourceFile, 'NgModule', '@angular/core');
608
- if (!metadata.length) {
609
- return;
307
+ }
308
+ /**
309
+ * Checks if the given node is an import to the HammerJS package. Imports to
310
+ * HammerJS which load specific symbols from the package are considered as
311
+ * runtime usage of Hammer. e.g. `import {Symbol} from "hammerjs";`.
312
+ */
313
+ _checkHammerImports(node) {
314
+ if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) &&
315
+ node.moduleSpecifier.text === HAMMER_MODULE_SPECIFIER) {
316
+ // If there is an import to HammerJS that imports symbols, or is namespaced
317
+ // (e.g. "import {A, B} from ..." or "import * as hammer from ..."), then we
318
+ // assume that some exports are used at runtime.
319
+ if (node.importClause &&
320
+ !(node.importClause.namedBindings && ts.isNamedImports(node.importClause.namedBindings) &&
321
+ node.importClause.namedBindings.elements.length === 0)) {
322
+ this._usedInRuntime = true;
610
323
  }
611
- const importsField = schematics_1.getMetadataField(metadata[0], 'imports')[0];
612
- const importIdentifiers = importsField ? findMatchingChildNodes(importsField, ts.isIdentifier) : null;
613
- const recorder = this.fileSystem.edit(this.fileSystem.resolve(sourceFile.fileName));
614
- const hammerModuleExpr = this._importManager.addImportToSourceFile(sourceFile, HAMMER_MODULE_NAME, HAMMER_MODULE_IMPORT);
615
- // If the "HammerModule" is not already imported in the app module, we set it up
616
- // by adding it to the "imports" field of the app module.
617
- if (!importIdentifiers ||
618
- !this._hammerModuleReferences.some(r => importIdentifiers.includes(r.node))) {
619
- schematics_1.addSymbolToNgModuleMetadata(sourceFile, relativePath, 'imports', this._printNode(hammerModuleExpr, sourceFile), null)
620
- .forEach(change => {
621
- if (change instanceof change_1.InsertChange) {
622
- recorder.insertRight(change.pos, change.toAdd);
623
- }
624
- });
324
+ else {
325
+ this._installImports.push(node);
625
326
  }
626
327
  }
627
- /** Prints a given node within the specified source file. */
628
- _printNode(node, sourceFile) {
629
- return this._printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
630
- }
631
- /** Gets all referenced gesture config identifiers of a given source file */
632
- _getGestureConfigIdentifiersOfFile(sourceFile) {
633
- return this._gestureConfigReferences.filter(d => d.node.getSourceFile() === sourceFile)
634
- .map(d => d.node);
635
- }
636
- /** Gets the symbol that contains the value declaration of the specified node. */
637
- _getDeclarationSymbolOfNode(node) {
638
- const symbol = this.typeChecker.getSymbolAtLocation(node);
639
- // Symbols can be aliases of the declaration symbol. e.g. in named import specifiers.
640
- // We need to resolve the aliased symbol back to the declaration symbol.
641
- // tslint:disable-next-line:no-bitwise
642
- if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {
643
- return this.typeChecker.getAliasedSymbol(symbol);
328
+ }
329
+ /**
330
+ * Checks if the given node accesses the global "Hammer" symbol at runtime. If so,
331
+ * the migration rule state will be updated to reflect that Hammer is used at runtime.
332
+ */
333
+ _checkForRuntimeHammerUsage(node) {
334
+ if (this._usedInRuntime) {
335
+ return;
336
+ }
337
+ // Detects usages of "window.Hammer".
338
+ if (ts.isPropertyAccessExpression(node) && node.name.text === 'Hammer') {
339
+ const originExpr = unwrapExpression(node.expression);
340
+ if (ts.isIdentifier(originExpr) && originExpr.text === 'window') {
341
+ this._usedInRuntime = true;
644
342
  }
645
- return symbol;
343
+ return;
646
344
  }
647
- /**
648
- * Checks whether the given expression resolves to a hammer gesture config
649
- * token reference from "@angular/platform-browser".
650
- */
651
- _isReferenceToHammerConfigToken(expr) {
652
- const unwrapped = unwrapExpression(expr);
653
- if (ts.isIdentifier(unwrapped)) {
654
- return this._hammerConfigTokenReferences.some(r => r.node === unwrapped);
345
+ // Detects usages of "window['Hammer']".
346
+ if (ts.isElementAccessExpression(node) && ts.isStringLiteral(node.argumentExpression) &&
347
+ node.argumentExpression.text === 'Hammer') {
348
+ const originExpr = unwrapExpression(node.expression);
349
+ if (ts.isIdentifier(originExpr) && originExpr.text === 'window') {
350
+ this._usedInRuntime = true;
351
+ }
352
+ return;
353
+ }
354
+ // Handles usages of plain identifier with the name "Hammer". These usage
355
+ // are valid if they resolve to "@types/hammerjs". e.g. "new Hammer(myElement)".
356
+ if (ts.isIdentifier(node) && node.text === 'Hammer' &&
357
+ !ts.isPropertyAccessExpression(node.parent) && !ts.isElementAccessExpression(node.parent)) {
358
+ const symbol = this._getDeclarationSymbolOfNode(node);
359
+ if (symbol && symbol.valueDeclaration &&
360
+ symbol.valueDeclaration.getSourceFile().fileName.includes('@types/hammerjs')) {
361
+ this._usedInRuntime = true;
655
362
  }
656
- else if (ts.isPropertyAccessExpression(unwrapped)) {
657
- return this._hammerConfigTokenReferences.some(r => r.node === unwrapped.name);
363
+ }
364
+ }
365
+ /**
366
+ * Checks if the given node references the gesture config from Angular Material.
367
+ * If so, we keep track of the found symbol reference.
368
+ */
369
+ _checkForMaterialGestureConfig(node) {
370
+ if (ts.isIdentifier(node)) {
371
+ const importData = schematics_1.getImportOfIdentifier(node, this.typeChecker);
372
+ if (importData && importData.symbolName === GESTURE_CONFIG_CLASS_NAME &&
373
+ importData.moduleName.startsWith('@angular/material/')) {
374
+ this._gestureConfigReferences.push({ node, importData, isImport: ts.isImportSpecifier(node.parent) });
658
375
  }
376
+ }
377
+ }
378
+ /**
379
+ * Checks if the given Hammer gesture config token reference is part of an
380
+ * Angular provider definition that sets up a custom gesture config.
381
+ */
382
+ _checkForCustomGestureConfigSetup(tokenRef) {
383
+ // Walk up the tree to look for a parent property assignment of the
384
+ // reference to the hammer gesture config token.
385
+ let propertyAssignment = tokenRef.node;
386
+ while (propertyAssignment && !ts.isPropertyAssignment(propertyAssignment)) {
387
+ propertyAssignment = propertyAssignment.parent;
388
+ }
389
+ if (!propertyAssignment || !ts.isPropertyAssignment(propertyAssignment) ||
390
+ getPropertyNameText(propertyAssignment.name) !== 'provide') {
659
391
  return false;
660
392
  }
661
- /**
662
- * Creates migration failures of the collected node failures. The returned migration
663
- * failures are updated to reflect the post-migration state of source files. Meaning
664
- * that failure positions are corrected if source file modifications shifted lines.
665
- */
666
- _createMigrationFailures() {
667
- return this._nodeFailures.map(({ node, message }) => {
668
- const sourceFile = node.getSourceFile();
669
- const offset = node.getStart();
670
- const position = ts.getLineAndCharacterOfPosition(sourceFile, node.getStart());
671
- return {
672
- position: this._importManager.correctNodePosition(node, offset, position),
673
- message: message,
674
- filePath: this.fileSystem.resolve(sourceFile.fileName),
675
- };
393
+ const objectLiteralExpr = propertyAssignment.parent;
394
+ const matchingIdentifiers = findMatchingChildNodes(objectLiteralExpr, ts.isIdentifier);
395
+ // We naively assume that if there is a reference to the "GestureConfig" export
396
+ // from Angular Material in the provider literal, that the provider sets up the
397
+ // Angular Material gesture config.
398
+ return !this._gestureConfigReferences.some(r => matchingIdentifiers.includes(r.node));
399
+ }
400
+ /**
401
+ * Determines an available file name for the gesture config which should
402
+ * be stored in the specified file path.
403
+ */
404
+ _getAvailableGestureConfigFileName(sourceRoot) {
405
+ if (!this.fileSystem.exists(core_1.join(sourceRoot, `${GESTURE_CONFIG_FILE_NAME}.ts`))) {
406
+ return `${GESTURE_CONFIG_FILE_NAME}.ts`;
407
+ }
408
+ let possibleName = `${GESTURE_CONFIG_FILE_NAME}-`;
409
+ let index = 1;
410
+ while (this.fileSystem.exists(core_1.join(sourceRoot, `${possibleName}-${index}.ts`))) {
411
+ index++;
412
+ }
413
+ return `${possibleName + index}.ts`;
414
+ }
415
+ /** Replaces a given gesture config reference with a new import. */
416
+ _replaceGestureConfigReference({ node, importData, isImport }, symbolName, moduleSpecifier) {
417
+ const sourceFile = node.getSourceFile();
418
+ const recorder = this.fileSystem.edit(this.fileSystem.resolve(sourceFile.fileName));
419
+ // List of all identifiers referring to the gesture config in the current file. This
420
+ // allows us to add an import for the copied gesture configuration without generating a
421
+ // new identifier for the import to avoid collisions. i.e. "GestureConfig_1". The import
422
+ // manager checks for possible name collisions, but is able to ignore specific identifiers.
423
+ // We use this to ignore all references to the original Angular Material gesture config,
424
+ // because these will be replaced and therefore will not interfere.
425
+ const gestureIdentifiersInFile = this._getGestureConfigIdentifiersOfFile(sourceFile);
426
+ // If the parent of the identifier is accessed through a namespace, we can just
427
+ // import the new gesture config without rewriting the import declaration because
428
+ // the config has been imported through a namespaced import.
429
+ if (isNamespacedIdentifierAccess(node)) {
430
+ const newExpression = this._importManager.addImportToSourceFile(sourceFile, symbolName, moduleSpecifier, false, gestureIdentifiersInFile);
431
+ recorder.remove(node.parent.getStart(), node.parent.getWidth());
432
+ recorder.insertRight(node.parent.getStart(), this._printNode(newExpression, sourceFile));
433
+ return;
434
+ }
435
+ // Delete the old import to the "GestureConfig".
436
+ this._importManager.deleteNamedBindingImport(sourceFile, GESTURE_CONFIG_CLASS_NAME, importData.moduleName);
437
+ // If the current reference is not from inside of a import, we need to add a new
438
+ // import to the copied gesture config and replace the identifier. For references
439
+ // within an import, we do nothing but removing the actual import. This allows us
440
+ // to remove unused imports to the Material gesture config.
441
+ if (!isImport) {
442
+ const newExpression = this._importManager.addImportToSourceFile(sourceFile, symbolName, moduleSpecifier, false, gestureIdentifiersInFile);
443
+ recorder.remove(node.getStart(), node.getWidth());
444
+ recorder.insertRight(node.getStart(), this._printNode(newExpression, sourceFile));
445
+ }
446
+ }
447
+ /**
448
+ * Removes a given gesture config reference and its corresponding import from
449
+ * its containing source file. Imports will be always removed, but in some cases,
450
+ * where it's not guaranteed that a removal can be performed safely, we just
451
+ * create a migration failure (and add a TODO if possible).
452
+ */
453
+ _removeGestureConfigReference({ node, importData, isImport }) {
454
+ const sourceFile = node.getSourceFile();
455
+ const recorder = this.fileSystem.edit(this.fileSystem.resolve(sourceFile.fileName));
456
+ // Only remove the import for the gesture config if the gesture config has
457
+ // been accessed through a non-namespaced identifier access.
458
+ if (!isNamespacedIdentifierAccess(node)) {
459
+ this._importManager.deleteNamedBindingImport(sourceFile, GESTURE_CONFIG_CLASS_NAME, importData.moduleName);
460
+ }
461
+ // For references from within an import, we do not need to do anything other than
462
+ // removing the import. For other references, we remove the import and the reference
463
+ // identifier if used inside of a provider definition.
464
+ if (isImport) {
465
+ return;
466
+ }
467
+ const providerAssignment = node.parent;
468
+ // Only remove references to the gesture config which are part of a statically
469
+ // analyzable provider definition. We only support the common case of a gesture
470
+ // config provider definition where the config is set up through "useClass".
471
+ // Otherwise, it's not guaranteed that we can safely remove the provider definition.
472
+ if (!ts.isPropertyAssignment(providerAssignment) ||
473
+ getPropertyNameText(providerAssignment.name) !== 'useClass') {
474
+ this._nodeFailures.push({ node, message: CANNOT_REMOVE_REFERENCE_ERROR });
475
+ return;
476
+ }
477
+ const objectLiteralExpr = providerAssignment.parent;
478
+ const provideToken = objectLiteralExpr.properties.find((p) => ts.isPropertyAssignment(p) && getPropertyNameText(p.name) === 'provide');
479
+ // Do not remove the reference if the gesture config is not part of a provider definition,
480
+ // or if the provided toke is not referring to the known HAMMER_GESTURE_CONFIG token
481
+ // from platform-browser.
482
+ if (!provideToken || !this._isReferenceToHammerConfigToken(provideToken.initializer)) {
483
+ this._nodeFailures.push({ node, message: CANNOT_REMOVE_REFERENCE_ERROR });
484
+ return;
485
+ }
486
+ // Collect all nested identifiers which will be deleted. This helps us
487
+ // determining if we can remove imports for the "HAMMER_GESTURE_CONFIG" token.
488
+ this._deletedIdentifiers.push(...findMatchingChildNodes(objectLiteralExpr, ts.isIdentifier));
489
+ // In case the found provider definition is not part of an array literal,
490
+ // we cannot safely remove the provider. This is because it could be declared
491
+ // as a variable. e.g. "const gestureProvider = {provide: .., useClass: GestureConfig}".
492
+ // In that case, we just add an empty object literal with TODO and print a failure.
493
+ if (!ts.isArrayLiteralExpression(objectLiteralExpr.parent)) {
494
+ recorder.remove(objectLiteralExpr.getStart(), objectLiteralExpr.getWidth());
495
+ recorder.insertRight(objectLiteralExpr.getStart(), `/* TODO: remove */ {}`);
496
+ this._nodeFailures.push({
497
+ node: objectLiteralExpr,
498
+ message: `Unable to delete provider definition for "GestureConfig" completely. ` +
499
+ `Please clean up the provider.`
676
500
  });
501
+ return;
677
502
  }
678
- /**
679
- * Static migration rule method that will be called once all project targets
680
- * have been migrated individually. This method can be used to make changes based
681
- * on the analysis of the individual targets. For example: we only remove Hammer
682
- * from the "package.json" if it is not used in *any* project target.
683
- */
684
- static globalPostMigration(tree, context) {
685
- // Always notify the developer that the Hammer v9 migration does not migrate tests.
686
- context.logger.info('\n⚠ General notice: The HammerJS v9 migration for Angular Components is not able to ' +
687
- 'migrate tests. Please manually clean up tests in your project if they rely on ' +
688
- (this.globalUsesHammer ? 'the deprecated Angular Material gesture config.' : 'HammerJS.'));
689
- context.logger.info('Read more about migrating tests: https://git.io/ng-material-v9-hammer-migrate-tests');
690
- if (!this.globalUsesHammer && this._removeHammerFromPackageJson(tree)) {
691
- // Since Hammer has been removed from the workspace "package.json" file,
692
- // we schedule a node package install task to refresh the lock file.
693
- return { runPackageManager: true };
694
- }
695
- // Clean global state once the workspace has been migrated. This is technically
696
- // not necessary in "ng update", but in tests we re-use the same rule class.
697
- this.globalUsesHammer = false;
503
+ // Removes the object literal from the parent array expression. Removes
504
+ // the trailing comma token if present.
505
+ remove_array_element_1.removeElementFromArrayExpression(objectLiteralExpr, recorder);
506
+ }
507
+ /** Removes the given hammer config token import if it is not used. */
508
+ _removeHammerConfigTokenImportIfUnused({ node, importData }) {
509
+ const sourceFile = node.getSourceFile();
510
+ const isTokenUsed = this._hammerConfigTokenReferences.some(r => !r.isImport && !isNamespacedIdentifierAccess(r.node) &&
511
+ r.node.getSourceFile() === sourceFile && !this._deletedIdentifiers.includes(r.node));
512
+ // We don't want to remove the import for the token if the token is
513
+ // still used somewhere.
514
+ if (!isTokenUsed) {
515
+ this._importManager.deleteNamedBindingImport(sourceFile, HAMMER_CONFIG_TOKEN_NAME, importData.moduleName);
698
516
  }
699
- /**
700
- * Removes the hammer package from the workspace "package.json".
701
- * @returns Whether Hammer was set up and has been removed from the "package.json"
702
- */
703
- static _removeHammerFromPackageJson(tree) {
704
- if (!tree.exists('/package.json')) {
705
- return false;
706
- }
707
- const packageJson = JSON.parse(tree.read('/package.json').toString('utf8'));
708
- // We do not handle the case where someone manually added "hammerjs" to the dev dependencies.
709
- if (packageJson.dependencies && packageJson.dependencies[HAMMER_MODULE_SPECIFIER]) {
710
- delete packageJson.dependencies[HAMMER_MODULE_SPECIFIER];
711
- tree.overwrite('/package.json', JSON.stringify(packageJson, null, 2));
712
- return true;
517
+ }
518
+ /** Removes Hammer from all index HTML files of the current project. */
519
+ _removeHammerFromIndexFile() {
520
+ const indexFilePaths = schematics_1.getProjectIndexFiles(this.context.project);
521
+ indexFilePaths.forEach(filePath => {
522
+ if (!this.fileSystem.exists(filePath)) {
523
+ return;
713
524
  }
525
+ const htmlContent = this.fileSystem.read(filePath);
526
+ const recorder = this.fileSystem.edit(filePath);
527
+ find_hammer_script_tags_1.findHammerScriptImportElements(htmlContent)
528
+ .forEach(el => remove_element_from_html_1.removeElementFromHtml(el, recorder));
529
+ });
530
+ }
531
+ /** Sets up the Hammer gesture config in the root module if needed. */
532
+ _setupNewGestureConfigInRootModule(gestureConfigPath) {
533
+ const { project } = this.context;
534
+ const mainFilePath = schematics_1.getProjectMainFile(project);
535
+ const rootModuleSymbol = this._getRootModuleSymbol(mainFilePath);
536
+ if (rootModuleSymbol === null) {
537
+ this.failures.push({
538
+ filePath: mainFilePath,
539
+ message: `Could not setup Hammer gestures in module. Please ` +
540
+ `manually ensure that the Hammer gesture config is set up.`,
541
+ });
542
+ return;
543
+ }
544
+ const sourceFile = rootModuleSymbol.valueDeclaration.getSourceFile();
545
+ const metadata = schematics_1.getDecoratorMetadata(sourceFile, 'NgModule', '@angular/core');
546
+ // If no "NgModule" definition is found inside the source file, we just do nothing.
547
+ if (!metadata.length) {
548
+ return;
549
+ }
550
+ const filePath = this.fileSystem.resolve(sourceFile.fileName);
551
+ const recorder = this.fileSystem.edit(filePath);
552
+ const providersField = schematics_1.getMetadataField(metadata[0], 'providers')[0];
553
+ const providerIdentifiers = providersField ? findMatchingChildNodes(providersField, ts.isIdentifier) : null;
554
+ const gestureConfigExpr = this._importManager.addImportToSourceFile(sourceFile, GESTURE_CONFIG_CLASS_NAME, getModuleSpecifier(gestureConfigPath, filePath), false, this._getGestureConfigIdentifiersOfFile(sourceFile));
555
+ const hammerConfigTokenExpr = this._importManager.addImportToSourceFile(sourceFile, HAMMER_CONFIG_TOKEN_NAME, HAMMER_CONFIG_TOKEN_MODULE);
556
+ const newProviderNode = ts.createObjectLiteral([
557
+ ts.createPropertyAssignment('provide', hammerConfigTokenExpr),
558
+ ts.createPropertyAssignment('useClass', gestureConfigExpr)
559
+ ]);
560
+ // If the providers field exists and already contains references to the hammer gesture
561
+ // config token and the gesture config, we naively assume that the gesture config is
562
+ // already set up. We only want to add the gesture config provider if it is not set up.
563
+ if (!providerIdentifiers ||
564
+ !(this._hammerConfigTokenReferences.some(r => providerIdentifiers.includes(r.node)) &&
565
+ this._gestureConfigReferences.some(r => providerIdentifiers.includes(r.node)))) {
566
+ const symbolName = this._printNode(newProviderNode, sourceFile);
567
+ schematics_1.addSymbolToNgModuleMetadata(sourceFile, sourceFile.fileName, 'providers', symbolName, null)
568
+ .forEach(change => {
569
+ if (change instanceof change_1.InsertChange) {
570
+ recorder.insertRight(change.pos, change.toAdd);
571
+ }
572
+ });
573
+ }
574
+ }
575
+ /**
576
+ * Gets the TypeScript symbol of the root module by looking for the module
577
+ * bootstrap expression in the specified source file.
578
+ */
579
+ _getRootModuleSymbol(mainFilePath) {
580
+ const mainFile = this.program.getSourceFile(mainFilePath);
581
+ if (!mainFile) {
582
+ return null;
583
+ }
584
+ const appModuleExpr = find_main_module_1.findMainModuleExpression(mainFile);
585
+ if (!appModuleExpr) {
586
+ return null;
587
+ }
588
+ const appModuleSymbol = this._getDeclarationSymbolOfNode(unwrapExpression(appModuleExpr));
589
+ if (!appModuleSymbol || !appModuleSymbol.valueDeclaration) {
590
+ return null;
591
+ }
592
+ return appModuleSymbol;
593
+ }
594
+ /** Sets up the "HammerModule" in the root module of the current project. */
595
+ _setupHammerModuleInRootModule() {
596
+ const { project } = this.context;
597
+ const mainFilePath = schematics_1.getProjectMainFile(project);
598
+ const rootModuleSymbol = this._getRootModuleSymbol(mainFilePath);
599
+ if (rootModuleSymbol === null) {
600
+ this.failures.push({
601
+ filePath: mainFilePath,
602
+ message: `Could not setup HammerModule. Please manually set up the "HammerModule" ` +
603
+ `from "@angular/platform-browser".`,
604
+ });
605
+ return;
606
+ }
607
+ const sourceFile = rootModuleSymbol.valueDeclaration.getSourceFile();
608
+ const metadata = schematics_1.getDecoratorMetadata(sourceFile, 'NgModule', '@angular/core');
609
+ if (!metadata.length) {
610
+ return;
611
+ }
612
+ const importsField = schematics_1.getMetadataField(metadata[0], 'imports')[0];
613
+ const importIdentifiers = importsField ? findMatchingChildNodes(importsField, ts.isIdentifier) : null;
614
+ const recorder = this.fileSystem.edit(this.fileSystem.resolve(sourceFile.fileName));
615
+ const hammerModuleExpr = this._importManager.addImportToSourceFile(sourceFile, HAMMER_MODULE_NAME, HAMMER_MODULE_IMPORT);
616
+ // If the "HammerModule" is not already imported in the app module, we set it up
617
+ // by adding it to the "imports" field of the app module.
618
+ if (!importIdentifiers ||
619
+ !this._hammerModuleReferences.some(r => importIdentifiers.includes(r.node))) {
620
+ const symbolName = this._printNode(hammerModuleExpr, sourceFile);
621
+ schematics_1.addSymbolToNgModuleMetadata(sourceFile, sourceFile.fileName, 'imports', symbolName, null)
622
+ .forEach(change => {
623
+ if (change instanceof change_1.InsertChange) {
624
+ recorder.insertRight(change.pos, change.toAdd);
625
+ }
626
+ });
627
+ }
628
+ }
629
+ /** Prints a given node within the specified source file. */
630
+ _printNode(node, sourceFile) {
631
+ return this._printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
632
+ }
633
+ /** Gets all referenced gesture config identifiers of a given source file */
634
+ _getGestureConfigIdentifiersOfFile(sourceFile) {
635
+ return this._gestureConfigReferences.filter(d => d.node.getSourceFile() === sourceFile)
636
+ .map(d => d.node);
637
+ }
638
+ /** Gets the symbol that contains the value declaration of the specified node. */
639
+ _getDeclarationSymbolOfNode(node) {
640
+ const symbol = this.typeChecker.getSymbolAtLocation(node);
641
+ // Symbols can be aliases of the declaration symbol. e.g. in named import specifiers.
642
+ // We need to resolve the aliased symbol back to the declaration symbol.
643
+ // tslint:disable-next-line:no-bitwise
644
+ if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {
645
+ return this.typeChecker.getAliasedSymbol(symbol);
646
+ }
647
+ return symbol;
648
+ }
649
+ /**
650
+ * Checks whether the given expression resolves to a hammer gesture config
651
+ * token reference from "@angular/platform-browser".
652
+ */
653
+ _isReferenceToHammerConfigToken(expr) {
654
+ const unwrapped = unwrapExpression(expr);
655
+ if (ts.isIdentifier(unwrapped)) {
656
+ return this._hammerConfigTokenReferences.some(r => r.node === unwrapped);
657
+ }
658
+ else if (ts.isPropertyAccessExpression(unwrapped)) {
659
+ return this._hammerConfigTokenReferences.some(r => r.node === unwrapped.name);
660
+ }
661
+ return false;
662
+ }
663
+ /**
664
+ * Creates migration failures of the collected node failures. The returned migration
665
+ * failures are updated to reflect the post-migration state of source files. Meaning
666
+ * that failure positions are corrected if source file modifications shifted lines.
667
+ */
668
+ _createMigrationFailures() {
669
+ return this._nodeFailures.map(({ node, message }) => {
670
+ const sourceFile = node.getSourceFile();
671
+ const offset = node.getStart();
672
+ const position = ts.getLineAndCharacterOfPosition(sourceFile, node.getStart());
673
+ return {
674
+ position: this._importManager.correctNodePosition(node, offset, position),
675
+ message: message,
676
+ filePath: this.fileSystem.resolve(sourceFile.fileName),
677
+ };
678
+ });
679
+ }
680
+ /**
681
+ * Static migration rule method that will be called once all project targets
682
+ * have been migrated individually. This method can be used to make changes based
683
+ * on the analysis of the individual targets. For example: we only remove Hammer
684
+ * from the "package.json" if it is not used in *any* project target.
685
+ */
686
+ static globalPostMigration(tree, context) {
687
+ // Always notify the developer that the Hammer v9 migration does not migrate tests.
688
+ context.logger.info('\n⚠ General notice: The HammerJS v9 migration for Angular Components is not able to ' +
689
+ 'migrate tests. Please manually clean up tests in your project if they rely on ' +
690
+ (this.globalUsesHammer ? 'the deprecated Angular Material gesture config.' : 'HammerJS.'));
691
+ context.logger.info('Read more about migrating tests: https://git.io/ng-material-v9-hammer-migrate-tests');
692
+ if (!this.globalUsesHammer && this._removeHammerFromPackageJson(tree)) {
693
+ // Since Hammer has been removed from the workspace "package.json" file,
694
+ // we schedule a node package install task to refresh the lock file.
695
+ return { runPackageManager: true };
696
+ }
697
+ // Clean global state once the workspace has been migrated. This is technically
698
+ // not necessary in "ng update", but in tests we re-use the same rule class.
699
+ this.globalUsesHammer = false;
700
+ }
701
+ /**
702
+ * Removes the hammer package from the workspace "package.json".
703
+ * @returns Whether Hammer was set up and has been removed from the "package.json"
704
+ */
705
+ static _removeHammerFromPackageJson(tree) {
706
+ if (!tree.exists('/package.json')) {
714
707
  return false;
715
708
  }
709
+ const packageJson = JSON.parse(tree.read('/package.json').toString('utf8'));
710
+ // We do not handle the case where someone manually added "hammerjs" to the dev dependencies.
711
+ if (packageJson.dependencies && packageJson.dependencies[HAMMER_MODULE_SPECIFIER]) {
712
+ delete packageJson.dependencies[HAMMER_MODULE_SPECIFIER];
713
+ tree.overwrite('/package.json', JSON.stringify(packageJson, null, 2));
714
+ return true;
715
+ }
716
+ return false;
716
717
  }
717
- /** Global state of whether Hammer is used in any analyzed project target. */
718
- HammerGesturesMigration.globalUsesHammer = false;
719
- return HammerGesturesMigration;
720
- })();
718
+ }
721
719
  exports.HammerGesturesMigration = HammerGesturesMigration;
720
+ /** Global state of whether Hammer is used in any analyzed project target. */
721
+ HammerGesturesMigration.globalUsesHammer = false;
722
722
  /**
723
723
  * Recursively unwraps a given expression if it is wrapped
724
724
  * by parenthesis, type casts or type assertions.
@@ -740,7 +740,7 @@ function unwrapExpression(node) {
740
740
  * relative to the given containing file.
741
741
  */
742
742
  function getModuleSpecifier(newPath, containingFile) {
743
- let result = path_1.relative(path_1.dirname(containingFile), newPath).replace(/\\/g, '/').replace(/\.ts$/, '');
743
+ let result = core_1.relative(core_1.dirname(containingFile), newPath).replace(/\\/g, '/').replace(/\.ts$/, '');
744
744
  if (!result.startsWith('.')) {
745
745
  result = `./${result}`;
746
746
  }
@@ -775,4 +775,4 @@ function findMatchingChildNodes(parent, predicate) {
775
775
  ts.forEachChild(parent, visitNode);
776
776
  return result;
777
777
  }
778
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFtbWVyLWdlc3R1cmVzLW1pZ3JhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYXRlcmlhbC9zY2hlbWF0aWNzL25nLXVwZGF0ZS9taWdyYXRpb25zL2hhbW1lci1nZXN0dXJlcy12OS9oYW1tZXItZ2VzdHVyZXMtbWlncmF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7O0dBTUc7OztBQUVILCtDQUs4QjtBQUU5Qix3REFhaUM7QUFDakMsK0RBQWdFO0FBQ2hFLDJCQUFnQztBQUNoQywrQkFBZ0Q7QUFDaEQsaUNBQWlDO0FBRWpDLHVFQUF5RTtBQUN6RSx5REFBNEQ7QUFDNUQsbUVBQWlFO0FBQ2pFLHFEQUErQztBQUMvQyxpRUFBd0U7QUFDeEUseUVBQWlFO0FBRWpFLE1BQU0seUJBQXlCLEdBQUcsZUFBZSxDQUFDO0FBQ2xELE1BQU0sd0JBQXdCLEdBQUcsZ0JBQWdCLENBQUM7QUFDbEQsTUFBTSw0QkFBNEIsR0FBRywyQkFBMkIsQ0FBQztBQUVqRSxNQUFNLHdCQUF3QixHQUFHLHVCQUF1QixDQUFDO0FBQ3pELE1BQU0sMEJBQTBCLEdBQUcsMkJBQTJCLENBQUM7QUFFL0QsTUFBTSxrQkFBa0IsR0FBRyxjQUFjLENBQUM7QUFDMUMsTUFBTSxvQkFBb0IsR0FBRywyQkFBMkIsQ0FBQztBQUV6RCxNQUFNLHVCQUF1QixHQUFHLFVBQVUsQ0FBQztBQUUzQyxNQUFNLDZCQUE2QixHQUMvQixxRUFBcUUsQ0FBQztBQVExRTtJQUFBLE1BQWEsdUJBQXdCLFNBQVEsNEJBQXFCO1FBQWxFOztZQUNFLHlGQUF5RjtZQUN6Rix5RUFBeUU7WUFDekUsNEZBQTRGO1lBQzVGLFlBQU8sR0FDSCxDQUFDLElBQUksQ0FBQyxhQUFhLEtBQUssMEJBQWEsQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLGFBQWEsS0FBSywwQkFBYSxDQUFDLEdBQUcsQ0FBQztnQkFDckYsQ0FB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QUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDdkYsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQVMsc0JBQXNCLENBQzNCLE1BQWUsRUFBRSxTQUF1QztJQUMxRCxNQUFNLE1BQU0sR0FBUSxFQUFFLENBQUM7SUFDdkIsTUFBTSxTQUFTLEdBQUcsQ0FBQyxJQUFhLEVBQUUsRUFBRTtRQUNsQyxJQUFJLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUNuQixNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ25CO1FBQ0QsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDbkMsQ0FBQyxDQUFDO0lBQ0YsRUFBRSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDbkMsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge1xuICBqb2luIGFzIGRldmtpdEpvaW4sXG4gIG5vcm1hbGl6ZSBhcyBkZXZraXROb3JtYWxpemUsXG4gIFBhdGgsXG4gIFBhdGggYXMgRGV2a2l0UGF0aFxufSBmcm9tICdAYW5ndWxhci1kZXZraXQvY29yZSc7XG5pbXBvcnQge1NjaGVtYXRpY0NvbnRleHQsIFRyZWV9IGZyb20gJ0Bhbmd1bGFyLWRldmtpdC9zY2hlbWF0aWNzJztcbmltcG9ydCB7XG4gIGFkZFN5bWJvbFRvTmdNb2R1bGVNZXRhZGF0YSxcbiAgRGV2a2l0TWlncmF0aW9uLFxuICBnZXREZWNvcmF0b3JNZXRhZGF0YSxcbiAgZ2V0SW1wb3J0T2ZJZGVudGlmaWVyLFxuICBnZXRNZXRhZGF0YUZpZWxkLFxuICBnZXRQcm9qZWN0SW5kZXhGaWxlcyxcbiAgZ2V0UHJvamVjdE1haW5GaWxlLFxuICBJbXBvcnQsXG4gIE1pZ3JhdGlvbkZhaWx1cmUsXG4gIFBvc3RNaWdyYXRpb25BY3Rpb24sXG4gIFJlc29sdmVkUmVzb3VyY2UsXG4gIFRhcmdldFZlcnNpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY2RrL3NjaGVtYXRpY3MnO1xuaW1wb3J0IHtJbnNlcnRDaGFuZ2V9IGZyb20gJ0BzY2hlbWF0aWNzL2FuZ3VsYXIvdXRpbGl0eS9jaGFuZ2UnO1xuaW1wb3J0IHtyZWFkRmlsZVN5bmN9IGZyb20gJ2ZzJztcbmltcG9ydCB7ZGlybmFtZSwgcmVsYXRpdmUsIHJlc29sdmV9IGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgdHMgZnJvbSAndHlwZXNjcmlwdCc7XG5cbmltcG9ydCB7ZmluZEhhbW1lclNjcmlwdEltcG9ydEVsZW1lbnRzfSBmcm9tICcuL2ZpbmQtaGFtbWVyLXNjcmlwdC10YWdzJztcbmltcG9ydCB7ZmluZE1haW5Nb2R1bGVFeHByZXNzaW9ufSBmcm9tICcuL2ZpbmQtbWFpbi1tb2R1bGUnO1xuaW1wb3J0IHtpc0hhbW1lckpzVXNlZEluVGVtcGxhdGV9IGZyb20gJy4vaGFtbWVyLXRlbXBsYXRlLWNoZWNrJztcbmltcG9ydCB7SW1wb3J0TWFuYWdlcn0gZnJvbSAnLi9pbXBvcnQtbWFuYWdlcic7XG5pbXBvcnQge3JlbW92ZUVsZW1lbnRGcm9tQXJyYXlFeHByZXNzaW9ufSBmcm9tICcuL3JlbW92ZS1hcnJheS1lbGVtZW50JztcbmltcG9ydCB7cmVtb3ZlRWxlbWVudEZyb21IdG1sfSBmcm9tICcuL3JlbW92ZS1lbGVtZW50LWZyb20taHRtbCc7XG5cbmNvbnN0IEdFU1RVUkVfQ09ORklHX0NMQVNTX05BTUUgPSAnR2VzdHVyZUNvbmZpZyc7XG5jb25zdCBHRVNUVVJFX0NPTkZJR19GSUxFX05BTUUgPSAnZ2VzdHVyZS1jb25maWcnO1xuY29uc3QgR0VTVFVSRV9DT05GSUdfVEVNUExBVEVfUEFUSCA9ICcuL2dlc3R1cmUtY29uZmlnLnRlbXBsYXRlJztcblxuY29uc3QgSEFNTUVSX0NPTkZJR19UT0tFTl9OQU1FID0gJ0hBTU1FUl9HRVNUVVJFX0NPTkZJRyc7XG5jb25zdCBIQU1NRVJfQ09ORklHX1RPS0VOX01PRFVMRSA9ICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcblxuY29uc3QgSEFNTUVSX01PRFVMRV9OQU1FID0gJ0hhbW1lck1vZHVsZSc7XG5jb25zdCBIQU1NRVJfTU9EVUxFX0lNUE9SVCA9ICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcblxuY29uc3QgSEFNTUVSX01PRFVMRV9TUEVDSUZJRVIgPSAnaGFtbWVyanMnO1xuXG5jb25zdCBDQU5OT1RfUkVNT1ZFX1JFRkVSRU5DRV9FUlJPUiA9XG4gICAgYENhbm5vdCByZW1vdmUgcmVmZXJlbmNlIHRvIFwiR2VzdHVyZUNvbmZpZ1wiLiBQbGVhc2UgcmVtb3ZlIG1hbnVhbGx5LmA7XG5cbmludGVyZmFjZSBJZGVudGlmaWVyUmVmZXJlbmNlIHtcbiAgbm9kZTogdHMuSWRlbnRpZmllcjtcbiAgaW1wb3J0RGF0YTogSW1wb3J0O1xuICBpc0ltcG9ydDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGNsYXNzIEhhbW1lckdlc3R1cmVzTWlncmF0aW9uIGV4dGVuZHMgRGV2a2l0TWlncmF0aW9uPG51bGw+IHtcbiAgLy8gT25seSBlbmFibGUgdGhpcyBydWxlIGlmIHRoZSBtaWdyYXRpb24gdGFyZ2V0cyB2OSBvciB2MTAgYW5kIGlzIHJ1bm5pbmcgZm9yIGEgbm9uLXRlc3RcbiAgLy8gdGFyZ2V0LiBXZSBjYW5ub3QgbWlncmF0ZSB0ZXN0IHRhcmdldHMgc2luY2UgdGhleSBoYXZlIGEgbGltaXRlZCBzY29wZVxuICAvLyAoaW4gcmVnYXJkcyB0byBzb3VyY2UgZmlsZXMpIGFuZCB0aGVyZWZvcmUgdGhlIEhhbW1lckpTIHVzYWdlIGRldGVjdGlvbiBjYW4gYmUgaW5jb3JyZWN0LlxuICBlbmFibGVkID1cbiAgICAgICh0aGlzLnRhcmdldFZlcnNpb24gPT09IFRhcmdldFZlcnNpb24uVjkgfHwgdGhpcy50YXJnZXRWZXJzaW9uID09PSBUYXJnZXRWZXJzaW9uLlYxMCkgJiZcbiAgICAgICF0aGlzLmNvbnRleHQuaXNUZXN0VGFyZ2V0O1xuXG4gIHByaXZhdGUgX3ByaW50ZXIgPSB0cy5jcmVhdGVQcmludGVyKCk7XG4gIHByaXZhdGUgX2ltcG9ydE1hbmFnZXIgPSBuZXcgSW1wb3J0TWFuYWdlcih0aGlzLmZpbGVTeXN0ZW0sIHRoaXMuX3ByaW50ZXIpO1xuICBwcml2YXRlIF9ub2RlRmFpbHVyZXM6IHtub2RlOiB0cy5Ob2RlLCBtZXNzYWdlOiBzdHJpbmd9W10gPSBbXTtcblxuICAvKipcbiAgICogV2hldGhlciBjdXN0b20gSGFtbWVySlMgZXZlbnRzIHByb3ZpZGVkIGJ5IHRoZSBNYXRlcmlhbCBnZXN0dXJlXG4gICAqIGNvbmZpZyBhcmUgdXNlZCBpbiBhIHRlbXBsYXRlLlxuICAgKi9cbiAgcHJpdmF0ZSBfY3VzdG9tRXZlbnRzVXNlZEluVGVtcGxhdGUgPSBmYWxzZTtcblxuICAvKiogV2hldGhlciBzdGFuZGFyZCBIYW1tZXJKUyBldmVudHMgYXJlIHVzZWQgaW4gYSB0ZW1wbGF0ZS4gKi9cbiAgcHJpdmF0ZSBfc3RhbmRhcmRFdmVudHNVc2VkSW5UZW1wbGF0ZSA9IGZhbHNlO1xuXG4gIC8qKiBXaGV0aGVyIEhhbW1lckpTIGlzIGFjY2Vzc2VkIGF0IHJ1bnRpbWUuICovXG4gIHByaXZhdGUgX3VzZWRJblJ1bnRpbWUgPSBmYWxzZTtcblxuICAvKipcbiAgICogTGlzdCBvZiBpbXBvcnRzIHRoYXQgbWFrZSBcImhhbW1lcmpzXCIgYXZhaWxhYmxlIGdsb2JhbGx5LiBXZSBrZWVwIHRyYWNrIG9mIHRoZXNlXG4gICAqIHNpbmNlIHdlIG1pZ2h0IG5lZWQgdG8gcmVtb3ZlIHRoZW0gaWYgSGFtbWVyIGlzIG5vdCB1c2VkLlxuICAgKi9cbiAgcHJpdmF0ZSBfaW5zdGFsbEltcG9ydHM6IHRzLkltcG9ydERlY2xhcmF0aW9uW10gPSBbXTtcblxuICAvKipcbiAgICogTGlzdCBvZiBpZGVudGlmaWVycyB3aGljaCByZXNvbHZlIHRvIHRoZSBnZXN0dXJlIGNvbmZpZyBmcm9tIEFuZ3VsYXIgTWF0ZXJpYWwuXG4gICAqL1xuICBwcml2YXRlIF9nZXN0dXJlQ29uZmlnUmVmZXJlbmNlczogSWRlbnRpZmllclJlZmVyZW5jZVtdID0gW107XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgaWRlbnRpZmllcnMgd2hpY2ggcmVzb2x2ZSB0byB0aGUgXCJIQU1NRVJfR0VTVFVSRV9DT05GSUdcIiB0b2tlbiBmcm9tXG4gICAqIFwiQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3NlclwiLlxuICAgKi9cbiAgcHJpdmF0ZSBfaGFtbWVyQ29uZmlnVG9rZW5SZWZlcmVuY2VzOiBJZGVudGlmaWVyUmVmZXJlbmNlW10gPSBbXTtcblxuICAvKipcbiAgICogTGlzdCBvZiBpZGVudGlmaWVycyB3aGljaCByZXNvbHZlIHRvIHRoZSBcIkhhbW1lck1vZHVsZVwiIGZyb21cbiAgICogXCJAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyXCIuXG4gICAqL1xuICBwcml2YXRlIF9oYW1tZXJNb2R1bGVSZWZlcmVuY2VzOiBJZGVudGlmaWVyUmVmZXJlbmNlW10gPSBbXTtcblxuICAvKipcbiAgICogTGlzdCBvZiBpZGVudGlmaWVycyB0aGF0IGhhdmUgYmVlbiBkZWxldGVkIGZyb20gc291cmNlIGZpbGVzLiBUaGlzIGNhbiBiZVxuICAgKiB1c2VkIHRvIGRldGVybWluZSBpZiBjZXJ0YWluIGltcG9ydHMgYXJlIHN0aWxsIHVzZWQgb3Igbm90LlxuICAgKi9cbiAgcHJpdmF0ZSBfZGVsZXRlZElkZW50aWZpZXJzOiB0cy5JZGVudGlmaWVyW10gPSBbXTtcblxuICB2aXNpdFRlbXBsYXRlKHRlbXBsYXRlOiBSZXNvbHZlZFJlc291cmNlKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLl9jdXN0b21FdmVudHNVc2VkSW5UZW1wbGF0ZSB8fCAhdGhpcy5fc3RhbmRhcmRFdmVudHNVc2VkSW5UZW1wbGF0ZSkge1xuICAgICAgY29uc3Qge3N0YW5kYXJkRXZlbnRzLCBjdXN0b21FdmVudHN9ID0gaXNIYW1tZXJKc1VzZWRJblRlbXBsYXRlKHRlbXBsYXRlLmNvbnRlbnQpO1xuICAgICAgdGhpcy5fY3VzdG9tRXZlbnRzVXNlZEluVGVtcGxhdGUgPSB0aGlzLl9jdXN0b21FdmVudHNVc2VkSW5UZW1wbGF0ZSB8fCBjdXN0b21FdmVudHM7XG4gICAgICB0aGlzLl9zdGFuZGFyZEV2ZW50c1VzZWRJblRlbXBsYXRlID0gdGhpcy5fc3RhbmRhcmRFdmVudHNVc2VkSW5UZW1wbGF0ZSB8fCBzdGFuZGFyZEV2ZW50cztcbiAgICB9XG4gIH1cblxuICB2aXNpdE5vZGUobm9kZTogdHMuTm9kZSk6IHZvaWQge1xuICAgIHRoaXMuX2NoZWNrSGFtbWVySW1wb3J0cyhub2RlKTtcbiAgICB0aGlzLl9jaGVja0ZvclJ1bnRpbWVIYW1tZXJVc2FnZShub2RlKTtcbiAgICB0aGlzLl9jaGVja0Zvck1hdGVyaWFsR2VzdHVyZUNvbmZpZyhub2RlKTtcbiAgICB0aGlzLl9jaGVja0ZvckhhbW1lckdlc3R1cmVDb25maWdUb2tlbihub2RlKTtcbiAgICB0aGlzLl9jaGVja0ZvckhhbW1lck1vZHVsZVJlZmVyZW5jZShub2RlKTtcbiAgfVxuXG4gIHBvc3RBbmFseXNpcygpOiB2b2lkIHtcbiAgICAvLyBXYWxrIHRocm91Z2ggYWxsIGhhbW1lciBjb25maWcgdG9rZW4gcmVmZXJlbmNlcyBhbmQgY2hlY2sgaWYgdGhlcmVcbiAgICAvLyBpcyBhIHBvdGVudGlhbCBjdXN0b20gZ2VzdHVyZSBjb25maWcgc2V0dXAuXG4gICAgY29uc3QgaGFzQ3VzdG9tR2VzdHVyZUNvbmZpZ1NldHVwID1cbiAgICAgICAgdGhpcy5faGFtbWVyQ29uZmlnVG9rZW5SZWZlcmVuY2VzLnNvbWUociA9PiB0aGlzLl9jaGVja0ZvckN1c3RvbUdlc3R1cmVDb25maWdTZXR1cChyKSk7XG4gICAgY29uc3QgdXNlZEluVGVtcGxhdGUgPSB0aGlzLl9zdGFuZGFyZEV2ZW50c1VzZWRJblRlbXBsYXRlIHx8IHRoaXMuX2N1c3RvbUV2ZW50c1VzZWRJblRlbXBsYXRlO1xuXG4gICAgLypcbiAgICAgIFBvc3NpYmxlIHNjZW5hcmlvcyBhbmQgaG93IHRoZSBtaWdyYXRpb24gc2hvdWxkIGNoYW5nZSB0aGUgcHJvamVjdDpcbiAgICAgICAgMS4gV2UgZGV0ZWN0IHRoYXQgYSBjdXN0b20gSGFtbWVySlMgZ2VzdHVyZSBjb25maWcgaXMgc2V0IHVwOlxuICAgICAgICAgICAgLSBSZW1vdmUgcmVmZXJlbmNlcyB0byB0aGUgTWF0ZXJpYWwgZ2VzdHVyZSBjb25maWcgaWYgbm8gSGFtbWVySlMgZXZlbnQgaXMgdXNlZC5cbiAgICAgICAgICAgIC0gUHJpbnQgYSB3YXJuaW5nIGFib3V0IGFtYmlndW91cyBjb25maWd1cmF0aW9uIHRoYXQgY2Fubm90IGJlIGhhbmRsZWQgY29tcGxldGVseVxuICAgICAgICAgICAgICBpZiB0aGVyZSBhcmUgcmVmZXJlbmNlcyB0byB0aGUgTWF0ZXJpYWwgZ2VzdHVyZSBjb25maWcuXG4gICAgICAgIDIuIFdlIGRldGVjdCB0aGF0IEhhbW1lckpTIGlzIG9ubHkgdXNlZCBwcm9ncmFtbWF0aWNhbGx5OlxuICAgICAgICAgICAgLSBSZW1vdmUgcmVmZXJlbmNlcyB0byBHZXN0dXJlQ29uZmlnIG9mIE1hdGVyaWFsLlxuICAgICAgICAgICAgLSBSZW1vdmUgcmVmZXJlbmNlcyB0byB0aGUgXCJIYW1tZXJNb2R1bGVcIiBpZiBwcmVzZW50LlxuICAgICAgICAzLiBXZSBkZXRlY3QgdGhhdCBzdGFuZGFyZCBIYW1tZXJKUyBldmVudHMgYXJlIHVzZWQgaW4gYSB0ZW1wbGF0ZTpcbiAgICAgICAgICAgIC0gU2V0IHVwIHRoZSBcIkhhbW1lck1vZHVsZVwiIGZyb20gcGxhdGZvcm0tYnJvd3Nlci5cbiAgICAgICAgICAgIC0gUmVtb3ZlIGFsbCBnZXN0dXJlIGNvbmZpZyByZWZlcmVuY2VzLlxuICAgICAgICA0LiBXZSBkZXRlY3QgdGhhdCBjdXN0b20gSGFtbWVySlMgZXZlbnRzIHByb3ZpZGVkIGJ5IHRoZSBNYXRlcmlhbCBnZXN0dXJlXG4gICAgICAgICAgIGNvbmZpZyBhcmUgdXNlZC5cbiAgICAgICAgICAgIC0gQ29weSB0aGUgTWF0ZXJpYWwgZ2VzdHVyZSBjb25maWcgaW50byB0aGUgYXBwLlxuICAgICAgICAgICAgLSBSZXdyaXRlIGFsbCBnZXN0dXJlIGNvbmZpZyByZWZlcmVuY2VzIHRvIHRoZSBuZXdseSBjb3BpZWQgb25lLlxuICAgICAgICAgICAgLSBTZXQgdXAgdGhlIG5ldyBnZXN0dXJlIGNvbmZpZyBpbiB0aGUgcm9vdCBhcHAgbW9kdWxlLlxuICAgICAgICAgICAgLSBTZXQgdXAgdGhlIFwiSGFtbWVyTW9kdWxlXCIgZnJvbSBwbGF0Zm9ybS1icm93c2VyLlxuICAgICAgICA0LiBXZSBkZXRlY3Qgbm8gSGFtbWVySlMgdXNhZ2UgYXQgYWxsOlxuICAgICAgICAgICAgLSBSZW1vdmUgSGFtbWVyIGltcG9ydHNcbiAgICAgICAgICAgIC0gUmVtb3ZlIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnIHJlZmVyZW5jZXNcbiAgICAgICAgICAgIC0gUmVtb3ZlIEhhbW1lck1vZHVsZSBzZXR1cCBpZiBwcmVzZW50LlxuICAgICAgICAgICAgLSBSZW1vdmUgSGFtbWVyIHNjcmlwdCBpbXBvcnRzIGluIFwiaW5kZXguaHRtbFwiIGZpbGVzLlxuICAgICovXG5cbiAgICBpZiAoaGFzQ3VzdG9tR2VzdHVyZUNvbmZpZ1NldHVwKSB7XG4gICAgICAvLyBJZiBhIGN1c3RvbSBnZXN0dXJlIGNvbmZpZyBpcyBwcm92aWRlZCwgd2UgYWx3YXlzIGFzc3VtZSB0aGF0IEhhbW1lckpTIGlzIHVzZWQuXG4gICAgICBIYW1tZXJHZXN0dXJlc01pZ3JhdGlvbi5nbG9iYWxVc2VzSGFtbWVyID0gdHJ1ZTtcbiAgICAgIGlmICghdXNlZEluVGVtcGxhdGUgJiYgdGhpcy5fZ2VzdHVyZUNvbmZpZ1JlZmVyZW5jZXMubGVuZ3RoKSB7XG4gICAgICAgIC8vIElmIHRoZSBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgZXZlbnRzIGFyZSBub3QgdXNlZCBhbmQgd2UgZm91bmQgYSBjdXN0b21cbiAgICAgICAgLy8gZ2VzdHVyZSBjb25maWcsIHdlIGNhbiBzYWZlbHkgcmVtb3ZlIHJlZmVyZW5jZXMgdG8gdGhlIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnXG4gICAgICAgIC8vIHNpbmNlIGV2ZW50cyBwcm92aWRlZCBieSB0aGUgTWF0ZXJpYWwgZ2VzdHVyZSBjb25maWcgYXJlIGd1YXJhbnRlZWQgdG8gYmUgdW51c2VkLlxuICAgICAgICB0aGlzLl9yZW1vdmVNYXRlcmlhbEdlc3R1cmVDb25maWdTZXR1cCgpO1xuICAgICAgICB0aGlzLnByaW50SW5mbyhcbiAgICAgICAgICAgICdUaGUgSGFtbWVySlMgdjkgbWlncmF0aW9uIGZvciBBbmd1bGFyIENvbXBvbmVudHMgZGV0ZWN0ZWQgdGhhdCBIYW1tZXJKUyBpcyAnICtcbiAgICAgICAgICAgICdtYW51YWxseSBzZXQgdXAgaW4gY29tYmluYXRpb24gd2l0aCByZWZlcmVuY2VzIHRvIHRoZSBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgJyArXG4gICAgICAgICAgICAnY29uZmlnLiBUaGlzIHRhcmdldCBjYW5ub3QgYmUgbWlncmF0ZWQgY29tcGxldGVseSwgYnV0IGFsbCByZWZlcmVuY2VzIHRvIHRoZSAnICtcbiAgICAgICAgICAgICdkZXByZWNhdGVkIEFuZ3VsYXIgTWF0ZXJpYWwgZ2VzdHVyZSBoYXZlIGJlZW4gcmVtb3ZlZC4gUmVhZCBtb3JlIGhlcmU6ICcgK1xuICAgICAgICAgICAgJ2h0dHBzOi8vZ2l0LmlvL25nLW1hdGVyaWFsLXY5LWhhbW1lci1hbWJpZ3VvdXMtdXNhZ2UnKTtcbiAgICAgIH0gZWxzZSBpZiAodXNlZEluVGVtcGxhdGUgJiYgdGhpcy5fZ2VzdHVyZUNvbmZpZ1JlZmVyZW5jZXMubGVuZ3RoKSB7XG4gICAgICAgIC8vIFNpbmNlIHRoZXJlIGlzIGEgcmVmZXJlbmNlIHRvIHRoZSBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLCBhbmQgd2UgZGV0ZWN0ZWRcbiAgICAgICAgLy8gdXNhZ2Ugb2YgYSBnZXN0dXJlIGV2ZW50IHRoYXQgY291bGQgYmUgcHJvdmlkZWQgYnkgQW5ndWxhciBNYXRlcmlhbCwgd2UgKmNhbm5vdCpcbiAgICAgICAgLy8gYXV0b21hdGljYWxseSByZW1vdmUgcmVmZXJlbmNlcy4gVGhpcyBpcyBiZWNhdXNlIHdlIGRvICpub3QqIGtub3cgd2hldGhlciB0aGVcbiAgICAgICAgLy8gZXZlbnQgaXMgYWN0dWFsbHkgcHJvdmlkZWQgYnkgdGhlIGN1c3RvbSBjb25maWcgb3IgYnkgdGhlIE1hdGVyaWFsIGNvbmZpZy5cbiAgICAgICAgdGhpcy5wcmludEluZm8oXG4gICAgICAgICAgICAnVGhlIEhhbW1lckpTIHY5IG1pZ3JhdGlvbiBmb3IgQW5ndWxhciBDb21wb25lbnRzIGRldGVjdGVkIHRoYXQgSGFtbWVySlMgaXMgJyArXG4gICAgICAgICAgICAnbWFudWFsbHkgc2V0IHVwIGluIGNvbWJpbmF0aW9uIHdpdGggcmVmZXJlbmNlcyB0byB0aGUgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlICcgK1xuICAgICAgICAgICAgJ2NvbmZpZy4gVGhpcyB0YXJnZXQgY2Fubm90IGJlIG1pZ3JhdGVkIGNvbXBsZXRlbHkuIFBsZWFzZSBtYW51YWxseSByZW1vdmUgJyArXG4gICAgICAgICAgICAncmVmZXJlbmNlcyB0byB0aGUgZGVwcmVjYXRlZCBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLiBSZWFkIG1vcmUgaGVyZTogJyArXG4gICAgICAgICAgICAnaHR0cHM6Ly9naXQuaW8vbmctbWF0ZXJpYWwtdjktaGFtbWVyLWFtYmlndW91cy11c2FnZScpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodGhpcy5fdXNlZEluUnVudGltZSB8fCB1c2VkSW5UZW1wbGF0ZSkge1xuICAgICAgLy8gV2Uga2VlcCB0cmFjayBvZiB3aGV0aGVyIEhhbW1lciBpcyB1c2VkIGdsb2JhbGx5LiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIHdlXG4gICAgICAvLyB3YW50IHRvIG9ubHkgcmVtb3ZlIEhhbW1lciBmcm9tIHRoZSBcInBhY2thZ2UuanNvblwiIGlmIGl0IGlzIG5vdCB1c2VkIGluIGFueSBwcm9qZWN0XG4gICAgICAvLyB0YXJnZXQuIEp1c3QgYmVjYXVzZSBpdCBpc24ndCB1c2VkIGluIG9uZSB0YXJnZXQgZG9lc24ndCBtZWFuIHRoYXQgd2UgY2FuIHNhZmVseVxuICAgICAgLy8gcmVtb3ZlIHRoZSBkZXBlbmRlbmN5LlxuICAgICAgSGFtbWVyR2VzdHVyZXNNaWdyYXRpb24uZ2xvYmFsVXNlc0hhbW1lciA9IHRydWU7XG5cbiAgICAgIC8vIElmIGhhbW1lciBpcyBvbmx5IHVzZWQgYXQgcnVudGltZSwgd2UgZG9uJ3QgbmVlZCB0aGUgZ2VzdHVyZSBjb25maWcgb3IgXCJIYW1tZXJNb2R1bGVcIlxuICAgICAgLy8gYW5kIGNhbiByZW1vdmUgaXQgKGFsb25nIHdpdGggdGhlIGhhbW1lciBjb25maWcgdG9rZW4gaW1wb3J0IGlmIG5vIGxvbmdlciBuZWVkZWQpLlxuICAgICAgaWYgKCF1c2VkSW5UZW1wbGF0ZSkge1xuICAgICAgICB0aGlzLl9yZW1vdmVNYXRlcmlhbEdlc3R1cmVDb25maWdTZXR1cCgpO1xuICAgICAgICB0aGlzLl9yZW1vdmVIYW1tZXJNb2R1bGVSZWZlcmVuY2VzKCk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuX3N0YW5kYXJkRXZlbnRzVXNlZEluVGVtcGxhdGUgJiYgIXRoaXMuX2N1c3RvbUV2ZW50c1VzZWRJblRlbXBsYXRlKSB7XG4gICAgICAgIHRoaXMuX3NldHVwSGFtbWVyV2l0aFN0YW5kYXJkRXZlbnRzKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLl9zZXR1cEhhbW1lcldpdGhDdXN0b21FdmVudHMoKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fcmVtb3ZlSGFtbWVyU2V0dXAoKTtcbiAgICB9XG5cbiAgICAvLyBSZWNvcmQgdGhlIGNoYW5nZXMgY29sbGVjdGVkIGluIHRoZSBpbXBvcnQgbWFuYWdlci4gQ2hhbmdlcyBuZWVkIHRvIGJlIGFwcGxpZWRcbiAgICAvLyBvbmNlIHRoZSBpbXBvcnQgbWFuYWdlciByZWdpc3RlcmVkIGFsbCBpbXBvcnQgbW9kaWZpY2F0aW9ucy4gVGhpcyBhdm9pZHMgY29sbGlzaW9ucy5cbiAgICB0aGlzLl9pbXBvcnRNYW5hZ2VyLnJlY29yZENoYW5nZXMoKTtcblxuICAgIC8vIENyZWF0ZSBtaWdyYXRpb24gZmFpbHVyZXMgdGhhdCB3aWxsIGJlIHByaW50ZWQgYnkgdGhlIHVwZGF0ZS10b29sIG9uIG1pZ3JhdGlvblxuICAgIC8vIGNvbXBsZXRpb24uIFdlIG5lZWQgc3BlY2lhbCBsb2dpYyBmb3IgdXBkYXRpbmcgZmFpbHVyZSBwb3NpdGlvbnMgdG8gcmVmbGVjdFxuICAgIC8vIHRoZSBuZXcgc291cmNlIGZpbGUgYWZ0ZXIgbW9kaWZpY2F0aW9ucyBmcm9tIHRoZSBpbXBvcnQgbWFuYWdlci5cbiAgICB0aGlzLmZhaWx1cmVzLnB1c2goLi4udGhpcy5fY3JlYXRlTWlncmF0aW9uRmFpbHVyZXMoKSk7XG5cbiAgICAvLyBUaGUgdGVtcGxhdGUgY2hlY2sgZm9yIEhhbW1lckpTIGV2ZW50cyBpcyBub3QgY29tcGxldGVseSByZWxpYWJsZSBhcyB0aGUgZXZlbnRcbiAgICAvLyBvdXRwdXQgY291bGQgYWxzbyBiZSBmcm9tIGEgY29tcG9uZW50IGhhdmluZyBhbiBvdXRwdXQgbmFtZWQgc2ltaWxhcmx5IHRvIGEga25vd25cbiAgICAvLyBoYW1tZXJqcyBldmVudCAoZS5nLiBcIkBPdXRwdXQoKSBzbGlkZVwiKS4gVGhlIHVzYWdlIGlzIHRoZXJlZm9yZSBzb21ld2hhdCBhbWJpZ3VvdXNcbiAgICAvLyBhbmQgd2Ugd2FudCB0byBwcmludCBhIG1lc3NhZ2UgdGhhdCBkZXZlbG9wZXJzIG1pZ2h0IGJlIGFibGUgdG8gcmVtb3ZlIEhhbW1lciBtYW51YWxseS5cbiAgICBpZiAoIWhhc0N1c3RvbUdlc3R1cmVDb25maWdTZXR1cCAmJiAhdGhpcy5fdXNlZEluUnVudGltZSAmJiB1c2VkSW5UZW1wbGF0ZSkge1xuICAgICAgdGhpcy5wcmludEluZm8oXG4gICAgICAgICAgJ1RoZSBIYW1tZXJKUyB2OSBtaWdyYXRpb24gZm9yIEFuZ3VsYXIgQ29tcG9uZW50cyBtaWdyYXRlZCB0aGUgJyArXG4gICAgICAgICAgJ3Byb2plY3QgdG8ga2VlcCBIYW1tZXJKUyBpbnN0YWxsZWQsIGJ1dCBkZXRlY3RlZCBhbWJpZ3VvdXMgdXNhZ2Ugb2YgSGFtbWVySlMuIFBsZWFzZSAnICtcbiAgICAgICAgICAnbWFudWFsbHkgY2hlY2sgaWYgeW91IGNhbiByZW1vdmUgSGFtbWVySlMgZnJvbSB5b3VyIGFwcGxpY2F0aW9uLiBNb3JlIGRldGFpbHM6ICcgK1xuICAgICAgICAgICdodHRwczovL2dpdC5pby9uZy1tYXRlcmlhbC12OS1oYW1tZXItYW1iaWd1b3VzLXVzYWdlJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdXAgdGhlIGhhbW1lciBnZXN0dXJlIGNvbmZpZyBpbiB0aGUgY3VycmVudCBwcm9qZWN0LiBUbyBhY2hpZXZlIHRoaXMsIHRoZVxuICAgKiBmb2xsb3dpbmcgc3RlcHMgYXJlIHBlcmZvcm1lZDpcbiAgICogICAxKSBDcmVhdGUgY29weSBvZiBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLlxuICAgKiAgIDIpIFJld3JpdGUgYWxsIHJlZmVyZW5jZXMgdG8gdGhlIEFuZ3VsYXIgTWF0ZXJpYWwgZ2VzdHVyZSBjb25maWcgdG8gdGhlXG4gICAqICAgICAgbmV3IGdlc3R1cmUgY29uZmlnLlxuICAgKiAgIDMpIFNldHVwIHRoZSBIQU1NRVJfR0VTVFVSRV9DT05GSUcgaW4gdGhlIHJvb3QgYXBwIG1vZHVsZSAoaWYgbm90IGRvbmUgYWxyZWFkeSkuXG4gICAqICAgNCkgU2V0dXAgdGhlIFwiSGFtbWVyTW9kdWxlXCIgaW4gdGhlIHJvb3QgYXBwIG1vZHVsZSAoaWYgbm90IGRvbmUgYWxyZWFkeSkuXG4gICAqL1xuICBwcml2YXRlIF9zZXR1cEhhbW1lcldpdGhDdXN0b21FdmVudHMoKSB7XG4gICAgY29uc3QgcHJvamVjdCA9IHRoaXMuY29udGV4dC5wcm9qZWN0O1xuICAgIGNvbnN0IHNvdXJjZVJvb3QgPSBkZXZraXROb3JtYWxpemUocHJvamVjdC5zb3VyY2VSb290IHx8IHByb2plY3Qucm9vdCk7XG4gICAgY29uc3QgbmV3Q29uZmlnUGF0aCA9XG4gICAgICAgIGRldmtpdEpvaW4oc291cmNlUm9vdCwgdGhpcy5fZ2V0QXZhaWxhYmxlR2VzdHVyZUNvbmZpZ0ZpbGVOYW1lKHNvdXJjZVJvb3QpKTtcblxuICAgIC8vIENvcHkgZ2VzdHVyZSBjb25maWcgdGVtcGxhdGUgaW50byB0aGUgQ0xJIHByb2plY3QuXG4gICAgdGhpcy5maWxlU3lzdGVtLmNyZWF0ZShcbiAgICAgICAgbmV3Q29uZmlnUGF0aCwgcmVhZEZpbGVTeW5jKHJlcXVpcmUucmVzb2x2ZShHRVNUVVJFX0NPTkZJR19URU1QTEFURV9QQVRIKSwgJ3V0ZjgnKSk7XG5cbiAgICAvLyBSZXBsYWNlIGFsbCBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZyByZWZlcmVuY2VzIHRvIHJlc29sdmUgdG8gdGhlXG4gICAgLy8gbmV3bHkgY29waWVkIGdlc3R1cmUgY29uZmlnLlxuICAgIHRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLmZvckVhY2goXG4gICAgICAgIGkgPT4gdGhpcy5fcmVwbGFjZUdlc3R1cmVDb25maWdSZWZlcmVuY2UoXG4gICAgICAgICAgICBpLCBHRVNUVVJFX0NPTkZJR19DTEFTU19OQU1FLFxuICAgICAgICAgICAgZ2V0TW9kdWxlU3BlY2lmaWVyKG5ld0NvbmZpZ1BhdGgsIGkubm9kZS5nZXRTb3VyY2VGaWxlKCkuZmlsZU5hbWUpKSk7XG5cbiAgICAvLyBTZXR1cCB0aGUgZ2VzdHVyZSBjb25maWcgcHJvdmlkZXIgYW5kIHRoZSBcIkhhbW1lck1vZHVsZVwiIGluIHRoZSByb290IG1vZHVsZVxuICAgIC8vIGlmIG5vdCBkb25lIGFscmVhZHkuIFRoZSBcIkhhbW1lck1vZHVsZVwiIGlzIG5lZWRlZCBpbiB2OSBzaW5jZSBpdCBlbmFibGVzIHRoZVxuICAgIC8vIEhhbW1lciBldmVudCBwbHVnaW4gdGhhdCB3YXMgcHJldmlvdXNseSBlbmFibGVkIGJ5IGRlZmF1bHQgaW4gdjguXG4gICAgdGhpcy5fc2V0dXBOZXdHZXN0dXJlQ29uZmlnSW5Sb290TW9kdWxlKG5ld0NvbmZpZ1BhdGgpO1xuICAgIHRoaXMuX3NldHVwSGFtbWVyTW9kdWxlSW5Sb290TW9kdWxlKCk7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB1cCB0aGUgc3RhbmRhcmQgaGFtbWVyIG1vZHVsZSBpbiB0aGUgcHJvamVjdCBhbmQgcmVtb3ZlcyBhbGxcbiAgICogcmVmZXJlbmNlcyB0byB0aGUgZGVwcmVjYXRlZCBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLlxuICAgKi9cbiAgcHJpdmF0ZSBfc2V0dXBIYW1tZXJXaXRoU3RhbmRhcmRFdmVudHMoKSB7XG4gICAgLy8gU2V0dXAgdGhlIEhhbW1lck1vZHVsZS4gVGhlIEhhbW1lck1vZHVsZSBlbmFibGVzIHN1cHBvcnQgZm9yXG4gICAgLy8gdGhlIHN0YW5kYXJkIEhhbW1lckpTIGV2ZW50cy5cbiAgICB0aGlzLl9zZXR1cEhhbW1lck1vZHVsZUluUm9vdE1vZHVsZSgpO1xuICAgIHRoaXMuX3JlbW92ZU1hdGVyaWFsR2VzdHVyZUNvbmZpZ1NldHVwKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBIYW1tZXIgZnJvbSB0aGUgY3VycmVudCBwcm9qZWN0LiBUaGUgZm9sbG93aW5nIHN0ZXBzIGFyZSBwZXJmb3JtZWQ6XG4gICAqICAgMSkgRGVsZXRlIGFsbCBUeXBlU2NyaXB0IGltcG9ydHMgdG8gXCJoYW1tZXJqc1wiLlxuICAgKiAgIDIpIFJlbW92ZSByZWZlcmVuY2VzIHRvIHRoZSBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLlxuICAgKiAgIDMpIFJlbW92ZSBcImhhbW1lcmpzXCIgZnJvbSBhbGwgaW5kZXggSFRNTCBmaWxlcyBvZiB0aGUgY3VycmVudCBwcm9qZWN0LlxuICAgKi9cbiAgcHJpdmF0ZSBfcmVtb3ZlSGFtbWVyU2V0dXAoKSB7XG4gICAgdGhpcy5faW5zdGFsbEltcG9ydHMuZm9yRWFjaChpID0+IHRoaXMuX2ltcG9ydE1hbmFnZXIuZGVsZXRlSW1wb3J0QnlEZWNsYXJhdGlvbihpKSk7XG5cbiAgICB0aGlzLl9yZW1vdmVNYXRlcmlhbEdlc3R1cmVDb25maWdTZXR1cCgpO1xuICAgIHRoaXMuX3JlbW92ZUhhbW1lck1vZHVsZVJlZmVyZW5jZXMoKTtcbiAgICB0aGlzLl9yZW1vdmVIYW1tZXJGcm9tSW5kZXhGaWxlKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyB0aGUgZ2VzdHVyZSBjb25maWcgc2V0dXAgYnkgZGVsZXRpbmcgYWxsIGZvdW5kIHJlZmVyZW5jZXMgdG8gdGhlIEFuZ3VsYXJcbiAgICogTWF0ZXJpYWwgZ2VzdHVyZSBjb25maWcuIEFkZGl0aW9uYWxseSwgdW51c2VkIGltcG9ydHMgdG8gdGhlIGhhbW1lciBnZXN0dXJlIGNvbmZpZ1xuICAgKiB0b2tlbiBmcm9tIFwiQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3NlclwiIHdpbGwgYmUgcmVtb3ZlZCBhcyB3ZWxsLlxuICAgKi9cbiAgcHJpdmF0ZSBfcmVtb3ZlTWF0ZXJpYWxHZXN0dXJlQ29uZmlnU2V0dXAoKSB7XG4gICAgdGhpcy5fZ2VzdHVyZUNvbmZpZ1JlZmVyZW5jZXMuZm9yRWFjaChyID0+IHRoaXMuX3JlbW92ZUdlc3R1cmVDb25maWdSZWZlcmVuY2UocikpO1xuXG4gICAgdGhpcy5faGFtbWVyQ29uZmlnVG9rZW5SZWZlcmVuY2VzLmZvckVhY2gociA9PiB7XG4gICAgICBpZiAoci5pc0ltcG9ydCkge1xuICAgICAgICB0aGlzLl9yZW1vdmVIYW1tZXJDb25maWdUb2tlbkltcG9ydElmVW51c2VkKHIpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqIFJlbW92ZXMgYWxsIHJlZmVyZW5jZXMgdG8gdGhlIFwiSGFtbWVyTW9kdWxlXCIgZnJvbSBcIkBhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXJcIi4gKi9cbiAgcHJpdmF0ZSBfcmVtb3ZlSGFtbWVyTW9kdWxlUmVmZXJlbmNlcygpIHtcbiAgICB0aGlzLl9oYW1tZXJNb2R1bGVSZWZlcmVuY2VzLmZvckVhY2goKHtub2RlLCBpc0ltcG9ydCwgaW1wb3J0RGF0YX0pID0+IHtcbiAgICAgIGNvbnN0IHNvdXJjZUZpbGUgPSBub2RlLmdldFNvdXJjZUZpbGUoKTtcbiAgICAgIGNvbnN0IHJlY29yZGVyID0gdGhpcy5maWxlU3lzdGVtLmVkaXQodGhpcy5maWxlU3lzdGVtLnJlc29sdmUoc291cmNlRmlsZS5maWxlTmFtZSkpO1xuXG4gICAgICAvLyBPbmx5IHJlbW92ZSB0aGUgaW1wb3J0IGZvciB0aGUgSGFtbWVyTW9kdWxlIGlmIHRoZSBtb2R1bGUgaGFzIGJlZW4gYWNjZXNzZWRcbiAgICAgIC8vIHRocm91Z2ggYSBub24tbmFtZXNwYWNlZCBpZGVudGlmaWVyIGFjY2Vzcy5cbiAgICAgIGlmICghaXNOYW1lc3BhY2VkSWRlbnRpZmllckFjY2Vzcyhub2RlKSkge1xuICAgICAgICB0aGlzLl9pbXBvcnRNYW5hZ2VyLmRlbGV0ZU5hbWVkQmluZGluZ0ltcG9ydChcbiAgICAgICAgICAgIHNvdXJjZUZpbGUsIEhBTU1FUl9NT0RVTEVfTkFNRSwgaW1wb3J0RGF0YS5tb2R1bGVOYW1lKTtcbiAgICAgIH1cblxuICAgICAgLy8gRm9yIHJlZmVyZW5jZXMgZnJvbSB3aXRoaW4gYW4gaW1wb3J0LCB3ZSBkbyBub3QgbmVlZCB0byBkbyBhbnl0aGluZyBvdGhlciB0aGFuXG4gICAgICAvLyByZW1vdmluZyB0aGUgaW1wb3J0LiBGb3Igb3RoZXIgcmVmZXJlbmNlcywgd2UgcmVtb3ZlIHRoZSBpbXBvcnQgYW5kIHRoZSBhY3R1YWxcbiAgICAgIC8vIGlkZW50aWZpZXIgaW4gdGhlIG1vZHVsZSBpbXBvcnRzLlxuICAgICAgaWYgKGlzSW1wb3J0KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgLy8gSWYgdGhlIFwiSGFtbWVyTW9kdWxlXCIgaXMgcmVmZXJlbmNlZCB3aXRoaW4gYW4gYXJyYXkgbGl0ZXJhbCwgd2UgY2FuXG4gICAgICAvLyByZW1vdmUgdGhlIGVsZW1lbnQgZWFzaWx5LiBPdGhlcndpc2UgaWYgaXQncyBvdXRzaWRlIG9mIGFuIGFycmF5IGxpdGVyYWwsXG4gICAgICAvLyB3ZSBuZWVkIHRvIHJlcGxhY2UgdGhlIHJlZmVyZW5jZSB3aXRoIGFuIGVtcHR5IG9iamVjdCBsaXRlcmFsIHcvIHRvZG8gdG9cbiAgICAgIC8vIG5vdCBicmVhayB0aGUgYXBwbGljYXRpb24uXG4gICAgICBpZiAodHMuaXNBcnJheUxpdGVyYWxFeHByZXNzaW9uKG5vZGUucGFyZW50KSkge1xuICAgICAgICAvLyBSZW1vdmVzIHRoZSBcIkhhbW1lck1vZHVsZVwiIGZyb20gdGhlIHBhcmVudCBhcnJheSBleHByZXNzaW9uLiBSZW1vdmVzXG4gICAgICAgIC8vIHRoZSB0cmFpbGluZyBjb21tYSB0b2tlbiBpZiBwcmVzZW50LlxuICAgICAgICByZW1vdmVFbGVtZW50RnJvbUFycmF5RXhwcmVzc2lvbihub2RlLCByZWNvcmRlcik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZWNvcmRlci5yZW1vdmUobm9kZS5nZXRTdGFydCgpLCBub2RlLmdldFdpZHRoKCkpO1xuICAgICAgICByZWNvcmRlci5pbnNlcnRSaWdodChub2RlLmdldFN0YXJ0KCksIGAvKiBUT0RPOiByZW1vdmUgKi8ge31gKTtcbiAgICAgICAgdGhpcy5fbm9kZUZhaWx1cmVzLnB1c2goe1xuICAgICAgICAgIG5vZGU6IG5vZGUsXG4gICAgICAgICAgbWVzc2FnZTogJ1VuYWJsZSB0byBkZWxldGUgcmVmZXJlbmNlIHRvIFwiSGFtbWVyTW9kdWxlXCIuJyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBub2RlIGlzIGEgcmVmZXJlbmNlIHRvIHRoZSBoYW1tZXIgZ2VzdHVyZSBjb25maWdcbiAgICogdG9rZW4gZnJvbSBwbGF0Zm9ybS1icm93c2VyLiBJZiBzbywga2VlcHMgdHJhY2sgb2YgdGhlIHJlZmVyZW5jZS5cbiAgICovXG4gIHByaXZhdGUgX2NoZWNrRm9ySGFtbWVyR2VzdHVyZUNvbmZpZ1Rva2VuKG5vZGU6IHRzLk5vZGUpIHtcbiAgICBpZiAodHMuaXNJZGVudGlmaWVyKG5vZGUpKSB7XG4gICAgICBjb25zdCBpbXBvcnREYXRhID0gZ2V0SW1wb3J0T2ZJZGVudGlmaWVyKG5vZGUsIHRoaXMudHlwZUNoZWNrZXIpO1xuICAgICAgaWYgKGltcG9ydERhdGEgJiYgaW1wb3J0RGF0YS5zeW1ib2xOYW1lID09PSBIQU1NRVJfQ09ORklHX1RPS0VOX05BTUUgJiZcbiAgICAgICAgICBpbXBvcnREYXRhLm1vZHVsZU5hbWUgPT09IEhBTU1FUl9DT05GSUdfVE9LRU5fTU9EVUxFKSB7XG4gICAgICAgIHRoaXMuX2hhbW1lckNvbmZpZ1Rva2VuUmVmZXJlbmNlcy5wdXNoKFxuICAgICAgICAgICAge25vZGUsIGltcG9ydERhdGEsIGlzSW1wb3J0OiB0cy5pc0ltcG9ydFNwZWNpZmllcihub2RlLnBhcmVudCl9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBub2RlIGlzIGEgcmVmZXJlbmNlIHRvIHRoZSBIYW1tZXJNb2R1bGUgZnJvbVxuICAgKiBcIkBhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXJcIi4gSWYgc28sIGtlZXBzIHRyYWNrIG9mIHRoZSByZWZlcmVuY2UuXG4gICAqL1xuICBwcml2YXRlIF9jaGVja0ZvckhhbW1lck1vZHVsZVJlZmVyZW5jZShub2RlOiB0cy5Ob2RlKSB7XG4gICAgaWYgKHRzLmlzSWRlbnRpZmllcihub2RlKSkge1xuICAgICAgY29uc3QgaW1wb3J0RGF0YSA9IGdldEltcG9ydE9mSWRlbnRpZmllcihub2RlLCB0aGlzLnR5cGVDaGVja2VyKTtcbiAgICAgIGlmIChpbXBvcnREYXRhICYmIGltcG9ydERhdGEuc3ltYm9sTmFtZSA9PT0gSEFNTUVSX01PRFVMRV9OQU1FICYmXG4gICAgICAgICAgaW1wb3J0RGF0YS5tb2R1bGVOYW1lID09PSBIQU1NRVJfTU9EVUxFX0lNUE9SVCkge1xuICAgICAgICB0aGlzLl9oYW1tZXJNb2R1bGVSZWZlcmVuY2VzLnB1c2goXG4gICAgICAgICAgICB7bm9kZSwgaW1wb3J0RGF0YSwgaXNJbXBvcnQ6IHRzLmlzSW1wb3J0U3BlY2lmaWVyKG5vZGUucGFyZW50KX0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhlIGdpdmVuIG5vZGUgaXMgYW4gaW1wb3J0IHRvIHRoZSBIYW1tZXJKUyBwYWNrYWdlLiBJbXBvcnRzIHRvXG4gICAqIEhhbW1lckpTIHdoaWNoIGxvYWQgc3BlY2lmaWMgc3ltYm9scyBmcm9tIHRoZSBwYWNrYWdlIGFyZSBjb25zaWRlcmVkIGFzXG4gICAqIHJ1bnRpbWUgdXNhZ2Ugb2YgSGFtbWVyLiBlLmcuIGBpbXBvcnQge1N5bWJvbH0gZnJvbSBcImhhbW1lcmpzXCI7YC5cbiAgICovXG4gIHByaXZhdGUgX2NoZWNrSGFtbWVySW1wb3J0cyhub2RlOiB0cy5Ob2RlKSB7XG4gICAgaWYgKHRzLmlzSW1wb3J0RGVjbGFyYXRpb24obm9kZSkgJiYgdHMuaXNTdHJpbmdMaXRlcmFsKG5vZGUubW9kdWxlU3BlY2lmaWVyKSAmJlxuICAgICAgICBub2RlLm1vZHVsZVNwZWNpZmllci50ZXh0ID09PSBIQU1NRVJfTU9EVUxFX1NQRUNJRklFUikge1xuICAgICAgLy8gSWYgdGhlcmUgaXMgYW4gaW1wb3J0IHRvIEhhbW1lckpTIHRoYXQgaW1wb3J0cyBzeW1ib2xzLCBvciBpcyBuYW1lc3BhY2VkXG4gICAgICAvLyAoZS5nLiBcImltcG9ydCB7QSwgQn0gZnJvbSAuLi5cIiBvciBcImltcG9ydCAqIGFzIGhhbW1lciBmcm9tIC4uLlwiKSwgdGhlbiB3ZVxuICAgICAgLy8gYXNzdW1lIHRoYXQgc29tZSBleHBvcnRzIGFyZSB1c2VkIGF0IHJ1bnRpbWUuXG4gICAgICBpZiAobm9kZS5pbXBvcnRDbGF1c2UgJiZcbiAgICAgICAgICAhKG5vZGUuaW1wb3J0Q2xhdXNlLm5hbWVkQmluZGluZ3MgJiYgdHMuaXNOYW1lZEltcG9ydHMobm9kZS5pbXBvcnRDbGF1c2UubmFtZWRCaW5kaW5ncykgJiZcbiAgICAgICAgICAgIG5vZGUuaW1wb3J0Q2xhdXNlLm5hbWVkQmluZGluZ3MuZWxlbWVudHMubGVuZ3RoID09PSAwKSkge1xuICAgICAgICB0aGlzLl91c2VkSW5SdW50aW1lID0gdHJ1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuX2luc3RhbGxJbXBvcnRzLnB1c2gobm9kZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gbm9kZSBhY2Nlc3NlcyB0aGUgZ2xvYmFsIFwiSGFtbWVyXCIgc3ltYm9sIGF0IHJ1bnRpbWUuIElmIHNvLFxuICAgKiB0aGUgbWlncmF0aW9uIHJ1bGUgc3RhdGUgd2lsbCBiZSB1cGRhdGVkIHRvIHJlZmxlY3QgdGhhdCBIYW1tZXIgaXMgdXNlZCBhdCBydW50aW1lLlxuICAgKi9cbiAgcHJpdmF0ZSBfY2hlY2tGb3JSdW50aW1lSGFtbWVyVXNhZ2Uobm9kZTogdHMuTm9kZSkge1xuICAgIGlmICh0aGlzLl91c2VkSW5SdW50aW1lKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gRGV0ZWN0cyB1c2FnZXMgb2YgXCJ3aW5kb3cuSGFtbWVyXCIuXG4gICAgaWYgKHRzLmlzUHJvcGVydHlBY2Nlc3NFeHByZXNzaW9uKG5vZGUpICYmIG5vZGUubmFtZS50ZXh0ID09PSAnSGFtbWVyJykge1xuICAgICAgY29uc3Qgb3JpZ2luRXhwciA9IHVud3JhcEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uKTtcbiAgICAgIGlmICh0cy5pc0lkZW50aWZpZXIob3JpZ2luRXhwcikgJiYgb3JpZ2luRXhwci50ZXh0ID09PSAnd2luZG93Jykge1xuICAgICAgICB0aGlzLl91c2VkSW5SdW50aW1lID0gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBEZXRlY3RzIHVzYWdlcyBvZiBcIndpbmRvd1snSGFtbWVyJ11cIi5cbiAgICBpZiAodHMuaXNFbGVtZW50QWNjZXNzRXhwcmVzc2lvbihub2RlKSAmJiB0cy5pc1N0cmluZ0xpdGVyYWwobm9kZS5hcmd1bWVudEV4cHJlc3Npb24pICYmXG4gICAgICAgIG5vZGUuYXJndW1lbnRFeHByZXNzaW9uLnRleHQgPT09ICdIYW1tZXInKSB7XG4gICAgICBjb25zdCBvcmlnaW5FeHByID0gdW53cmFwRXhwcmVzc2lvbihub2RlLmV4cHJlc3Npb24pO1xuICAgICAgaWYgKHRzLmlzSWRlbnRpZmllcihvcmlnaW5FeHByKSAmJiBvcmlnaW5FeHByLnRleHQgPT09ICd3aW5kb3cnKSB7XG4gICAgICAgIHRoaXMuX3VzZWRJblJ1bnRpbWUgPSB0cnVlO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEhhbmRsZXMgdXNhZ2VzIG9mIHBsYWluIGlkZW50aWZpZXIgd2l0aCB0aGUgbmFtZSBcIkhhbW1lclwiLiBUaGVzZSB1c2FnZVxuICAgIC8vIGFyZSB2YWxpZCBpZiB0aGV5IHJlc29sdmUgdG8gXCJAdHlwZXMvaGFtbWVyanNcIi4gZS5nLiBcIm5ldyBIYW1tZXIobXlFbGVtZW50KVwiLlxuICAgIGlmICh0cy5pc0lkZW50aWZpZXIobm9kZSkgJiYgbm9kZS50ZXh0ID09PSAnSGFtbWVyJyAmJlxuICAgICAgICAhdHMuaXNQcm9wZXJ0eUFjY2Vzc0V4cHJlc3Npb24obm9kZS5wYXJlbnQpICYmICF0cy5pc0VsZW1lbnRBY2Nlc3NFeHByZXNzaW9uKG5vZGUucGFyZW50KSkge1xuICAgICAgY29uc3Qgc3ltYm9sID0gdGhpcy5fZ2V0RGVjbGFyYXRpb25TeW1ib2xPZk5vZGUobm9kZSk7XG4gICAgICBpZiAoc3ltYm9sICYmIHN5bWJvbC52YWx1ZURlY2xhcmF0aW9uICYmXG4gICAgICAgICAgc3ltYm9sLnZhbHVlRGVjbGFyYXRpb24uZ2V0U291cmNlRmlsZSgpLmZpbGVOYW1lLmluY2x1ZGVzKCdAdHlwZXMvaGFtbWVyanMnKSkge1xuICAgICAgICB0aGlzLl91c2VkSW5SdW50aW1lID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBub2RlIHJlZmVyZW5jZXMgdGhlIGdlc3R1cmUgY29uZmlnIGZyb20gQW5ndWxhciBNYXRlcmlhbC5cbiAgICogSWYgc28sIHdlIGtlZXAgdHJhY2sgb2YgdGhlIGZvdW5kIHN5bWJvbCByZWZlcmVuY2UuXG4gICAqL1xuICBwcml2YXRlIF9jaGVja0Zvck1hdGVyaWFsR2VzdHVyZUNvbmZpZyhub2RlOiB0cy5Ob2RlKSB7XG4gICAgaWYgKHRzLmlzSWRlbnRpZmllcihub2RlKSkge1xuICAgICAgY29uc3QgaW1wb3J0RGF0YSA9IGdldEltcG9ydE9mSWRlbnRpZmllcihub2RlLCB0aGlzLnR5cGVDaGVja2VyKTtcbiAgICAgIGlmIChpbXBvcnREYXRhICYmIGltcG9ydERhdGEuc3ltYm9sTmFtZSA9PT0gR0VTVFVSRV9DT05GSUdfQ0xBU1NfTkFNRSAmJlxuICAgICAgICAgIGltcG9ydERhdGEubW9kdWxlTmFtZS5zdGFydHNXaXRoKCdAYW5ndWxhci9tYXRlcmlhbC8nKSkge1xuICAgICAgICB0aGlzLl9nZXN0dXJlQ29uZmlnUmVmZXJlbmNlcy5wdXNoKFxuICAgICAgICAgICAge25vZGUsIGltcG9ydERhdGEsIGlzSW1wb3J0OiB0cy5pc0ltcG9ydFNwZWNpZmllcihub2RlLnBhcmVudCl9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBIYW1tZXIgZ2VzdHVyZSBjb25maWcgdG9rZW4gcmVmZXJlbmNlIGlzIHBhcnQgb2YgYW5cbiAgICogQW5ndWxhciBwcm92aWRlciBkZWZpbml0aW9uIHRoYXQgc2V0cyB1cCBhIGN1c3RvbSBnZXN0dXJlIGNvbmZpZy5cbiAgICovXG4gIHByaXZhdGUgX2NoZWNrRm9yQ3VzdG9tR2VzdHVyZUNvbmZpZ1NldHVwKHRva2VuUmVmOiBJZGVudGlmaWVyUmVmZXJlbmNlKTogYm9vbGVhbiB7XG4gICAgLy8gV2FsayB1cCB0aGUgdHJlZSB0byBsb29rIGZvciBhIHBhcmVudCBwcm9wZXJ0eSBhc3NpZ25tZW50IG9mIHRoZVxuICAgIC8vIHJlZmVyZW5jZSB0byB0aGUgaGFtbWVyIGdlc3R1cmUgY29uZmlnIHRva2VuLlxuICAgIGxldCBwcm9wZXJ0eUFzc2lnbm1lbnQ6IHRzLk5vZGUgPSB0b2tlblJlZi5ub2RlO1xuICAgIHdoaWxlIChwcm9wZXJ0eUFzc2lnbm1lbnQgJiYgIXRzLmlzUHJvcGVydHlBc3NpZ25tZW50KHByb3BlcnR5QXNzaWdubWVudCkpIHtcbiAgICAgIHByb3BlcnR5QXNzaWdubWVudCA9IHByb3BlcnR5QXNzaWdubWVudC5wYXJlbnQ7XG4gICAgfVxuXG4gICAgaWYgKCFwcm9wZXJ0eUFzc2lnbm1lbnQgfHwgIXRzLmlzUHJvcGVydHlBc3NpZ25tZW50KHByb3BlcnR5QXNzaWdubWVudCkgfHxcbiAgICAgICAgZ2V0UHJvcGVydHlOYW1lVGV4dChwcm9wZXJ0eUFzc2lnbm1lbnQubmFtZSkgIT09ICdwcm92aWRlJykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IG9iamVjdExpdGVyYWxFeHByID0gcHJvcGVydHlBc3NpZ25tZW50LnBhcmVudDtcbiAgICBjb25zdCBtYXRjaGluZ0lkZW50aWZpZXJzID0gZmluZE1hdGNoaW5nQ2hpbGROb2RlcyhvYmplY3RMaXRlcmFsRXhwciwgdHMuaXNJZGVudGlmaWVyKTtcblxuICAgIC8vIFdlIG5haXZlbHkgYXNzdW1lIHRoYXQgaWYgdGhlcmUgaXMgYSByZWZlcmVuY2UgdG8gdGhlIFwiR2VzdHVyZUNvbmZpZ1wiIGV4cG9ydFxuICAgIC8vIGZyb20gQW5ndWxhciBNYXRlcmlhbCBpbiB0aGUgcHJvdmlkZXIgbGl0ZXJhbCwgdGhhdCB0aGUgcHJvdmlkZXIgc2V0cyB1cCB0aGVcbiAgICAvLyBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLlxuICAgIHJldHVybiAhdGhpcy5fZ2VzdHVyZUNvbmZpZ1JlZmVyZW5jZXMuc29tZShyID0+IG1hdGNoaW5nSWRlbnRpZmllcnMuaW5jbHVkZXMoci5ub2RlKSk7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyBhbiBhdmFpbGFibGUgZmlsZSBuYW1lIGZvciB0aGUgZ2VzdHVyZSBjb25maWcgd2hpY2ggc2hvdWxkXG4gICAqIGJlIHN0b3JlZCBpbiB0aGUgc3BlY2lmaWVkIGZpbGUgcGF0aC5cbiAgICovXG4gIHByaXZhdGUgX2dldEF2YWlsYWJsZUdlc3R1cmVDb25maWdGaWxlTmFtZShzb3VyY2VSb290OiBEZXZraXRQYXRoKSB7XG4gICAgaWYgKCF0aGlzLmZpbGVTeXN0ZW0uZXhpc3RzKGRldmtpdEpvaW4oc291cmNlUm9vdCwgYCR7R0VTVFVSRV9DT05GSUdfRklMRV9OQU1FfS50c2ApKSkge1xuICAgICAgcmV0dXJuIGAke0dFU1RVUkVfQ09ORklHX0ZJTEVfTkFNRX0udHNgO1xuICAgIH1cblxuICAgIGxldCBwb3NzaWJsZU5hbWUgPSBgJHtHRVNUVVJFX0NPTkZJR19GSUxFX05BTUV9LWA7XG4gICAgbGV0IGluZGV4ID0gMTtcbiAgICB3aGlsZSAodGhpcy5maWxlU3lzdGVtLmV4aXN0cyhkZXZraXRKb2luKHNvdXJjZVJvb3QsIGAke3Bvc3NpYmxlTmFtZX0tJHtpbmRleH0udHNgKSkpIHtcbiAgICAgIGluZGV4Kys7XG4gICAgfVxuICAgIHJldHVybiBgJHtwb3NzaWJsZU5hbWUgKyBpbmRleH0udHNgO1xuICB9XG5cbiAgLyoqIFJlcGxhY2VzIGEgZ2l2ZW4gZ2VzdHVyZSBjb25maWcgcmVmZXJlbmNlIHdpdGggYSBuZXcgaW1wb3J0LiAqL1xuICBwcml2YXRlIF9yZXBsYWNlR2VzdHVyZUNvbmZpZ1JlZmVyZW5jZShcbiAgICAgIHtub2RlLCBpbXBvcnREYXRhLCBpc0ltcG9ydH06IElkZW50aWZpZXJSZWZlcmVuY2UsIHN5bWJvbE5hbWU6IHN0cmluZyxcbiAgICAgIG1vZHVsZVNwZWNpZmllcjogc3RyaW5nKSB7XG4gICAgY29uc3Qgc291cmNlRmlsZSA9IG5vZGUuZ2V0U291cmNlRmlsZSgpO1xuICAgIGNvbnN0IHJlY29yZGVyID0gdGhpcy5maWxlU3lzdGVtLmVkaXQodGhpcy5maWxlU3lzdGVtLnJlc29sdmUoc291cmNlRmlsZS5maWxlTmFtZSkpO1xuXG4gICAgLy8gTGlzdCBvZiBhbGwgaWRlbnRpZmllcnMgcmVmZXJyaW5nIHRvIHRoZSBnZXN0dXJlIGNvbmZpZyBpbiB0aGUgY3VycmVudCBmaWxlLiBUaGlzXG4gICAgLy8gYWxsb3dzIHVzIHRvIGFkZCBhbiBpbXBvcnQgZm9yIHRoZSBjb3BpZWQgZ2VzdHVyZSBjb25maWd1cmF0aW9uIHdpdGhvdXQgZ2VuZXJhdGluZyBhXG4gICAgLy8gbmV3IGlkZW50aWZpZXIgZm9yIHRoZSBpbXBvcnQgdG8gYXZvaWQgY29sbGlzaW9ucy4gaS5lLiBcIkdlc3R1cmVDb25maWdfMVwiLiBUaGUgaW1wb3J0XG4gICAgLy8gbWFuYWdlciBjaGVja3MgZm9yIHBvc3NpYmxlIG5hbWUgY29sbGlzaW9ucywgYnV0IGlzIGFibGUgdG8gaWdub3JlIHNwZWNpZmljIGlkZW50aWZpZXJzLlxuICAgIC8vIFdlIHVzZSB0aGlzIHRvIGlnbm9yZSBhbGwgcmVmZXJlbmNlcyB0byB0aGUgb3JpZ2luYWwgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZyxcbiAgICAvLyBiZWNhdXNlIHRoZXNlIHdpbGwgYmUgcmVwbGFjZWQgYW5kIHRoZXJlZm9yZSB3aWxsIG5vdCBpbnRlcmZlcmUuXG4gICAgY29uc3QgZ2VzdHVyZUlkZW50aWZpZXJzSW5GaWxlID0gdGhpcy5fZ2V0R2VzdHVyZUNvbmZpZ0lkZW50aWZpZXJzT2ZGaWxlKHNvdXJjZUZpbGUpO1xuXG4gICAgLy8gSWYgdGhlIHBhcmVudCBvZiB0aGUgaWRlbnRpZmllciBpcyBhY2Nlc3NlZCB0aHJvdWdoIGEgbmFtZXNwYWNlLCB3ZSBjYW4ganVzdFxuICAgIC8vIGltcG9ydCB0aGUgbmV3IGdlc3R1cmUgY29uZmlnIHdpdGhvdXQgcmV3cml0aW5nIHRoZSBpbXBvcnQgZGVjbGFyYXRpb24gYmVjYXVzZVxuICAgIC8vIHRoZSBjb25maWcgaGFzIGJlZW4gaW1wb3J0ZWQgdGhyb3VnaCBhIG5hbWVzcGFjZWQgaW1wb3J0LlxuICAgIGlmIChpc05hbWVzcGFjZWRJZGVudGlmaWVyQWNjZXNzKG5vZGUpKSB7XG4gICAgICBjb25zdCBuZXdFeHByZXNzaW9uID0gdGhpcy5faW1wb3J0TWFuYWdlci5hZGRJbXBvcnRUb1NvdXJjZUZpbGUoXG4gICAgICAgICAgc291cmNlRmlsZSwgc3ltYm9sTmFtZSwgbW9kdWxlU3BlY2lmaWVyLCBmYWxzZSwgZ2VzdHVyZUlkZW50aWZpZXJzSW5GaWxlKTtcblxuICAgICAgcmVjb3JkZXIucmVtb3ZlKG5vZGUucGFyZW50LmdldFN0YXJ0KCksIG5vZGUucGFyZW50LmdldFdpZHRoKCkpO1xuICAgICAgcmVjb3JkZXIuaW5zZXJ0UmlnaHQobm9kZS5wYXJlbnQuZ2V0U3RhcnQoKSwgdGhpcy5fcHJpbnROb2RlKG5ld0V4cHJlc3Npb24sIHNvdXJjZUZpbGUpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBEZWxldGUgdGhlIG9sZCBpbXBvcnQgdG8gdGhlIFwiR2VzdHVyZUNvbmZpZ1wiLlxuICAgIHRoaXMuX2ltcG9ydE1hbmFnZXIuZGVsZXRlTmFtZWRCaW5kaW5nSW1wb3J0KFxuICAgICAgICBzb3VyY2VGaWxlLCBHRVNUVVJFX0NPTkZJR19DTEFTU19OQU1FLCBpbXBvcnREYXRhLm1vZHVsZU5hbWUpO1xuXG4gICAgLy8gSWYgdGhlIGN1cnJlbnQgcmVmZXJlbmNlIGlzIG5vdCBmcm9tIGluc2lkZSBvZiBhIGltcG9ydCwgd2UgbmVlZCB0byBhZGQgYSBuZXdcbiAgICAvLyBpbXBvcnQgdG8gdGhlIGNvcGllZCBnZXN0dXJlIGNvbmZpZyBhbmQgcmVwbGFjZSB0aGUgaWRlbnRpZmllci4gRm9yIHJlZmVyZW5jZXNcbiAgICAvLyB3aXRoaW4gYW4gaW1wb3J0LCB3ZSBkbyBub3RoaW5nIGJ1dCByZW1vdmluZyB0aGUgYWN0dWFsIGltcG9ydC4gVGhpcyBhbGxvd3MgdXNcbiAgICAvLyB0byByZW1vdmUgdW51c2VkIGltcG9ydHMgdG8gdGhlIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLlxuICAgIGlmICghaXNJbXBvcnQpIHtcbiAgICAgIGNvbnN0IG5ld0V4cHJlc3Npb24gPSB0aGlzLl9pbXBvcnRNYW5hZ2VyLmFkZEltcG9ydFRvU291cmNlRmlsZShcbiAgICAgICAgICBzb3VyY2VGaWxlLCBzeW1ib2xOYW1lLCBtb2R1bGVTcGVjaWZpZXIsIGZhbHNlLCBnZXN0dXJlSWRlbnRpZmllcnNJbkZpbGUpO1xuXG4gICAgICByZWNvcmRlci5yZW1vdmUobm9kZS5nZXRTdGFydCgpLCBub2RlLmdldFdpZHRoKCkpO1xuICAgICAgcmVjb3JkZXIuaW5zZXJ0UmlnaHQobm9kZS5nZXRTdGFydCgpLCB0aGlzLl9wcmludE5vZGUobmV3RXhwcmVzc2lvbiwgc291cmNlRmlsZSkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGEgZ2l2ZW4gZ2VzdHVyZSBjb25maWcgcmVmZXJlbmNlIGFuZCBpdHMgY29ycmVzcG9uZGluZyBpbXBvcnQgZnJvbVxuICAgKiBpdHMgY29udGFpbmluZyBzb3VyY2UgZmlsZS4gSW1wb3J0cyB3aWxsIGJlIGFsd2F5cyByZW1vdmVkLCBidXQgaW4gc29tZSBjYXNlcyxcbiAgICogd2hlcmUgaXQncyBub3QgZ3VhcmFudGVlZCB0aGF0IGEgcmVtb3ZhbCBjYW4gYmUgcGVyZm9ybWVkIHNhZmVseSwgd2UganVzdFxuICAgKiBjcmVhdGUgYSBtaWdyYXRpb24gZmFpbHVyZSAoYW5kIGFkZCBhIFRPRE8gaWYgcG9zc2libGUpLlxuICAgKi9cbiAgcHJpdmF0ZSBfcmVtb3ZlR2VzdHVyZUNvbmZpZ1JlZmVyZW5jZSh7bm9kZSwgaW1wb3J0RGF0YSwgaXNJbXBvcnR9OiBJZGVudGlmaWVyUmVmZXJlbmNlKSB7XG4gICAgY29uc3Qgc291cmNlRmlsZSA9IG5vZGUuZ2V0U291cmNlRmlsZSgpO1xuICAgIGNvbnN0IHJlY29yZGVyID0gdGhpcy5maWxlU3lzdGVtLmVkaXQodGhpcy5maWxlU3lzdGVtLnJlc29sdmUoc291cmNlRmlsZS5maWxlTmFtZSkpO1xuICAgIC8vIE9ubHkgcmVtb3ZlIHRoZSBpbXBvcnQgZm9yIHRoZSBnZXN0dXJlIGNvbmZpZyBpZiB0aGUgZ2VzdHVyZSBjb25maWcgaGFzXG4gICAgLy8gYmVlbiBhY2Nlc3NlZCB0aHJvdWdoIGEgbm9uLW5hbWVzcGFjZWQgaWRlbnRpZmllciBhY2Nlc3MuXG4gICAgaWYgKCFpc05hbWVzcGFjZWRJZGVudGlmaWVyQWNjZXNzKG5vZGUpKSB7XG4gICAgICB0aGlzLl9pbXBvcnRNYW5hZ2VyLmRlbGV0ZU5hbWVkQmluZGluZ0ltcG9ydChcbiAgICAgICAgICBzb3VyY2VGaWxlLCBHRVNUVVJFX0NPTkZJR19DTEFTU19OQU1FLCBpbXBvcnREYXRhLm1vZHVsZU5hbWUpO1xuICAgIH1cblxuICAgIC8vIEZvciByZWZlcmVuY2VzIGZyb20gd2l0aGluIGFuIGltcG9ydCwgd2UgZG8gbm90IG5lZWQgdG8gZG8gYW55dGhpbmcgb3RoZXIgdGhhblxuICAgIC8vIHJlbW92aW5nIHRoZSBpbXBvcnQuIEZvciBvdGhlciByZWZlcmVuY2VzLCB3ZSByZW1vdmUgdGhlIGltcG9ydCBhbmQgdGhlIHJlZmVyZW5jZVxuICAgIC8vIGlkZW50aWZpZXIgaWYgdXNlZCBpbnNpZGUgb2YgYSBwcm92aWRlciBkZWZpbml0aW9uLlxuICAgIGlmIChpc0ltcG9ydCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHByb3ZpZGVyQXNzaWdubWVudCA9IG5vZGUucGFyZW50O1xuXG4gICAgLy8gT25seSByZW1vdmUgcmVmZXJlbmNlcyB0byB0aGUgZ2VzdHVyZSBjb25maWcgd2hpY2ggYXJlIHBhcnQgb2YgYSBzdGF0aWNhbGx5XG4gICAgLy8gYW5hbHl6YWJsZSBwcm92aWRlciBkZWZpbml0aW9uLiBXZSBvbmx5IHN1cHBvcnQgdGhlIGNvbW1vbiBjYXNlIG9mIGEgZ2VzdHVyZVxuICAgIC8vIGNvbmZpZyBwcm92aWRlciBkZWZpbml0aW9uIHdoZXJlIHRoZSBjb25maWcgaXMgc2V0IHVwIHRocm91Z2ggXCJ1c2VDbGFzc1wiLlxuICAgIC8vIE90aGVyd2lzZSwgaXQncyBub3QgZ3VhcmFudGVlZCB0aGF0IHdlIGNhbiBzYWZlbHkgcmVtb3ZlIHRoZSBwcm92aWRlciBkZWZpbml0aW9uLlxuICAgIGlmICghdHMuaXNQcm9wZXJ0eUFzc2lnbm1lbnQocHJvdmlkZXJBc3NpZ25tZW50KSB8fFxuICAgICAgICBnZXRQcm9wZXJ0eU5hbWVUZXh0KHByb3ZpZGVyQXNzaWdubWVudC5uYW1lKSAhPT0gJ3VzZUNsYXNzJykge1xuICAgICAgdGhpcy5fbm9kZUZhaWx1cmVzLnB1c2goe25vZGUsIG1lc3NhZ2U6IENBTk5PVF9SRU1PVkVfUkVGRVJFTkNFX0VSUk9SfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgb2JqZWN0TGl0ZXJhbEV4cHIgPSBwcm92aWRlckFzc2lnbm1lbnQucGFyZW50O1xuICAgIGNvbnN0IHByb3ZpZGVUb2tlbiA9IG9iamVjdExpdGVyYWxFeHByLnByb3BlcnRpZXMuZmluZChcbiAgICAgICAgKHApOiBwIGlzIHRzLlByb3BlcnR5QXNzaWdubWVudCA9PlxuICAgICAgICAgICAgdHMuaXNQcm9wZXJ0eUFzc2lnbm1lbnQocCkgJiYgZ2V0UHJvcGVydHlOYW1lVGV4dChwLm5hbWUpID09PSAncHJvdmlkZScpO1xuXG4gICAgLy8gRG8gbm90IHJlbW92ZSB0aGUgcmVmZXJlbmNlIGlmIHRoZSBnZXN0dXJlIGNvbmZpZyBpcyBub3QgcGFydCBvZiBhIHByb3ZpZGVyIGRlZmluaXRpb24sXG4gICAgLy8gb3IgaWYgdGhlIHByb3ZpZGVkIHRva2UgaXMgbm90IHJlZmVycmluZyB0byB0aGUga25vd24gSEFNTUVSX0dFU1RVUkVfQ09ORklHIHRva2VuXG4gICAgLy8gZnJvbSBwbGF0Zm9ybS1icm93c2VyLlxuICAgIGlmICghcHJvdmlkZVRva2VuIHx8ICF0aGlzLl9pc1JlZmVyZW5jZVRvSGFtbWVyQ29uZmlnVG9rZW4ocHJvdmlkZVRva2VuLmluaXRpYWxpemVyKSkge1xuICAgICAgdGhpcy5fbm9kZUZhaWx1cmVzLnB1c2goe25vZGUsIG1lc3NhZ2U6IENBTk5PVF9SRU1PVkVfUkVGRVJFTkNFX0VSUk9SfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gQ29sbGVjdCBhbGwgbmVzdGVkIGlkZW50aWZpZXJzIHdoaWNoIHdpbGwgYmUgZGVsZXRlZC4gVGhpcyBoZWxwcyB1c1xuICAgIC8vIGRldGVybWluaW5nIGlmIHdlIGNhbiByZW1vdmUgaW1wb3J0cyBmb3IgdGhlIFwiSEFNTUVSX0dFU1RVUkVfQ09ORklHXCIgdG9rZW4uXG4gICAgdGhpcy5fZGVsZXRlZElkZW50aWZpZXJzLnB1c2goLi4uZmluZE1hdGNoaW5nQ2hpbGROb2RlcyhvYmplY3RMaXRlcmFsRXhwciwgdHMuaXNJZGVudGlmaWVyKSk7XG5cbiAgICAvLyBJbiBjYXNlIHRoZSBmb3VuZCBwcm92aWRlciBkZWZpbml0aW9uIGlzIG5vdCBwYXJ0IG9mIGFuIGFycmF5IGxpdGVyYWwsXG4gICAgLy8gd2UgY2Fubm90IHNhZmVseSByZW1vdmUgdGhlIHByb3ZpZGVyLiBUaGlzIGlzIGJlY2F1c2UgaXQgY291bGQgYmUgZGVjbGFyZWRcbiAgICAvLyBhcyBhIHZhcmlhYmxlLiBlLmcuIFwiY29uc3QgZ2VzdHVyZVByb3ZpZGVyID0ge3Byb3ZpZGU6IC4uLCB1c2VDbGFzczogR2VzdHVyZUNvbmZpZ31cIi5cbiAgICAvLyBJbiB0aGF0IGNhc2UsIHdlIGp1c3QgYWRkIGFuIGVtcHR5IG9iamVjdCBsaXRlcmFsIHdpdGggVE9ETyBhbmQgcHJpbnQgYSBmYWlsdXJlLlxuICAgIGlmICghdHMuaXNBcnJheUxpdGVyYWxFeHByZXNzaW9uKG9iamVjdExpdGVyYWxFeHByLnBhcmVudCkpIHtcbiAgICAgIHJlY29yZGVyLnJlbW92ZShvYmplY3RMaXRlcmFsRXhwci5nZXRTdGFydCgpLCBvYmplY3RMaXRlcmFsRXhwci5nZXRXaWR0aCgpKTtcbiAgICAgIHJlY29yZGVyLmluc2VydFJpZ2h0KG9iamVjdExpdGVyYWxFeHByLmdldFN0YXJ0KCksIGAvKiBUT0RPOiByZW1vdmUgKi8ge31gKTtcbiAgICAgIHRoaXMuX25vZGVGYWlsdXJlcy5wdXNoKHtcbiAgICAgICAgbm9kZTogb2JqZWN0TGl0ZXJhbEV4cHIsXG4gICAgICAgIG1lc3NhZ2U6IGBVbmFibGUgdG8gZGVsZXRlIHByb3ZpZGVyIGRlZmluaXRpb24gZm9yIFwiR2VzdHVyZUNvbmZpZ1wiIGNvbXBsZXRlbHkuIGAgK1xuICAgICAgICAgICAgYFBsZWFzZSBjbGVhbiB1cCB0aGUgcHJvdmlkZXIuYFxuICAgICAgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUmVtb3ZlcyB0aGUgb2JqZWN0IGxpdGVyYWwgZnJvbSB0aGUgcGFyZW50IGFycmF5IGV4cHJlc3Npb24uIFJlbW92ZXNcbiAgICAvLyB0aGUgdHJhaWxpbmcgY29tbWEgdG9rZW4gaWYgcHJlc2VudC5cbiAgICByZW1vdmVFbGVtZW50RnJvbUFycmF5RXhwcmVzc2lvbihvYmplY3RMaXRlcmFsRXhwciwgcmVjb3JkZXIpO1xuICB9XG5cbiAgLyoqIFJlbW92ZXMgdGhlIGdpdmVuIGhhbW1lciBjb25maWcgdG9rZW4gaW1wb3J0IGlmIGl0IGlzIG5vdCB1c2VkLiAqL1xuICBwcml2YXRlIF9yZW1vdmVIYW1tZXJDb25maWdUb2tlbkltcG9ydElmVW51c2VkKHtub2RlLCBpbXBvcnREYXRhfTogSWRlbnRpZmllclJlZmVyZW5jZSkge1xuICAgIGNvbnN0IHNvdXJjZUZpbGUgPSBub2RlLmdldFNvdXJjZUZpbGUoKTtcbiAgICBjb25zdCBpc1Rva2VuVXNlZCA9IHRoaXMuX2hhbW1lckNvbmZpZ1Rva2VuUmVmZXJlbmNlcy5zb21lKFxuICAgICAgICByID0+ICFyLmlzSW1wb3J0ICYmICFpc05hbWVzcGFjZWRJZGVudGlmaWVyQWNjZXNzKHIubm9kZSkgJiZcbiAgICAgICAgICAgIHIubm9kZS5nZXRTb3VyY2VGaWxlKCkgPT09IHNvdXJjZUZpbGUgJiYgIXRoaXMuX2RlbGV0ZWRJZGVudGlmaWVycy5pbmNsdWRlcyhyLm5vZGUpKTtcblxuICAgIC8vIFdlIGRvbid0IHdhbnQgdG8gcmVtb3ZlIHRoZSBpbXBvcnQgZm9yIHRoZSB0b2tlbiBpZiB0aGUgdG9rZW4gaXNcbiAgICAvLyBzdGlsbCB1c2VkIHNvbWV3aGVyZS5cbiAgICBpZiAoIWlzVG9rZW5Vc2VkKSB7XG4gICAgICB0aGlzLl9pbXBvcnRNYW5hZ2VyLmRlbGV0ZU5hbWVkQmluZGluZ0ltcG9ydChcbiAgICAgICAgICBzb3VyY2VGaWxlLCBIQU1NRVJfQ09ORklHX1RPS0VOX05BTUUsIGltcG9ydERhdGEubW9kdWxlTmFtZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFJlbW92ZXMgSGFtbWVyIGZyb20gYWxsIGluZGV4IEhUTUwgZmlsZXMgb2YgdGhlIGN1cnJlbnQgcHJvamVjdC4gKi9cbiAgcHJpdmF0ZSBfcmVtb3ZlSGFtbWVyRnJvbUluZGV4RmlsZSgpIHtcbiAgICBjb25zdCBpbmRleEZpbGVQYXRocyA9IGdldFByb2plY3RJbmRleEZpbGVzKHRoaXMuY29udGV4dC5wcm9qZWN0KTtcbiAgICBpbmRleEZpbGVQYXRocy5mb3JFYWNoKGZpbGVQYXRoID0+IHtcbiAgICAgIGlmICghdGhpcy5maWxlU3lzdGVtLmV4aXN0cyhmaWxlUGF0aCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBodG1sQ29udGVudCA9IHRoaXMuZmlsZVN5c3RlbS5yZWFkKGZpbGVQYXRoKSE7XG4gICAgICBjb25zdCByZWNvcmRlciA9IHRoaXMuZmlsZVN5c3RlbS5lZGl0KGZpbGVQYXRoKTtcblxuICAgICAgZmluZEhhbW1lclNjcmlwdEltcG9ydEVsZW1lbnRzKGh0bWxDb250ZW50KVxuICAgICAgICAgIC5mb3JFYWNoKGVsID0+IHJlbW92ZUVsZW1lbnRGcm9tSHRtbChlbCwgcmVjb3JkZXIpKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBTZXRzIHVwIHRoZSBIYW1tZXIgZ2VzdHVyZSBjb25maWcgaW4gdGhlIHJvb3QgbW9kdWxlIGlmIG5lZWRlZC4gKi9cbiAgcHJpdmF0ZSBfc2V0dXBOZXdHZXN0dXJlQ29uZmlnSW5Sb290TW9kdWxlKGdlc3R1cmVDb25maWdQYXRoOiBzdHJpbmcpIHtcbiAgICBjb25zdCB7d29ya3NwYWNlRnNQYXRoLCBwcm9qZWN0fSA9IHRoaXMuY29udGV4dDtcbiAgICBjb25zdCBtYWluRmlsZVBhdGggPSBnZXRQcm9qZWN0TWFpbkZpbGUocHJvamVjdCk7XG4gICAgY29uc3Qgcm9vdE1vZHVsZVN5bWJvbCA9IHRoaXMuX2dldFJvb3RNb2R1bGVTeW1ib2wobWFpbkZpbGVQYXRoKTtcblxuICAgIGlmIChyb290TW9kdWxlU3ltYm9sID09PSBudWxsKSB7XG4gICAgICB0aGlzLmZhaWx1cmVzLnB1c2goe1xuICAgICAgICBmaWxlUGF0aDogbWFpbkZpbGVQYXRoLFxuICAgICAgICBtZXNzYWdlOiBgQ291bGQgbm90IHNldHVwIEhhbW1lciBnZXN0dXJlcyBpbiBtb2R1bGUuIFBsZWFzZSBgICtcbiAgICAgICAgICAgIGBtYW51YWxseSBlbnN1cmUgdGhhdCB0aGUgSGFtbWVyIGdlc3R1cmUgY29uZmlnIGlzIHNldCB1cC5gLFxuICAgICAgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgc291cmNlRmlsZSA9IHJvb3RNb2R1bGVTeW1ib2wudmFsdWVEZWNsYXJhdGlvbi5nZXRTb3VyY2VGaWxlKCk7XG4gICAgY29uc3QgcmVsYXRpdmVQYXRoID0gcmVsYXRpdmUod29ya3NwYWNlRnNQYXRoLCBzb3VyY2VGaWxlLmZpbGVOYW1lKTtcbiAgICBjb25zdCBtZXRhZGF0YSA9IGdldERlY29yYXRvck1ldGFkYXRhKHNvdXJjZUZpbGUsICdOZ01vZHVsZScsICdAYW5ndWxhci9jb3JlJykgYXNcbiAgICAgICAgdHMuT2JqZWN0TGl0ZXJhbEV4cHJlc3Npb25bXTtcblxuICAgIC8vIElmIG5vIFwiTmdNb2R1bGVcIiBkZWZpbml0aW9uIGlzIGZvdW5kIGluc2lkZSB0aGUgc291cmNlIGZpbGUsIHdlIGp1c3QgZG8gbm90aGluZy5cbiAgICBpZiAoIW1ldGFkYXRhLmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJlY29yZGVyID0gdGhpcy5maWxlU3lzdGVtLmVkaXQodGhpcy5maWxlU3lzdGVtLnJlc29sdmUoc291cmNlRmlsZS5maWxlTmFtZSkpO1xuICAgIGNvbnN0IHByb3ZpZGVyc0ZpZWxkID0gZ2V0TWV0YWRhdGFGaWVsZChtZXRhZGF0YVswXSwgJ3Byb3ZpZGVycycpWzBdO1xuICAgIGNvbnN0IHByb3ZpZGVySWRlbnRpZmllcnMgPVxuICAgICAgICBwcm92aWRlcnNGaWVsZCA/IGZpbmRNYXRjaGluZ0NoaWxkTm9kZXMocHJvdmlkZXJzRmllbGQsIHRzLmlzSWRlbnRpZmllcikgOiBudWxsO1xuICAgIGNvbnN0IGdlc3R1cmVDb25maWdFeHByID0gdGhpcy5faW1wb3J0TWFuYWdlci5hZGRJbXBvcnRUb1NvdXJjZUZpbGUoXG4gICAgICAgIHNvdXJjZUZpbGUsIEdFU1RVUkVfQ09ORklHX0NMQVNTX05BTUUsXG4gICAgICAgIGdldE1vZHVsZVNwZWNpZmllcihnZXN0dXJlQ29uZmlnUGF0aCwgc291cmNlRmlsZS5maWxlTmFtZSksIGZhbHNlLFxuICAgICAgICB0aGlzLl9nZXRHZXN0dXJlQ29uZmlnSWRlbnRpZmllcnNPZkZpbGUoc291cmNlRmlsZSkpO1xuICAgIGNvbnN0IGhhbW1lckNvbmZpZ1Rva2VuRXhwciA9IHRoaXMuX2ltcG9ydE1hbmFnZXIuYWRkSW1wb3J0VG9Tb3VyY2VGaWxlKFxuICAgICAgICBzb3VyY2VGaWxlLCBIQU1NRVJfQ09ORklHX1RPS0VOX05BTUUsIEhBTU1FUl9DT05GSUdfVE9LRU5fTU9EVUxFKTtcbiAgICBjb25zdCBuZXdQcm92aWRlck5vZGUgPSB0cy5jcmVhdGVPYmplY3RMaXRlcmFsKFtcbiAgICAgIHRzLmNyZWF0ZVByb3BlcnR5QXNzaWdubWVudCgncHJvdmlkZScsIGhhbW1lckNvbmZpZ1Rva2VuRXhwciksXG4gICAgICB0cy5jcmVhdGVQcm9wZXJ0eUFzc2lnbm1lbnQoJ3VzZUNsYXNzJywgZ2VzdHVyZUNvbmZpZ0V4cHIpXG4gICAgXSk7XG5cbiAgICAvLyBJZiB0aGUgcHJvdmlkZXJzIGZpZWxkIGV4aXN0cyBhbmQgYWxyZWFkeSBjb250YWlucyByZWZlcmVuY2VzIHRvIHRoZSBoYW1tZXIgZ2VzdHVyZVxuICAgIC8vIGNvbmZpZyB0b2tlbiBhbmQgdGhlIGdlc3R1cmUgY29uZmlnLCB3ZSBuYWl2ZWx5IGFzc3VtZSB0aGF0IHRoZSBnZXN0dXJlIGNvbmZpZyBpc1xuICAgIC8vIGFscmVhZHkgc2V0IHVwLiBXZSBvbmx5IHdhbnQgdG8gYWRkIHRoZSBnZXN0dXJlIGNvbmZpZyBwcm92aWRlciBpZiBpdCBpcyBub3Qgc2V0IHVwLlxuICAgIGlmICghcHJvdmlkZXJJZGVudGlmaWVycyB8fFxuICAgICAgICAhKHRoaXMuX2hhbW1lckNvbmZpZ1Rva2VuUmVmZXJlbmNlcy5zb21lKHIgPT4gcHJvdmlkZXJJZGVudGlmaWVycy5pbmNsdWRlcyhyLm5vZGUpKSAmJlxuICAgICAgICAgIHRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLnNvbWUociA9PiBwcm92aWRlcklkZW50aWZpZXJzLmluY2x1ZGVzKHIubm9kZSkpKSkge1xuICAgICAgYWRkU3ltYm9sVG9OZ01vZHVsZU1ldGFkYXRhKFxuICAgICAgICAgIHNvdXJjZUZpbGUsIHJlbGF0aXZlUGF0aCwgJ3Byb3ZpZGVycycsIHRoaXMuX3ByaW50Tm9kZShuZXdQcm92aWRlck5vZGUsIHNvdXJjZUZpbGUpLCBudWxsKVxuICAgICAgICAgIC5mb3JFYWNoKGNoYW5nZSA9PiB7XG4gICAgICAgICAgICBpZiAoY2hhbmdlIGluc3RhbmNlb2YgSW5zZXJ0Q2hhbmdlKSB7XG4gICAgICAgICAgICAgIHJlY29yZGVyLmluc2VydFJpZ2h0KGNoYW5nZS5wb3MsIGNoYW5nZS50b0FkZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIFR5cGVTY3JpcHQgc3ltYm9sIG9mIHRoZSByb290IG1vZHVsZSBieSBsb29raW5nIGZvciB0aGUgbW9kdWxlXG4gICAqIGJvb3RzdHJhcCBleHByZXNzaW9uIGluIHRoZSBzcGVjaWZpZWQgc291cmNlIGZpbGUuXG4gICAqL1xuICBwcml2YXRlIF9nZXRSb290TW9kdWxlU3ltYm9sKG1haW5GaWxlUGF0aDogUGF0aCk6IHRzLlN5bWJvbHxudWxsIHtcbiAgICBjb25zdCBtYWluRmlsZSA9IHRoaXMucHJvZ3JhbS5nZXRTb3VyY2VGaWxlKHJlc29sdmUoXG4gICAgICAgIHRoaXMuY29udGV4dC53b3Jrc3BhY2VGc1BhdGgsIG1haW5GaWxlUGF0aCkpO1xuICAgIGlmICghbWFpbkZpbGUpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IGFwcE1vZHVsZUV4cHIgPSBmaW5kTWFpbk1vZHVsZUV4cHJlc3Npb24obWFpbkZpbGUpO1xuICAgIGlmICghYXBwTW9kdWxlRXhwcikge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgYXBwTW9kdWxlU3ltYm9sID0gdGhpcy5fZ2V0RGVjbGFyYXRpb25TeW1ib2xPZk5vZGUodW53cmFwRXhwcmVzc2lvbihhcHBNb2R1bGVFeHByKSk7XG4gICAgaWYgKCFhcHBNb2R1bGVTeW1ib2wgfHwgIWFwcE1vZHVsZVN5bWJvbC52YWx1ZURlY2xhcmF0aW9uKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgcmV0dXJuIGFwcE1vZHVsZVN5bWJvbDtcbiAgfVxuXG4gIC8qKiBTZXRzIHVwIHRoZSBcIkhhbW1lck1vZHVsZVwiIGluIHRoZSByb290IG1vZHVsZSBvZiB0aGUgY3VycmVudCBwcm9qZWN0LiAqL1xuICBwcml2YXRlIF9zZXR1cEhhbW1lck1vZHVsZUluUm9vdE1vZHVsZSgpIHtcbiAgICBjb25zdCB7d29ya3NwYWNlRnNQYXRoLCBwcm9qZWN0fSA9IHRoaXMuY29udGV4dDtcbiAgICBjb25zdCBtYWluRmlsZVBhdGggPSBnZXRQcm9qZWN0TWFpbkZpbGUocHJvamVjdCk7XG4gICAgY29uc3Qgcm9vdE1vZHVsZVN5bWJvbCA9IHRoaXMuX2dldFJvb3RNb2R1bGVTeW1ib2wobWFpbkZpbGVQYXRoKTtcblxuICAgIGlmIChyb290TW9kdWxlU3ltYm9sID09PSBudWxsKSB7XG4gICAgICB0aGlzLmZhaWx1cmVzLnB1c2goe1xuICAgICAgICBmaWxlUGF0aDogbWFpbkZpbGVQYXRoLFxuICAgICAgICBtZXNzYWdlOiBgQ291bGQgbm90IHNldHVwIEhhbW1lck1vZHVsZS4gUGxlYXNlIG1hbnVhbGx5IHNldCB1cCB0aGUgXCJIYW1tZXJNb2R1bGVcIiBgICtcbiAgICAgICAgICAgIGBmcm9tIFwiQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3NlclwiLmAsXG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzb3VyY2VGaWxlID0gcm9vdE1vZHVsZVN5bWJvbC52YWx1ZURlY2xhcmF0aW9uLmdldFNvdXJjZUZpbGUoKTtcbiAgICBjb25zdCByZWxhdGl2ZVBhdGggPSByZWxhdGl2ZSh3b3Jrc3BhY2VGc1BhdGgsIHNvdXJjZUZpbGUuZmlsZU5hbWUpO1xuICAgIGNvbnN0IG1ldGFkYXRhID0gZ2V0RGVjb3JhdG9yTWV0YWRhdGEoc291cmNlRmlsZSwgJ05nTW9kdWxlJywgJ0Bhbmd1bGFyL2NvcmUnKSBhc1xuICAgICAgICB0cy5PYmplY3RMaXRlcmFsRXhwcmVzc2lvbltdO1xuICAgIGlmICghbWV0YWRhdGEubGVuZ3RoKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgaW1wb3J0c0ZpZWxkID0gZ2V0TWV0YWRhdGFGaWVsZChtZXRhZGF0YVswXSwgJ2ltcG9ydHMnKVswXTtcbiAgICBjb25zdCBpbXBvcnRJZGVudGlmaWVycyA9XG4gICAgICAgIGltcG9ydHNGaWVsZCA/IGZpbmRNYXRjaGluZ0NoaWxkTm9kZXMoaW1wb3J0c0ZpZWxkLCB0cy5pc0lkZW50aWZpZXIpIDogbnVsbDtcbiAgICBjb25zdCByZWNvcmRlciA9IHRoaXMuZmlsZVN5c3RlbS5lZGl0KHRoaXMuZmlsZVN5c3RlbS5yZXNvbHZlKHNvdXJjZUZpbGUuZmlsZU5hbWUpKTtcbiAgICBjb25zdCBoYW1tZXJNb2R1bGVFeHByID0gdGhpcy5faW1wb3J0TWFuYWdlci5hZGRJbXBvcnRUb1NvdXJjZUZpbGUoXG4gICAgICAgIHNvdXJjZUZpbGUsIEhBTU1FUl9NT0RVTEVfTkFNRSwgSEFNTUVSX01PRFVMRV9JTVBPUlQpO1xuXG4gICAgLy8gSWYgdGhlIFwiSGFtbWVyTW9kdWxlXCIgaXMgbm90IGFscmVhZHkgaW1wb3J0ZWQgaW4gdGhlIGFwcCBtb2R1bGUsIHdlIHNldCBpdCB1cFxuICAgIC8vIGJ5IGFkZGluZyBpdCB0byB0aGUgXCJpbXBvcnRzXCIgZmllbGQgb2YgdGhlIGFwcCBtb2R1bGUuXG4gICAgaWYgKCFpbXBvcnRJZGVudGlmaWVycyB8fFxuICAgICAgICAhdGhpcy5faGFtbWVyTW9kdWxlUmVmZXJlbmNlcy5zb21lKHIgPT4gaW1wb3J0SWRlbnRpZmllcnMuaW5jbHVkZXMoci5ub2RlKSkpIHtcbiAgICAgIGFkZFN5bWJvbFRvTmdNb2R1bGVNZXRhZGF0YShcbiAgICAgICAgICBzb3VyY2VGaWxlLCByZWxhdGl2ZVBhdGgsICdpbXBvcnRzJywgdGhpcy5fcHJpbnROb2RlKGhhbW1lck1vZHVsZUV4cHIsIHNvdXJjZUZpbGUpLCBudWxsKVxuICAgICAgICAgIC5mb3JFYWNoKGNoYW5nZSA9PiB7XG4gICAgICAgICAgICBpZiAoY2hhbmdlIGluc3RhbmNlb2YgSW5zZXJ0Q2hhbmdlKSB7XG4gICAgICAgICAgICAgIHJlY29yZGVyLmluc2VydFJpZ2h0KGNoYW5nZS5wb3MsIGNoYW5nZS50b0FkZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFByaW50cyBhIGdpdmVuIG5vZGUgd2l0aGluIHRoZSBzcGVjaWZpZWQgc291cmNlIGZpbGUuICovXG4gIHByaXZhdGUgX3ByaW50Tm9kZShub2RlOiB0cy5Ob2RlLCBzb3VyY2VGaWxlOiB0cy5Tb3VyY2VGaWxlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fcHJpbnRlci5wcmludE5vZGUodHMuRW1pdEhpbnQuVW5zcGVjaWZpZWQsIG5vZGUsIHNvdXJjZUZpbGUpO1xuICB9XG5cbiAgLyoqIEdldHMgYWxsIHJlZmVyZW5jZWQgZ2VzdHVyZSBjb25maWcgaWRlbnRpZmllcnMgb2YgYSBnaXZlbiBzb3VyY2UgZmlsZSAqL1xuICBwcml2YXRlIF9nZXRHZXN0dXJlQ29uZmlnSWRlbnRpZmllcnNPZkZpbGUoc291cmNlRmlsZTogdHMuU291cmNlRmlsZSk6IHRzLklkZW50aWZpZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLmZpbHRlcihkID0+IGQubm9kZS5nZXRTb3VyY2VGaWxlKCkgPT09IHNvdXJjZUZpbGUpXG4gICAgICAgIC5tYXAoZCA9PiBkLm5vZGUpO1xuICB9XG5cbiAgLyoqIEdldHMgdGhlIHN5bWJvbCB0aGF0IGNvbnRhaW5zIHRoZSB2YWx1ZSBkZWNsYXJhdGlvbiBvZiB0aGUgc3BlY2lmaWVkIG5vZGUuICovXG4gIHByaXZhdGUgX2dldERlY2xhcmF0aW9uU3ltYm9sT2ZOb2RlKG5vZGU6IHRzLk5vZGUpOiB0cy5TeW1ib2x8dW5kZWZpbmVkIHtcbiAgICBjb25zdCBzeW1ib2wgPSB0aGlzLnR5cGVDaGVja2VyLmdldFN5bWJvbEF0TG9jYXRpb24obm9kZSk7XG5cbiAgICAvLyBTeW1ib2xzIGNhbiBiZSBhbGlhc2VzIG9mIHRoZSBkZWNsYXJhdGlvbiBzeW1ib2wuIGUuZy4gaW4gbmFtZWQgaW1wb3J0IHNwZWNpZmllcnMuXG4gICAgLy8gV2UgbmVlZCB0byByZXNvbHZlIHRoZSBhbGlhc2VkIHN5bWJvbCBiYWNrIHRvIHRoZSBkZWNsYXJhdGlvbiBzeW1ib2wuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcbiAgICBpZiAoc3ltYm9sICYmIChzeW1ib2wuZmxhZ3MgJiB0cy5TeW1ib2xGbGFncy5BbGlhcykgIT09IDApIHtcbiAgICAgIHJldHVybiB0aGlzLnR5cGVDaGVja2VyLmdldEFsaWFzZWRTeW1ib2woc3ltYm9sKTtcbiAgICB9XG4gICAgcmV0dXJuIHN5bWJvbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciB0aGUgZ2l2ZW4gZXhwcmVzc2lvbiByZXNvbHZlcyB0byBhIGhhbW1lciBnZXN0dXJlIGNvbmZpZ1xuICAgKiB0b2tlbiByZWZlcmVuY2UgZnJvbSBcIkBhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXJcIi5cbiAgICovXG4gIHByaXZhdGUgX2lzUmVmZXJlbmNlVG9IYW1tZXJDb25maWdUb2tlbihleHByOiB0cy5FeHByZXNzaW9uKSB7XG4gICAgY29uc3QgdW53cmFwcGVkID0gdW53cmFwRXhwcmVzc2lvbihleHByKTtcbiAgICBpZiAodHMuaXNJZGVudGlmaWVyKHVud3JhcHBlZCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW1tZXJDb25maWdUb2tlblJlZmVyZW5jZXMuc29tZShyID0+IHIubm9kZSA9PT0gdW53cmFwcGVkKTtcbiAgICB9IGVsc2UgaWYgKHRzLmlzUHJvcGVydHlBY2Nlc3NFeHByZXNzaW9uKHVud3JhcHBlZCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW1tZXJDb25maWdUb2tlblJlZmVyZW5jZXMuc29tZShyID0+IHIubm9kZSA9PT0gdW53cmFwcGVkLm5hbWUpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBtaWdyYXRpb24gZmFpbHVyZXMgb2YgdGhlIGNvbGxlY3RlZCBub2RlIGZhaWx1cmVzLiBUaGUgcmV0dXJuZWQgbWlncmF0aW9uXG4gICAqIGZhaWx1cmVzIGFyZSB1cGRhdGVkIHRvIHJlZmxlY3QgdGhlIHBvc3QtbWlncmF0aW9uIHN0YXRlIG9mIHNvdXJjZSBmaWxlcy4gTWVhbmluZ1xuICAgKiB0aGF0IGZhaWx1cmUgcG9zaXRpb25zIGFyZSBjb3JyZWN0ZWQgaWYgc291cmNlIGZpbGUgbW9kaWZpY2F0aW9ucyBzaGlmdGVkIGxpbmVzLlxuICAgKi9cbiAgcHJpdmF0ZSBfY3JlYXRlTWlncmF0aW9uRmFpbHVyZXMoKTogTWlncmF0aW9uRmFpbHVyZVtdIHtcbiAgICByZXR1cm4gdGhpcy5fbm9kZUZhaWx1cmVzLm1hcCgoe25vZGUsIG1lc3NhZ2V9KSA9PiB7XG4gICAgICBjb25zdCBzb3VyY2VGaWxlID0gbm9kZS5nZXRTb3VyY2VGaWxlKCk7XG4gICAgICBjb25zdCBvZmZzZXQgPSBub2RlLmdldFN0YXJ0KCk7XG4gICAgICBjb25zdCBwb3NpdGlvbiA9IHRzLmdldExpbmVBbmRDaGFyYWN0ZXJPZlBvc2l0aW9uKHNvdXJjZUZpbGUsIG5vZGUuZ2V0U3RhcnQoKSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBwb3NpdGlvbjogdGhpcy5faW1wb3J0TWFuYWdlci5jb3JyZWN0Tm9kZVBvc2l0aW9uKG5vZGUsIG9mZnNldCwgcG9zaXRpb24pLFxuICAgICAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgICAgICBmaWxlUGF0aDogdGhpcy5maWxlU3lzdGVtLnJlc29sdmUoc291cmNlRmlsZS5maWxlTmFtZSksXG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqIEdsb2JhbCBzdGF0ZSBvZiB3aGV0aGVyIEhhbW1lciBpcyB1c2VkIGluIGFueSBhbmFseXplZCBwcm9qZWN0IHRhcmdldC4gKi9cbiAgc3RhdGljIGdsb2JhbFVzZXNIYW1tZXIgPSBmYWxzZTtcblxuICAvKipcbiAgICogU3RhdGljIG1pZ3JhdGlvbiBydWxlIG1ldGhvZCB0aGF0IHdpbGwgYmUgY2FsbGVkIG9uY2UgYWxsIHByb2plY3QgdGFyZ2V0c1xuICAgKiBoYXZlIGJlZW4gbWlncmF0ZWQgaW5kaXZpZHVhbGx5LiBUaGlzIG1ldGhvZCBjYW4gYmUgdXNlZCB0byBtYWtlIGNoYW5nZXMgYmFzZWRcbiAgICogb24gdGhlIGFuYWx5c2lzIG9mIHRoZSBpbmRpdmlkdWFsIHRhcmdldHMuIEZvciBleGFtcGxlOiB3ZSBvbmx5IHJlbW92ZSBIYW1tZXJcbiAgICogZnJvbSB0aGUgXCJwYWNrYWdlLmpzb25cIiBpZiBpdCBpcyBub3QgdXNlZCBpbiAqYW55KiBwcm9qZWN0IHRhcmdldC5cbiAgICovXG4gIHN0YXRpYyBnbG9iYWxQb3N0TWlncmF0aW9uKHRyZWU6IFRyZWUsIGNvbnRleHQ6IFNjaGVtYXRpY0NvbnRleHQpOiBQb3N0TWlncmF0aW9uQWN0aW9uIHtcbiAgICAvLyBBbHdheXMgbm90aWZ5IHRoZSBkZXZlbG9wZXIgdGhhdCB0aGUgSGFtbWVyIHY5IG1pZ3JhdGlvbiBkb2VzIG5vdCBtaWdyYXRlIHRlc3RzLlxuICAgIGNvbnRleHQubG9nZ2VyLmluZm8oXG4gICAgICAgICdcXG7imqAgIEdlbmVyYWwgbm90aWNlOiBUaGUgSGFtbWVySlMgdjkgbWlncmF0aW9uIGZvciBBbmd1bGFyIENvbXBvbmVudHMgaXMgbm90IGFibGUgdG8gJyArXG4gICAgICAgICdtaWdyYXRlIHRlc3RzLiBQbGVhc2UgbWFudWFsbHkgY2xlYW4gdXAgdGVzdHMgaW4geW91ciBwcm9qZWN0IGlmIHRoZXkgcmVseSBvbiAnICtcbiAgICAgICAgKHRoaXMuZ2xvYmFsVXNlc0hhbW1lciA/ICd0aGUgZGVwcmVjYXRlZCBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLicgOiAnSGFtbWVySlMuJykpO1xuICAgIGNvbnRleHQubG9nZ2VyLmluZm8oXG4gICAgICAgICdSZWFkIG1vcmUgYWJvdXQgbWlncmF0aW5nIHRlc3RzOiBodHRwczovL2dpdC5pby9uZy1tYXRlcmlhbC12OS1oYW1tZXItbWlncmF0ZS10ZXN0cycpO1xuXG4gICAgaWYgKCF0aGlzLmdsb2JhbFVzZXNIYW1tZXIgJiYgdGhpcy5fcmVtb3ZlSGFtbWVyRnJvbVBhY2thZ2VKc29uKHRyZWUpKSB7XG4gICAgICAvLyBTaW5jZSBIYW1tZXIgaGFzIGJlZW4gcmVtb3ZlZCBmcm9tIHRoZSB3b3Jrc3BhY2UgXCJwYWNrYWdlLmpzb25cIiBmaWxlLFxuICAgICAgLy8gd2Ugc2NoZWR1bGUgYSBub2RlIHBhY2thZ2UgaW5zdGFsbCB0YXNrIHRvIHJlZnJlc2ggdGhlIGxvY2sgZmlsZS5cbiAgICAgIHJldHVybiB7cnVuUGFja2FnZU1hbmFnZXI6IHRydWV9O1xuICAgIH1cblxuICAgIC8vIENsZWFuIGdsb2JhbCBzdGF0ZSBvbmNlIHRoZSB3b3Jrc3BhY2UgaGFzIGJlZW4gbWlncmF0ZWQuIFRoaXMgaXMgdGVjaG5pY2FsbHlcbiAgICAvLyBub3QgbmVjZXNzYXJ5IGluIFwibmcgdXBkYXRlXCIsIGJ1dCBpbiB0ZXN0cyB3ZSByZS11c2UgdGhlIHNhbWUgcnVsZSBjbGFzcy5cbiAgICB0aGlzLmdsb2JhbFVzZXNIYW1tZXIgPSBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHRoZSBoYW1tZXIgcGFja2FnZSBmcm9tIHRoZSB3b3Jrc3BhY2UgXCJwYWNrYWdlLmpzb25cIi5cbiAgICogQHJldHVybnMgV2hldGhlciBIYW1tZXIgd2FzIHNldCB1cCBhbmQgaGFzIGJlZW4gcmVtb3ZlZCBmcm9tIHRoZSBcInBhY2thZ2UuanNvblwiXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBfcmVtb3ZlSGFtbWVyRnJvbVBhY2thZ2VKc29uKHRyZWU6IFRyZWUpOiBib29sZWFuIHtcbiAgICBpZiAoIXRyZWUuZXhpc3RzKCcvcGFja2FnZS5qc29uJykpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBwYWNrYWdlSnNvbiA9IEpTT04ucGFyc2UodHJlZS5yZWFkKCcvcGFja2FnZS5qc29uJykhLnRvU3RyaW5nKCd1dGY4JykpO1xuXG4gICAgLy8gV2UgZG8gbm90IGhhbmRsZSB0aGUgY2FzZSB3aGVyZSBzb21lb25lIG1hbnVhbGx5IGFkZGVkIFwiaGFtbWVyanNcIiB0byB0aGUgZGV2IGRlcGVuZGVuY2llcy5cbiAgICBpZiAocGFja2FnZUpzb24uZGVwZW5kZW5jaWVzICYmIHBhY2thZ2VKc29uLmRlcGVuZGVuY2llc1tIQU1NRVJfTU9EVUxFX1NQRUNJRklFUl0pIHtcbiAgICAgIGRlbGV0ZSBwYWNrYWdlSnNvbi5kZXBlbmRlbmNpZXNbSEFNTUVSX01PRFVMRV9TUEVDSUZJRVJdO1xuICAgICAgdHJlZS5vdmVyd3JpdGUoJy9wYWNrYWdlLmpzb24nLCBKU09OLnN0cmluZ2lmeShwYWNrYWdlSnNvbiwgbnVsbCwgMikpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG4vKipcbiAqIFJlY3Vyc2l2ZWx5IHVud3JhcHMgYSBnaXZlbiBleHByZXNzaW9uIGlmIGl0IGlzIHdyYXBwZWRcbiAqIGJ5IHBhcmVudGhlc2lzLCB0eXBlIGNhc3RzIG9yIHR5cGUgYXNzZXJ0aW9ucy5cbiAqL1xuZnVuY3Rpb24gdW53cmFwRXhwcmVzc2lvbihub2RlOiB0cy5Ob2RlKTogdHMuTm9kZSB7XG4gIGlmICh0cy5pc1BhcmVudGhlc2l6ZWRFeHByZXNzaW9uKG5vZGUpKSB7XG4gICAgcmV0dXJuIHVud3JhcEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uKTtcbiAgfSBlbHNlIGlmICh0cy5pc0FzRXhwcmVzc2lvbihub2RlKSkge1xuICAgIHJldHVybiB1bndyYXBFeHByZXNzaW9uKG5vZGUuZXhwcmVzc2lvbik7XG4gIH0gZWxzZSBpZiAodHMuaXNUeXBlQXNzZXJ0aW9uKG5vZGUpKSB7XG4gICAgcmV0dXJuIHVud3JhcEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uKTtcbiAgfVxuICByZXR1cm4gbm9kZTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgc3BlY2lmaWVkIHBhdGggdG8gYSB2YWxpZCBUeXBlU2NyaXB0IG1vZHVsZSBzcGVjaWZpZXIgd2hpY2ggaXNcbiAqIHJlbGF0aXZlIHRvIHRoZSBnaXZlbiBjb250YWluaW5nIGZpbGUuXG4gKi9cbmZ1bmN0aW9uIGdldE1vZHVsZVNwZWNpZmllcihuZXdQYXRoOiBzdHJpbmcsIGNvbnRhaW5pbmdGaWxlOiBzdHJpbmcpIHtcbiAgbGV0IHJlc3VsdCA9IHJlbGF0aXZlKGRpcm5hbWUoY29udGFpbmluZ0ZpbGUpLCBuZXdQYXRoKS5yZXBsYWNlKC9cXFxcL2csICcvJykucmVwbGFjZSgvXFwudHMkLywgJycpO1xuICBpZiAoIXJlc3VsdC5zdGFydHNXaXRoKCcuJykpIHtcbiAgICByZXN1bHQgPSBgLi8ke3Jlc3VsdH1gO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogR2V0cyB0aGUgdGV4dCBvZiB0aGUgZ2l2ZW4gcHJvcGVydHkgbmFtZS5cbiAqIEByZXR1cm5zIFRleHQgb2YgdGhlIGdpdmVuIHByb3BlcnR5IG5hbWUuIE51bGwgaWYgbm90IHN0YXRpY2FsbHkgYW5hbHl6YWJsZS5cbiAqL1xuZnVuY3Rpb24gZ2V0UHJvcGVydHlOYW1lVGV4dChub2RlOiB0cy5Qcm9wZXJ0eU5hbWUpOiBzdHJpbmd8bnVsbCB7XG4gIGlmICh0cy5pc0lkZW50aWZpZXIobm9kZSkgfHwgdHMuaXNTdHJpbmdMaXRlcmFsTGlrZShub2RlKSkge1xuICAgIHJldHVybiBub2RlLnRleHQ7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKiBDaGVja3Mgd2hldGhlciB0aGUgZ2l2ZW4gaWRlbnRpZmllciBpcyBwYXJ0IG9mIGEgbmFtZXNwYWNlZCBhY2Nlc3MuICovXG5mdW5jdGlvbiBpc05hbWVzcGFjZWRJZGVudGlmaWVyQWNjZXNzKG5vZGU6IHRzLklkZW50aWZpZXIpOiBib29sZWFuIHtcbiAgcmV0dXJuIHRzLmlzUXVhbGlmaWVkTmFtZShub2RlLnBhcmVudCkgfHwgdHMuaXNQcm9wZXJ0eUFjY2Vzc0V4cHJlc3Npb24obm9kZS5wYXJlbnQpO1xufVxuXG4vKipcbiAqIFdhbGtzIHRocm91Z2ggdGhlIHNwZWNpZmllZCBub2RlIGFuZCByZXR1cm5zIGFsbCBjaGlsZCBub2RlcyB3aGljaCBtYXRjaCB0aGVcbiAqIGdpdmVuIHByZWRpY2F0ZS5cbiAqL1xuZnVuY3Rpb24gZmluZE1hdGNoaW5nQ2hpbGROb2RlczxUIGV4dGVuZHMgdHMuTm9kZT4oXG4gICAgcGFyZW50OiB0cy5Ob2RlLCBwcmVkaWNhdGU6IChub2RlOiB0cy5Ob2RlKSA9PiBub2RlIGlzIFQpOiBUW10ge1xuICBjb25zdCByZXN1bHQ6IFRbXSA9IFtdO1xuICBjb25zdCB2aXNpdE5vZGUgPSAobm9kZTogdHMuTm9kZSkgPT4ge1xuICAgIGlmIChwcmVkaWNhdGUobm9kZSkpIHtcbiAgICAgIHJlc3VsdC5wdXNoKG5vZGUpO1xuICAgIH1cbiAgICB0cy5mb3JFYWNoQ2hpbGQobm9kZSwgdmlzaXROb2RlKTtcbiAgfTtcbiAgdHMuZm9yRWFjaENoaWxkKHBhcmVudCwgdmlzaXROb2RlKTtcbiAgcmV0dXJuIHJlc3VsdDtcbn1cbiJdfQ==
778
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFtbWVyLWdlc3R1cmVzLW1pZ3JhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYXRlcmlhbC9zY2hlbWF0aWNzL25nLXVwZGF0ZS9taWdyYXRpb25zL2hhbW1lci1nZXN0dXJlcy12OS9oYW1tZXItZ2VzdHVyZXMtbWlncmF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7O0dBTUc7OztBQUVILCtDQUs4QjtBQUU5Qix3REFhaUM7QUFDakMsK0RBQWdFO0FBQ2hFLDJCQUFnQztBQUNoQyxpQ0FBaUM7QUFFakMsdUVBQXlFO0FBQ3pFLHlEQUE0RDtBQUM1RCxtRUFBaUU7QUFDakUscURBQStDO0FBQy9DLGlFQUF3RTtBQUN4RSx5RUFBaUU7QUFFakUsTUFBTSx5QkFBeUIsR0FBRyxlQUFlLENBQUM7QUFDbEQsTUFBTSx3QkFBd0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUNsRCxNQUFNLDRCQUE0QixHQUFHLDJCQUEyQixDQUFDO0FBRWpFLE1BQU0sd0JBQXdCLEdBQUcsdUJBQXVCLENBQUM7QUFDekQsTUFBTSwwQkFBMEIsR0FBRywyQkFBMkIsQ0FBQztBQUUvRCxNQUFNLGtCQUFrQixHQUFHLGNBQWMsQ0FBQztBQUMxQyxNQUFNLG9CQUFvQixHQUFHLDJCQUEyQixDQUFDO0FBRXpELE1BQU0sdUJBQXVCLEdBQUcsVUFBVSxDQUFDO0FBRTNDLE1BQU0sNkJBQTZCLEdBQy9CLHFFQUFxRSxDQUFDO0FBUTFFLE1BQWEsdUJBQXdCLFNBQVEsNEJBQXFCO0lBQWxFOztRQUNFLHlGQUF5RjtRQUN6Rix5RUFBeUU7UUFDekUsNEZBQTRGO1FBQzVGLFlBQU8sR0FDSCxDQUFDLElBQUksQ0FBQyxhQUFhLEtBQUssMEJBQWEsQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLGFBQWEsS0FBSywwQkFBYSxDQUFDLEdBQUcsQ0FBQztZQUNyRixDQUFDLElBQUksQ0FBQyxPQUFPLENB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QixNQUFNLFNBQVMsR0FBRyxDQUFDLElBQWEsRUFBRSxFQUFFO1FBQ2xDLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ25CLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDbkI7UUFDRCxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQztJQUNuQyxDQUFDLENBQUM7SUFDRixFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztJQUNuQyxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7XG4gIGpvaW4sXG4gIFBhdGgsXG4gIHJlbGF0aXZlLFxuICBkaXJuYW1lXG59IGZyb20gJ0Bhbmd1bGFyLWRldmtpdC9jb3JlJztcbmltcG9ydCB7U2NoZW1hdGljQ29udGV4dCwgVHJlZX0gZnJvbSAnQGFuZ3VsYXItZGV2a2l0L3NjaGVtYXRpY3MnO1xuaW1wb3J0IHtcbiAgYWRkU3ltYm9sVG9OZ01vZHVsZU1ldGFkYXRhLFxuICBEZXZraXRNaWdyYXRpb24sXG4gIGdldERlY29yYXRvck1ldGFkYXRhLFxuICBnZXRJbXBvcnRPZklkZW50aWZpZXIsXG4gIGdldE1ldGFkYXRhRmllbGQsXG4gIGdldFByb2plY3RJbmRleEZpbGVzLFxuICBnZXRQcm9qZWN0TWFpbkZpbGUsXG4gIEltcG9ydCxcbiAgTWlncmF0aW9uRmFpbHVyZSxcbiAgUG9zdE1pZ3JhdGlvbkFjdGlvbixcbiAgUmVzb2x2ZWRSZXNvdXJjZSxcbiAgVGFyZ2V0VmVyc2lvbixcbn0gZnJvbSAnQGFuZ3VsYXIvY2RrL3NjaGVtYXRpY3MnO1xuaW1wb3J0IHtJbnNlcnRDaGFuZ2V9IGZyb20gJ0BzY2hlbWF0aWNzL2FuZ3VsYXIvdXRpbGl0eS9jaGFuZ2UnO1xuaW1wb3J0IHtyZWFkRmlsZVN5bmN9IGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHRzIGZyb20gJ3R5cGVzY3JpcHQnO1xuXG5pbXBvcnQge2ZpbmRIYW1tZXJTY3JpcHRJbXBvcnRFbGVtZW50c30gZnJvbSAnLi9maW5kLWhhbW1lci1zY3JpcHQtdGFncyc7XG5pbXBvcnQge2ZpbmRNYWluTW9kdWxlRXhwcmVzc2lvbn0gZnJvbSAnLi9maW5kLW1haW4tbW9kdWxlJztcbmltcG9ydCB7aXNIYW1tZXJKc1VzZWRJblRlbXBsYXRlfSBmcm9tICcuL2hhbW1lci10ZW1wbGF0ZS1jaGVjayc7XG5pbXBvcnQge0ltcG9ydE1hbmFnZXJ9IGZyb20gJy4vaW1wb3J0LW1hbmFnZXInO1xuaW1wb3J0IHtyZW1vdmVFbGVtZW50RnJvbUFycmF5RXhwcmVzc2lvbn0gZnJvbSAnLi9yZW1vdmUtYXJyYXktZWxlbWVudCc7XG5pbXBvcnQge3JlbW92ZUVsZW1lbnRGcm9tSHRtbH0gZnJvbSAnLi9yZW1vdmUtZWxlbWVudC1mcm9tLWh0bWwnO1xuXG5jb25zdCBHRVNUVVJFX0NPTkZJR19DTEFTU19OQU1FID0gJ0dlc3R1cmVDb25maWcnO1xuY29uc3QgR0VTVFVSRV9DT05GSUdfRklMRV9OQU1FID0gJ2dlc3R1cmUtY29uZmlnJztcbmNvbnN0IEdFU1RVUkVfQ09ORklHX1RFTVBMQVRFX1BBVEggPSAnLi9nZXN0dXJlLWNvbmZpZy50ZW1wbGF0ZSc7XG5cbmNvbnN0IEhBTU1FUl9DT05GSUdfVE9LRU5fTkFNRSA9ICdIQU1NRVJfR0VTVFVSRV9DT05GSUcnO1xuY29uc3QgSEFNTUVSX0NPTkZJR19UT0tFTl9NT0RVTEUgPSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XG5cbmNvbnN0IEhBTU1FUl9NT0RVTEVfTkFNRSA9ICdIYW1tZXJNb2R1bGUnO1xuY29uc3QgSEFNTUVSX01PRFVMRV9JTVBPUlQgPSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XG5cbmNvbnN0IEhBTU1FUl9NT0RVTEVfU1BFQ0lGSUVSID0gJ2hhbW1lcmpzJztcblxuY29uc3QgQ0FOTk9UX1JFTU9WRV9SRUZFUkVOQ0VfRVJST1IgPVxuICAgIGBDYW5ub3QgcmVtb3ZlIHJlZmVyZW5jZSB0byBcIkdlc3R1cmVDb25maWdcIi4gUGxlYXNlIHJlbW92ZSBtYW51YWxseS5gO1xuXG5pbnRlcmZhY2UgSWRlbnRpZmllclJlZmVyZW5jZSB7XG4gIG5vZGU6IHRzLklkZW50aWZpZXI7XG4gIGltcG9ydERhdGE6IEltcG9ydDtcbiAgaXNJbXBvcnQ6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjbGFzcyBIYW1tZXJHZXN0dXJlc01pZ3JhdGlvbiBleHRlbmRzIERldmtpdE1pZ3JhdGlvbjxudWxsPiB7XG4gIC8vIE9ubHkgZW5hYmxlIHRoaXMgcnVsZSBpZiB0aGUgbWlncmF0aW9uIHRhcmdldHMgdjkgb3IgdjEwIGFuZCBpcyBydW5uaW5nIGZvciBhIG5vbi10ZXN0XG4gIC8vIHRhcmdldC4gV2UgY2Fubm90IG1pZ3JhdGUgdGVzdCB0YXJnZXRzIHNpbmNlIHRoZXkgaGF2ZSBhIGxpbWl0ZWQgc2NvcGVcbiAgLy8gKGluIHJlZ2FyZHMgdG8gc291cmNlIGZpbGVzKSBhbmQgdGhlcmVmb3JlIHRoZSBIYW1tZXJKUyB1c2FnZSBkZXRlY3Rpb24gY2FuIGJlIGluY29ycmVjdC5cbiAgZW5hYmxlZCA9XG4gICAgICAodGhpcy50YXJnZXRWZXJzaW9uID09PSBUYXJnZXRWZXJzaW9uLlY5IHx8IHRoaXMudGFyZ2V0VmVyc2lvbiA9PT0gVGFyZ2V0VmVyc2lvbi5WMTApICYmXG4gICAgICAhdGhpcy5jb250ZXh0LmlzVGVzdFRhcmdldDtcblxuICBwcml2YXRlIF9wcmludGVyID0gdHMuY3JlYXRlUHJpbnRlcigpO1xuICBwcml2YXRlIF9pbXBvcnRNYW5hZ2VyID0gbmV3IEltcG9ydE1hbmFnZXIodGhpcy5maWxlU3lzdGVtLCB0aGlzLl9wcmludGVyKTtcbiAgcHJpdmF0ZSBfbm9kZUZhaWx1cmVzOiB7bm9kZTogdHMuTm9kZSwgbWVzc2FnZTogc3RyaW5nfVtdID0gW107XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgY3VzdG9tIEhhbW1lckpTIGV2ZW50cyBwcm92aWRlZCBieSB0aGUgTWF0ZXJpYWwgZ2VzdHVyZVxuICAgKiBjb25maWcgYXJlIHVzZWQgaW4gYSB0ZW1wbGF0ZS5cbiAgICovXG4gIHByaXZhdGUgX2N1c3RvbUV2ZW50c1VzZWRJblRlbXBsYXRlID0gZmFsc2U7XG5cbiAgLyoqIFdoZXRoZXIgc3RhbmRhcmQgSGFtbWVySlMgZXZlbnRzIGFyZSB1c2VkIGluIGEgdGVtcGxhdGUuICovXG4gIHByaXZhdGUgX3N0YW5kYXJkRXZlbnRzVXNlZEluVGVtcGxhdGUgPSBmYWxzZTtcblxuICAvKiogV2hldGhlciBIYW1tZXJKUyBpcyBhY2Nlc3NlZCBhdCBydW50aW1lLiAqL1xuICBwcml2YXRlIF91c2VkSW5SdW50aW1lID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgaW1wb3J0cyB0aGF0IG1ha2UgXCJoYW1tZXJqc1wiIGF2YWlsYWJsZSBnbG9iYWxseS4gV2Uga2VlcCB0cmFjayBvZiB0aGVzZVxuICAgKiBzaW5jZSB3ZSBtaWdodCBuZWVkIHRvIHJlbW92ZSB0aGVtIGlmIEhhbW1lciBpcyBub3QgdXNlZC5cbiAgICovXG4gIHByaXZhdGUgX2luc3RhbGxJbXBvcnRzOiB0cy5JbXBvcnREZWNsYXJhdGlvbltdID0gW107XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgaWRlbnRpZmllcnMgd2hpY2ggcmVzb2x2ZSB0byB0aGUgZ2VzdHVyZSBjb25maWcgZnJvbSBBbmd1bGFyIE1hdGVyaWFsLlxuICAgKi9cbiAgcHJpdmF0ZSBfZ2VzdHVyZUNvbmZpZ1JlZmVyZW5jZXM6IElkZW50aWZpZXJSZWZlcmVuY2VbXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBMaXN0IG9mIGlkZW50aWZpZXJzIHdoaWNoIHJlc29sdmUgdG8gdGhlIFwiSEFNTUVSX0dFU1RVUkVfQ09ORklHXCIgdG9rZW4gZnJvbVxuICAgKiBcIkBhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXJcIi5cbiAgICovXG4gIHByaXZhdGUgX2hhbW1lckNvbmZpZ1Rva2VuUmVmZXJlbmNlczogSWRlbnRpZmllclJlZmVyZW5jZVtdID0gW107XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgaWRlbnRpZmllcnMgd2hpY2ggcmVzb2x2ZSB0byB0aGUgXCJIYW1tZXJNb2R1bGVcIiBmcm9tXG4gICAqIFwiQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3NlclwiLlxuICAgKi9cbiAgcHJpdmF0ZSBfaGFtbWVyTW9kdWxlUmVmZXJlbmNlczogSWRlbnRpZmllclJlZmVyZW5jZVtdID0gW107XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgaWRlbnRpZmllcnMgdGhhdCBoYXZlIGJlZW4gZGVsZXRlZCBmcm9tIHNvdXJjZSBmaWxlcy4gVGhpcyBjYW4gYmVcbiAgICogdXNlZCB0byBkZXRlcm1pbmUgaWYgY2VydGFpbiBpbXBvcnRzIGFyZSBzdGlsbCB1c2VkIG9yIG5vdC5cbiAgICovXG4gIHByaXZhdGUgX2RlbGV0ZWRJZGVudGlmaWVyczogdHMuSWRlbnRpZmllcltdID0gW107XG5cbiAgdmlzaXRUZW1wbGF0ZSh0ZW1wbGF0ZTogUmVzb2x2ZWRSZXNvdXJjZSk6IHZvaWQge1xuICAgIGlmICghdGhpcy5fY3VzdG9tRXZlbnRzVXNlZEluVGVtcGxhdGUgfHwgIXRoaXMuX3N0YW5kYXJkRXZlbnRzVXNlZEluVGVtcGxhdGUpIHtcbiAgICAgIGNvbnN0IHtzdGFuZGFyZEV2ZW50cywgY3VzdG9tRXZlbnRzfSA9IGlzSGFtbWVySnNVc2VkSW5UZW1wbGF0ZSh0ZW1wbGF0ZS5jb250ZW50KTtcbiAgICAgIHRoaXMuX2N1c3RvbUV2ZW50c1VzZWRJblRlbXBsYXRlID0gdGhpcy5fY3VzdG9tRXZlbnRzVXNlZEluVGVtcGxhdGUgfHwgY3VzdG9tRXZlbnRzO1xuICAgICAgdGhpcy5fc3RhbmRhcmRFdmVudHNVc2VkSW5UZW1wbGF0ZSA9IHRoaXMuX3N0YW5kYXJkRXZlbnRzVXNlZEluVGVtcGxhdGUgfHwgc3RhbmRhcmRFdmVudHM7XG4gICAgfVxuICB9XG5cbiAgdmlzaXROb2RlKG5vZGU6IHRzLk5vZGUpOiB2b2lkIHtcbiAgICB0aGlzLl9jaGVja0hhbW1lckltcG9ydHMobm9kZSk7XG4gICAgdGhpcy5fY2hlY2tGb3JSdW50aW1lSGFtbWVyVXNhZ2Uobm9kZSk7XG4gICAgdGhpcy5fY2hlY2tGb3JNYXRlcmlhbEdlc3R1cmVDb25maWcobm9kZSk7XG4gICAgdGhpcy5fY2hlY2tGb3JIYW1tZXJHZXN0dXJlQ29uZmlnVG9rZW4obm9kZSk7XG4gICAgdGhpcy5fY2hlY2tGb3JIYW1tZXJNb2R1bGVSZWZlcmVuY2Uobm9kZSk7XG4gIH1cblxuICBwb3N0QW5hbHlzaXMoKTogdm9pZCB7XG4gICAgLy8gV2FsayB0aHJvdWdoIGFsbCBoYW1tZXIgY29uZmlnIHRva2VuIHJlZmVyZW5jZXMgYW5kIGNoZWNrIGlmIHRoZXJlXG4gICAgLy8gaXMgYSBwb3RlbnRpYWwgY3VzdG9tIGdlc3R1cmUgY29uZmlnIHNldHVwLlxuICAgIGNvbnN0IGhhc0N1c3RvbUdlc3R1cmVDb25maWdTZXR1cCA9XG4gICAgICAgIHRoaXMuX2hhbW1lckNvbmZpZ1Rva2VuUmVmZXJlbmNlcy5zb21lKHIgPT4gdGhpcy5fY2hlY2tGb3JDdXN0b21HZXN0dXJlQ29uZmlnU2V0dXAocikpO1xuICAgIGNvbnN0IHVzZWRJblRlbXBsYXRlID0gdGhpcy5fc3RhbmRhcmRFdmVudHNVc2VkSW5UZW1wbGF0ZSB8fCB0aGlzLl9jdXN0b21FdmVudHNVc2VkSW5UZW1wbGF0ZTtcblxuICAgIC8qXG4gICAgICBQb3NzaWJsZSBzY2VuYXJpb3MgYW5kIGhvdyB0aGUgbWlncmF0aW9uIHNob3VsZCBjaGFuZ2UgdGhlIHByb2plY3Q6XG4gICAgICAgIDEuIFdlIGRldGVjdCB0aGF0IGEgY3VzdG9tIEhhbW1lckpTIGdlc3R1cmUgY29uZmlnIGlzIHNldCB1cDpcbiAgICAgICAgICAgIC0gUmVtb3ZlIHJlZmVyZW5jZXMgdG8gdGhlIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnIGlmIG5vIEhhbW1lckpTIGV2ZW50IGlzIHVzZWQuXG4gICAgICAgICAgICAtIFByaW50IGEgd2FybmluZyBhYm91dCBhbWJpZ3VvdXMgY29uZmlndXJhdGlvbiB0aGF0IGNhbm5vdCBiZSBoYW5kbGVkIGNvbXBsZXRlbHlcbiAgICAgICAgICAgICAgaWYgdGhlcmUgYXJlIHJlZmVyZW5jZXMgdG8gdGhlIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLlxuICAgICAgICAyLiBXZSBkZXRlY3QgdGhhdCBIYW1tZXJKUyBpcyBvbmx5IHVzZWQgcHJvZ3JhbW1hdGljYWxseTpcbiAgICAgICAgICAgIC0gUmVtb3ZlIHJlZmVyZW5jZXMgdG8gR2VzdHVyZUNvbmZpZyBvZiBNYXRlcmlhbC5cbiAgICAgICAgICAgIC0gUmVtb3ZlIHJlZmVyZW5jZXMgdG8gdGhlIFwiSGFtbWVyTW9kdWxlXCIgaWYgcHJlc2VudC5cbiAgICAgICAgMy4gV2UgZGV0ZWN0IHRoYXQgc3RhbmRhcmQgSGFtbWVySlMgZXZlbnRzIGFyZSB1c2VkIGluIGEgdGVtcGxhdGU6XG4gICAgICAgICAgICAtIFNldCB1cCB0aGUgXCJIYW1tZXJNb2R1bGVcIiBmcm9tIHBsYXRmb3JtLWJyb3dzZXIuXG4gICAgICAgICAgICAtIFJlbW92ZSBhbGwgZ2VzdHVyZSBjb25maWcgcmVmZXJlbmNlcy5cbiAgICAgICAgNC4gV2UgZGV0ZWN0IHRoYXQgY3VzdG9tIEhhbW1lckpTIGV2ZW50cyBwcm92aWRlZCBieSB0aGUgTWF0ZXJpYWwgZ2VzdHVyZVxuICAgICAgICAgICBjb25maWcgYXJlIHVzZWQuXG4gICAgICAgICAgICAtIENvcHkgdGhlIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnIGludG8gdGhlIGFwcC5cbiAgICAgICAgICAgIC0gUmV3cml0ZSBhbGwgZ2VzdHVyZSBjb25maWcgcmVmZXJlbmNlcyB0byB0aGUgbmV3bHkgY29waWVkIG9uZS5cbiAgICAgICAgICAgIC0gU2V0IHVwIHRoZSBuZXcgZ2VzdHVyZSBjb25maWcgaW4gdGhlIHJvb3QgYXBwIG1vZHVsZS5cbiAgICAgICAgICAgIC0gU2V0IHVwIHRoZSBcIkhhbW1lck1vZHVsZVwiIGZyb20gcGxhdGZvcm0tYnJvd3Nlci5cbiAgICAgICAgNC4gV2UgZGV0ZWN0IG5vIEhhbW1lckpTIHVzYWdlIGF0IGFsbDpcbiAgICAgICAgICAgIC0gUmVtb3ZlIEhhbW1lciBpbXBvcnRzXG4gICAgICAgICAgICAtIFJlbW92ZSBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZyByZWZlcmVuY2VzXG4gICAgICAgICAgICAtIFJlbW92ZSBIYW1tZXJNb2R1bGUgc2V0dXAgaWYgcHJlc2VudC5cbiAgICAgICAgICAgIC0gUmVtb3ZlIEhhbW1lciBzY3JpcHQgaW1wb3J0cyBpbiBcImluZGV4Lmh0bWxcIiBmaWxlcy5cbiAgICAqL1xuXG4gICAgaWYgKGhhc0N1c3RvbUdlc3R1cmVDb25maWdTZXR1cCkge1xuICAgICAgLy8gSWYgYSBjdXN0b20gZ2VzdHVyZSBjb25maWcgaXMgcHJvdmlkZWQsIHdlIGFsd2F5cyBhc3N1bWUgdGhhdCBIYW1tZXJKUyBpcyB1c2VkLlxuICAgICAgSGFtbWVyR2VzdHVyZXNNaWdyYXRpb24uZ2xvYmFsVXNlc0hhbW1lciA9IHRydWU7XG4gICAgICBpZiAoIXVzZWRJblRlbXBsYXRlICYmIHRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLmxlbmd0aCkge1xuICAgICAgICAvLyBJZiB0aGUgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlIGV2ZW50cyBhcmUgbm90IHVzZWQgYW5kIHdlIGZvdW5kIGEgY3VzdG9tXG4gICAgICAgIC8vIGdlc3R1cmUgY29uZmlnLCB3ZSBjYW4gc2FmZWx5IHJlbW92ZSByZWZlcmVuY2VzIHRvIHRoZSBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZ1xuICAgICAgICAvLyBzaW5jZSBldmVudHMgcHJvdmlkZWQgYnkgdGhlIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnIGFyZSBndWFyYW50ZWVkIHRvIGJlIHVudXNlZC5cbiAgICAgICAgdGhpcy5fcmVtb3ZlTWF0ZXJpYWxHZXN0dXJlQ29uZmlnU2V0dXAoKTtcbiAgICAgICAgdGhpcy5wcmludEluZm8oXG4gICAgICAgICAgICAnVGhlIEhhbW1lckpTIHY5IG1pZ3JhdGlvbiBmb3IgQW5ndWxhciBDb21wb25lbnRzIGRldGVjdGVkIHRoYXQgSGFtbWVySlMgaXMgJyArXG4gICAgICAgICAgICAnbWFudWFsbHkgc2V0IHVwIGluIGNvbWJpbmF0aW9uIHdpdGggcmVmZXJlbmNlcyB0byB0aGUgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlICcgK1xuICAgICAgICAgICAgJ2NvbmZpZy4gVGhpcyB0YXJnZXQgY2Fubm90IGJlIG1pZ3JhdGVkIGNvbXBsZXRlbHksIGJ1dCBhbGwgcmVmZXJlbmNlcyB0byB0aGUgJyArXG4gICAgICAgICAgICAnZGVwcmVjYXRlZCBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgaGF2ZSBiZWVuIHJlbW92ZWQuIFJlYWQgbW9yZSBoZXJlOiAnICtcbiAgICAgICAgICAgICdodHRwczovL2dpdC5pby9uZy1tYXRlcmlhbC12OS1oYW1tZXItYW1iaWd1b3VzLXVzYWdlJyk7XG4gICAgICB9IGVsc2UgaWYgKHVzZWRJblRlbXBsYXRlICYmIHRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLmxlbmd0aCkge1xuICAgICAgICAvLyBTaW5jZSB0aGVyZSBpcyBhIHJlZmVyZW5jZSB0byB0aGUgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZywgYW5kIHdlIGRldGVjdGVkXG4gICAgICAgIC8vIHVzYWdlIG9mIGEgZ2VzdHVyZSBldmVudCB0aGF0IGNvdWxkIGJlIHByb3ZpZGVkIGJ5IEFuZ3VsYXIgTWF0ZXJpYWwsIHdlICpjYW5ub3QqXG4gICAgICAgIC8vIGF1dG9tYXRpY2FsbHkgcmVtb3ZlIHJlZmVyZW5jZXMuIFRoaXMgaXMgYmVjYXVzZSB3ZSBkbyAqbm90KiBrbm93IHdoZXRoZXIgdGhlXG4gICAgICAgIC8vIGV2ZW50IGlzIGFjdHVhbGx5IHByb3ZpZGVkIGJ5IHRoZSBjdXN0b20gY29uZmlnIG9yIGJ5IHRoZSBNYXRlcmlhbCBjb25maWcuXG4gICAgICAgIHRoaXMucHJpbnRJbmZvKFxuICAgICAgICAgICAgJ1RoZSBIYW1tZXJKUyB2OSBtaWdyYXRpb24gZm9yIEFuZ3VsYXIgQ29tcG9uZW50cyBkZXRlY3RlZCB0aGF0IEhhbW1lckpTIGlzICcgK1xuICAgICAgICAgICAgJ21hbnVhbGx5IHNldCB1cCBpbiBjb21iaW5hdGlvbiB3aXRoIHJlZmVyZW5jZXMgdG8gdGhlIEFuZ3VsYXIgTWF0ZXJpYWwgZ2VzdHVyZSAnICtcbiAgICAgICAgICAgICdjb25maWcuIFRoaXMgdGFyZ2V0IGNhbm5vdCBiZSBtaWdyYXRlZCBjb21wbGV0ZWx5LiBQbGVhc2UgbWFudWFsbHkgcmVtb3ZlICcgK1xuICAgICAgICAgICAgJ3JlZmVyZW5jZXMgdG8gdGhlIGRlcHJlY2F0ZWQgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZy4gUmVhZCBtb3JlIGhlcmU6ICcgK1xuICAgICAgICAgICAgJ2h0dHBzOi8vZ2l0LmlvL25nLW1hdGVyaWFsLXY5LWhhbW1lci1hbWJpZ3VvdXMtdXNhZ2UnKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHRoaXMuX3VzZWRJblJ1bnRpbWUgfHwgdXNlZEluVGVtcGxhdGUpIHtcbiAgICAgIC8vIFdlIGtlZXAgdHJhY2sgb2Ygd2hldGhlciBIYW1tZXIgaXMgdXNlZCBnbG9iYWxseS4gVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSB3ZVxuICAgICAgLy8gd2FudCB0byBvbmx5IHJlbW92ZSBIYW1tZXIgZnJvbSB0aGUgXCJwYWNrYWdlLmpzb25cIiBpZiBpdCBpcyBub3QgdXNlZCBpbiBhbnkgcHJvamVjdFxuICAgICAgLy8gdGFyZ2V0LiBKdXN0IGJlY2F1c2UgaXQgaXNuJ3QgdXNlZCBpbiBvbmUgdGFyZ2V0IGRvZXNuJ3QgbWVhbiB0aGF0IHdlIGNhbiBzYWZlbHlcbiAgICAgIC8vIHJlbW92ZSB0aGUgZGVwZW5kZW5jeS5cbiAgICAgIEhhbW1lckdlc3R1cmVzTWlncmF0aW9uLmdsb2JhbFVzZXNIYW1tZXIgPSB0cnVlO1xuXG4gICAgICAvLyBJZiBoYW1tZXIgaXMgb25seSB1c2VkIGF0IHJ1bnRpbWUsIHdlIGRvbid0IG5lZWQgdGhlIGdlc3R1cmUgY29uZmlnIG9yIFwiSGFtbWVyTW9kdWxlXCJcbiAgICAgIC8vIGFuZCBjYW4gcmVtb3ZlIGl0IChhbG9uZyB3aXRoIHRoZSBoYW1tZXIgY29uZmlnIHRva2VuIGltcG9ydCBpZiBubyBsb25nZXIgbmVlZGVkKS5cbiAgICAgIGlmICghdXNlZEluVGVtcGxhdGUpIHtcbiAgICAgICAgdGhpcy5fcmVtb3ZlTWF0ZXJpYWxHZXN0dXJlQ29uZmlnU2V0dXAoKTtcbiAgICAgICAgdGhpcy5fcmVtb3ZlSGFtbWVyTW9kdWxlUmVmZXJlbmNlcygpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLl9zdGFuZGFyZEV2ZW50c1VzZWRJblRlbXBsYXRlICYmICF0aGlzLl9jdXN0b21FdmVudHNVc2VkSW5UZW1wbGF0ZSkge1xuICAgICAgICB0aGlzLl9zZXR1cEhhbW1lcldpdGhTdGFuZGFyZEV2ZW50cygpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5fc2V0dXBIYW1tZXJXaXRoQ3VzdG9tRXZlbnRzKCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX3JlbW92ZUhhbW1lclNldHVwKCk7XG4gICAgfVxuXG4gICAgLy8gUmVjb3JkIHRoZSBjaGFuZ2VzIGNvbGxlY3RlZCBpbiB0aGUgaW1wb3J0IG1hbmFnZXIuIENoYW5nZXMgbmVlZCB0byBiZSBhcHBsaWVkXG4gICAgLy8gb25jZSB0aGUgaW1wb3J0IG1hbmFnZXIgcmVnaXN0ZXJlZCBhbGwgaW1wb3J0IG1vZGlmaWNhdGlvbnMuIFRoaXMgYXZvaWRzIGNvbGxpc2lvbnMuXG4gICAgdGhpcy5faW1wb3J0TWFuYWdlci5yZWNvcmRDaGFuZ2VzKCk7XG5cbiAgICAvLyBDcmVhdGUgbWlncmF0aW9uIGZhaWx1cmVzIHRoYXQgd2lsbCBiZSBwcmludGVkIGJ5IHRoZSB1cGRhdGUtdG9vbCBvbiBtaWdyYXRpb25cbiAgICAvLyBjb21wbGV0aW9uLiBXZSBuZWVkIHNwZWNpYWwgbG9naWMgZm9yIHVwZGF0aW5nIGZhaWx1cmUgcG9zaXRpb25zIHRvIHJlZmxlY3RcbiAgICAvLyB0aGUgbmV3IHNvdXJjZSBmaWxlIGFmdGVyIG1vZGlmaWNhdGlvbnMgZnJvbSB0aGUgaW1wb3J0IG1hbmFnZXIuXG4gICAgdGhpcy5mYWlsdXJlcy5wdXNoKC4uLnRoaXMuX2NyZWF0ZU1pZ3JhdGlvbkZhaWx1cmVzKCkpO1xuXG4gICAgLy8gVGhlIHRlbXBsYXRlIGNoZWNrIGZvciBIYW1tZXJKUyBldmVudHMgaXMgbm90IGNvbXBsZXRlbHkgcmVsaWFibGUgYXMgdGhlIGV2ZW50XG4gICAgLy8gb3V0cHV0IGNvdWxkIGFsc28gYmUgZnJvbSBhIGNvbXBvbmVudCBoYXZpbmcgYW4gb3V0cHV0IG5hbWVkIHNpbWlsYXJseSB0byBhIGtub3duXG4gICAgLy8gaGFtbWVyanMgZXZlbnQgKGUuZy4gXCJAT3V0cHV0KCkgc2xpZGVcIikuIFRoZSB1c2FnZSBpcyB0aGVyZWZvcmUgc29tZXdoYXQgYW1iaWd1b3VzXG4gICAgLy8gYW5kIHdlIHdhbnQgdG8gcHJpbnQgYSBtZXNzYWdlIHRoYXQgZGV2ZWxvcGVycyBtaWdodCBiZSBhYmxlIHRvIHJlbW92ZSBIYW1tZXIgbWFudWFsbHkuXG4gICAgaWYgKCFoYXNDdXN0b21HZXN0dXJlQ29uZmlnU2V0dXAgJiYgIXRoaXMuX3VzZWRJblJ1bnRpbWUgJiYgdXNlZEluVGVtcGxhdGUpIHtcbiAgICAgIHRoaXMucHJpbnRJbmZvKFxuICAgICAgICAgICdUaGUgSGFtbWVySlMgdjkgbWlncmF0aW9uIGZvciBBbmd1bGFyIENvbXBvbmVudHMgbWlncmF0ZWQgdGhlICcgK1xuICAgICAgICAgICdwcm9qZWN0IHRvIGtlZXAgSGFtbWVySlMgaW5zdGFsbGVkLCBidXQgZGV0ZWN0ZWQgYW1iaWd1b3VzIHVzYWdlIG9mIEhhbW1lckpTLiBQbGVhc2UgJyArXG4gICAgICAgICAgJ21hbnVhbGx5IGNoZWNrIGlmIHlvdSBjYW4gcmVtb3ZlIEhhbW1lckpTIGZyb20geW91ciBhcHBsaWNhdGlvbi4gTW9yZSBkZXRhaWxzOiAnICtcbiAgICAgICAgICAnaHR0cHM6Ly9naXQuaW8vbmctbWF0ZXJpYWwtdjktaGFtbWVyLWFtYmlndW91cy11c2FnZScpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHVwIHRoZSBoYW1tZXIgZ2VzdHVyZSBjb25maWcgaW4gdGhlIGN1cnJlbnQgcHJvamVjdC4gVG8gYWNoaWV2ZSB0aGlzLCB0aGVcbiAgICogZm9sbG93aW5nIHN0ZXBzIGFyZSBwZXJmb3JtZWQ6XG4gICAqICAgMSkgQ3JlYXRlIGNvcHkgb2YgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZy5cbiAgICogICAyKSBSZXdyaXRlIGFsbCByZWZlcmVuY2VzIHRvIHRoZSBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnIHRvIHRoZVxuICAgKiAgICAgIG5ldyBnZXN0dXJlIGNvbmZpZy5cbiAgICogICAzKSBTZXR1cCB0aGUgSEFNTUVSX0dFU1RVUkVfQ09ORklHIGluIHRoZSByb290IGFwcCBtb2R1bGUgKGlmIG5vdCBkb25lIGFscmVhZHkpLlxuICAgKiAgIDQpIFNldHVwIHRoZSBcIkhhbW1lck1vZHVsZVwiIGluIHRoZSByb290IGFwcCBtb2R1bGUgKGlmIG5vdCBkb25lIGFscmVhZHkpLlxuICAgKi9cbiAgcHJpdmF0ZSBfc2V0dXBIYW1tZXJXaXRoQ3VzdG9tRXZlbnRzKCkge1xuICAgIGNvbnN0IHByb2plY3QgPSB0aGlzLmNvbnRleHQucHJvamVjdDtcbiAgICBjb25zdCBzb3VyY2VSb290ID0gdGhpcy5maWxlU3lzdGVtLnJlc29sdmUocHJvamVjdC5zb3VyY2VSb290IHx8IHByb2plY3Qucm9vdCk7XG4gICAgY29uc3QgbmV3Q29uZmlnUGF0aCA9XG4gICAgICAgIGpvaW4oc291cmNlUm9vdCwgdGhpcy5fZ2V0QXZhaWxhYmxlR2VzdHVyZUNvbmZpZ0ZpbGVOYW1lKHNvdXJjZVJvb3QpKTtcblxuICAgIC8vIENvcHkgZ2VzdHVyZSBjb25maWcgdGVtcGxhdGUgaW50byB0aGUgQ0xJIHByb2plY3QuXG4gICAgdGhpcy5maWxlU3lzdGVtLmNyZWF0ZShcbiAgICAgICAgbmV3Q29uZmlnUGF0aCwgcmVhZEZpbGVTeW5jKHJlcXVpcmUucmVzb2x2ZShHRVNUVVJFX0NPTkZJR19URU1QTEFURV9QQVRIKSwgJ3V0ZjgnKSk7XG5cbiAgICAvLyBSZXBsYWNlIGFsbCBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZyByZWZlcmVuY2VzIHRvIHJlc29sdmUgdG8gdGhlXG4gICAgLy8gbmV3bHkgY29waWVkIGdlc3R1cmUgY29uZmlnLlxuICAgIHRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLmZvckVhY2goaSA9PiB7XG4gICAgICBjb25zdCBmaWxlUGF0aCA9IHRoaXMuZmlsZVN5c3RlbS5yZXNvbHZlKGkubm9kZS5nZXRTb3VyY2VGaWxlKCkuZmlsZU5hbWUpO1xuICAgICAgcmV0dXJuIHRoaXMuX3JlcGxhY2VHZXN0dXJlQ29uZmlnUmVmZXJlbmNlKGksIEdFU1RVUkVfQ09ORklHX0NMQVNTX05BTUUsXG4gICAgICAgIGdldE1vZHVsZVNwZWNpZmllcihuZXdDb25maWdQYXRoLCBmaWxlUGF0aCkpO1xuICAgIH0pO1xuXG4gICAgLy8gU2V0dXAgdGhlIGdlc3R1cmUgY29uZmlnIHByb3ZpZGVyIGFuZCB0aGUgXCJIYW1tZXJNb2R1bGVcIiBpbiB0aGUgcm9vdCBtb2R1bGVcbiAgICAvLyBpZiBub3QgZG9uZSBhbHJlYWR5LiBUaGUgXCJIYW1tZXJNb2R1bGVcIiBpcyBuZWVkZWQgaW4gdjkgc2luY2UgaXQgZW5hYmxlcyB0aGVcbiAgICAvLyBIYW1tZXIgZXZlbnQgcGx1Z2luIHRoYXQgd2FzIHByZXZpb3VzbHkgZW5hYmxlZCBieSBkZWZhdWx0IGluIHY4LlxuICAgIHRoaXMuX3NldHVwTmV3R2VzdHVyZUNvbmZpZ0luUm9vdE1vZHVsZShuZXdDb25maWdQYXRoKTtcbiAgICB0aGlzLl9zZXR1cEhhbW1lck1vZHVsZUluUm9vdE1vZHVsZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdXAgdGhlIHN0YW5kYXJkIGhhbW1lciBtb2R1bGUgaW4gdGhlIHByb2plY3QgYW5kIHJlbW92ZXMgYWxsXG4gICAqIHJlZmVyZW5jZXMgdG8gdGhlIGRlcHJlY2F0ZWQgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZy5cbiAgICovXG4gIHByaXZhdGUgX3NldHVwSGFtbWVyV2l0aFN0YW5kYXJkRXZlbnRzKCkge1xuICAgIC8vIFNldHVwIHRoZSBIYW1tZXJNb2R1bGUuIFRoZSBIYW1tZXJNb2R1bGUgZW5hYmxlcyBzdXBwb3J0IGZvclxuICAgIC8vIHRoZSBzdGFuZGFyZCBIYW1tZXJKUyBldmVudHMuXG4gICAgdGhpcy5fc2V0dXBIYW1tZXJNb2R1bGVJblJvb3RNb2R1bGUoKTtcbiAgICB0aGlzLl9yZW1vdmVNYXRlcmlhbEdlc3R1cmVDb25maWdTZXR1cCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgSGFtbWVyIGZyb20gdGhlIGN1cnJlbnQgcHJvamVjdC4gVGhlIGZvbGxvd2luZyBzdGVwcyBhcmUgcGVyZm9ybWVkOlxuICAgKiAgIDEpIERlbGV0ZSBhbGwgVHlwZVNjcmlwdCBpbXBvcnRzIHRvIFwiaGFtbWVyanNcIi5cbiAgICogICAyKSBSZW1vdmUgcmVmZXJlbmNlcyB0byB0aGUgQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZy5cbiAgICogICAzKSBSZW1vdmUgXCJoYW1tZXJqc1wiIGZyb20gYWxsIGluZGV4IEhUTUwgZmlsZXMgb2YgdGhlIGN1cnJlbnQgcHJvamVjdC5cbiAgICovXG4gIHByaXZhdGUgX3JlbW92ZUhhbW1lclNldHVwKCkge1xuICAgIHRoaXMuX2luc3RhbGxJbXBvcnRzLmZvckVhY2goaSA9PiB0aGlzLl9pbXBvcnRNYW5hZ2VyLmRlbGV0ZUltcG9ydEJ5RGVjbGFyYXRpb24oaSkpO1xuXG4gICAgdGhpcy5fcmVtb3ZlTWF0ZXJpYWxHZXN0dXJlQ29uZmlnU2V0dXAoKTtcbiAgICB0aGlzLl9yZW1vdmVIYW1tZXJNb2R1bGVSZWZlcmVuY2VzKCk7XG4gICAgdGhpcy5fcmVtb3ZlSGFtbWVyRnJvbUluZGV4RmlsZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgdGhlIGdlc3R1cmUgY29uZmlnIHNldHVwIGJ5IGRlbGV0aW5nIGFsbCBmb3VuZCByZWZlcmVuY2VzIHRvIHRoZSBBbmd1bGFyXG4gICAqIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLiBBZGRpdGlvbmFsbHksIHVudXNlZCBpbXBvcnRzIHRvIHRoZSBoYW1tZXIgZ2VzdHVyZSBjb25maWdcbiAgICogdG9rZW4gZnJvbSBcIkBhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXJcIiB3aWxsIGJlIHJlbW92ZWQgYXMgd2VsbC5cbiAgICovXG4gIHByaXZhdGUgX3JlbW92ZU1hdGVyaWFsR2VzdHVyZUNvbmZpZ1NldHVwKCkge1xuICAgIHRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLmZvckVhY2gociA9PiB0aGlzLl9yZW1vdmVHZXN0dXJlQ29uZmlnUmVmZXJlbmNlKHIpKTtcblxuICAgIHRoaXMuX2hhbW1lckNvbmZpZ1Rva2VuUmVmZXJlbmNlcy5mb3JFYWNoKHIgPT4ge1xuICAgICAgaWYgKHIuaXNJbXBvcnQpIHtcbiAgICAgICAgdGhpcy5fcmVtb3ZlSGFtbWVyQ29uZmlnVG9rZW5JbXBvcnRJZlVudXNlZChyKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBSZW1vdmVzIGFsbCByZWZlcmVuY2VzIHRvIHRoZSBcIkhhbW1lck1vZHVsZVwiIGZyb20gXCJAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyXCIuICovXG4gIHByaXZhdGUgX3JlbW92ZUhhbW1lck1vZHVsZVJlZmVyZW5jZXMoKSB7XG4gICAgdGhpcy5faGFtbWVyTW9kdWxlUmVmZXJlbmNlcy5mb3JFYWNoKCh7bm9kZSwgaXNJbXBvcnQsIGltcG9ydERhdGF9KSA9PiB7XG4gICAgICBjb25zdCBzb3VyY2VGaWxlID0gbm9kZS5nZXRTb3VyY2VGaWxlKCk7XG4gICAgICBjb25zdCByZWNvcmRlciA9IHRoaXMuZmlsZVN5c3RlbS5lZGl0KHRoaXMuZmlsZVN5c3RlbS5yZXNvbHZlKHNvdXJjZUZpbGUuZmlsZU5hbWUpKTtcblxuICAgICAgLy8gT25seSByZW1vdmUgdGhlIGltcG9ydCBmb3IgdGhlIEhhbW1lck1vZHVsZSBpZiB0aGUgbW9kdWxlIGhhcyBiZWVuIGFjY2Vzc2VkXG4gICAgICAvLyB0aHJvdWdoIGEgbm9uLW5hbWVzcGFjZWQgaWRlbnRpZmllciBhY2Nlc3MuXG4gICAgICBpZiAoIWlzTmFtZXNwYWNlZElkZW50aWZpZXJBY2Nlc3Mobm9kZSkpIHtcbiAgICAgICAgdGhpcy5faW1wb3J0TWFuYWdlci5kZWxldGVOYW1lZEJpbmRpbmdJbXBvcnQoXG4gICAgICAgICAgICBzb3VyY2VGaWxlLCBIQU1NRVJfTU9EVUxFX05BTUUsIGltcG9ydERhdGEubW9kdWxlTmFtZSk7XG4gICAgICB9XG5cbiAgICAgIC8vIEZvciByZWZlcmVuY2VzIGZyb20gd2l0aGluIGFuIGltcG9ydCwgd2UgZG8gbm90IG5lZWQgdG8gZG8gYW55dGhpbmcgb3RoZXIgdGhhblxuICAgICAgLy8gcmVtb3ZpbmcgdGhlIGltcG9ydC4gRm9yIG90aGVyIHJlZmVyZW5jZXMsIHdlIHJlbW92ZSB0aGUgaW1wb3J0IGFuZCB0aGUgYWN0dWFsXG4gICAgICAvLyBpZGVudGlmaWVyIGluIHRoZSBtb2R1bGUgaW1wb3J0cy5cbiAgICAgIGlmIChpc0ltcG9ydCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIElmIHRoZSBcIkhhbW1lck1vZHVsZVwiIGlzIHJlZmVyZW5jZWQgd2l0aGluIGFuIGFycmF5IGxpdGVyYWwsIHdlIGNhblxuICAgICAgLy8gcmVtb3ZlIHRoZSBlbGVtZW50IGVhc2lseS4gT3RoZXJ3aXNlIGlmIGl0J3Mgb3V0c2lkZSBvZiBhbiBhcnJheSBsaXRlcmFsLFxuICAgICAgLy8gd2UgbmVlZCB0byByZXBsYWNlIHRoZSByZWZlcmVuY2Ugd2l0aCBhbiBlbXB0eSBvYmplY3QgbGl0ZXJhbCB3LyB0b2RvIHRvXG4gICAgICAvLyBub3QgYnJlYWsgdGhlIGFwcGxpY2F0aW9uLlxuICAgICAgaWYgKHRzLmlzQXJyYXlMaXRlcmFsRXhwcmVzc2lvbihub2RlLnBhcmVudCkpIHtcbiAgICAgICAgLy8gUmVtb3ZlcyB0aGUgXCJIYW1tZXJNb2R1bGVcIiBmcm9tIHRoZSBwYXJlbnQgYXJyYXkgZXhwcmVzc2lvbi4gUmVtb3Zlc1xuICAgICAgICAvLyB0aGUgdHJhaWxpbmcgY29tbWEgdG9rZW4gaWYgcHJlc2VudC5cbiAgICAgICAgcmVtb3ZlRWxlbWVudEZyb21BcnJheUV4cHJlc3Npb24obm9kZSwgcmVjb3JkZXIpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVjb3JkZXIucmVtb3ZlKG5vZGUuZ2V0U3RhcnQoKSwgbm9kZS5nZXRXaWR0aCgpKTtcbiAgICAgICAgcmVjb3JkZXIuaW5zZXJ0UmlnaHQobm9kZS5nZXRTdGFydCgpLCBgLyogVE9ETzogcmVtb3ZlICovIHt9YCk7XG4gICAgICAgIHRoaXMuX25vZGVGYWlsdXJlcy5wdXNoKHtcbiAgICAgICAgICBub2RlOiBub2RlLFxuICAgICAgICAgIG1lc3NhZ2U6ICdVbmFibGUgdG8gZGVsZXRlIHJlZmVyZW5jZSB0byBcIkhhbW1lck1vZHVsZVwiLicsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gbm9kZSBpcyBhIHJlZmVyZW5jZSB0byB0aGUgaGFtbWVyIGdlc3R1cmUgY29uZmlnXG4gICAqIHRva2VuIGZyb20gcGxhdGZvcm0tYnJvd3Nlci4gSWYgc28sIGtlZXBzIHRyYWNrIG9mIHRoZSByZWZlcmVuY2UuXG4gICAqL1xuICBwcml2YXRlIF9jaGVja0ZvckhhbW1lckdlc3R1cmVDb25maWdUb2tlbihub2RlOiB0cy5Ob2RlKSB7XG4gICAgaWYgKHRzLmlzSWRlbnRpZmllcihub2RlKSkge1xuICAgICAgY29uc3QgaW1wb3J0RGF0YSA9IGdldEltcG9ydE9mSWRlbnRpZmllcihub2RlLCB0aGlzLnR5cGVDaGVja2VyKTtcbiAgICAgIGlmIChpbXBvcnREYXRhICYmIGltcG9ydERhdGEuc3ltYm9sTmFtZSA9PT0gSEFNTUVSX0NPTkZJR19UT0tFTl9OQU1FICYmXG4gICAgICAgICAgaW1wb3J0RGF0YS5tb2R1bGVOYW1lID09PSBIQU1NRVJfQ09ORklHX1RPS0VOX01PRFVMRSkge1xuICAgICAgICB0aGlzLl9oYW1tZXJDb25maWdUb2tlblJlZmVyZW5jZXMucHVzaChcbiAgICAgICAgICAgIHtub2RlLCBpbXBvcnREYXRhLCBpc0ltcG9ydDogdHMuaXNJbXBvcnRTcGVjaWZpZXIobm9kZS5wYXJlbnQpfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gbm9kZSBpcyBhIHJlZmVyZW5jZSB0byB0aGUgSGFtbWVyTW9kdWxlIGZyb21cbiAgICogXCJAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyXCIuIElmIHNvLCBrZWVwcyB0cmFjayBvZiB0aGUgcmVmZXJlbmNlLlxuICAgKi9cbiAgcHJpdmF0ZSBfY2hlY2tGb3JIYW1tZXJNb2R1bGVSZWZlcmVuY2Uobm9kZTogdHMuTm9kZSkge1xuICAgIGlmICh0cy5pc0lkZW50aWZpZXIobm9kZSkpIHtcbiAgICAgIGNvbnN0IGltcG9ydERhdGEgPSBnZXRJbXBvcnRPZklkZW50aWZpZXIobm9kZSwgdGhpcy50eXBlQ2hlY2tlcik7XG4gICAgICBpZiAoaW1wb3J0RGF0YSAmJiBpbXBvcnREYXRhLnN5bWJvbE5hbWUgPT09IEhBTU1FUl9NT0RVTEVfTkFNRSAmJlxuICAgICAgICAgIGltcG9ydERhdGEubW9kdWxlTmFtZSA9PT0gSEFNTUVSX01PRFVMRV9JTVBPUlQpIHtcbiAgICAgICAgdGhpcy5faGFtbWVyTW9kdWxlUmVmZXJlbmNlcy5wdXNoKFxuICAgICAgICAgICAge25vZGUsIGltcG9ydERhdGEsIGlzSW1wb3J0OiB0cy5pc0ltcG9ydFNwZWNpZmllcihub2RlLnBhcmVudCl9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBub2RlIGlzIGFuIGltcG9ydCB0byB0aGUgSGFtbWVySlMgcGFja2FnZS4gSW1wb3J0cyB0b1xuICAgKiBIYW1tZXJKUyB3aGljaCBsb2FkIHNwZWNpZmljIHN5bWJvbHMgZnJvbSB0aGUgcGFja2FnZSBhcmUgY29uc2lkZXJlZCBhc1xuICAgKiBydW50aW1lIHVzYWdlIG9mIEhhbW1lci4gZS5nLiBgaW1wb3J0IHtTeW1ib2x9IGZyb20gXCJoYW1tZXJqc1wiO2AuXG4gICAqL1xuICBwcml2YXRlIF9jaGVja0hhbW1lckltcG9ydHMobm9kZTogdHMuTm9kZSkge1xuICAgIGlmICh0cy5pc0ltcG9ydERlY2xhcmF0aW9uKG5vZGUpICYmIHRzLmlzU3RyaW5nTGl0ZXJhbChub2RlLm1vZHVsZVNwZWNpZmllcikgJiZcbiAgICAgICAgbm9kZS5tb2R1bGVTcGVjaWZpZXIudGV4dCA9PT0gSEFNTUVSX01PRFVMRV9TUEVDSUZJRVIpIHtcbiAgICAgIC8vIElmIHRoZXJlIGlzIGFuIGltcG9ydCB0byBIYW1tZXJKUyB0aGF0IGltcG9ydHMgc3ltYm9scywgb3IgaXMgbmFtZXNwYWNlZFxuICAgICAgLy8gKGUuZy4gXCJpbXBvcnQge0EsIEJ9IGZyb20gLi4uXCIgb3IgXCJpbXBvcnQgKiBhcyBoYW1tZXIgZnJvbSAuLi5cIiksIHRoZW4gd2VcbiAgICAgIC8vIGFzc3VtZSB0aGF0IHNvbWUgZXhwb3J0cyBhcmUgdXNlZCBhdCBydW50aW1lLlxuICAgICAgaWYgKG5vZGUuaW1wb3J0Q2xhdXNlICYmXG4gICAgICAgICAgIShub2RlLmltcG9ydENsYXVzZS5uYW1lZEJpbmRpbmdzICYmIHRzLmlzTmFtZWRJbXBvcnRzKG5vZGUuaW1wb3J0Q2xhdXNlLm5hbWVkQmluZGluZ3MpICYmXG4gICAgICAgICAgICBub2RlLmltcG9ydENsYXVzZS5uYW1lZEJpbmRpbmdzLmVsZW1lbnRzLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgICAgdGhpcy5fdXNlZEluUnVudGltZSA9IHRydWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLl9pbnN0YWxsSW1wb3J0cy5wdXNoKG5vZGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhlIGdpdmVuIG5vZGUgYWNjZXNzZXMgdGhlIGdsb2JhbCBcIkhhbW1lclwiIHN5bWJvbCBhdCBydW50aW1lLiBJZiBzbyxcbiAgICogdGhlIG1pZ3JhdGlvbiBydWxlIHN0YXRlIHdpbGwgYmUgdXBkYXRlZCB0byByZWZsZWN0IHRoYXQgSGFtbWVyIGlzIHVzZWQgYXQgcnVudGltZS5cbiAgICovXG4gIHByaXZhdGUgX2NoZWNrRm9yUnVudGltZUhhbW1lclVzYWdlKG5vZGU6IHRzLk5vZGUpIHtcbiAgICBpZiAodGhpcy5fdXNlZEluUnVudGltZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIERldGVjdHMgdXNhZ2VzIG9mIFwid2luZG93LkhhbW1lclwiLlxuICAgIGlmICh0cy5pc1Byb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihub2RlKSAmJiBub2RlLm5hbWUudGV4dCA9PT0gJ0hhbW1lcicpIHtcbiAgICAgIGNvbnN0IG9yaWdpbkV4cHIgPSB1bndyYXBFeHByZXNzaW9uKG5vZGUuZXhwcmVzc2lvbik7XG4gICAgICBpZiAodHMuaXNJZGVudGlmaWVyKG9yaWdpbkV4cHIpICYmIG9yaWdpbkV4cHIudGV4dCA9PT0gJ3dpbmRvdycpIHtcbiAgICAgICAgdGhpcy5fdXNlZEluUnVudGltZSA9IHRydWU7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gRGV0ZWN0cyB1c2FnZXMgb2YgXCJ3aW5kb3dbJ0hhbW1lciddXCIuXG4gICAgaWYgKHRzLmlzRWxlbWVudEFjY2Vzc0V4cHJlc3Npb24obm9kZSkgJiYgdHMuaXNTdHJpbmdMaXRlcmFsKG5vZGUuYXJndW1lbnRFeHByZXNzaW9uKSAmJlxuICAgICAgICBub2RlLmFyZ3VtZW50RXhwcmVzc2lvbi50ZXh0ID09PSAnSGFtbWVyJykge1xuICAgICAgY29uc3Qgb3JpZ2luRXhwciA9IHVud3JhcEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uKTtcbiAgICAgIGlmICh0cy5pc0lkZW50aWZpZXIob3JpZ2luRXhwcikgJiYgb3JpZ2luRXhwci50ZXh0ID09PSAnd2luZG93Jykge1xuICAgICAgICB0aGlzLl91c2VkSW5SdW50aW1lID0gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBIYW5kbGVzIHVzYWdlcyBvZiBwbGFpbiBpZGVudGlmaWVyIHdpdGggdGhlIG5hbWUgXCJIYW1tZXJcIi4gVGhlc2UgdXNhZ2VcbiAgICAvLyBhcmUgdmFsaWQgaWYgdGhleSByZXNvbHZlIHRvIFwiQHR5cGVzL2hhbW1lcmpzXCIuIGUuZy4gXCJuZXcgSGFtbWVyKG15RWxlbWVudClcIi5cbiAgICBpZiAodHMuaXNJZGVudGlmaWVyKG5vZGUpICYmIG5vZGUudGV4dCA9PT0gJ0hhbW1lcicgJiZcbiAgICAgICAgIXRzLmlzUHJvcGVydHlBY2Nlc3NFeHByZXNzaW9uKG5vZGUucGFyZW50KSAmJiAhdHMuaXNFbGVtZW50QWNjZXNzRXhwcmVzc2lvbihub2RlLnBhcmVudCkpIHtcbiAgICAgIGNvbnN0IHN5bWJvbCA9IHRoaXMuX2dldERlY2xhcmF0aW9uU3ltYm9sT2ZOb2RlKG5vZGUpO1xuICAgICAgaWYgKHN5bWJvbCAmJiBzeW1ib2wudmFsdWVEZWNsYXJhdGlvbiAmJlxuICAgICAgICAgIHN5bWJvbC52YWx1ZURlY2xhcmF0aW9uLmdldFNvdXJjZUZpbGUoKS5maWxlTmFtZS5pbmNsdWRlcygnQHR5cGVzL2hhbW1lcmpzJykpIHtcbiAgICAgICAgdGhpcy5fdXNlZEluUnVudGltZSA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gbm9kZSByZWZlcmVuY2VzIHRoZSBnZXN0dXJlIGNvbmZpZyBmcm9tIEFuZ3VsYXIgTWF0ZXJpYWwuXG4gICAqIElmIHNvLCB3ZSBrZWVwIHRyYWNrIG9mIHRoZSBmb3VuZCBzeW1ib2wgcmVmZXJlbmNlLlxuICAgKi9cbiAgcHJpdmF0ZSBfY2hlY2tGb3JNYXRlcmlhbEdlc3R1cmVDb25maWcobm9kZTogdHMuTm9kZSkge1xuICAgIGlmICh0cy5pc0lkZW50aWZpZXIobm9kZSkpIHtcbiAgICAgIGNvbnN0IGltcG9ydERhdGEgPSBnZXRJbXBvcnRPZklkZW50aWZpZXIobm9kZSwgdGhpcy50eXBlQ2hlY2tlcik7XG4gICAgICBpZiAoaW1wb3J0RGF0YSAmJiBpbXBvcnREYXRhLnN5bWJvbE5hbWUgPT09IEdFU1RVUkVfQ09ORklHX0NMQVNTX05BTUUgJiZcbiAgICAgICAgICBpbXBvcnREYXRhLm1vZHVsZU5hbWUuc3RhcnRzV2l0aCgnQGFuZ3VsYXIvbWF0ZXJpYWwvJykpIHtcbiAgICAgICAgdGhpcy5fZ2VzdHVyZUNvbmZpZ1JlZmVyZW5jZXMucHVzaChcbiAgICAgICAgICAgIHtub2RlLCBpbXBvcnREYXRhLCBpc0ltcG9ydDogdHMuaXNJbXBvcnRTcGVjaWZpZXIobm9kZS5wYXJlbnQpfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gSGFtbWVyIGdlc3R1cmUgY29uZmlnIHRva2VuIHJlZmVyZW5jZSBpcyBwYXJ0IG9mIGFuXG4gICAqIEFuZ3VsYXIgcHJvdmlkZXIgZGVmaW5pdGlvbiB0aGF0IHNldHMgdXAgYSBjdXN0b20gZ2VzdHVyZSBjb25maWcuXG4gICAqL1xuICBwcml2YXRlIF9jaGVja0ZvckN1c3RvbUdlc3R1cmVDb25maWdTZXR1cCh0b2tlblJlZjogSWRlbnRpZmllclJlZmVyZW5jZSk6IGJvb2xlYW4ge1xuICAgIC8vIFdhbGsgdXAgdGhlIHRyZWUgdG8gbG9vayBmb3IgYSBwYXJlbnQgcHJvcGVydHkgYXNzaWdubWVudCBvZiB0aGVcbiAgICAvLyByZWZlcmVuY2UgdG8gdGhlIGhhbW1lciBnZXN0dXJlIGNvbmZpZyB0b2tlbi5cbiAgICBsZXQgcHJvcGVydHlBc3NpZ25tZW50OiB0cy5Ob2RlID0gdG9rZW5SZWYubm9kZTtcbiAgICB3aGlsZSAocHJvcGVydHlBc3NpZ25tZW50ICYmICF0cy5pc1Byb3BlcnR5QXNzaWdubWVudChwcm9wZXJ0eUFzc2lnbm1lbnQpKSB7XG4gICAgICBwcm9wZXJ0eUFzc2lnbm1lbnQgPSBwcm9wZXJ0eUFzc2lnbm1lbnQucGFyZW50O1xuICAgIH1cblxuICAgIGlmICghcHJvcGVydHlBc3NpZ25tZW50IHx8ICF0cy5pc1Byb3BlcnR5QXNzaWdubWVudChwcm9wZXJ0eUFzc2lnbm1lbnQpIHx8XG4gICAgICAgIGdldFByb3BlcnR5TmFtZVRleHQocHJvcGVydHlBc3NpZ25tZW50Lm5hbWUpICE9PSAncHJvdmlkZScpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBvYmplY3RMaXRlcmFsRXhwciA9IHByb3BlcnR5QXNzaWdubWVudC5wYXJlbnQ7XG4gICAgY29uc3QgbWF0Y2hpbmdJZGVudGlmaWVycyA9IGZpbmRNYXRjaGluZ0NoaWxkTm9kZXMob2JqZWN0TGl0ZXJhbEV4cHIsIHRzLmlzSWRlbnRpZmllcik7XG5cbiAgICAvLyBXZSBuYWl2ZWx5IGFzc3VtZSB0aGF0IGlmIHRoZXJlIGlzIGEgcmVmZXJlbmNlIHRvIHRoZSBcIkdlc3R1cmVDb25maWdcIiBleHBvcnRcbiAgICAvLyBmcm9tIEFuZ3VsYXIgTWF0ZXJpYWwgaW4gdGhlIHByb3ZpZGVyIGxpdGVyYWwsIHRoYXQgdGhlIHByb3ZpZGVyIHNldHMgdXAgdGhlXG4gICAgLy8gQW5ndWxhciBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZy5cbiAgICByZXR1cm4gIXRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLnNvbWUociA9PiBtYXRjaGluZ0lkZW50aWZpZXJzLmluY2x1ZGVzKHIubm9kZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgYW4gYXZhaWxhYmxlIGZpbGUgbmFtZSBmb3IgdGhlIGdlc3R1cmUgY29uZmlnIHdoaWNoIHNob3VsZFxuICAgKiBiZSBzdG9yZWQgaW4gdGhlIHNwZWNpZmllZCBmaWxlIHBhdGguXG4gICAqL1xuICBwcml2YXRlIF9nZXRBdmFpbGFibGVHZXN0dXJlQ29uZmlnRmlsZU5hbWUoc291cmNlUm9vdDogUGF0aCkge1xuICAgIGlmICghdGhpcy5maWxlU3lzdGVtLmV4aXN0cyhqb2luKHNvdXJjZVJvb3QsIGAke0dFU1RVUkVfQ09ORklHX0ZJTEVfTkFNRX0udHNgKSkpIHtcbiAgICAgIHJldHVybiBgJHtHRVNUVVJFX0NPTkZJR19GSUxFX05BTUV9LnRzYDtcbiAgICB9XG5cbiAgICBsZXQgcG9zc2libGVOYW1lID0gYCR7R0VTVFVSRV9DT05GSUdfRklMRV9OQU1FfS1gO1xuICAgIGxldCBpbmRleCA9IDE7XG4gICAgd2hpbGUgKHRoaXMuZmlsZVN5c3RlbS5leGlzdHMoam9pbihzb3VyY2VSb290LCBgJHtwb3NzaWJsZU5hbWV9LSR7aW5kZXh9LnRzYCkpKSB7XG4gICAgICBpbmRleCsrO1xuICAgIH1cbiAgICByZXR1cm4gYCR7cG9zc2libGVOYW1lICsgaW5kZXh9LnRzYDtcbiAgfVxuXG4gIC8qKiBSZXBsYWNlcyBhIGdpdmVuIGdlc3R1cmUgY29uZmlnIHJlZmVyZW5jZSB3aXRoIGEgbmV3IGltcG9ydC4gKi9cbiAgcHJpdmF0ZSBfcmVwbGFjZUdlc3R1cmVDb25maWdSZWZlcmVuY2UoXG4gICAgICB7bm9kZSwgaW1wb3J0RGF0YSwgaXNJbXBvcnR9OiBJZGVudGlmaWVyUmVmZXJlbmNlLCBzeW1ib2xOYW1lOiBzdHJpbmcsXG4gICAgICBtb2R1bGVTcGVjaWZpZXI6IHN0cmluZykge1xuICAgIGNvbnN0IHNvdXJjZUZpbGUgPSBub2RlLmdldFNvdXJjZUZpbGUoKTtcbiAgICBjb25zdCByZWNvcmRlciA9IHRoaXMuZmlsZVN5c3RlbS5lZGl0KHRoaXMuZmlsZVN5c3RlbS5yZXNvbHZlKHNvdXJjZUZpbGUuZmlsZU5hbWUpKTtcblxuICAgIC8vIExpc3Qgb2YgYWxsIGlkZW50aWZpZXJzIHJlZmVycmluZyB0byB0aGUgZ2VzdHVyZSBjb25maWcgaW4gdGhlIGN1cnJlbnQgZmlsZS4gVGhpc1xuICAgIC8vIGFsbG93cyB1cyB0byBhZGQgYW4gaW1wb3J0IGZvciB0aGUgY29waWVkIGdlc3R1cmUgY29uZmlndXJhdGlvbiB3aXRob3V0IGdlbmVyYXRpbmcgYVxuICAgIC8vIG5ldyBpZGVudGlmaWVyIGZvciB0aGUgaW1wb3J0IHRvIGF2b2lkIGNvbGxpc2lvbnMuIGkuZS4gXCJHZXN0dXJlQ29uZmlnXzFcIi4gVGhlIGltcG9ydFxuICAgIC8vIG1hbmFnZXIgY2hlY2tzIGZvciBwb3NzaWJsZSBuYW1lIGNvbGxpc2lvbnMsIGJ1dCBpcyBhYmxlIHRvIGlnbm9yZSBzcGVjaWZpYyBpZGVudGlmaWVycy5cbiAgICAvLyBXZSB1c2UgdGhpcyB0byBpZ25vcmUgYWxsIHJlZmVyZW5jZXMgdG8gdGhlIG9yaWdpbmFsIEFuZ3VsYXIgTWF0ZXJpYWwgZ2VzdHVyZSBjb25maWcsXG4gICAgLy8gYmVjYXVzZSB0aGVzZSB3aWxsIGJlIHJlcGxhY2VkIGFuZCB0aGVyZWZvcmUgd2lsbCBub3QgaW50ZXJmZXJlLlxuICAgIGNvbnN0IGdlc3R1cmVJZGVudGlmaWVyc0luRmlsZSA9IHRoaXMuX2dldEdlc3R1cmVDb25maWdJZGVudGlmaWVyc09mRmlsZShzb3VyY2VGaWxlKTtcblxuICAgIC8vIElmIHRoZSBwYXJlbnQgb2YgdGhlIGlkZW50aWZpZXIgaXMgYWNjZXNzZWQgdGhyb3VnaCBhIG5hbWVzcGFjZSwgd2UgY2FuIGp1c3RcbiAgICAvLyBpbXBvcnQgdGhlIG5ldyBnZXN0dXJlIGNvbmZpZyB3aXRob3V0IHJld3JpdGluZyB0aGUgaW1wb3J0IGRlY2xhcmF0aW9uIGJlY2F1c2VcbiAgICAvLyB0aGUgY29uZmlnIGhhcyBiZWVuIGltcG9ydGVkIHRocm91Z2ggYSBuYW1lc3BhY2VkIGltcG9ydC5cbiAgICBpZiAoaXNOYW1lc3BhY2VkSWRlbnRpZmllckFjY2Vzcyhub2RlKSkge1xuICAgICAgY29uc3QgbmV3RXhwcmVzc2lvbiA9IHRoaXMuX2ltcG9ydE1hbmFnZXIuYWRkSW1wb3J0VG9Tb3VyY2VGaWxlKFxuICAgICAgICAgIHNvdXJjZUZpbGUsIHN5bWJvbE5hbWUsIG1vZHVsZVNwZWNpZmllciwgZmFsc2UsIGdlc3R1cmVJZGVudGlmaWVyc0luRmlsZSk7XG5cbiAgICAgIHJlY29yZGVyLnJlbW92ZShub2RlLnBhcmVudC5nZXRTdGFydCgpLCBub2RlLnBhcmVudC5nZXRXaWR0aCgpKTtcbiAgICAgIHJlY29yZGVyLmluc2VydFJpZ2h0KG5vZGUucGFyZW50LmdldFN0YXJ0KCksIHRoaXMuX3ByaW50Tm9kZShuZXdFeHByZXNzaW9uLCBzb3VyY2VGaWxlKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gRGVsZXRlIHRoZSBvbGQgaW1wb3J0IHRvIHRoZSBcIkdlc3R1cmVDb25maWdcIi5cbiAgICB0aGlzLl9pbXBvcnRNYW5hZ2VyLmRlbGV0ZU5hbWVkQmluZGluZ0ltcG9ydChcbiAgICAgICAgc291cmNlRmlsZSwgR0VTVFVSRV9DT05GSUdfQ0xBU1NfTkFNRSwgaW1wb3J0RGF0YS5tb2R1bGVOYW1lKTtcblxuICAgIC8vIElmIHRoZSBjdXJyZW50IHJlZmVyZW5jZSBpcyBub3QgZnJvbSBpbnNpZGUgb2YgYSBpbXBvcnQsIHdlIG5lZWQgdG8gYWRkIGEgbmV3XG4gICAgLy8gaW1wb3J0IHRvIHRoZSBjb3BpZWQgZ2VzdHVyZSBjb25maWcgYW5kIHJlcGxhY2UgdGhlIGlkZW50aWZpZXIuIEZvciByZWZlcmVuY2VzXG4gICAgLy8gd2l0aGluIGFuIGltcG9ydCwgd2UgZG8gbm90aGluZyBidXQgcmVtb3ZpbmcgdGhlIGFjdHVhbCBpbXBvcnQuIFRoaXMgYWxsb3dzIHVzXG4gICAgLy8gdG8gcmVtb3ZlIHVudXNlZCBpbXBvcnRzIHRvIHRoZSBNYXRlcmlhbCBnZXN0dXJlIGNvbmZpZy5cbiAgICBpZiAoIWlzSW1wb3J0KSB7XG4gICAgICBjb25zdCBuZXdFeHByZXNzaW9uID0gdGhpcy5faW1wb3J0TWFuYWdlci5hZGRJbXBvcnRUb1NvdXJjZUZpbGUoXG4gICAgICAgICAgc291cmNlRmlsZSwgc3ltYm9sTmFtZSwgbW9kdWxlU3BlY2lmaWVyLCBmYWxzZSwgZ2VzdHVyZUlkZW50aWZpZXJzSW5GaWxlKTtcblxuICAgICAgcmVjb3JkZXIucmVtb3ZlKG5vZGUuZ2V0U3RhcnQoKSwgbm9kZS5nZXRXaWR0aCgpKTtcbiAgICAgIHJlY29yZGVyLmluc2VydFJpZ2h0KG5vZGUuZ2V0U3RhcnQoKSwgdGhpcy5fcHJpbnROb2RlKG5ld0V4cHJlc3Npb24sIHNvdXJjZUZpbGUpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIGdpdmVuIGdlc3R1cmUgY29uZmlnIHJlZmVyZW5jZSBhbmQgaXRzIGNvcnJlc3BvbmRpbmcgaW1wb3J0IGZyb21cbiAgICogaXRzIGNvbnRhaW5pbmcgc291cmNlIGZpbGUuIEltcG9ydHMgd2lsbCBiZSBhbHdheXMgcmVtb3ZlZCwgYnV0IGluIHNvbWUgY2FzZXMsXG4gICAqIHdoZXJlIGl0J3Mgbm90IGd1YXJhbnRlZWQgdGhhdCBhIHJlbW92YWwgY2FuIGJlIHBlcmZvcm1lZCBzYWZlbHksIHdlIGp1c3RcbiAgICogY3JlYXRlIGEgbWlncmF0aW9uIGZhaWx1cmUgKGFuZCBhZGQgYSBUT0RPIGlmIHBvc3NpYmxlKS5cbiAgICovXG4gIHByaXZhdGUgX3JlbW92ZUdlc3R1cmVDb25maWdSZWZlcmVuY2Uoe25vZGUsIGltcG9ydERhdGEsIGlzSW1wb3J0fTogSWRlbnRpZmllclJlZmVyZW5jZSkge1xuICAgIGNvbnN0IHNvdXJjZUZpbGUgPSBub2RlLmdldFNvdXJjZUZpbGUoKTtcbiAgICBjb25zdCByZWNvcmRlciA9IHRoaXMuZmlsZVN5c3RlbS5lZGl0KHRoaXMuZmlsZVN5c3RlbS5yZXNvbHZlKHNvdXJjZUZpbGUuZmlsZU5hbWUpKTtcbiAgICAvLyBPbmx5IHJlbW92ZSB0aGUgaW1wb3J0IGZvciB0aGUgZ2VzdHVyZSBjb25maWcgaWYgdGhlIGdlc3R1cmUgY29uZmlnIGhhc1xuICAgIC8vIGJlZW4gYWNjZXNzZWQgdGhyb3VnaCBhIG5vbi1uYW1lc3BhY2VkIGlkZW50aWZpZXIgYWNjZXNzLlxuICAgIGlmICghaXNOYW1lc3BhY2VkSWRlbnRpZmllckFjY2Vzcyhub2RlKSkge1xuICAgICAgdGhpcy5faW1wb3J0TWFuYWdlci5kZWxldGVOYW1lZEJpbmRpbmdJbXBvcnQoXG4gICAgICAgICAgc291cmNlRmlsZSwgR0VTVFVSRV9DT05GSUdfQ0xBU1NfTkFNRSwgaW1wb3J0RGF0YS5tb2R1bGVOYW1lKTtcbiAgICB9XG5cbiAgICAvLyBGb3IgcmVmZXJlbmNlcyBmcm9tIHdpdGhpbiBhbiBpbXBvcnQsIHdlIGRvIG5vdCBuZWVkIHRvIGRvIGFueXRoaW5nIG90aGVyIHRoYW5cbiAgICAvLyByZW1vdmluZyB0aGUgaW1wb3J0LiBGb3Igb3RoZXIgcmVmZXJlbmNlcywgd2UgcmVtb3ZlIHRoZSBpbXBvcnQgYW5kIHRoZSByZWZlcmVuY2VcbiAgICAvLyBpZGVudGlmaWVyIGlmIHVzZWQgaW5zaWRlIG9mIGEgcHJvdmlkZXIgZGVmaW5pdGlvbi5cbiAgICBpZiAoaXNJbXBvcnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwcm92aWRlckFzc2lnbm1lbnQgPSBub2RlLnBhcmVudDtcblxuICAgIC8vIE9ubHkgcmVtb3ZlIHJlZmVyZW5jZXMgdG8gdGhlIGdlc3R1cmUgY29uZmlnIHdoaWNoIGFyZSBwYXJ0IG9mIGEgc3RhdGljYWxseVxuICAgIC8vIGFuYWx5emFibGUgcHJvdmlkZXIgZGVmaW5pdGlvbi4gV2Ugb25seSBzdXBwb3J0IHRoZSBjb21tb24gY2FzZSBvZiBhIGdlc3R1cmVcbiAgICAvLyBjb25maWcgcHJvdmlkZXIgZGVmaW5pdGlvbiB3aGVyZSB0aGUgY29uZmlnIGlzIHNldCB1cCB0aHJvdWdoIFwidXNlQ2xhc3NcIi5cbiAgICAvLyBPdGhlcndpc2UsIGl0J3Mgbm90IGd1YXJhbnRlZWQgdGhhdCB3ZSBjYW4gc2FmZWx5IHJlbW92ZSB0aGUgcHJvdmlkZXIgZGVmaW5pdGlvbi5cbiAgICBpZiAoIXRzLmlzUHJvcGVydHlBc3NpZ25tZW50KHByb3ZpZGVyQXNzaWdubWVudCkgfHxcbiAgICAgICAgZ2V0UHJvcGVydHlOYW1lVGV4dChwcm92aWRlckFzc2lnbm1lbnQubmFtZSkgIT09ICd1c2VDbGFzcycpIHtcbiAgICAgIHRoaXMuX25vZGVGYWlsdXJlcy5wdXNoKHtub2RlLCBtZXNzYWdlOiBDQU5OT1RfUkVNT1ZFX1JFRkVSRU5DRV9FUlJPUn0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IG9iamVjdExpdGVyYWxFeHByID0gcHJvdmlkZXJBc3NpZ25tZW50LnBhcmVudDtcbiAgICBjb25zdCBwcm92aWRlVG9rZW4gPSBvYmplY3RMaXRlcmFsRXhwci5wcm9wZXJ0aWVzLmZpbmQoXG4gICAgICAgIChwKTogcCBpcyB0cy5Qcm9wZXJ0eUFzc2lnbm1lbnQgPT5cbiAgICAgICAgICAgIHRzLmlzUHJvcGVydHlBc3NpZ25tZW50KHApICYmIGdldFByb3BlcnR5TmFtZVRleHQocC5uYW1lKSA9PT0gJ3Byb3ZpZGUnKTtcblxuICAgIC8vIERvIG5vdCByZW1vdmUgdGhlIHJlZmVyZW5jZSBpZiB0aGUgZ2VzdHVyZSBjb25maWcgaXMgbm90IHBhcnQgb2YgYSBwcm92aWRlciBkZWZpbml0aW9uLFxuICAgIC8vIG9yIGlmIHRoZSBwcm92aWRlZCB0b2tlIGlzIG5vdCByZWZlcnJpbmcgdG8gdGhlIGtub3duIEhBTU1FUl9HRVNUVVJFX0NPTkZJRyB0b2tlblxuICAgIC8vIGZyb20gcGxhdGZvcm0tYnJvd3Nlci5cbiAgICBpZiAoIXByb3ZpZGVUb2tlbiB8fCAhdGhpcy5faXNSZWZlcmVuY2VUb0hhbW1lckNvbmZpZ1Rva2VuKHByb3ZpZGVUb2tlbi5pbml0aWFsaXplcikpIHtcbiAgICAgIHRoaXMuX25vZGVGYWlsdXJlcy5wdXNoKHtub2RlLCBtZXNzYWdlOiBDQU5OT1RfUkVNT1ZFX1JFRkVSRU5DRV9FUlJPUn0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIENvbGxlY3QgYWxsIG5lc3RlZCBpZGVudGlmaWVycyB3aGljaCB3aWxsIGJlIGRlbGV0ZWQuIFRoaXMgaGVscHMgdXNcbiAgICAvLyBkZXRlcm1pbmluZyBpZiB3ZSBjYW4gcmVtb3ZlIGltcG9ydHMgZm9yIHRoZSBcIkhBTU1FUl9HRVNUVVJFX0NPTkZJR1wiIHRva2VuLlxuICAgIHRoaXMuX2RlbGV0ZWRJZGVudGlmaWVycy5wdXNoKC4uLmZpbmRNYXRjaGluZ0NoaWxkTm9kZXMob2JqZWN0TGl0ZXJhbEV4cHIsIHRzLmlzSWRlbnRpZmllcikpO1xuXG4gICAgLy8gSW4gY2FzZSB0aGUgZm91bmQgcHJvdmlkZXIgZGVmaW5pdGlvbiBpcyBub3QgcGFydCBvZiBhbiBhcnJheSBsaXRlcmFsLFxuICAgIC8vIHdlIGNhbm5vdCBzYWZlbHkgcmVtb3ZlIHRoZSBwcm92aWRlci4gVGhpcyBpcyBiZWNhdXNlIGl0IGNvdWxkIGJlIGRlY2xhcmVkXG4gICAgLy8gYXMgYSB2YXJpYWJsZS4gZS5nLiBcImNvbnN0IGdlc3R1cmVQcm92aWRlciA9IHtwcm92aWRlOiAuLiwgdXNlQ2xhc3M6IEdlc3R1cmVDb25maWd9XCIuXG4gICAgLy8gSW4gdGhhdCBjYXNlLCB3ZSBqdXN0IGFkZCBhbiBlbXB0eSBvYmplY3QgbGl0ZXJhbCB3aXRoIFRPRE8gYW5kIHByaW50IGEgZmFpbHVyZS5cbiAgICBpZiAoIXRzLmlzQXJyYXlMaXRlcmFsRXhwcmVzc2lvbihvYmplY3RMaXRlcmFsRXhwci5wYXJlbnQpKSB7XG4gICAgICByZWNvcmRlci5yZW1vdmUob2JqZWN0TGl0ZXJhbEV4cHIuZ2V0U3RhcnQoKSwgb2JqZWN0TGl0ZXJhbEV4cHIuZ2V0V2lkdGgoKSk7XG4gICAgICByZWNvcmRlci5pbnNlcnRSaWdodChvYmplY3RMaXRlcmFsRXhwci5nZXRTdGFydCgpLCBgLyogVE9ETzogcmVtb3ZlICovIHt9YCk7XG4gICAgICB0aGlzLl9ub2RlRmFpbHVyZXMucHVzaCh7XG4gICAgICAgIG5vZGU6IG9iamVjdExpdGVyYWxFeHByLFxuICAgICAgICBtZXNzYWdlOiBgVW5hYmxlIHRvIGRlbGV0ZSBwcm92aWRlciBkZWZpbml0aW9uIGZvciBcIkdlc3R1cmVDb25maWdcIiBjb21wbGV0ZWx5LiBgICtcbiAgICAgICAgICAgIGBQbGVhc2UgY2xlYW4gdXAgdGhlIHByb3ZpZGVyLmBcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFJlbW92ZXMgdGhlIG9iamVjdCBsaXRlcmFsIGZyb20gdGhlIHBhcmVudCBhcnJheSBleHByZXNzaW9uLiBSZW1vdmVzXG4gICAgLy8gdGhlIHRyYWlsaW5nIGNvbW1hIHRva2VuIGlmIHByZXNlbnQuXG4gICAgcmVtb3ZlRWxlbWVudEZyb21BcnJheUV4cHJlc3Npb24ob2JqZWN0TGl0ZXJhbEV4cHIsIHJlY29yZGVyKTtcbiAgfVxuXG4gIC8qKiBSZW1vdmVzIHRoZSBnaXZlbiBoYW1tZXIgY29uZmlnIHRva2VuIGltcG9ydCBpZiBpdCBpcyBub3QgdXNlZC4gKi9cbiAgcHJpdmF0ZSBfcmVtb3ZlSGFtbWVyQ29uZmlnVG9rZW5JbXBvcnRJZlVudXNlZCh7bm9kZSwgaW1wb3J0RGF0YX06IElkZW50aWZpZXJSZWZlcmVuY2UpIHtcbiAgICBjb25zdCBzb3VyY2VGaWxlID0gbm9kZS5nZXRTb3VyY2VGaWxlKCk7XG4gICAgY29uc3QgaXNUb2tlblVzZWQgPSB0aGlzLl9oYW1tZXJDb25maWdUb2tlblJlZmVyZW5jZXMuc29tZShcbiAgICAgICAgciA9PiAhci5pc0ltcG9ydCAmJiAhaXNOYW1lc3BhY2VkSWRlbnRpZmllckFjY2VzcyhyLm5vZGUpICYmXG4gICAgICAgICAgICByLm5vZGUuZ2V0U291cmNlRmlsZSgpID09PSBzb3VyY2VGaWxlICYmICF0aGlzLl9kZWxldGVkSWRlbnRpZmllcnMuaW5jbHVkZXMoci5ub2RlKSk7XG5cbiAgICAvLyBXZSBkb24ndCB3YW50IHRvIHJlbW92ZSB0aGUgaW1wb3J0IGZvciB0aGUgdG9rZW4gaWYgdGhlIHRva2VuIGlzXG4gICAgLy8gc3RpbGwgdXNlZCBzb21ld2hlcmUuXG4gICAgaWYgKCFpc1Rva2VuVXNlZCkge1xuICAgICAgdGhpcy5faW1wb3J0TWFuYWdlci5kZWxldGVOYW1lZEJpbmRpbmdJbXBvcnQoXG4gICAgICAgICAgc291cmNlRmlsZSwgSEFNTUVSX0NPTkZJR19UT0tFTl9OQU1FLCBpbXBvcnREYXRhLm1vZHVsZU5hbWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBSZW1vdmVzIEhhbW1lciBmcm9tIGFsbCBpbmRleCBIVE1MIGZpbGVzIG9mIHRoZSBjdXJyZW50IHByb2plY3QuICovXG4gIHByaXZhdGUgX3JlbW92ZUhhbW1lckZyb21JbmRleEZpbGUoKSB7XG4gICAgY29uc3QgaW5kZXhGaWxlUGF0aHMgPSBnZXRQcm9qZWN0SW5kZXhGaWxlcyh0aGlzLmNvbnRleHQucHJvamVjdCk7XG4gICAgaW5kZXhGaWxlUGF0aHMuZm9yRWFjaChmaWxlUGF0aCA9PiB7XG4gICAgICBpZiAoIXRoaXMuZmlsZVN5c3RlbS5leGlzdHMoZmlsZVBhdGgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaHRtbENvbnRlbnQgPSB0aGlzLmZpbGVTeXN0ZW0ucmVhZChmaWxlUGF0aCkhO1xuICAgICAgY29uc3QgcmVjb3JkZXIgPSB0aGlzLmZpbGVTeXN0ZW0uZWRpdChmaWxlUGF0aCk7XG5cbiAgICAgIGZpbmRIYW1tZXJTY3JpcHRJbXBvcnRFbGVtZW50cyhodG1sQ29udGVudClcbiAgICAgICAgICAuZm9yRWFjaChlbCA9PiByZW1vdmVFbGVtZW50RnJvbUh0bWwoZWwsIHJlY29yZGVyKSk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogU2V0cyB1cCB0aGUgSGFtbWVyIGdlc3R1cmUgY29uZmlnIGluIHRoZSByb290IG1vZHVsZSBpZiBuZWVkZWQuICovXG4gIHByaXZhdGUgX3NldHVwTmV3R2VzdHVyZUNvbmZpZ0luUm9vdE1vZHVsZShnZXN0dXJlQ29uZmlnUGF0aDogUGF0aCkge1xuICAgIGNvbnN0IHtwcm9qZWN0fSA9IHRoaXMuY29udGV4dDtcbiAgICBjb25zdCBtYWluRmlsZVBhdGggPSBnZXRQcm9qZWN0TWFpbkZpbGUocHJvamVjdCk7XG4gICAgY29uc3Qgcm9vdE1vZHVsZVN5bWJvbCA9IHRoaXMuX2dldFJvb3RNb2R1bGVTeW1ib2wobWFpbkZpbGVQYXRoKTtcblxuICAgIGlmIChyb290TW9kdWxlU3ltYm9sID09PSBudWxsKSB7XG4gICAgICB0aGlzLmZhaWx1cmVzLnB1c2goe1xuICAgICAgICBmaWxlUGF0aDogbWFpbkZpbGVQYXRoLFxuICAgICAgICBtZXNzYWdlOiBgQ291bGQgbm90IHNldHVwIEhhbW1lciBnZXN0dXJlcyBpbiBtb2R1bGUuIFBsZWFzZSBgICtcbiAgICAgICAgICAgIGBtYW51YWxseSBlbnN1cmUgdGhhdCB0aGUgSGFtbWVyIGdlc3R1cmUgY29uZmlnIGlzIHNldCB1cC5gLFxuICAgICAgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgc291cmNlRmlsZSA9IHJvb3RNb2R1bGVTeW1ib2wudmFsdWVEZWNsYXJhdGlvbi5nZXRTb3VyY2VGaWxlKCk7XG4gICAgY29uc3QgbWV0YWRhdGEgPSBnZXREZWNvcmF0b3JNZXRhZGF0YShzb3VyY2VGaWxlLCAnTmdNb2R1bGUnLCAnQGFuZ3VsYXIvY29yZScpIGFzXG4gICAgICAgIHRzLk9iamVjdExpdGVyYWxFeHByZXNzaW9uW107XG5cbiAgICAvLyBJZiBubyBcIk5nTW9kdWxlXCIgZGVmaW5pdGlvbiBpcyBmb3VuZCBpbnNpZGUgdGhlIHNvdXJjZSBmaWxlLCB3ZSBqdXN0IGRvIG5vdGhpbmcuXG4gICAgaWYgKCFtZXRhZGF0YS5sZW5ndGgpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBmaWxlUGF0aCA9IHRoaXMuZmlsZVN5c3RlbS5yZXNvbHZlKHNvdXJjZUZpbGUuZmlsZU5hbWUpO1xuICAgIGNvbnN0IHJlY29yZGVyID0gdGhpcy5maWxlU3lzdGVtLmVkaXQoZmlsZVBhdGgpO1xuICAgIGNvbnN0IHByb3ZpZGVyc0ZpZWxkID0gZ2V0TWV0YWRhdGFGaWVsZChtZXRhZGF0YVswXSwgJ3Byb3ZpZGVycycpWzBdO1xuICAgIGNvbnN0IHByb3ZpZGVySWRlbnRpZmllcnMgPVxuICAgICAgICBwcm92aWRlcnNGaWVsZCA/IGZpbmRNYXRjaGluZ0NoaWxkTm9kZXMocHJvdmlkZXJzRmllbGQsIHRzLmlzSWRlbnRpZmllcikgOiBudWxsO1xuICAgIGNvbnN0IGdlc3R1cmVDb25maWdFeHByID0gdGhpcy5faW1wb3J0TWFuYWdlci5hZGRJbXBvcnRUb1NvdXJjZUZpbGUoXG4gICAgICAgIHNvdXJjZUZpbGUsIEdFU1RVUkVfQ09ORklHX0NMQVNTX05BTUUsXG4gICAgICAgIGdldE1vZHVsZVNwZWNpZmllcihnZXN0dXJlQ29uZmlnUGF0aCwgZmlsZVBhdGgpLCBmYWxzZSxcbiAgICAgICAgdGhpcy5fZ2V0R2VzdHVyZUNvbmZpZ0lkZW50aWZpZXJzT2ZGaWxlKHNvdXJjZUZpbGUpKTtcbiAgICBjb25zdCBoYW1tZXJDb25maWdUb2tlbkV4cHIgPSB0aGlzLl9pbXBvcnRNYW5hZ2VyLmFkZEltcG9ydFRvU291cmNlRmlsZShcbiAgICAgICAgc291cmNlRmlsZSwgSEFNTUVSX0NPTkZJR19UT0tFTl9OQU1FLCBIQU1NRVJfQ09ORklHX1RPS0VOX01PRFVMRSk7XG4gICAgY29uc3QgbmV3UHJvdmlkZXJOb2RlID0gdHMuY3JlYXRlT2JqZWN0TGl0ZXJhbChbXG4gICAgICB0cy5jcmVhdGVQcm9wZXJ0eUFzc2lnbm1lbnQoJ3Byb3ZpZGUnLCBoYW1tZXJDb25maWdUb2tlbkV4cHIpLFxuICAgICAgdHMuY3JlYXRlUHJvcGVydHlBc3NpZ25tZW50KCd1c2VDbGFzcycsIGdlc3R1cmVDb25maWdFeHByKVxuICAgIF0pO1xuXG4gICAgLy8gSWYgdGhlIHByb3ZpZGVycyBmaWVsZCBleGlzdHMgYW5kIGFscmVhZHkgY29udGFpbnMgcmVmZXJlbmNlcyB0byB0aGUgaGFtbWVyIGdlc3R1cmVcbiAgICAvLyBjb25maWcgdG9rZW4gYW5kIHRoZSBnZXN0dXJlIGNvbmZpZywgd2UgbmFpdmVseSBhc3N1bWUgdGhhdCB0aGUgZ2VzdHVyZSBjb25maWcgaXNcbiAgICAvLyBhbHJlYWR5IHNldCB1cC4gV2Ugb25seSB3YW50IHRvIGFkZCB0aGUgZ2VzdHVyZSBjb25maWcgcHJvdmlkZXIgaWYgaXQgaXMgbm90IHNldCB1cC5cbiAgICBpZiAoIXByb3ZpZGVySWRlbnRpZmllcnMgfHxcbiAgICAgICAgISh0aGlzLl9oYW1tZXJDb25maWdUb2tlblJlZmVyZW5jZXMuc29tZShyID0+IHByb3ZpZGVySWRlbnRpZmllcnMuaW5jbHVkZXMoci5ub2RlKSkgJiZcbiAgICAgICAgICB0aGlzLl9nZXN0dXJlQ29uZmlnUmVmZXJlbmNlcy5zb21lKHIgPT4gcHJvdmlkZXJJZGVudGlmaWVycy5pbmNsdWRlcyhyLm5vZGUpKSkpIHtcbiAgICAgIGNvbnN0IHN5bWJvbE5hbWUgPSB0aGlzLl9wcmludE5vZGUobmV3UHJvdmlkZXJOb2RlLCBzb3VyY2VGaWxlKTtcbiAgICAgIGFkZFN5bWJvbFRvTmdNb2R1bGVNZXRhZGF0YShzb3VyY2VGaWxlLCBzb3VyY2VGaWxlLmZpbGVOYW1lLCAncHJvdmlkZXJzJywgc3ltYm9sTmFtZSwgbnVsbClcbiAgICAgICAgLmZvckVhY2goY2hhbmdlID0+IHtcbiAgICAgICAgICBpZiAoY2hhbmdlIGluc3RhbmNlb2YgSW5zZXJ0Q2hhbmdlKSB7XG4gICAgICAgICAgICByZWNvcmRlci5pbnNlcnRSaWdodChjaGFuZ2UucG9zLCBjaGFuZ2UudG9BZGQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIFR5cGVTY3JpcHQgc3ltYm9sIG9mIHRoZSByb290IG1vZHVsZSBieSBsb29raW5nIGZvciB0aGUgbW9kdWxlXG4gICAqIGJvb3RzdHJhcCBleHByZXNzaW9uIGluIHRoZSBzcGVjaWZpZWQgc291cmNlIGZpbGUuXG4gICAqL1xuICBwcml2YXRlIF9nZXRSb290TW9kdWxlU3ltYm9sKG1haW5GaWxlUGF0aDogUGF0aCk6IHRzLlN5bWJvbHxudWxsIHtcbiAgICBjb25zdCBtYWluRmlsZSA9IHRoaXMucHJvZ3JhbS5nZXRTb3VyY2VGaWxlKG1haW5GaWxlUGF0aCk7XG4gICAgaWYgKCFtYWluRmlsZSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgYXBwTW9kdWxlRXhwciA9IGZpbmRNYWluTW9kdWxlRXhwcmVzc2lvbihtYWluRmlsZSk7XG4gICAgaWYgKCFhcHBNb2R1bGVFeHByKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBhcHBNb2R1bGVTeW1ib2wgPSB0aGlzLl9nZXREZWNsYXJhdGlvblN5bWJvbE9mTm9kZSh1bndyYXBFeHByZXNzaW9uKGFwcE1vZHVsZUV4cHIpKTtcbiAgICBpZiAoIWFwcE1vZHVsZVN5bWJvbCB8fCAhYXBwTW9kdWxlU3ltYm9sLnZhbHVlRGVjbGFyYXRpb24pIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gYXBwTW9kdWxlU3ltYm9sO1xuICB9XG5cbiAgLyoqIFNldHMgdXAgdGhlIFwiSGFtbWVyTW9kdWxlXCIgaW4gdGhlIHJvb3QgbW9kdWxlIG9mIHRoZSBjdXJyZW50IHByb2plY3QuICovXG4gIHByaXZhdGUgX3NldHVwSGFtbWVyTW9kdWxlSW5Sb290TW9kdWxlKCkge1xuICAgIGNvbnN0IHtwcm9qZWN0fSA9IHRoaXMuY29udGV4dDtcbiAgICBjb25zdCBtYWluRmlsZVBhdGggPSBnZXRQcm9qZWN0TWFpbkZpbGUocHJvamVjdCk7XG4gICAgY29uc3Qgcm9vdE1vZHVsZVN5bWJvbCA9IHRoaXMuX2dldFJvb3RNb2R1bGVTeW1ib2wobWFpbkZpbGVQYXRoKTtcblxuICAgIGlmIChyb290TW9kdWxlU3ltYm9sID09PSBudWxsKSB7XG4gICAgICB0aGlzLmZhaWx1cmVzLnB1c2goe1xuICAgICAgICBmaWxlUGF0aDogbWFpbkZpbGVQYXRoLFxuICAgICAgICBtZXNzYWdlOiBgQ291bGQgbm90IHNldHVwIEhhbW1lck1vZHVsZS4gUGxlYXNlIG1hbnVhbGx5IHNldCB1cCB0aGUgXCJIYW1tZXJNb2R1bGVcIiBgICtcbiAgICAgICAgICAgIGBmcm9tIFwiQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3NlclwiLmAsXG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzb3VyY2VGaWxlID0gcm9vdE1vZHVsZVN5bWJvbC52YWx1ZURlY2xhcmF0aW9uLmdldFNvdXJjZUZpbGUoKTtcbiAgICBjb25zdCBtZXRhZGF0YSA9IGdldERlY29yYXRvck1ldGFkYXRhKHNvdXJjZUZpbGUsICdOZ01vZHVsZScsICdAYW5ndWxhci9jb3JlJykgYXNcbiAgICAgICAgdHMuT2JqZWN0TGl0ZXJhbEV4cHJlc3Npb25bXTtcbiAgICBpZiAoIW1ldGFkYXRhLmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGltcG9ydHNGaWVsZCA9IGdldE1ldGFkYXRhRmllbGQobWV0YWRhdGFbMF0sICdpbXBvcnRzJylbMF07XG4gICAgY29uc3QgaW1wb3J0SWRlbnRpZmllcnMgPVxuICAgICAgICBpbXBvcnRzRmllbGQgPyBmaW5kTWF0Y2hpbmdDaGlsZE5vZGVzKGltcG9ydHNGaWVsZCwgdHMuaXNJZGVudGlmaWVyKSA6IG51bGw7XG4gICAgY29uc3QgcmVjb3JkZXIgPSB0aGlzLmZpbGVTeXN0ZW0uZWRpdCh0aGlzLmZpbGVTeXN0ZW0ucmVzb2x2ZShzb3VyY2VGaWxlLmZpbGVOYW1lKSk7XG4gICAgY29uc3QgaGFtbWVyTW9kdWxlRXhwciA9IHRoaXMuX2ltcG9ydE1hbmFnZXIuYWRkSW1wb3J0VG9Tb3VyY2VGaWxlKFxuICAgICAgICBzb3VyY2VGaWxlLCBIQU1NRVJfTU9EVUxFX05BTUUsIEhBTU1FUl9NT0RVTEVfSU1QT1JUKTtcblxuICAgIC8vIElmIHRoZSBcIkhhbW1lck1vZHVsZVwiIGlzIG5vdCBhbHJlYWR5IGltcG9ydGVkIGluIHRoZSBhcHAgbW9kdWxlLCB3ZSBzZXQgaXQgdXBcbiAgICAvLyBieSBhZGRpbmcgaXQgdG8gdGhlIFwiaW1wb3J0c1wiIGZpZWxkIG9mIHRoZSBhcHAgbW9kdWxlLlxuICAgIGlmICghaW1wb3J0SWRlbnRpZmllcnMgfHxcbiAgICAgICAgIXRoaXMuX2hhbW1lck1vZHVsZVJlZmVyZW5jZXMuc29tZShyID0+IGltcG9ydElkZW50aWZpZXJzLmluY2x1ZGVzKHIubm9kZSkpKSB7XG4gICAgICBjb25zdCBzeW1ib2xOYW1lID0gdGhpcy5fcHJpbnROb2RlKGhhbW1lck1vZHVsZUV4cHIsIHNvdXJjZUZpbGUpO1xuICAgICAgYWRkU3ltYm9sVG9OZ01vZHVsZU1ldGFkYXRhKHNvdXJjZUZpbGUsIHNvdXJjZUZpbGUuZmlsZU5hbWUsICdpbXBvcnRzJywgc3ltYm9sTmFtZSwgbnVsbClcbiAgICAgICAgLmZvckVhY2goY2hhbmdlID0+IHtcbiAgICAgICAgICBpZiAoY2hhbmdlIGluc3RhbmNlb2YgSW5zZXJ0Q2hhbmdlKSB7XG4gICAgICAgICAgICByZWNvcmRlci5pbnNlcnRSaWdodChjaGFuZ2UucG9zLCBjaGFuZ2UudG9BZGQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFByaW50cyBhIGdpdmVuIG5vZGUgd2l0aGluIHRoZSBzcGVjaWZpZWQgc291cmNlIGZpbGUuICovXG4gIHByaXZhdGUgX3ByaW50Tm9kZShub2RlOiB0cy5Ob2RlLCBzb3VyY2VGaWxlOiB0cy5Tb3VyY2VGaWxlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fcHJpbnRlci5wcmludE5vZGUodHMuRW1pdEhpbnQuVW5zcGVjaWZpZWQsIG5vZGUsIHNvdXJjZUZpbGUpO1xuICB9XG5cbiAgLyoqIEdldHMgYWxsIHJlZmVyZW5jZWQgZ2VzdHVyZSBjb25maWcgaWRlbnRpZmllcnMgb2YgYSBnaXZlbiBzb3VyY2UgZmlsZSAqL1xuICBwcml2YXRlIF9nZXRHZXN0dXJlQ29uZmlnSWRlbnRpZmllcnNPZkZpbGUoc291cmNlRmlsZTogdHMuU291cmNlRmlsZSk6IHRzLklkZW50aWZpZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMuX2dlc3R1cmVDb25maWdSZWZlcmVuY2VzLmZpbHRlcihkID0+IGQubm9kZS5nZXRTb3VyY2VGaWxlKCkgPT09IHNvdXJjZUZpbGUpXG4gICAgICAgIC5tYXAoZCA9PiBkLm5vZGUpO1xuICB9XG5cbiAgLyoqIEdldHMgdGhlIHN5bWJvbCB0aGF0IGNvbnRhaW5zIHRoZSB2YWx1ZSBkZWNsYXJhdGlvbiBvZiB0aGUgc3BlY2lmaWVkIG5vZGUuICovXG4gIHByaXZhdGUgX2dldERlY2xhcmF0aW9uU3ltYm9sT2ZOb2RlKG5vZGU6IHRzLk5vZGUpOiB0cy5TeW1ib2x8dW5kZWZpbmVkIHtcbiAgICBjb25zdCBzeW1ib2wgPSB0aGlzLnR5cGVDaGVja2VyLmdldFN5bWJvbEF0TG9jYXRpb24obm9kZSk7XG5cbiAgICAvLyBTeW1ib2xzIGNhbiBiZSBhbGlhc2VzIG9mIHRoZSBkZWNsYXJhdGlvbiBzeW1ib2wuIGUuZy4gaW4gbmFtZWQgaW1wb3J0IHNwZWNpZmllcnMuXG4gICAgLy8gV2UgbmVlZCB0byByZXNvbHZlIHRoZSBhbGlhc2VkIHN5bWJvbCBiYWNrIHRvIHRoZSBkZWNsYXJhdGlvbiBzeW1ib2wuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcbiAgICBpZiAoc3ltYm9sICYmIChzeW1ib2wuZmxhZ3MgJiB0cy5TeW1ib2xGbGFncy5BbGlhcykgIT09IDApIHtcbiAgICAgIHJldHVybiB0aGlzLnR5cGVDaGVja2VyLmdldEFsaWFzZWRTeW1ib2woc3ltYm9sKTtcbiAgICB9XG4gICAgcmV0dXJuIHN5bWJvbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciB0aGUgZ2l2ZW4gZXhwcmVzc2lvbiByZXNvbHZlcyB0byBhIGhhbW1lciBnZXN0dXJlIGNvbmZpZ1xuICAgKiB0b2tlbiByZWZlcmVuY2UgZnJvbSBcIkBhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXJcIi5cbiAgICovXG4gIHByaXZhdGUgX2lzUmVmZXJlbmNlVG9IYW1tZXJDb25maWdUb2tlbihleHByOiB0cy5FeHByZXNzaW9uKSB7XG4gICAgY29uc3QgdW53cmFwcGVkID0gdW53cmFwRXhwcmVzc2lvbihleHByKTtcbiAgICBpZiAodHMuaXNJZGVudGlmaWVyKHVud3JhcHBlZCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW1tZXJDb25maWdUb2tlblJlZmVyZW5jZXMuc29tZShyID0+IHIubm9kZSA9PT0gdW53cmFwcGVkKTtcbiAgICB9IGVsc2UgaWYgKHRzLmlzUHJvcGVydHlBY2Nlc3NFeHByZXNzaW9uKHVud3JhcHBlZCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW1tZXJDb25maWdUb2tlblJlZmVyZW5jZXMuc29tZShyID0+IHIubm9kZSA9PT0gdW53cmFwcGVkLm5hbWUpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBtaWdyYXRpb24gZmFpbHVyZXMgb2YgdGhlIGNvbGxlY3RlZCBub2RlIGZhaWx1cmVzLiBUaGUgcmV0dXJuZWQgbWlncmF0aW9uXG4gICAqIGZhaWx1cmVzIGFyZSB1cGRhdGVkIHRvIHJlZmxlY3QgdGhlIHBvc3QtbWlncmF0aW9uIHN0YXRlIG9mIHNvdXJjZSBmaWxlcy4gTWVhbmluZ1xuICAgKiB0aGF0IGZhaWx1cmUgcG9zaXRpb25zIGFyZSBjb3JyZWN0ZWQgaWYgc291cmNlIGZpbGUgbW9kaWZpY2F0aW9ucyBzaGlmdGVkIGxpbmVzLlxuICAgKi9cbiAgcHJpdmF0ZSBfY3JlYXRlTWlncmF0aW9uRmFpbHVyZXMoKTogTWlncmF0aW9uRmFpbHVyZVtdIHtcbiAgICByZXR1cm4gdGhpcy5fbm9kZUZhaWx1cmVzLm1hcCgoe25vZGUsIG1lc3NhZ2V9KSA9PiB7XG4gICAgICBjb25zdCBzb3VyY2VGaWxlID0gbm9kZS5nZXRTb3VyY2VGaWxlKCk7XG4gICAgICBjb25zdCBvZmZzZXQgPSBub2RlLmdldFN0YXJ0KCk7XG4gICAgICBjb25zdCBwb3NpdGlvbiA9IHRzLmdldExpbmVBbmRDaGFyYWN0ZXJPZlBvc2l0aW9uKHNvdXJjZUZpbGUsIG5vZGUuZ2V0U3RhcnQoKSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBwb3NpdGlvbjogdGhpcy5faW1wb3J0TWFuYWdlci5jb3JyZWN0Tm9kZVBvc2l0aW9uKG5vZGUsIG9mZnNldCwgcG9zaXRpb24pLFxuICAgICAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgICAgICBmaWxlUGF0aDogdGhpcy5maWxlU3lzdGVtLnJlc29sdmUoc291cmNlRmlsZS5maWxlTmFtZSksXG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqIEdsb2JhbCBzdGF0ZSBvZiB3aGV0aGVyIEhhbW1lciBpcyB1c2VkIGluIGFueSBhbmFseXplZCBwcm9qZWN0IHRhcmdldC4gKi9cbiAgc3RhdGljIGdsb2JhbFVzZXNIYW1tZXIgPSBmYWxzZTtcblxuICAvKipcbiAgICogU3RhdGljIG1pZ3JhdGlvbiBydWxlIG1ldGhvZCB0aGF0IHdpbGwgYmUgY2FsbGVkIG9uY2UgYWxsIHByb2plY3QgdGFyZ2V0c1xuICAgKiBoYXZlIGJlZW4gbWlncmF0ZWQgaW5kaXZpZHVhbGx5LiBUaGlzIG1ldGhvZCBjYW4gYmUgdXNlZCB0byBtYWtlIGNoYW5nZXMgYmFzZWRcbiAgICogb24gdGhlIGFuYWx5c2lzIG9mIHRoZSBpbmRpdmlkdWFsIHRhcmdldHMuIEZvciBleGFtcGxlOiB3ZSBvbmx5IHJlbW92ZSBIYW1tZXJcbiAgICogZnJvbSB0aGUgXCJwYWNrYWdlLmpzb25cIiBpZiBpdCBpcyBub3QgdXNlZCBpbiAqYW55KiBwcm9qZWN0IHRhcmdldC5cbiAgICovXG4gIHN0YXRpYyBnbG9iYWxQb3N0TWlncmF0aW9uKHRyZWU6IFRyZWUsIGNvbnRleHQ6IFNjaGVtYXRpY0NvbnRleHQpOiBQb3N0TWlncmF0aW9uQWN0aW9uIHtcbiAgICAvLyBBbHdheXMgbm90aWZ5IHRoZSBkZXZlbG9wZXIgdGhhdCB0aGUgSGFtbWVyIHY5IG1pZ3JhdGlvbiBkb2VzIG5vdCBtaWdyYXRlIHRlc3RzLlxuICAgIGNvbnRleHQubG9nZ2VyLmluZm8oXG4gICAgICAgICdcXG7imqAgIEdlbmVyYWwgbm90aWNlOiBUaGUgSGFtbWVySlMgdjkgbWlncmF0aW9uIGZvciBBbmd1bGFyIENvbXBvbmVudHMgaXMgbm90IGFibGUgdG8gJyArXG4gICAgICAgICdtaWdyYXRlIHRlc3RzLiBQbGVhc2UgbWFudWFsbHkgY2xlYW4gdXAgdGVzdHMgaW4geW91ciBwcm9qZWN0IGlmIHRoZXkgcmVseSBvbiAnICtcbiAgICAgICAgKHRoaXMuZ2xvYmFsVXNlc0hhbW1lciA/ICd0aGUgZGVwcmVjYXRlZCBBbmd1bGFyIE1hdGVyaWFsIGdlc3R1cmUgY29uZmlnLicgOiAnSGFtbWVySlMuJykpO1xuICAgIGNvbnRleHQubG9nZ2VyLmluZm8oXG4gICAgICAgICdSZWFkIG1vcmUgYWJvdXQgbWlncmF0aW5nIHRlc3RzOiBodHRwczovL2dpdC5pby9uZy1tYXRlcmlhbC12OS1oYW1tZXItbWlncmF0ZS10ZXN0cycpO1xuXG4gICAgaWYgKCF0aGlzLmdsb2JhbFVzZXNIYW1tZXIgJiYgdGhpcy5fcmVtb3ZlSGFtbWVyRnJvbVBhY2thZ2VKc29uKHRyZWUpKSB7XG4gICAgICAvLyBTaW5jZSBIYW1tZXIgaGFzIGJlZW4gcmVtb3ZlZCBmcm9tIHRoZSB3b3Jrc3BhY2UgXCJwYWNrYWdlLmpzb25cIiBmaWxlLFxuICAgICAgLy8gd2Ugc2NoZWR1bGUgYSBub2RlIHBhY2thZ2UgaW5zdGFsbCB0YXNrIHRvIHJlZnJlc2ggdGhlIGxvY2sgZmlsZS5cbiAgICAgIHJldHVybiB7cnVuUGFja2FnZU1hbmFnZXI6IHRydWV9O1xuICAgIH1cblxuICAgIC8vIENsZWFuIGdsb2JhbCBzdGF0ZSBvbmNlIHRoZSB3b3Jrc3BhY2UgaGFzIGJlZW4gbWlncmF0ZWQuIFRoaXMgaXMgdGVjaG5pY2FsbHlcbiAgICAvLyBub3QgbmVjZXNzYXJ5IGluIFwibmcgdXBkYXRlXCIsIGJ1dCBpbiB0ZXN0cyB3ZSByZS11c2UgdGhlIHNhbWUgcnVsZSBjbGFzcy5cbiAgICB0aGlzLmdsb2JhbFVzZXNIYW1tZXIgPSBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHRoZSBoYW1tZXIgcGFja2FnZSBmcm9tIHRoZSB3b3Jrc3BhY2UgXCJwYWNrYWdlLmpzb25cIi5cbiAgICogQHJldHVybnMgV2hldGhlciBIYW1tZXIgd2FzIHNldCB1cCBhbmQgaGFzIGJlZW4gcmVtb3ZlZCBmcm9tIHRoZSBcInBhY2thZ2UuanNvblwiXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBfcmVtb3ZlSGFtbWVyRnJvbVBhY2thZ2VKc29uKHRyZWU6IFRyZWUpOiBib29sZWFuIHtcbiAgICBpZiAoIXRyZWUuZXhpc3RzKCcvcGFja2FnZS5qc29uJykpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBwYWNrYWdlSnNvbiA9IEpTT04ucGFyc2UodHJlZS5yZWFkKCcvcGFja2FnZS5qc29uJykhLnRvU3RyaW5nKCd1dGY4JykpO1xuXG4gICAgLy8gV2UgZG8gbm90IGhhbmRsZSB0aGUgY2FzZSB3aGVyZSBzb21lb25lIG1hbnVhbGx5IGFkZGVkIFwiaGFtbWVyanNcIiB0byB0aGUgZGV2IGRlcGVuZGVuY2llcy5cbiAgICBpZiAocGFja2FnZUpzb24uZGVwZW5kZW5jaWVzICYmIHBhY2thZ2VKc29uLmRlcGVuZGVuY2llc1tIQU1NRVJfTU9EVUxFX1NQRUNJRklFUl0pIHtcbiAgICAgIGRlbGV0ZSBwYWNrYWdlSnNvbi5kZXBlbmRlbmNpZXNbSEFNTUVSX01PRFVMRV9TUEVDSUZJRVJdO1xuICAgICAgdHJlZS5vdmVyd3JpdGUoJy9wYWNrYWdlLmpzb24nLCBKU09OLnN0cmluZ2lmeShwYWNrYWdlSnNvbiwgbnVsbCwgMikpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG4vKipcbiAqIFJlY3Vyc2l2ZWx5IHVud3JhcHMgYSBnaXZlbiBleHByZXNzaW9uIGlmIGl0IGlzIHdyYXBwZWRcbiAqIGJ5IHBhcmVudGhlc2lzLCB0eXBlIGNhc3RzIG9yIHR5cGUgYXNzZXJ0aW9ucy5cbiAqL1xuZnVuY3Rpb24gdW53cmFwRXhwcmVzc2lvbihub2RlOiB0cy5Ob2RlKTogdHMuTm9kZSB7XG4gIGlmICh0cy5pc1BhcmVudGhlc2l6ZWRFeHByZXNzaW9uKG5vZGUpKSB7XG4gICAgcmV0dXJuIHVud3JhcEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uKTtcbiAgfSBlbHNlIGlmICh0cy5pc0FzRXhwcmVzc2lvbihub2RlKSkge1xuICAgIHJldHVybiB1bndyYXBFeHByZXNzaW9uKG5vZGUuZXhwcmVzc2lvbik7XG4gIH0gZWxzZSBpZiAodHMuaXNUeXBlQXNzZXJ0aW9uKG5vZGUpKSB7XG4gICAgcmV0dXJuIHVud3JhcEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uKTtcbiAgfVxuICByZXR1cm4gbm9kZTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgc3BlY2lmaWVkIHBhdGggdG8gYSB2YWxpZCBUeXBlU2NyaXB0IG1vZHVsZSBzcGVjaWZpZXIgd2hpY2ggaXNcbiAqIHJlbGF0aXZlIHRvIHRoZSBnaXZlbiBjb250YWluaW5nIGZpbGUuXG4gKi9cbmZ1bmN0aW9uIGdldE1vZHVsZVNwZWNpZmllcihuZXdQYXRoOiBQYXRoLCBjb250YWluaW5nRmlsZTogUGF0aCkge1xuICBsZXQgcmVzdWx0ID0gcmVsYXRpdmUoZGlybmFtZShjb250YWluaW5nRmlsZSksIG5ld1BhdGgpLnJlcGxhY2UoL1xcXFwvZywgJy8nKS5yZXBsYWNlKC9cXC50cyQvLCAnJyk7XG4gIGlmICghcmVzdWx0LnN0YXJ0c1dpdGgoJy4nKSkge1xuICAgIHJlc3VsdCA9IGAuLyR7cmVzdWx0fWA7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSB0ZXh0IG9mIHRoZSBnaXZlbiBwcm9wZXJ0eSBuYW1lLlxuICogQHJldHVybnMgVGV4dCBvZiB0aGUgZ2l2ZW4gcHJvcGVydHkgbmFtZS4gTnVsbCBpZiBub3Qgc3RhdGljYWxseSBhbmFseXphYmxlLlxuICovXG5mdW5jdGlvbiBnZXRQcm9wZXJ0eU5hbWVUZXh0KG5vZGU6IHRzLlByb3BlcnR5TmFtZSk6IHN0cmluZ3xudWxsIHtcbiAgaWYgKHRzLmlzSWRlbnRpZmllcihub2RlKSB8fCB0cy5pc1N0cmluZ0xpdGVyYWxMaWtlKG5vZGUpKSB7XG4gICAgcmV0dXJuIG5vZGUudGV4dDtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqIENoZWNrcyB3aGV0aGVyIHRoZSBnaXZlbiBpZGVudGlmaWVyIGlzIHBhcnQgb2YgYSBuYW1lc3BhY2VkIGFjY2Vzcy4gKi9cbmZ1bmN0aW9uIGlzTmFtZXNwYWNlZElkZW50aWZpZXJBY2Nlc3Mobm9kZTogdHMuSWRlbnRpZmllcik6IGJvb2xlYW4ge1xuICByZXR1cm4gdHMuaXNRdWFsaWZpZWROYW1lKG5vZGUucGFyZW50KSB8fCB0cy5pc1Byb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihub2RlLnBhcmVudCk7XG59XG5cbi8qKlxuICogV2Fsa3MgdGhyb3VnaCB0aGUgc3BlY2lmaWVkIG5vZGUgYW5kIHJldHVybnMgYWxsIGNoaWxkIG5vZGVzIHdoaWNoIG1hdGNoIHRoZVxuICogZ2l2ZW4gcHJlZGljYXRlLlxuICovXG5mdW5jdGlvbiBmaW5kTWF0Y2hpbmdDaGlsZE5vZGVzPFQgZXh0ZW5kcyB0cy5Ob2RlPihcbiAgICBwYXJlbnQ6IHRzLk5vZGUsIHByZWRpY2F0ZTogKG5vZGU6IHRzLk5vZGUpID0+IG5vZGUgaXMgVCk6IFRbXSB7XG4gIGNvbnN0IHJlc3VsdDogVFtdID0gW107XG4gIGNvbnN0IHZpc2l0Tm9kZSA9IChub2RlOiB0cy5Ob2RlKSA9PiB7XG4gICAgaWYgKHByZWRpY2F0ZShub2RlKSkge1xuICAgICAgcmVzdWx0LnB1c2gobm9kZSk7XG4gICAgfVxuICAgIHRzLmZvckVhY2hDaGlsZChub2RlLCB2aXNpdE5vZGUpO1xuICB9O1xuICB0cy5mb3JFYWNoQ2hpbGQocGFyZW50LCB2aXNpdE5vZGUpO1xuICByZXR1cm4gcmVzdWx0O1xufVxuIl19