@cartanova/qgrid-cli 2.10.9 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/bundle/dist/_virtual/_rolldown/runtime.js +1 -10
  2. package/bundle/dist/application/monit/log-buffer.js +12 -6
  3. package/bundle/dist/application/monit/monit.frame.js +11 -3
  4. package/bundle/dist/application/monit/monit.types.js +1 -1
  5. package/bundle/dist/application/qgrid/conv-routing.js +9 -6
  6. package/bundle/dist/application/qgrid/expired-token-reminder.js +2 -2
  7. package/bundle/dist/application/qgrid/oauth.js +31 -4
  8. package/bundle/dist/application/qgrid/qgrid-image-generation.js +1 -1
  9. package/bundle/dist/application/qgrid/qgrid-response-format.js +22 -20
  10. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +43 -34
  11. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +128 -93
  12. package/bundle/dist/application/qgrid/qgrid.frame.js +930 -49
  13. package/bundle/dist/application/qgrid/qgrid.types.js +212 -5
  14. package/bundle/dist/application/qgrid/schema-prompt.js +75 -48
  15. package/bundle/dist/application/qgrid/slack-user-map.js +1 -1
  16. package/bundle/dist/application/qgrid/token-death.js +1 -1
  17. package/bundle/dist/application/qgrid/token-subscriber.js +83 -30
  18. package/bundle/dist/application/qgrid/token-trigger-setup.js +1 -1
  19. package/bundle/dist/application/qgrid/token-window-keepalive.js +8 -6
  20. package/bundle/dist/application/qgrid/tool-emulation-schema.js +13 -13
  21. package/bundle/dist/application/qgrid/tool-emulation.js +19 -15
  22. package/bundle/dist/application/request-log/json-schema-type-text.js +29 -12
  23. package/bundle/dist/application/request-log/request-log.model.js +83 -69
  24. package/bundle/dist/application/request-log/request-log.types.js +8 -2
  25. package/bundle/dist/application/request-log/zod-code-format.js +1 -1
  26. package/bundle/dist/application/request-log-step/request-log-step.model.js +1 -1
  27. package/bundle/dist/application/request-log-step/request-log-step.types.js +1 -1
  28. package/bundle/dist/application/setting/setting.constant.js +1 -1
  29. package/bundle/dist/application/setting/setting.model.js +2 -2
  30. package/bundle/dist/application/setting/setting.store.js +2 -2
  31. package/bundle/dist/application/setting/setting.types.js +1 -1
  32. package/bundle/dist/application/sonamu.generated.js +40 -16
  33. package/bundle/dist/application/sonamu.generated.sso.js +2 -1
  34. package/bundle/dist/application/token/token.model.js +26 -9
  35. package/bundle/dist/application/token/token.types.js +20 -3
  36. package/bundle/dist/i18n/en.js +15 -1
  37. package/bundle/dist/i18n/ko.js +15 -1
  38. package/bundle/dist/i18n/sd.generated.js +2 -1
  39. package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
  40. package/bundle/dist/migrations/20261018215031_alter_request_logs_add1_alter1.js +15 -0
  41. package/bundle/dist/server-bootstrap.js +4 -2
  42. package/bundle/dist/server-error-handler.js +1 -1
  43. package/bundle/dist/sonamu.config.js +37 -8
  44. package/bundle/dist/startup-migrations.js +17 -7
  45. package/bundle/dist/testing/global.js +1 -1
  46. package/bundle/dist/testing/schema-bench.js +0 -0
  47. package/bundle/dist/testing/test-database-name.js +1 -1
  48. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
  49. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
  50. package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
  51. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
  52. package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
  53. package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
  54. package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
  55. package/bundle/dist/utils/providers/common/credentials.js +5 -1
  56. package/bundle/dist/utils/providers/common/effort.js +3 -3
  57. package/bundle/dist/utils/providers/common/model-cost.js +69 -14
  58. package/bundle/dist/utils/providers/common/provider-types.js +29 -1
  59. package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
  60. package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
  61. package/bundle/dist/utils/providers/common/strictifier.js +62 -43
  62. package/bundle/dist/utils/providers/common/thinking.js +3 -2
  63. package/bundle/dist/utils/providers/common/ttft.js +1 -1
  64. package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
  65. package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
  66. package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
  67. package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
  68. package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
  69. package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
  70. package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
  71. package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
  72. package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
  73. package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
  74. package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
  75. package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
  76. package/bundle/dist/utils/providers/grok/index.js +11 -0
  77. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
  78. package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
  79. package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
  80. package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
  81. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
  82. package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
  83. package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
  84. package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
  85. package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
  86. package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
  87. package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
  88. package/bundle/dist/utils/quiet-hours.js +1 -1
  89. package/bundle/dist/utils/slack-notify.js +14 -8
  90. package/bundle/dist/utils/subset-loaders.js +4 -5
  91. package/bundle/src/application/monit/log-buffer.ts +23 -9
  92. package/bundle/src/application/monit/monit.frame.ts +22 -5
  93. package/bundle/src/application/monit/monit.types.ts +6 -0
  94. package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
  95. package/bundle/src/application/qgrid/conv-routing.ts +35 -9
  96. package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
  97. package/bundle/src/application/qgrid/oauth.ts +51 -15
  98. package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
  99. package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
  100. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +33 -0
  101. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +87 -40
  102. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
  103. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
  104. package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
  105. package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
  106. package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
  107. package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
  108. package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
  109. package/bundle/src/application/qgrid/token-death.ts +4 -0
  110. package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
  111. package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
  112. package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
  113. package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
  114. package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
  115. package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
  116. package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
  117. package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
  118. package/bundle/src/application/request-log/request-log.entity.json +8 -0
  119. package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
  120. package/bundle/src/application/request-log/request-log.model.ts +279 -145
  121. package/bundle/src/application/request-log/request-log.types.ts +17 -0
  122. package/bundle/src/application/request-log/zod-code-format.ts +11 -0
  123. package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
  124. package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
  125. package/bundle/src/application/setting/setting.constant.ts +9 -0
  126. package/bundle/src/application/setting/setting.model.ts +12 -2
  127. package/bundle/src/application/setting/setting.store.ts +5 -1
  128. package/bundle/src/application/setting/setting.types.ts +8 -0
  129. package/bundle/src/application/sonamu.generated.http +135 -0
  130. package/bundle/src/application/sonamu.generated.sso.ts +3 -0
  131. package/bundle/src/application/sonamu.generated.ts +29 -0
  132. package/bundle/src/application/token/token.identity.test.ts +20 -0
  133. package/bundle/src/application/token/token.model.ts +66 -7
  134. package/bundle/src/application/token/token.types.ts +24 -1
  135. package/bundle/src/i18n/en.ts +19 -0
  136. package/bundle/src/i18n/ko.ts +21 -0
  137. package/bundle/src/i18n/sd.generated.ts +24 -2
  138. package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
  139. package/bundle/src/migrations/20261018215031_alter_request_logs_add1_alter1.ts +15 -0
  140. package/bundle/src/server-bootstrap.ts +4 -2
  141. package/bundle/src/server-error-handler.ts +1 -0
  142. package/bundle/src/sonamu.config.ts +69 -7
  143. package/bundle/src/startup-migrations.ts +27 -9
  144. package/bundle/src/testing/global.ts +20 -0
  145. package/bundle/src/testing/schema-bench.ts +105 -30
  146. package/bundle/src/testing/test-database-name.ts +2 -0
  147. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
  148. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
  149. package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
  150. package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
  151. package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
  152. package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
  153. package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
  154. package/bundle/src/utils/providers/common/credentials.ts +8 -0
  155. package/bundle/src/utils/providers/common/effort.ts +9 -2
  156. package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
  157. package/bundle/src/utils/providers/common/model-cost.ts +259 -158
  158. package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
  159. package/bundle/src/utils/providers/common/provider-types.ts +46 -3
  160. package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
  161. package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
  162. package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
  163. package/bundle/src/utils/providers/common/strictifier.ts +185 -59
  164. package/bundle/src/utils/providers/common/thinking.ts +2 -2
  165. package/bundle/src/utils/providers/common/ttft.ts +4 -2
  166. package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
  167. package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
  168. package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
  169. package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
  170. package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
  171. package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
  172. package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
  173. package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
  174. package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
  175. package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
  176. package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
  177. package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
  178. package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
  179. package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
  180. package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
  181. package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
  182. package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
  183. package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
  184. package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
  185. package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
  186. package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
  187. package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
  188. package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
  189. package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
  190. package/bundle/src/utils/providers/grok/index.ts +20 -0
  191. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
  192. package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
  193. package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
  194. package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
  195. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
  196. package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
  197. package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
  198. package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
  199. package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
  200. package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
  201. package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
  202. package/bundle/src/utils/quiet-hours.ts +12 -1
  203. package/bundle/src/utils/slack-notify.ts +44 -13
  204. package/bundle/src/utils/subset-loaders.ts +7 -7
  205. package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
  206. package/bundle/web-dist/client/assets/index-BA7uQ-6c.js +31 -0
  207. package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
  208. package/bundle/web-dist/client/assets/logs-C47OJGEI.js +1 -0
  209. package/bundle/web-dist/client/assets/monit-BS9no0dU.js +4 -0
  210. package/bundle/web-dist/client/assets/plus-sdACTfH0.js +1 -0
  211. package/bundle/web-dist/client/assets/refresh-cw-CY8o_1cT.js +1 -0
  212. package/bundle/web-dist/client/assets/request-model-BRtFuZvj.js +1 -0
  213. package/bundle/web-dist/client/assets/routes-kqgkUxE8.js +5 -0
  214. package/bundle/web-dist/client/assets/{services.generated-BsieU37H.js → services.generated-CefiDXEv.js} +5 -5
  215. package/bundle/web-dist/client/assets/settings-DNDvFGSw.js +1 -0
  216. package/bundle/web-dist/client/assets/show-u8Np69q3.js +2 -0
  217. package/bundle/web-dist/client/assets/tokens-QvP410NW.js +1 -0
  218. package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
  219. package/bundle/web-dist/client/assets/use-oauth-login-flow-Bzdh28Ws.js +1 -0
  220. package/bundle/web-dist/client/assets/use-update-token-mutation-CfJKaxmR.js +1 -0
  221. package/bundle/web-dist/client/assets/vendor-react-CUFFrVN9.js +244 -0
  222. package/bundle/web-dist/client/assets/vendor-tanstack-Bf_jag9G.js +1 -0
  223. package/bundle/web-dist/client/index.html +6 -6
  224. package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
  225. package/bundle/web-dist/server/assets/{lazyRouteComponent-Dtd0NR4r.js → lazyRouteComponent-D8iTIHyn.js} +129 -2
  226. package/bundle/web-dist/server/assets/logs-B3OTd9hy.js +825 -0
  227. package/bundle/web-dist/server/assets/{monit-DvzribSE.js → monit-B2hqorPe.js} +385 -126
  228. package/bundle/web-dist/server/assets/plus-DwG7h9kq.js +28 -0
  229. package/bundle/web-dist/server/assets/{react-dom-B4a6-uuR.js → react-dom-BIYQzBqG.js} +2 -129
  230. package/bundle/web-dist/server/assets/refresh-cw-mMBkwOq0.js +44 -0
  231. package/bundle/web-dist/server/assets/{request-model-CbqfnQOJ.js → request-model-I6OdODSH.js} +15 -6
  232. package/bundle/web-dist/server/assets/{routes-BAPWTizT.js → routes-B95YlUv2.js} +760 -213
  233. package/bundle/web-dist/server/assets/{services.generated-CEbGjsI0.js → services.generated-DQATJ6qf.js} +12821 -12194
  234. package/bundle/web-dist/server/assets/settings-C3gbGk0m.js +830 -0
  235. package/bundle/web-dist/server/assets/{show-CxVZTAdv.js → show-Bxaj3rhH.js} +1355 -419
  236. package/bundle/web-dist/server/assets/tokens-CZjH3cB7.js +1038 -0
  237. package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
  238. package/bundle/web-dist/server/assets/use-oauth-login-flow-CKDHgc3U.js +2379 -0
  239. package/bundle/web-dist/server/assets/{use-update-token-mutation-CfYmk_4_.js → use-update-token-mutation-BEbgOzaa.js} +1 -1
  240. package/bundle/web-dist/server/entry-server.generated.js +4303 -22810
  241. package/dist/cli.js +9 -9
  242. package/package.json +4 -11
  243. package/postinstall.mjs +12 -0
  244. package/skills/qgrid/SKILL.md +1 -0
  245. package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
  246. package/skills/qgrid/references/decision-rationale.md +24 -1
  247. package/skills/qgrid/references/grok-runtime.md +89 -0
  248. package/skills/qgrid/references/provider-runtime-differences.md +30 -29
  249. package/skills/qgrid/references/repo-map.md +10 -0
  250. package/skills/qgrid/references/request-log-run-lifecycle.md +1 -1
  251. package/skills/qgrid/references/sonamu-api-web-flow.md +1 -1
  252. package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
  253. package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
  254. package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
  255. package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  256. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
  257. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
  258. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
  259. package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
  260. package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
  261. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
  262. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
  263. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
  264. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
  265. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
  266. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
  267. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
  268. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
  269. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
  270. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
  271. package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
  272. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  273. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  274. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  275. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  276. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  277. package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
  278. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  279. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  280. package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
  281. package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
  282. package/bundle/dist/node_modules/.pnpm/vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50/node_modules/vite/dist/node/module-runner.js +0 -1265
  283. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js +0 -9
  284. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/benchmark.CX_oY03V.js +0 -41
  285. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js +0 -19
  286. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.Chj8NDwU.js +0 -202
  287. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.DdgEv5B1.js +0 -46
  288. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/rpc.MzXet3jl.js +0 -119
  289. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js +0 -3044
  290. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js +0 -59
  291. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/index.js +0 -28
  292. package/bundle/dist/testing/setup-mocks.js +0 -16
  293. package/bundle/src/testing/setup-mocks.ts +0 -44
  294. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
  295. package/bundle/web-dist/client/assets/index-CrXKu_J8.js +0 -106
  296. package/bundle/web-dist/client/assets/logs-B2SmWJXA.js +0 -1
  297. package/bundle/web-dist/client/assets/monit-D-JwXXoA.js +0 -1
  298. package/bundle/web-dist/client/assets/plus-B62CuqT8.js +0 -1
  299. package/bundle/web-dist/client/assets/refresh-cw-NNcU0Cmq.js +0 -1
  300. package/bundle/web-dist/client/assets/request-model-CojtinqK.js +0 -1
  301. package/bundle/web-dist/client/assets/routes-C5r4gTvY.js +0 -5
  302. package/bundle/web-dist/client/assets/settings-D3tDSAck.js +0 -1
  303. package/bundle/web-dist/client/assets/show-Cah_kUKC.js +0 -2
  304. package/bundle/web-dist/client/assets/tokens-DU2Iyxxd.js +0 -1
  305. package/bundle/web-dist/client/assets/use-oauth-login-flow-D0UaR9_e.js +0 -1
  306. package/bundle/web-dist/client/assets/use-update-token-mutation-DAq0F8p-.js +0 -1
  307. package/bundle/web-dist/client/assets/vendor-react-DH4kUfK2.js +0 -9
  308. package/bundle/web-dist/client/assets/vendor-tanstack-DJRQAbrY.js +0 -1
  309. package/bundle/web-dist/server/assets/logs-l91avYif.js +0 -509
  310. package/bundle/web-dist/server/assets/plus-KZrECewT.js +0 -19
  311. package/bundle/web-dist/server/assets/refresh-cw-BND93JrF.js +0 -23
  312. package/bundle/web-dist/server/assets/settings-BZR5HSAL.js +0 -461
  313. package/bundle/web-dist/server/assets/tokens-D1hb4eKk.js +0 -448
  314. package/bundle/web-dist/server/assets/use-oauth-login-flow-Cvdy0zF8.js +0 -178
  315. package/dist/cli.d.ts +0 -10
  316. /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
  317. /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  318. /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
@@ -1,2756 +0,0 @@
1
- import { format, formatRegExp, objDisplay } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js";
2
- import { assertTypes, createDefer, filterOutComments, isNegativeNaN, isObject, objectAttr, ordinal, shuffle, toArray, unique } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js";
3
- import { processError } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js";
4
- import { getSafeTimers } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js";
5
- import { parseSingleStack } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js";
6
- import { b as relative } from "../../../../../pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js";
7
- import "../../../../../pathe@2.0.3/node_modules/pathe/dist/index.js";
8
- //#region ../../node_modules/.pnpm/@vitest+runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js
9
- var PendingError = class extends Error {
10
- code = "VITEST_PENDING";
11
- taskId;
12
- constructor(message, task, note) {
13
- super(message);
14
- this.message = message;
15
- this.note = note;
16
- this.taskId = task.id;
17
- }
18
- };
19
- var TestRunAbortError = class extends Error {
20
- name = "TestRunAbortError";
21
- reason;
22
- constructor(message, reason) {
23
- super(message);
24
- this.reason = reason;
25
- }
26
- };
27
- var FixtureDependencyError = class extends Error {
28
- name = "FixtureDependencyError";
29
- };
30
- var FixtureAccessError = class extends Error {
31
- name = "FixtureAccessError";
32
- };
33
- var FixtureParseError = class extends Error {
34
- name = "FixtureParseError";
35
- };
36
- var AroundHookSetupError = class extends Error {
37
- name = "AroundHookSetupError";
38
- };
39
- var AroundHookTeardownError = class extends Error {
40
- name = "AroundHookTeardownError";
41
- };
42
- var AroundHookMultipleCallsError = class extends Error {
43
- name = "AroundHookMultipleCallsError";
44
- };
45
- const fnMap = /* @__PURE__ */ new WeakMap();
46
- const testFixtureMap = /* @__PURE__ */ new WeakMap();
47
- const hooksMap = /* @__PURE__ */ new WeakMap();
48
- function setFn(key, fn) {
49
- fnMap.set(key, fn);
50
- }
51
- function getFn(key) {
52
- return fnMap.get(key);
53
- }
54
- function setTestFixture(key, fixture) {
55
- testFixtureMap.set(key, fixture);
56
- }
57
- function getTestFixtures(key) {
58
- return testFixtureMap.get(key);
59
- }
60
- function setHooks(key, hooks) {
61
- hooksMap.set(key, hooks);
62
- }
63
- function getHooks(key) {
64
- return hooksMap.get(key);
65
- }
66
- const FIXTURE_STACK_TRACE_KEY = Symbol.for("VITEST_FIXTURE_STACK_TRACE");
67
- var TestFixtures = class TestFixtures {
68
- _suiteContexts;
69
- _overrides = /* @__PURE__ */ new WeakMap();
70
- _registrations;
71
- static _definitions = [];
72
- static _builtinFixtures = [
73
- "task",
74
- "signal",
75
- "onTestFailed",
76
- "onTestFinished",
77
- "skip",
78
- "annotate"
79
- ];
80
- static _fixtureOptionKeys = [
81
- "auto",
82
- "injected",
83
- "scope"
84
- ];
85
- static _fixtureScopes = [
86
- "test",
87
- "file",
88
- "worker"
89
- ];
90
- static _workerContextSuite = { type: "worker" };
91
- static clearDefinitions() {
92
- TestFixtures._definitions.length = 0;
93
- }
94
- static getWorkerContexts() {
95
- return TestFixtures._definitions.map((f) => f.getWorkerContext());
96
- }
97
- static getFileContexts(file) {
98
- return TestFixtures._definitions.map((f) => f.getFileContext(file));
99
- }
100
- static isFixtureOptions(obj) {
101
- return isObject(obj) && Object.keys(obj).some((key) => TestFixtures._fixtureOptionKeys.includes(key));
102
- }
103
- constructor(registrations) {
104
- this._registrations = registrations ?? /* @__PURE__ */ new Map();
105
- this._suiteContexts = /* @__PURE__ */ new WeakMap();
106
- TestFixtures._definitions.push(this);
107
- }
108
- extend(runner, userFixtures) {
109
- const { suite } = getCurrentSuite();
110
- const isTopLevel = !suite || suite.file === suite;
111
- const registrations = this.parseUserFixtures(runner, userFixtures, isTopLevel);
112
- return new TestFixtures(registrations);
113
- }
114
- get(suite) {
115
- let currentSuite = suite;
116
- while (currentSuite) {
117
- const overrides = this._overrides.get(currentSuite);
118
- if (overrides) return overrides;
119
- if (currentSuite === currentSuite.file) break;
120
- currentSuite = currentSuite.suite || currentSuite.file;
121
- }
122
- return this._registrations;
123
- }
124
- override(runner, userFixtures) {
125
- const { suite: currentSuite, file } = getCurrentSuite();
126
- const suite = currentSuite || file;
127
- const isTopLevel = !currentSuite || currentSuite.file === currentSuite;
128
- const suiteRegistrations = new Map(this.get(suite));
129
- const registrations = this.parseUserFixtures(runner, userFixtures, isTopLevel, suiteRegistrations);
130
- if (isTopLevel) this._registrations = registrations;
131
- else this._overrides.set(suite, registrations);
132
- }
133
- getFileContext(file) {
134
- if (!this._suiteContexts.has(file)) this._suiteContexts.set(file, Object.create(null));
135
- return this._suiteContexts.get(file);
136
- }
137
- getWorkerContext() {
138
- if (!this._suiteContexts.has(TestFixtures._workerContextSuite)) this._suiteContexts.set(TestFixtures._workerContextSuite, Object.create(null));
139
- return this._suiteContexts.get(TestFixtures._workerContextSuite);
140
- }
141
- parseUserFixtures(runner, userFixtures, supportNonTest, registrations = new Map(this._registrations)) {
142
- const errors = [];
143
- Object.entries(userFixtures).forEach(([name, fn]) => {
144
- let options;
145
- let value;
146
- let _options;
147
- if (Array.isArray(fn) && fn.length >= 2 && TestFixtures.isFixtureOptions(fn[1])) {
148
- _options = fn[1];
149
- options = {
150
- auto: _options.auto ?? false,
151
- scope: _options.scope ?? "test",
152
- injected: _options.injected ?? false
153
- };
154
- value = options.injected ? runner.injectValue?.(name) ?? fn[0] : fn[0];
155
- } else value = fn;
156
- const parent = registrations.get(name);
157
- if (parent && options) {
158
- if (parent.scope !== options.scope) errors.push(new FixtureDependencyError(`The "${name}" fixture was already registered with a "${options.scope}" scope.`));
159
- if (parent.auto !== options.auto) errors.push(new FixtureDependencyError(`The "${name}" fixture was already registered as { auto: ${options.auto} }.`));
160
- } else if (parent) options = {
161
- auto: parent.auto,
162
- scope: parent.scope,
163
- injected: parent.injected
164
- };
165
- else if (!options) options = {
166
- auto: false,
167
- injected: false,
168
- scope: "test"
169
- };
170
- if (options.scope && !TestFixtures._fixtureScopes.includes(options.scope)) errors.push(new FixtureDependencyError(`The "${name}" fixture has unknown scope "${options.scope}".`));
171
- if (!supportNonTest && options.scope !== "test") errors.push(new FixtureDependencyError(`The "${name}" fixture cannot be defined with a ${options.scope} scope${!_options?.scope && parent?.scope ? " (inherited from the base fixture)" : ""} inside the describe block. Define it at the top level of the file instead.`));
172
- const deps = isFixtureFunction(value) ? getUsedProps(value) : /* @__PURE__ */ new Set();
173
- const item = {
174
- name,
175
- value,
176
- auto: options.auto ?? false,
177
- injected: options.injected ?? false,
178
- scope: options.scope ?? "test",
179
- deps,
180
- parent
181
- };
182
- if (isFixtureFunction(value)) Object.assign(value, { [FIXTURE_STACK_TRACE_KEY]: /* @__PURE__ */ new Error("STACK_TRACE_ERROR") });
183
- registrations.set(name, item);
184
- if (item.scope === "worker" && (runner.pool === "vmThreads" || runner.pool === "vmForks")) item.scope = "file";
185
- });
186
- for (const fixture of registrations.values()) for (const depName of fixture.deps) {
187
- if (TestFixtures._builtinFixtures.includes(depName)) continue;
188
- const dep = registrations.get(depName);
189
- if (!dep) {
190
- errors.push(new FixtureDependencyError(`The "${fixture.name}" fixture depends on unknown fixture "${depName}".`));
191
- continue;
192
- }
193
- if (depName === fixture.name && !fixture.parent) {
194
- errors.push(new FixtureDependencyError(`The "${fixture.name}" fixture depends on itself, but does not have a base implementation.`));
195
- continue;
196
- }
197
- if (TestFixtures._fixtureScopes.indexOf(fixture.scope) > TestFixtures._fixtureScopes.indexOf(dep.scope)) {
198
- errors.push(new FixtureDependencyError(`The ${fixture.scope} "${fixture.name}" fixture cannot depend on a ${dep.scope} fixture "${dep.name}".`));
199
- continue;
200
- }
201
- }
202
- if (errors.length === 1) throw errors[0];
203
- else if (errors.length > 1) throw new AggregateError(errors, "Cannot resolve user fixtures. See errors for more information.");
204
- return registrations;
205
- }
206
- };
207
- const cleanupFnArrayMap = /* @__PURE__ */ new WeakMap();
208
- async function callFixtureCleanup(context) {
209
- const cleanupFnArray = cleanupFnArrayMap.get(context) ?? [];
210
- for (const cleanup of cleanupFnArray.reverse()) await cleanup();
211
- cleanupFnArrayMap.delete(context);
212
- }
213
- /**
214
- * Returns the current number of cleanup functions registered for the context.
215
- * This can be used as a checkpoint to later clean up only fixtures added after this point.
216
- */
217
- function getFixtureCleanupCount(context) {
218
- return cleanupFnArrayMap.get(context)?.length ?? 0;
219
- }
220
- /**
221
- * Cleans up only fixtures that were added after the given checkpoint index.
222
- * This is used by aroundEach to clean up fixtures created inside runTest()
223
- * while preserving fixtures that were created for aroundEach itself.
224
- */
225
- async function callFixtureCleanupFrom(context, fromIndex) {
226
- const cleanupFnArray = cleanupFnArrayMap.get(context);
227
- if (!cleanupFnArray || cleanupFnArray.length <= fromIndex) return;
228
- const toCleanup = cleanupFnArray.slice(fromIndex);
229
- for (const cleanup of toCleanup.reverse()) await cleanup();
230
- cleanupFnArray.length = fromIndex;
231
- }
232
- const contextHasFixturesCache = /* @__PURE__ */ new WeakMap();
233
- function withFixtures(fn, options) {
234
- const collector = getCurrentSuite();
235
- const suite = options?.suite || collector.suite || collector.file;
236
- return async (hookContext) => {
237
- const context = hookContext || options?.context;
238
- if (!context) {
239
- if (options?.suiteHook) validateSuiteHook(fn, options.suiteHook, options.stackTraceError);
240
- return fn({});
241
- }
242
- const fixtures = options?.fixtures || getTestFixtures(context);
243
- if (!fixtures) return fn(context);
244
- const registrations = fixtures.get(suite);
245
- if (!registrations.size) return fn(context);
246
- const usedFixtures = [];
247
- const usedProps = getUsedProps(fn);
248
- for (const fixture of registrations.values()) if (isAutoFixture(fixture, options) || usedProps.has(fixture.name)) usedFixtures.push(fixture);
249
- if (!usedFixtures.length) return fn(context);
250
- if (!cleanupFnArrayMap.has(context)) cleanupFnArrayMap.set(context, []);
251
- const cleanupFnArray = cleanupFnArrayMap.get(context);
252
- const pendingFixtures = resolveDeps(usedFixtures, registrations);
253
- if (!pendingFixtures.length) return fn(context);
254
- if (options?.suiteHook) {
255
- const testScopedFixtures = pendingFixtures.filter((f) => f.scope === "test");
256
- if (testScopedFixtures.length > 0) {
257
- const fixtureNames = testScopedFixtures.map((f) => `"${f.name}"`).join(", ");
258
- const error = new FixtureDependencyError(`Test-scoped fixtures cannot be used inside ${options.suiteHook} hook. The following fixtures are test-scoped: ${fixtureNames}. Use { scope: 'file' } or { scope: 'worker' } fixtures instead, or move the logic to ${{
259
- aroundAll: "aroundEach",
260
- beforeAll: "beforeEach",
261
- afterAll: "afterEach"
262
- }[options.suiteHook]} hook.`);
263
- if (options.stackTraceError?.stack) error.stack = error.message + options.stackTraceError.stack.replace(options.stackTraceError.message, "");
264
- throw error;
265
- }
266
- }
267
- if (!contextHasFixturesCache.has(context)) contextHasFixturesCache.set(context, /* @__PURE__ */ new WeakSet());
268
- const cachedFixtures = contextHasFixturesCache.get(context);
269
- for (const fixture of pendingFixtures) if (fixture.scope === "test") {
270
- if (cachedFixtures.has(fixture)) continue;
271
- cachedFixtures.add(fixture);
272
- const resolvedValue = await resolveTestFixtureValue(fixture, context, cleanupFnArray);
273
- context[fixture.name] = resolvedValue;
274
- cleanupFnArray.push(() => {
275
- cachedFixtures.delete(fixture);
276
- });
277
- } else {
278
- const resolvedValue = await resolveScopeFixtureValue(fixtures, suite, fixture);
279
- context[fixture.name] = resolvedValue;
280
- }
281
- return fn(context);
282
- };
283
- }
284
- function isAutoFixture(fixture, options) {
285
- if (!fixture.auto) return false;
286
- if (options?.suiteHook && fixture.scope === "test") return false;
287
- return true;
288
- }
289
- function isFixtureFunction(value) {
290
- return typeof value === "function";
291
- }
292
- function resolveTestFixtureValue(fixture, context, cleanupFnArray) {
293
- if (!isFixtureFunction(fixture.value)) return fixture.value;
294
- return resolveFixtureFunction(fixture.value, fixture.name, context, cleanupFnArray);
295
- }
296
- const scopedFixturePromiseCache = /* @__PURE__ */ new WeakMap();
297
- async function resolveScopeFixtureValue(fixtures, suite, fixture) {
298
- const workerContext = fixtures.getWorkerContext();
299
- const fileContext = fixtures.getFileContext(suite.file);
300
- const fixtureContext = fixture.scope === "worker" ? workerContext : fileContext;
301
- if (!isFixtureFunction(fixture.value)) {
302
- fixtureContext[fixture.name] = fixture.value;
303
- return fixture.value;
304
- }
305
- if (fixture.name in fixtureContext) return fixtureContext[fixture.name];
306
- if (scopedFixturePromiseCache.has(fixture)) return scopedFixturePromiseCache.get(fixture);
307
- if (!cleanupFnArrayMap.has(fixtureContext)) cleanupFnArrayMap.set(fixtureContext, []);
308
- const cleanupFnFileArray = cleanupFnArrayMap.get(fixtureContext);
309
- const promise = resolveFixtureFunction(fixture.value, fixture.name, fixture.scope === "file" ? {
310
- ...workerContext,
311
- ...fileContext
312
- } : fixtureContext, cleanupFnFileArray).then((value) => {
313
- fixtureContext[fixture.name] = value;
314
- scopedFixturePromiseCache.delete(fixture);
315
- return value;
316
- });
317
- scopedFixturePromiseCache.set(fixture, promise);
318
- return promise;
319
- }
320
- async function resolveFixtureFunction(fixtureFn, fixtureName, context, cleanupFnArray) {
321
- const useFnArgPromise = createDefer();
322
- const stackTraceError = FIXTURE_STACK_TRACE_KEY in fixtureFn && fixtureFn[FIXTURE_STACK_TRACE_KEY] instanceof Error ? fixtureFn[FIXTURE_STACK_TRACE_KEY] : void 0;
323
- let isUseFnArgResolved = false;
324
- const fixtureReturn = fixtureFn(context, async (useFnArg) => {
325
- isUseFnArgResolved = true;
326
- useFnArgPromise.resolve(useFnArg);
327
- const useReturnPromise = createDefer();
328
- cleanupFnArray.push(async () => {
329
- useReturnPromise.resolve();
330
- await fixtureReturn;
331
- });
332
- await useReturnPromise;
333
- }).then(() => {
334
- if (!isUseFnArgResolved) {
335
- const error = /* @__PURE__ */ new Error(`Fixture "${fixtureName}" returned without calling "use". Make sure to call "use" in every code path of the fixture function.`);
336
- if (stackTraceError?.stack) error.stack = error.message + stackTraceError.stack.replace(stackTraceError.message, "");
337
- useFnArgPromise.reject(error);
338
- }
339
- }).catch((e) => {
340
- if (!isUseFnArgResolved) {
341
- useFnArgPromise.reject(e);
342
- return;
343
- }
344
- throw e;
345
- });
346
- return useFnArgPromise;
347
- }
348
- function resolveDeps(usedFixtures, registrations, depSet = /* @__PURE__ */ new Set(), pendingFixtures = []) {
349
- usedFixtures.forEach((fixture) => {
350
- if (pendingFixtures.includes(fixture)) return;
351
- if (!isFixtureFunction(fixture.value) || !fixture.deps) {
352
- pendingFixtures.push(fixture);
353
- return;
354
- }
355
- if (depSet.has(fixture)) if (fixture.parent) fixture = fixture.parent;
356
- else throw new Error(`Circular fixture dependency detected: ${fixture.name} <- ${[...depSet].reverse().map((d) => d.name).join(" <- ")}`);
357
- depSet.add(fixture);
358
- resolveDeps([...fixture.deps].map((n) => n === fixture.name ? fixture.parent : registrations.get(n)).filter((n) => !!n), registrations, depSet, pendingFixtures);
359
- pendingFixtures.push(fixture);
360
- depSet.clear();
361
- });
362
- return pendingFixtures;
363
- }
364
- function validateSuiteHook(fn, hook, suiteError) {
365
- const usedProps = getUsedProps(fn, {
366
- sourceError: suiteError,
367
- suiteHook: hook
368
- });
369
- if (usedProps.size) {
370
- const error = new FixtureAccessError(`The ${hook} hook uses fixtures "${[...usedProps].join("\", \"")}", but has no access to context. Did you forget to call it as "test.${hook}()" instead of "${hook}()"?\nIf you used internal "suite" task as the first argument previously, access it in the second argument instead. See https://vitest.dev/guide/test-context#suite-level-hooks`);
371
- if (suiteError) error.stack = suiteError.stack?.replace(suiteError.message, error.message);
372
- throw error;
373
- }
374
- }
375
- const kPropsSymbol = Symbol("$vitest:fixture-props");
376
- const kPropNamesSymbol = Symbol("$vitest:fixture-prop-names");
377
- function configureProps(fn, options) {
378
- Object.defineProperty(fn, kPropsSymbol, {
379
- value: options,
380
- enumerable: false
381
- });
382
- }
383
- function memoProps(fn, props) {
384
- fn[kPropNamesSymbol] = props;
385
- return props;
386
- }
387
- function getUsedProps(fn, { sourceError, suiteHook } = {}) {
388
- if (kPropNamesSymbol in fn) return fn[kPropNamesSymbol];
389
- const { index: fixturesIndex = 0, original: implementation = fn } = kPropsSymbol in fn ? fn[kPropsSymbol] : {};
390
- let fnString = filterOutComments(implementation.toString());
391
- if (/__async\((?:this|null), (?:null|arguments|\[[_0-9, ]*\]), function\*/.test(fnString)) fnString = fnString.split(/__async\((?:this|null),/)[1];
392
- const match = fnString.match(/[^(]*\(([^)]*)/);
393
- if (!match) return memoProps(fn, /* @__PURE__ */ new Set());
394
- const args = splitByComma(match[1]);
395
- if (!args.length) return memoProps(fn, /* @__PURE__ */ new Set());
396
- const fixturesArgument = args[fixturesIndex];
397
- if (!fixturesArgument) return memoProps(fn, /* @__PURE__ */ new Set());
398
- if (!(fixturesArgument[0] === "{" && fixturesArgument.endsWith("}"))) {
399
- const ordinalArgument = ordinal(fixturesIndex + 1);
400
- const error = new FixtureParseError(`The ${ordinalArgument} argument inside a fixture must use object destructuring pattern, e.g. ({ task } => {}). Instead, received "${fixturesArgument}".${suiteHook ? ` If you used internal "suite" task as the ${ordinalArgument} argument previously, access it in the ${ordinal(fixturesIndex + 2)} argument instead.` : ""}`);
401
- if (sourceError) error.stack = sourceError.stack?.replace(sourceError.message, error.message);
402
- throw error;
403
- }
404
- const props = splitByComma(fixturesArgument.slice(1, -1).replace(/\s/g, "")).map((prop) => {
405
- return prop.replace(/:.*|=.*/g, "");
406
- });
407
- const last = props.at(-1);
408
- if (last && last.startsWith("...")) {
409
- const error = new FixtureParseError(`Rest parameters are not supported in fixtures, received "${last}".`);
410
- if (sourceError) error.stack = sourceError.stack?.replace(sourceError.message, error.message);
411
- throw error;
412
- }
413
- return memoProps(fn, new Set(props));
414
- }
415
- function splitByComma(s) {
416
- const result = [];
417
- const stack = [];
418
- let start = 0;
419
- for (let i = 0; i < s.length; i++) if (s[i] === "{" || s[i] === "[") stack.push(s[i] === "{" ? "}" : "]");
420
- else if (s[i] === stack.at(-1)) stack.pop();
421
- else if (!stack.length && s[i] === ",") {
422
- const token = s.substring(start, i).trim();
423
- if (token) result.push(token);
424
- start = i + 1;
425
- }
426
- const lastToken = s.substring(start).trim();
427
- if (lastToken) result.push(lastToken);
428
- return result;
429
- }
430
- let _test;
431
- function setCurrentTest(test) {
432
- _test = test;
433
- }
434
- function getCurrentTest() {
435
- return _test;
436
- }
437
- const tests = [];
438
- function addRunningTest(test) {
439
- tests.push(test);
440
- return () => {
441
- tests.splice(tests.indexOf(test));
442
- };
443
- }
444
- function getRunningTests() {
445
- return tests;
446
- }
447
- const kChainableContext = Symbol("kChainableContext");
448
- function getChainableContext(chainable) {
449
- return chainable?.[kChainableContext];
450
- }
451
- function createChainable(keys, fn, context) {
452
- function create(context) {
453
- const chain = function(...args) {
454
- return fn.apply(context, args);
455
- };
456
- Object.assign(chain, fn);
457
- Object.defineProperty(chain, kChainableContext, {
458
- value: {
459
- withContext: () => chain.bind(context),
460
- getFixtures: () => context.fixtures,
461
- setContext: (key, value) => {
462
- context[key] = value;
463
- },
464
- mergeContext: (ctx) => {
465
- Object.assign(context, ctx);
466
- }
467
- },
468
- enumerable: false
469
- });
470
- for (const key of keys) Object.defineProperty(chain, key, { get() {
471
- return create({
472
- ...context,
473
- [key]: true
474
- });
475
- } });
476
- return chain;
477
- }
478
- const chain = create(context ?? {});
479
- Object.defineProperty(chain, "fn", {
480
- value: fn,
481
- enumerable: false
482
- });
483
- return chain;
484
- }
485
- function getDefaultHookTimeout() {
486
- return getRunner().config.hookTimeout;
487
- }
488
- const CLEANUP_TIMEOUT_KEY = Symbol.for("VITEST_CLEANUP_TIMEOUT");
489
- const CLEANUP_STACK_TRACE_KEY = Symbol.for("VITEST_CLEANUP_STACK_TRACE");
490
- const AROUND_TIMEOUT_KEY = Symbol.for("VITEST_AROUND_TIMEOUT");
491
- const AROUND_STACK_TRACE_KEY = Symbol.for("VITEST_AROUND_STACK_TRACE");
492
- function getBeforeHookCleanupCallback(hook, result, context) {
493
- if (typeof result === "function") return withTimeout(result, CLEANUP_TIMEOUT_KEY in hook && typeof hook[CLEANUP_TIMEOUT_KEY] === "number" ? hook[CLEANUP_TIMEOUT_KEY] : getDefaultHookTimeout(), true, CLEANUP_STACK_TRACE_KEY in hook && hook[CLEANUP_STACK_TRACE_KEY] instanceof Error ? hook[CLEANUP_STACK_TRACE_KEY] : void 0, (_, error) => {
494
- if (context) abortContextSignal(context, error);
495
- });
496
- }
497
- /**
498
- * Registers a callback function to be executed once before all tests within the current suite.
499
- * This hook is useful for scenarios where you need to perform setup operations that are common to all tests in a suite, such as initializing a database connection or setting up a test environment.
500
- *
501
- * **Note:** The `beforeAll` hooks are executed in the order they are defined one after another. You can configure this by changing the `sequence.hooks` option in the config file.
502
- *
503
- * @param {Function} fn - The callback function to be executed before all tests.
504
- * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
505
- * @returns {void}
506
- * @example
507
- * ```ts
508
- * // Example of using beforeAll to set up a database connection
509
- * beforeAll(async () => {
510
- * await database.connect();
511
- * });
512
- * ```
513
- */
514
- function beforeAll(fn, timeout = getDefaultHookTimeout()) {
515
- assertTypes(fn, "\"beforeAll\" callback", ["function"]);
516
- const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
517
- const context = getChainableContext(this);
518
- return getCurrentSuite().on("beforeAll", Object.assign(withTimeout(withSuiteFixtures("beforeAll", fn, context, stackTraceError), timeout, true, stackTraceError), {
519
- [CLEANUP_TIMEOUT_KEY]: timeout,
520
- [CLEANUP_STACK_TRACE_KEY]: stackTraceError
521
- }));
522
- }
523
- /**
524
- * Registers a callback function to be executed once after all tests within the current suite have completed.
525
- * This hook is useful for scenarios where you need to perform cleanup operations after all tests in a suite have run, such as closing database connections or cleaning up temporary files.
526
- *
527
- * **Note:** The `afterAll` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
528
- *
529
- * @param {Function} fn - The callback function to be executed after all tests.
530
- * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
531
- * @returns {void}
532
- * @example
533
- * ```ts
534
- * // Example of using afterAll to close a database connection
535
- * afterAll(async () => {
536
- * await database.disconnect();
537
- * });
538
- * ```
539
- */
540
- function afterAll(fn, timeout) {
541
- assertTypes(fn, "\"afterAll\" callback", ["function"]);
542
- const context = getChainableContext(this);
543
- const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
544
- return getCurrentSuite().on("afterAll", withTimeout(withSuiteFixtures("afterAll", fn, context, stackTraceError), timeout ?? getDefaultHookTimeout(), true, stackTraceError));
545
- }
546
- /**
547
- * Registers a callback function to be executed before each test within the current suite.
548
- * This hook is useful for scenarios where you need to reset or reinitialize the test environment before each test runs, such as resetting database states, clearing caches, or reinitializing variables.
549
- *
550
- * **Note:** The `beforeEach` hooks are executed in the order they are defined one after another. You can configure this by changing the `sequence.hooks` option in the config file.
551
- *
552
- * @param {Function} fn - The callback function to be executed before each test. This function receives an `TestContext` parameter if additional test context is needed.
553
- * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
554
- * @returns {void}
555
- * @example
556
- * ```ts
557
- * // Example of using beforeEach to reset a database state
558
- * beforeEach(async () => {
559
- * await database.reset();
560
- * });
561
- * ```
562
- */
563
- function beforeEach(fn, timeout = getDefaultHookTimeout()) {
564
- assertTypes(fn, "\"beforeEach\" callback", ["function"]);
565
- const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
566
- const wrapper = (context, suite) => {
567
- return withFixtures(fn, { suite })(context);
568
- };
569
- return getCurrentSuite().on("beforeEach", Object.assign(withTimeout(wrapper, timeout ?? getDefaultHookTimeout(), true, stackTraceError, abortIfTimeout), {
570
- [CLEANUP_TIMEOUT_KEY]: timeout,
571
- [CLEANUP_STACK_TRACE_KEY]: stackTraceError
572
- }));
573
- }
574
- /**
575
- * Registers a callback function to be executed after each test within the current suite has completed.
576
- * This hook is useful for scenarios where you need to clean up or reset the test environment after each test runs, such as deleting temporary files, clearing test-specific database entries, or resetting mocked functions.
577
- *
578
- * **Note:** The `afterEach` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
579
- *
580
- * @param {Function} fn - The callback function to be executed after each test. This function receives an `TestContext` parameter if additional test context is needed.
581
- * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
582
- * @returns {void}
583
- * @example
584
- * ```ts
585
- * // Example of using afterEach to delete temporary files created during a test
586
- * afterEach(async () => {
587
- * await fileSystem.deleteTempFiles();
588
- * });
589
- * ```
590
- */
591
- function afterEach(fn, timeout) {
592
- assertTypes(fn, "\"afterEach\" callback", ["function"]);
593
- const wrapper = (context, suite) => {
594
- return withFixtures(fn, { suite })(context);
595
- };
596
- return getCurrentSuite().on("afterEach", withTimeout(wrapper, timeout ?? getDefaultHookTimeout(), true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), abortIfTimeout));
597
- }
598
- /**
599
- * Registers a callback function to be executed when a test fails within the current suite.
600
- * This function allows for custom actions to be performed in response to test failures, such as logging, cleanup, or additional diagnostics.
601
- *
602
- * **Note:** The `onTestFailed` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
603
- *
604
- * @param {Function} fn - The callback function to be executed upon a test failure. The function receives the test result (including errors).
605
- * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
606
- * @throws {Error} Throws an error if the function is not called within a test.
607
- * @returns {void}
608
- * @example
609
- * ```ts
610
- * // Example of using onTestFailed to log failure details
611
- * onTestFailed(({ errors }) => {
612
- * console.log(`Test failed: ${test.name}`, errors);
613
- * });
614
- * ```
615
- */
616
- const onTestFailed = createTestHook("onTestFailed", (test, handler, timeout) => {
617
- test.onFailed ||= [];
618
- test.onFailed.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), abortIfTimeout));
619
- });
620
- /**
621
- * Registers a callback function to be executed when the current test finishes, regardless of the outcome (pass or fail).
622
- * This function is ideal for performing actions that should occur after every test execution, such as cleanup, logging, or resetting shared resources.
623
- *
624
- * This hook is useful if you have access to a resource in the test itself and you want to clean it up after the test finishes. It is a more compact way to clean up resources than using the combination of `beforeEach` and `afterEach`.
625
- *
626
- * **Note:** The `onTestFinished` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
627
- *
628
- * **Note:** The `onTestFinished` hook is not called if the test is canceled with a dynamic `ctx.skip()` call.
629
- *
630
- * @param {Function} fn - The callback function to be executed after a test finishes. The function can receive parameters providing details about the completed test, including its success or failure status.
631
- * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
632
- * @throws {Error} Throws an error if the function is not called within a test.
633
- * @returns {void}
634
- * @example
635
- * ```ts
636
- * // Example of using onTestFinished for cleanup
637
- * const db = await connectToDatabase();
638
- * onTestFinished(async () => {
639
- * await db.disconnect();
640
- * });
641
- * ```
642
- */
643
- const onTestFinished = createTestHook("onTestFinished", (test, handler, timeout) => {
644
- test.onFinished ||= [];
645
- test.onFinished.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), abortIfTimeout));
646
- });
647
- /**
648
- * Registers a callback function that wraps around all tests within the current suite.
649
- * The callback receives a `runSuite` function that must be called to run the suite's tests.
650
- * This hook is useful for scenarios where you need to wrap an entire suite in a context
651
- * (e.g., starting a server, opening a database connection that all tests share).
652
- *
653
- * **Note:** When multiple `aroundAll` hooks are registered, they are nested inside each other.
654
- * The first registered hook is the outermost wrapper.
655
- *
656
- * @param {Function} fn - The callback function that wraps the suite. Must call `runSuite()` to run the tests.
657
- * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
658
- * @returns {void}
659
- * @example
660
- * ```ts
661
- * // Example of using aroundAll to wrap suite in a tracing span
662
- * aroundAll(async (runSuite) => {
663
- * await tracer.trace('test-suite', runSuite);
664
- * });
665
- * ```
666
- * @example
667
- * ```ts
668
- * // Example of using aroundAll with fixtures
669
- * aroundAll(async (runSuite, { db }) => {
670
- * await db.transaction(() => runSuite());
671
- * });
672
- * ```
673
- */
674
- function aroundAll(fn, timeout) {
675
- assertTypes(fn, "\"aroundAll\" callback", ["function"]);
676
- const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
677
- const resolvedTimeout = timeout ?? getDefaultHookTimeout();
678
- const context = getChainableContext(this);
679
- return getCurrentSuite().on("aroundAll", Object.assign(withSuiteFixtures("aroundAll", fn, context, stackTraceError, 1), {
680
- [AROUND_TIMEOUT_KEY]: resolvedTimeout,
681
- [AROUND_STACK_TRACE_KEY]: stackTraceError
682
- }));
683
- }
684
- /**
685
- * Registers a callback function that wraps around each test within the current suite.
686
- * The callback receives a `runTest` function that must be called to run the test.
687
- * This hook is useful for scenarios where you need to wrap tests in a context (e.g., database transactions).
688
- *
689
- * **Note:** When multiple `aroundEach` hooks are registered, they are nested inside each other.
690
- * The first registered hook is the outermost wrapper.
691
- *
692
- * @param {Function} fn - The callback function that wraps the test. Must call `runTest()` to run the test.
693
- * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
694
- * @returns {void}
695
- * @example
696
- * ```ts
697
- * // Example of using aroundEach to wrap tests in a database transaction
698
- * aroundEach(async (runTest) => {
699
- * await database.transaction(() => runTest());
700
- * });
701
- * ```
702
- * @example
703
- * ```ts
704
- * // Example of using aroundEach with fixtures
705
- * aroundEach(async (runTest, { db }) => {
706
- * await db.transaction(() => runTest());
707
- * });
708
- * ```
709
- */
710
- function aroundEach(fn, timeout) {
711
- assertTypes(fn, "\"aroundEach\" callback", ["function"]);
712
- const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
713
- const resolvedTimeout = timeout ?? getDefaultHookTimeout();
714
- const wrapper = (runTest, context, suite) => {
715
- const innerFn = (ctx) => fn(runTest, ctx, suite);
716
- configureProps(innerFn, {
717
- index: 1,
718
- original: fn
719
- });
720
- return withFixtures(innerFn, { suite })(context);
721
- };
722
- return getCurrentSuite().on("aroundEach", Object.assign(wrapper, {
723
- [AROUND_TIMEOUT_KEY]: resolvedTimeout,
724
- [AROUND_STACK_TRACE_KEY]: stackTraceError
725
- }));
726
- }
727
- function withSuiteFixtures(suiteHook, fn, context, stackTraceError, contextIndex = 0) {
728
- return (...args) => {
729
- const suite = args.at(-1);
730
- const prefix = args.slice(0, -1);
731
- const wrapper = (ctx) => fn(...prefix, ctx, suite);
732
- configureProps(wrapper, {
733
- index: contextIndex,
734
- original: fn
735
- });
736
- const fixtures = context?.getFixtures();
737
- const fileContext = fixtures?.getFileContext(suite.file);
738
- return withFixtures(wrapper, {
739
- suiteHook,
740
- fixtures,
741
- context: fileContext,
742
- stackTraceError
743
- })();
744
- };
745
- }
746
- function getAroundHookTimeout(hook) {
747
- return AROUND_TIMEOUT_KEY in hook && typeof hook[AROUND_TIMEOUT_KEY] === "number" ? hook[AROUND_TIMEOUT_KEY] : getDefaultHookTimeout();
748
- }
749
- function getAroundHookStackTrace(hook) {
750
- return AROUND_STACK_TRACE_KEY in hook && hook[AROUND_STACK_TRACE_KEY] instanceof Error ? hook[AROUND_STACK_TRACE_KEY] : void 0;
751
- }
752
- function createTestHook(name, handler) {
753
- return (fn, timeout) => {
754
- assertTypes(fn, `"${name}" callback`, ["function"]);
755
- const current = getCurrentTest();
756
- if (!current) throw new Error(`Hook ${name}() can only be called inside a test`);
757
- return handler(current, fn, timeout);
758
- };
759
- }
760
- /**
761
- * If any tasks been marked as `only`, mark all other tasks as `skip`.
762
- */
763
- function interpretTaskModes(file, namePattern, testLocations, testIds, testTagsFilter, onlyMode, parentIsOnly, allowOnly) {
764
- const matchedLocations = [];
765
- const traverseSuite = (suite, parentIsOnly, parentMatchedWithLocation) => {
766
- const suiteIsOnly = parentIsOnly || suite.mode === "only";
767
- const hasSomeTasksOnly = onlyMode && suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
768
- suite.tasks.forEach((t) => {
769
- const includeTask = hasSomeTasksOnly ? t.mode === "only" || t.type === "suite" && someTasksAreOnly(t) : suiteIsOnly || t.mode === "only";
770
- if (onlyMode) {
771
- if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
772
- if (t.mode === "only") {
773
- checkAllowOnly(t, allowOnly);
774
- t.mode = "run";
775
- }
776
- } else if (t.mode === "run" && !includeTask) t.mode = "skip";
777
- else if (t.mode === "only") {
778
- checkAllowOnly(t, allowOnly);
779
- t.mode = "run";
780
- }
781
- }
782
- let hasLocationMatch = parentMatchedWithLocation;
783
- if (testLocations !== void 0 && testLocations.length !== 0) {
784
- if (t.location && testLocations?.includes(t.location.line)) {
785
- t.mode = "run";
786
- matchedLocations.push(t.location.line);
787
- hasLocationMatch = true;
788
- } else if (parentMatchedWithLocation) t.mode = "run";
789
- else if (t.type === "test") t.mode = "skip";
790
- }
791
- if (t.type === "test") {
792
- if (namePattern && !getTaskFullName(t).match(namePattern)) t.mode = "skip";
793
- if (testIds && !testIds.includes(t.id)) t.mode = "skip";
794
- if (testTagsFilter && !testTagsFilter(t.tags || [])) t.mode = "skip";
795
- } else if (t.type === "suite") if (t.mode === "skip") skipAllTasks(t);
796
- else if (t.mode === "todo") todoAllTasks(t);
797
- else traverseSuite(t, includeTask, hasLocationMatch);
798
- });
799
- if (suite.mode === "run" || suite.mode === "queued") {
800
- if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run" && i.mode !== "queued")) suite.mode = "skip";
801
- }
802
- };
803
- traverseSuite(file, parentIsOnly, false);
804
- const nonMatching = testLocations?.filter((loc) => !matchedLocations.includes(loc));
805
- if (nonMatching && nonMatching.length !== 0) {
806
- const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
807
- if (file.result === void 0) file.result = {
808
- state: "fail",
809
- errors: []
810
- };
811
- if (file.result.errors === void 0) file.result.errors = [];
812
- file.result.errors.push(processError(/* @__PURE__ */ new Error(`No test found in ${file.name} in ${message}`)));
813
- }
814
- }
815
- function getTaskFullName(task) {
816
- return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
817
- }
818
- function someTasksAreOnly(suite) {
819
- return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
820
- }
821
- function skipAllTasks(suite) {
822
- suite.tasks.forEach((t) => {
823
- if (t.mode === "run" || t.mode === "queued") {
824
- t.mode = "skip";
825
- if (t.type === "suite") skipAllTasks(t);
826
- }
827
- });
828
- }
829
- function todoAllTasks(suite) {
830
- suite.tasks.forEach((t) => {
831
- if (t.mode === "run" || t.mode === "queued") {
832
- t.mode = "todo";
833
- if (t.type === "suite") todoAllTasks(t);
834
- }
835
- });
836
- }
837
- function checkAllowOnly(task, allowOnly) {
838
- if (allowOnly) return;
839
- task.result = {
840
- state: "fail",
841
- errors: [processError(/* @__PURE__ */ new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"))]
842
- };
843
- }
844
- /* @__NO_SIDE_EFFECTS__ */
845
- function generateHash(str) {
846
- let hash = 0;
847
- if (str.length === 0) return `${hash}`;
848
- for (let i = 0; i < str.length; i++) {
849
- const char = str.charCodeAt(i);
850
- hash = (hash << 5) - hash + char;
851
- hash = hash & hash;
852
- }
853
- return `${hash}`;
854
- }
855
- function calculateSuiteHash(parent) {
856
- parent.tasks.forEach((t, idx) => {
857
- t.id = `${parent.id}_${idx}`;
858
- if (t.type === "suite") calculateSuiteHash(t);
859
- });
860
- }
861
- function createFileTask(filepath, root, projectName, pool, viteEnvironment) {
862
- const path = relative(root, filepath);
863
- const file = {
864
- id: /* @__PURE__ */ generateFileHash(path, projectName),
865
- name: path,
866
- fullName: path,
867
- type: "suite",
868
- mode: "queued",
869
- filepath,
870
- tasks: [],
871
- meta: Object.create(null),
872
- projectName,
873
- file: void 0,
874
- pool,
875
- viteEnvironment
876
- };
877
- file.file = file;
878
- return file;
879
- }
880
- /**
881
- * Generate a unique ID for a file based on its path and project name
882
- * @param file File relative to the root of the project to keep ID the same between different machines
883
- * @param projectName The name of the test project
884
- */
885
- /* @__NO_SIDE_EFFECTS__ */
886
- function generateFileHash(file, projectName) {
887
- return /* @__PURE__ */ generateHash(`${file}${projectName || ""}`);
888
- }
889
- function findTestFileStackTrace(testFilePath, error) {
890
- const lines = error.split("\n").slice(1);
891
- for (const line of lines) {
892
- const stack = parseSingleStack(line);
893
- if (stack && stack.file === testFilePath) return stack;
894
- }
895
- }
896
- /**
897
- * Return a function for running multiple async operations with limited concurrency.
898
- */
899
- function limitConcurrency(concurrency = Infinity) {
900
- let count = 0;
901
- let head;
902
- let tail;
903
- const finish = () => {
904
- count--;
905
- if (head) {
906
- head[0]();
907
- head = head[1];
908
- tail = head && tail;
909
- }
910
- };
911
- const acquire = () => {
912
- let released = false;
913
- const release = () => {
914
- if (!released) {
915
- released = true;
916
- finish();
917
- }
918
- };
919
- if (count++ < concurrency) return release;
920
- return new Promise((resolve) => {
921
- if (tail) tail = tail[1] = [() => resolve(release)];
922
- else head = tail = [() => resolve(release)];
923
- });
924
- };
925
- const limiterFn = (func, ...args) => {
926
- function run(release) {
927
- try {
928
- const result = func(...args);
929
- if (result instanceof Promise) return result.finally(release);
930
- release();
931
- return Promise.resolve(result);
932
- } catch (error) {
933
- release();
934
- return Promise.reject(error);
935
- }
936
- }
937
- const release = acquire();
938
- return release instanceof Promise ? release.then(run) : run(release);
939
- };
940
- return Object.assign(limiterFn, { acquire });
941
- }
942
- /**
943
- * Partition in tasks groups by consecutive concurrent
944
- */
945
- function partitionSuiteChildren(suite) {
946
- let tasksGroup = [];
947
- const tasksGroups = [];
948
- for (const c of suite.tasks) if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) tasksGroup.push(c);
949
- else {
950
- tasksGroups.push(tasksGroup);
951
- tasksGroup = [c];
952
- }
953
- if (tasksGroup.length > 0) tasksGroups.push(tasksGroup);
954
- return tasksGroups;
955
- }
956
- const filterMap = /* @__PURE__ */ new WeakMap();
957
- /**
958
- * @experimental
959
- */
960
- function matchesTags(testTags) {
961
- const runner = getRunner();
962
- const tagsFilter = runner._currentSpecification?.testTagsFilter ?? runner.config.tagsFilter;
963
- if (!tagsFilter) return true;
964
- let tagsFilterPredicate = filterMap.get(tagsFilter);
965
- if (!tagsFilterPredicate) {
966
- tagsFilterPredicate = createTagsFilter(tagsFilter, runner.config.tags);
967
- filterMap.set(tagsFilter, tagsFilterPredicate);
968
- }
969
- return tagsFilterPredicate(testTags);
970
- }
971
- function validateTags(config, tags) {
972
- if (!config.strictTags) return;
973
- const availableTags = new Set(config.tags.map((tag) => tag.name));
974
- for (const tag of tags) if (!availableTags.has(tag)) throw createNoTagsError(config.tags, tag);
975
- }
976
- function createNoTagsError(availableTags, tag, prefix = "tag") {
977
- if (!availableTags.length) throw new Error(`The Vitest config does't define any "tags", cannot apply "${tag}" ${prefix} for this test. See: https://vitest.dev/guide/test-tags`);
978
- throw new Error(`The ${prefix} "${tag}" is not defined in the configuration. Available tags are:\n${availableTags.map((t) => `- ${t.name}${t.description ? `: ${t.description}` : ""}`).join("\n")}`);
979
- }
980
- function createTagsFilter(tagsExpr, availableTags) {
981
- const matchers = tagsExpr.map((expr) => parseTagsExpression(expr, availableTags));
982
- return (testTags) => {
983
- return matchers.every((matcher) => matcher(testTags));
984
- };
985
- }
986
- function parseTagsExpression(expr, availableTags) {
987
- const stream = new TokenStream(tokenize(expr), expr);
988
- const ast = parseOrExpression(stream, availableTags);
989
- if (stream.peek().type !== "EOF") throw new Error(`Invalid tags expression: unexpected "${formatToken(stream.peek())}" in "${expr}"`);
990
- return (tags) => evaluateNode(ast, tags);
991
- }
992
- function formatToken(token) {
993
- switch (token.type) {
994
- case "TAG": return token.value;
995
- default: return formatTokenType(token.type);
996
- }
997
- }
998
- function tokenize(expr) {
999
- const tokens = [];
1000
- let i = 0;
1001
- while (i < expr.length) {
1002
- if (expr[i] === " " || expr[i] === " ") {
1003
- i++;
1004
- continue;
1005
- }
1006
- if (expr[i] === "(") {
1007
- tokens.push({ type: "LPAREN" });
1008
- i++;
1009
- continue;
1010
- }
1011
- if (expr[i] === ")") {
1012
- tokens.push({ type: "RPAREN" });
1013
- i++;
1014
- continue;
1015
- }
1016
- if (expr[i] === "!") {
1017
- tokens.push({ type: "NOT" });
1018
- i++;
1019
- continue;
1020
- }
1021
- if (expr.slice(i, i + 2) === "&&") {
1022
- tokens.push({ type: "AND" });
1023
- i += 2;
1024
- continue;
1025
- }
1026
- if (expr.slice(i, i + 2) === "||") {
1027
- tokens.push({ type: "OR" });
1028
- i += 2;
1029
- continue;
1030
- }
1031
- if (/^and(?:\s|\)|$)/i.test(expr.slice(i))) {
1032
- tokens.push({ type: "AND" });
1033
- i += 3;
1034
- continue;
1035
- }
1036
- if (/^or(?:\s|\)|$)/i.test(expr.slice(i))) {
1037
- tokens.push({ type: "OR" });
1038
- i += 2;
1039
- continue;
1040
- }
1041
- if (/^not\s/i.test(expr.slice(i))) {
1042
- tokens.push({ type: "NOT" });
1043
- i += 3;
1044
- continue;
1045
- }
1046
- let tag = "";
1047
- while (i < expr.length && expr[i] !== " " && expr[i] !== " " && expr[i] !== "(" && expr[i] !== ")" && expr[i] !== "!" && expr[i] !== "&" && expr[i] !== "|") {
1048
- const remaining = expr.slice(i);
1049
- if (tag === "" && (/^and(?:\s|\)|$)/i.test(remaining) || /^or(?:\s|\)|$)/i.test(remaining) || /^not\s/i.test(remaining))) break;
1050
- tag += expr[i];
1051
- i++;
1052
- }
1053
- if (tag) tokens.push({
1054
- type: "TAG",
1055
- value: tag
1056
- });
1057
- }
1058
- tokens.push({ type: "EOF" });
1059
- return tokens;
1060
- }
1061
- var TokenStream = class {
1062
- pos = 0;
1063
- constructor(tokens, expr) {
1064
- this.tokens = tokens;
1065
- this.expr = expr;
1066
- }
1067
- peek() {
1068
- return this.tokens[this.pos];
1069
- }
1070
- next() {
1071
- return this.tokens[this.pos++];
1072
- }
1073
- expect(type) {
1074
- const token = this.next();
1075
- if (token.type !== type) {
1076
- if (type === "RPAREN" && token.type === "EOF") throw new Error(`Invalid tags expression: missing closing ")" in "${this.expr}"`);
1077
- throw new Error(`Invalid tags expression: expected "${formatTokenType(type)}" but got "${formatToken(token)}" in "${this.expr}"`);
1078
- }
1079
- return token;
1080
- }
1081
- unexpectedToken() {
1082
- const token = this.peek();
1083
- if (token.type === "EOF") throw new Error(`Invalid tags expression: unexpected end of expression in "${this.expr}"`);
1084
- throw new Error(`Invalid tags expression: unexpected "${formatToken(token)}" in "${this.expr}"`);
1085
- }
1086
- };
1087
- function formatTokenType(type) {
1088
- switch (type) {
1089
- case "TAG": return "tag";
1090
- case "AND": return "and";
1091
- case "OR": return "or";
1092
- case "NOT": return "not";
1093
- case "LPAREN": return "(";
1094
- case "RPAREN": return ")";
1095
- case "EOF": return "end of expression";
1096
- }
1097
- }
1098
- function parseOrExpression(stream, availableTags) {
1099
- let left = parseAndExpression(stream, availableTags);
1100
- while (stream.peek().type === "OR") {
1101
- stream.next();
1102
- const right = parseAndExpression(stream, availableTags);
1103
- left = {
1104
- type: "or",
1105
- left,
1106
- right
1107
- };
1108
- }
1109
- return left;
1110
- }
1111
- function parseAndExpression(stream, availableTags) {
1112
- let left = parseUnaryExpression(stream, availableTags);
1113
- while (stream.peek().type === "AND") {
1114
- stream.next();
1115
- const right = parseUnaryExpression(stream, availableTags);
1116
- left = {
1117
- type: "and",
1118
- left,
1119
- right
1120
- };
1121
- }
1122
- return left;
1123
- }
1124
- function parseUnaryExpression(stream, availableTags) {
1125
- if (stream.peek().type === "NOT") {
1126
- stream.next();
1127
- return {
1128
- type: "not",
1129
- operand: parseUnaryExpression(stream, availableTags)
1130
- };
1131
- }
1132
- return parsePrimaryExpression(stream, availableTags);
1133
- }
1134
- function parsePrimaryExpression(stream, availableTags) {
1135
- const token = stream.peek();
1136
- if (token.type === "LPAREN") {
1137
- stream.next();
1138
- const expr = parseOrExpression(stream, availableTags);
1139
- stream.expect("RPAREN");
1140
- return expr;
1141
- }
1142
- if (token.type === "TAG") {
1143
- stream.next();
1144
- const tagValue = token.value;
1145
- return {
1146
- type: "tag",
1147
- value: tagValue,
1148
- pattern: resolveTagPattern(tagValue, availableTags)
1149
- };
1150
- }
1151
- stream.unexpectedToken();
1152
- }
1153
- function createWildcardRegex(pattern) {
1154
- return new RegExp(`^${pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`);
1155
- }
1156
- function resolveTagPattern(tagPattern, availableTags) {
1157
- if (tagPattern.includes("*")) {
1158
- const regex = createWildcardRegex(tagPattern);
1159
- if (!availableTags.some((tag) => regex.test(tag.name))) throw createNoTagsError(availableTags, tagPattern, "tag pattern");
1160
- return regex;
1161
- }
1162
- if (!availableTags.length || !availableTags.some((tag) => tag.name === tagPattern)) throw createNoTagsError(availableTags, tagPattern, "tag pattern");
1163
- return null;
1164
- }
1165
- function evaluateNode(node, tags) {
1166
- switch (node.type) {
1167
- case "tag":
1168
- if (node.pattern) return tags.some((tag) => node.pattern.test(tag));
1169
- return tags.includes(node.value);
1170
- case "not": return !evaluateNode(node.operand, tags);
1171
- case "and": return evaluateNode(node.left, tags) && evaluateNode(node.right, tags);
1172
- case "or": return evaluateNode(node.left, tags) || evaluateNode(node.right, tags);
1173
- }
1174
- }
1175
- function isTestCase(s) {
1176
- return s.type === "test";
1177
- }
1178
- function getTests(suite) {
1179
- const tests = [];
1180
- const arraySuites = toArray(suite);
1181
- for (const s of arraySuites) if (isTestCase(s)) tests.push(s);
1182
- else for (const task of s.tasks) if (isTestCase(task)) tests.push(task);
1183
- else {
1184
- const taskTests = getTests(task);
1185
- for (const test of taskTests) tests.push(test);
1186
- }
1187
- return tests;
1188
- }
1189
- function getTasks(tasks = []) {
1190
- return toArray(tasks).flatMap((s) => isTestCase(s) ? [s] : [s, ...getTasks(s.tasks)]);
1191
- }
1192
- function getSuites(suite) {
1193
- return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
1194
- }
1195
- function hasTests(suite) {
1196
- return toArray(suite).some((s) => s.tasks.some((c) => isTestCase(c) || hasTests(c)));
1197
- }
1198
- function hasFailed(suite) {
1199
- return toArray(suite).some((s) => s.result?.state === "fail" || s.type === "suite" && hasFailed(s.tasks));
1200
- }
1201
- function getNames(task) {
1202
- const names = [task.name];
1203
- let current = task;
1204
- while (current?.suite) {
1205
- current = current.suite;
1206
- if (current?.name) names.unshift(current.name);
1207
- }
1208
- if (current !== task.file) names.unshift(task.file.name);
1209
- return names;
1210
- }
1211
- function getFullName(task, separator = " > ") {
1212
- return getNames(task).join(separator);
1213
- }
1214
- function getTestName(task, separator = " > ") {
1215
- return getNames(task).slice(1).join(separator);
1216
- }
1217
- function createTaskName(names, separator = " > ") {
1218
- return names.filter((name) => name !== void 0).join(separator);
1219
- }
1220
- /**
1221
- * Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
1222
- * Suites can contain both tests and other suites, enabling complex test structures.
1223
- *
1224
- * @param {string} name - The name of the suite, used for identification and reporting.
1225
- * @param {Function} fn - A function that defines the tests and suites within this suite.
1226
- * @example
1227
- * ```ts
1228
- * // Define a suite with two tests
1229
- * suite('Math operations', () => {
1230
- * test('should add two numbers', () => {
1231
- * expect(add(1, 2)).toBe(3);
1232
- * });
1233
- *
1234
- * test('should subtract two numbers', () => {
1235
- * expect(subtract(5, 2)).toBe(3);
1236
- * });
1237
- * });
1238
- * ```
1239
- * @example
1240
- * ```ts
1241
- * // Define nested suites
1242
- * suite('String operations', () => {
1243
- * suite('Trimming', () => {
1244
- * test('should trim whitespace from start and end', () => {
1245
- * expect(' hello '.trim()).toBe('hello');
1246
- * });
1247
- * });
1248
- *
1249
- * suite('Concatenation', () => {
1250
- * test('should concatenate two strings', () => {
1251
- * expect('hello' + ' ' + 'world').toBe('hello world');
1252
- * });
1253
- * });
1254
- * });
1255
- * ```
1256
- */
1257
- const suite = createSuite();
1258
- /**
1259
- * Defines a test case with a given name and test function. The test function can optionally be configured with test options.
1260
- *
1261
- * @param {string | Function} name - The name of the test or a function that will be used as a test name.
1262
- * @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
1263
- * @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
1264
- * @throws {Error} If called inside another test function.
1265
- * @example
1266
- * ```ts
1267
- * // Define a simple test
1268
- * test('should add two numbers', () => {
1269
- * expect(add(1, 2)).toBe(3);
1270
- * });
1271
- * ```
1272
- * @example
1273
- * ```ts
1274
- * // Define a test with options
1275
- * test('should subtract two numbers', { retry: 3 }, () => {
1276
- * expect(subtract(5, 2)).toBe(3);
1277
- * });
1278
- * ```
1279
- */
1280
- const test = createTest(function(name, optionsOrFn, optionsOrTest) {
1281
- if (getCurrentTest()) throw new Error("Calling the test function inside another test function is not allowed. Please put it inside \"describe\" or \"suite\" so it can be properly collected.");
1282
- getCurrentSuite().test.fn.call(this, formatName(name), optionsOrFn, optionsOrTest);
1283
- });
1284
- /**
1285
- * Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
1286
- * Suites can contain both tests and other suites, enabling complex test structures.
1287
- *
1288
- * @param {string} name - The name of the suite, used for identification and reporting.
1289
- * @param {Function} fn - A function that defines the tests and suites within this suite.
1290
- * @example
1291
- * ```ts
1292
- * // Define a suite with two tests
1293
- * describe('Math operations', () => {
1294
- * test('should add two numbers', () => {
1295
- * expect(add(1, 2)).toBe(3);
1296
- * });
1297
- *
1298
- * test('should subtract two numbers', () => {
1299
- * expect(subtract(5, 2)).toBe(3);
1300
- * });
1301
- * });
1302
- * ```
1303
- * @example
1304
- * ```ts
1305
- * // Define nested suites
1306
- * describe('String operations', () => {
1307
- * describe('Trimming', () => {
1308
- * test('should trim whitespace from start and end', () => {
1309
- * expect(' hello '.trim()).toBe('hello');
1310
- * });
1311
- * });
1312
- *
1313
- * describe('Concatenation', () => {
1314
- * test('should concatenate two strings', () => {
1315
- * expect('hello' + ' ' + 'world').toBe('hello world');
1316
- * });
1317
- * });
1318
- * });
1319
- * ```
1320
- */
1321
- const describe = suite;
1322
- /**
1323
- * Defines a test case with a given name and test function. The test function can optionally be configured with test options.
1324
- *
1325
- * @param {string | Function} name - The name of the test or a function that will be used as a test name.
1326
- * @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
1327
- * @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
1328
- * @throws {Error} If called inside another test function.
1329
- * @example
1330
- * ```ts
1331
- * // Define a simple test
1332
- * it('adds two numbers', () => {
1333
- * expect(add(1, 2)).toBe(3);
1334
- * });
1335
- * ```
1336
- * @example
1337
- * ```ts
1338
- * // Define a test with options
1339
- * it('subtracts two numbers', { retry: 3 }, () => {
1340
- * expect(subtract(5, 2)).toBe(3);
1341
- * });
1342
- * ```
1343
- */
1344
- const it = test;
1345
- let runner;
1346
- let defaultSuite;
1347
- let currentTestFilepath;
1348
- function assert(condition, message) {
1349
- if (!condition) throw new Error(`Vitest failed to find ${message}. One of the following is possible:
1350
- - "vitest" is imported directly without running "vitest" command
1351
- - "vitest" is imported inside "globalSetup" (to fix this, use "setupFiles" instead, because "globalSetup" runs in a different context)
1352
- - "vitest" is imported inside Vite / Vitest config file
1353
- - Otherwise, it might be a Vitest bug. Please report it to https://github.com/vitest-dev/vitest/issues
1354
- `);
1355
- }
1356
- function getDefaultSuite() {
1357
- assert(defaultSuite, "the default suite");
1358
- return defaultSuite;
1359
- }
1360
- function getRunner() {
1361
- assert(runner, "the runner");
1362
- return runner;
1363
- }
1364
- function createDefaultSuite(runner) {
1365
- const config = runner.config.sequence;
1366
- const options = {};
1367
- if (config.concurrent != null) options.concurrent = config.concurrent;
1368
- const collector = suite("", options, () => {});
1369
- delete collector.suite;
1370
- return collector;
1371
- }
1372
- function clearCollectorContext(file, currentRunner) {
1373
- currentTestFilepath = file.filepath;
1374
- runner = currentRunner;
1375
- if (!defaultSuite) defaultSuite = createDefaultSuite(currentRunner);
1376
- defaultSuite.file = file;
1377
- collectorContext.tasks.length = 0;
1378
- defaultSuite.clear();
1379
- collectorContext.currentSuite = defaultSuite;
1380
- }
1381
- function getCurrentSuite() {
1382
- const currentSuite = collectorContext.currentSuite || defaultSuite;
1383
- assert(currentSuite, "the current suite");
1384
- return currentSuite;
1385
- }
1386
- function createSuiteHooks() {
1387
- return {
1388
- beforeAll: [],
1389
- afterAll: [],
1390
- beforeEach: [],
1391
- afterEach: [],
1392
- aroundEach: [],
1393
- aroundAll: []
1394
- };
1395
- }
1396
- const POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
1397
- function parseArguments(optionsOrFn, timeoutOrTest) {
1398
- if (timeoutOrTest != null && typeof timeoutOrTest === "object") throw new TypeError(`Signature "test(name, fn, { ... })" was deprecated in Vitest 3 and removed in Vitest 4. Please, provide options as a second argument instead.`);
1399
- let options = {};
1400
- let fn;
1401
- if (typeof timeoutOrTest === "number") options = { timeout: timeoutOrTest };
1402
- else if (typeof optionsOrFn === "object") options = optionsOrFn;
1403
- if (typeof optionsOrFn === "function") {
1404
- if (typeof timeoutOrTest === "function") throw new TypeError("Cannot use two functions as arguments. Please use the second argument for options.");
1405
- fn = optionsOrFn;
1406
- } else if (typeof timeoutOrTest === "function") fn = timeoutOrTest;
1407
- return {
1408
- options,
1409
- handler: fn
1410
- };
1411
- }
1412
- function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions) {
1413
- const tasks = [];
1414
- let suite;
1415
- initSuite(true);
1416
- const task = function(name = "", options = {}) {
1417
- const currentSuite = collectorContext.currentSuite?.suite;
1418
- const testTags = unique([...(currentSuite ?? collectorContext.currentSuite?.file)?.tags || [], ...toArray(options.tags)]);
1419
- const tagsOptions = testTags.map((tag) => {
1420
- const tagDefinition = runner.config.tags?.find((t) => t.name === tag);
1421
- if (!tagDefinition && runner.config.strictTags) throw createNoTagsError(runner.config.tags, tag);
1422
- return tagDefinition;
1423
- }).filter((r) => r != null).sort((tag1, tag2) => (tag2.priority ?? POSITIVE_INFINITY) - (tag1.priority ?? POSITIVE_INFINITY)).reduce((acc, tag) => {
1424
- const { name, description, priority, meta, ...options } = tag;
1425
- Object.assign(acc, options);
1426
- if (meta) acc.meta = Object.assign(acc.meta ?? Object.create(null), meta);
1427
- return acc;
1428
- }, {});
1429
- const testOwnMeta = options.meta;
1430
- options = {
1431
- ...tagsOptions,
1432
- ...options
1433
- };
1434
- const timeout = options.timeout ?? runner.config.testTimeout;
1435
- const parentMeta = currentSuite?.meta;
1436
- const tagMeta = tagsOptions.meta;
1437
- const testMeta = Object.create(null);
1438
- if (tagMeta) Object.assign(testMeta, tagMeta);
1439
- if (parentMeta) Object.assign(testMeta, parentMeta);
1440
- if (testOwnMeta) Object.assign(testMeta, testOwnMeta);
1441
- const task = {
1442
- id: "",
1443
- name,
1444
- fullName: createTaskName([currentSuite?.fullName ?? collectorContext.currentSuite?.file?.fullName, name]),
1445
- fullTestName: createTaskName([currentSuite?.fullTestName, name]),
1446
- suite: currentSuite,
1447
- each: options.each,
1448
- fails: options.fails,
1449
- context: void 0,
1450
- type: "test",
1451
- file: currentSuite?.file ?? collectorContext.currentSuite?.file,
1452
- timeout,
1453
- retry: options.retry ?? runner.config.retry,
1454
- repeats: options.repeats,
1455
- mode: options.only ? "only" : options.skip ? "skip" : options.todo ? "todo" : "run",
1456
- meta: testMeta,
1457
- annotations: [],
1458
- artifacts: [],
1459
- tags: testTags
1460
- };
1461
- const handler = options.handler;
1462
- if (task.mode === "run" && !handler) task.mode = "todo";
1463
- if (options.concurrent ?? (!options.sequential && runner.config.sequence.concurrent)) task.concurrent = true;
1464
- task.shuffle = suiteOptions?.shuffle;
1465
- const context = createTestContext(task, runner);
1466
- Object.defineProperty(task, "context", {
1467
- value: context,
1468
- enumerable: false
1469
- });
1470
- setTestFixture(context, options.fixtures ?? new TestFixtures());
1471
- const limit = Error.stackTraceLimit;
1472
- Error.stackTraceLimit = 10;
1473
- const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
1474
- Error.stackTraceLimit = limit;
1475
- if (handler) setFn(task, withTimeout(withCancel(withAwaitAsyncAssertions(withFixtures(handler, { context }), task), task.context.signal), timeout, false, stackTraceError, (_, error) => abortIfTimeout([context], error)));
1476
- if (runner.config.includeTaskLocation) {
1477
- const error = stackTraceError.stack;
1478
- const stack = findTestFileStackTrace(currentTestFilepath, error);
1479
- if (stack) task.location = {
1480
- line: stack.line,
1481
- column: stack.column
1482
- };
1483
- }
1484
- tasks.push(task);
1485
- return task;
1486
- };
1487
- const test = createTest(function(name, optionsOrFn, timeoutOrTest) {
1488
- let { options, handler } = parseArguments(optionsOrFn, timeoutOrTest);
1489
- if (typeof suiteOptions === "object") options = Object.assign({}, suiteOptions, options);
1490
- const concurrent = this.concurrent ?? (!this.sequential && options?.concurrent);
1491
- if (options.concurrent != null && concurrent != null) options.concurrent = concurrent;
1492
- const sequential = this.sequential ?? (!this.concurrent && options?.sequential);
1493
- if (options.sequential != null && sequential != null) options.sequential = sequential;
1494
- const test = task(formatName(name), {
1495
- ...this,
1496
- ...options,
1497
- handler
1498
- });
1499
- test.type = "test";
1500
- });
1501
- const collector = {
1502
- type: "collector",
1503
- name,
1504
- mode,
1505
- suite,
1506
- options: suiteOptions,
1507
- test,
1508
- file: suite.file,
1509
- tasks,
1510
- collect,
1511
- task,
1512
- clear,
1513
- on: addHook
1514
- };
1515
- function addHook(name, ...fn) {
1516
- getHooks(suite)[name].push(...fn);
1517
- }
1518
- function initSuite(includeLocation) {
1519
- if (typeof suiteOptions === "number") suiteOptions = { timeout: suiteOptions };
1520
- const currentSuite = collectorContext.currentSuite?.suite;
1521
- const parentTask = currentSuite ?? collectorContext.currentSuite?.file;
1522
- const suiteTags = toArray(suiteOptions?.tags);
1523
- validateTags(runner.config, suiteTags);
1524
- suite = {
1525
- id: "",
1526
- type: "suite",
1527
- name,
1528
- fullName: createTaskName([currentSuite?.fullName ?? collectorContext.currentSuite?.file?.fullName, name]),
1529
- fullTestName: createTaskName([currentSuite?.fullTestName, name]),
1530
- suite: currentSuite,
1531
- mode,
1532
- each,
1533
- file: currentSuite?.file ?? collectorContext.currentSuite?.file,
1534
- shuffle: suiteOptions?.shuffle,
1535
- tasks: [],
1536
- meta: suiteOptions?.meta ?? Object.create(null),
1537
- concurrent: suiteOptions?.concurrent,
1538
- tags: unique([...parentTask?.tags || [], ...suiteTags])
1539
- };
1540
- if (runner && includeLocation && runner.config.includeTaskLocation) {
1541
- const limit = Error.stackTraceLimit;
1542
- Error.stackTraceLimit = 15;
1543
- const error = (/* @__PURE__ */ new Error("stacktrace")).stack;
1544
- Error.stackTraceLimit = limit;
1545
- const stack = findTestFileStackTrace(currentTestFilepath, error);
1546
- if (stack) suite.location = {
1547
- line: stack.line,
1548
- column: stack.column
1549
- };
1550
- }
1551
- setHooks(suite, createSuiteHooks());
1552
- }
1553
- function clear() {
1554
- tasks.length = 0;
1555
- initSuite(false);
1556
- }
1557
- async function collect(file) {
1558
- if (!file) throw new TypeError("File is required to collect tasks.");
1559
- if (factory) await runWithSuite(collector, () => factory(test));
1560
- const allChildren = [];
1561
- for (const i of tasks) allChildren.push(i.type === "collector" ? await i.collect(file) : i);
1562
- suite.tasks = allChildren;
1563
- return suite;
1564
- }
1565
- collectTask(collector);
1566
- return collector;
1567
- }
1568
- function withAwaitAsyncAssertions(fn, task) {
1569
- return (async (...args) => {
1570
- const fnResult = await fn(...args);
1571
- if (task.promises) {
1572
- const errors = (await Promise.allSettled(task.promises)).map((r) => r.status === "rejected" ? r.reason : void 0).filter(Boolean);
1573
- if (errors.length) throw errors;
1574
- }
1575
- return fnResult;
1576
- });
1577
- }
1578
- function createSuite() {
1579
- function suiteFn(name, factoryOrOptions, optionsOrFactory) {
1580
- if (getCurrentTest()) throw new Error("Calling the suite function inside test function is not allowed. It can be only called at the top level or inside another suite function.");
1581
- const currentSuite = collectorContext.currentSuite || defaultSuite;
1582
- let { options, handler: factory } = parseArguments(factoryOrOptions, optionsOrFactory);
1583
- const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false;
1584
- const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false;
1585
- const { meta: parentMeta, ...parentOptions } = currentSuite?.options || {};
1586
- options = {
1587
- ...parentOptions,
1588
- ...options
1589
- };
1590
- const shuffle = this.shuffle ?? options.shuffle ?? currentSuite?.options?.shuffle ?? runner?.config.sequence.shuffle;
1591
- if (shuffle != null) options.shuffle = shuffle;
1592
- let mode = this.only ?? options.only ? "only" : this.skip ?? options.skip ? "skip" : this.todo ?? options.todo ? "todo" : "run";
1593
- if (mode === "run" && !factory) mode = "todo";
1594
- const isConcurrent = isConcurrentSpecified || options.concurrent && !isSequentialSpecified;
1595
- const isSequential = isSequentialSpecified || options.sequential && !isConcurrentSpecified;
1596
- if (isConcurrent != null) options.concurrent = isConcurrent && !isSequential;
1597
- if (isSequential != null) options.sequential = isSequential && !isConcurrent;
1598
- if (parentMeta) options.meta = Object.assign(Object.create(null), parentMeta, options.meta);
1599
- return createSuiteCollector(formatName(name), factory, mode, this.each, options);
1600
- }
1601
- suiteFn.each = function(cases, ...args) {
1602
- const context = getChainableContext(this);
1603
- const suite = context.withContext();
1604
- context.setContext("each", true);
1605
- if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
1606
- return (name, optionsOrFn, fnOrOptions) => {
1607
- const _name = formatName(name);
1608
- const arrayOnlyCases = cases.every(Array.isArray);
1609
- const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
1610
- const fnFirst = typeof optionsOrFn === "function";
1611
- cases.forEach((i, idx) => {
1612
- const items = Array.isArray(i) ? i : [i];
1613
- if (fnFirst) if (arrayOnlyCases) suite(formatTitle(_name, items, idx), handler ? () => handler(...items) : void 0, options.timeout);
1614
- else suite(formatTitle(_name, items, idx), handler ? () => handler(i) : void 0, options.timeout);
1615
- else if (arrayOnlyCases) suite(formatTitle(_name, items, idx), options, handler ? () => handler(...items) : void 0);
1616
- else suite(formatTitle(_name, items, idx), options, handler ? () => handler(i) : void 0);
1617
- });
1618
- context.setContext("each", void 0);
1619
- };
1620
- };
1621
- suiteFn.for = function(cases, ...args) {
1622
- if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
1623
- return (name, optionsOrFn, fnOrOptions) => {
1624
- const name_ = formatName(name);
1625
- const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
1626
- cases.forEach((item, idx) => {
1627
- suite(formatTitle(name_, toArray(item), idx), options, handler ? () => handler(item) : void 0);
1628
- });
1629
- };
1630
- };
1631
- suiteFn.skipIf = (condition) => condition ? suite.skip : suite;
1632
- suiteFn.runIf = (condition) => condition ? suite : suite.skip;
1633
- return createChainable([
1634
- "concurrent",
1635
- "sequential",
1636
- "shuffle",
1637
- "skip",
1638
- "only",
1639
- "todo"
1640
- ], suiteFn);
1641
- }
1642
- function createTaskCollector(fn) {
1643
- const taskFn = fn;
1644
- taskFn.each = function(cases, ...args) {
1645
- const context = getChainableContext(this);
1646
- const test = context.withContext();
1647
- context.setContext("each", true);
1648
- if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
1649
- return (name, optionsOrFn, fnOrOptions) => {
1650
- const _name = formatName(name);
1651
- const arrayOnlyCases = cases.every(Array.isArray);
1652
- const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
1653
- const fnFirst = typeof optionsOrFn === "function";
1654
- cases.forEach((i, idx) => {
1655
- const items = Array.isArray(i) ? i : [i];
1656
- if (fnFirst) if (arrayOnlyCases) test(formatTitle(_name, items, idx), handler ? () => handler(...items) : void 0, options.timeout);
1657
- else test(formatTitle(_name, items, idx), handler ? () => handler(i) : void 0, options.timeout);
1658
- else if (arrayOnlyCases) test(formatTitle(_name, items, idx), options, handler ? () => handler(...items) : void 0);
1659
- else test(formatTitle(_name, items, idx), options, handler ? () => handler(i) : void 0);
1660
- });
1661
- context.setContext("each", void 0);
1662
- };
1663
- };
1664
- taskFn.for = function(cases, ...args) {
1665
- const test = getChainableContext(this).withContext();
1666
- if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
1667
- return (name, optionsOrFn, fnOrOptions) => {
1668
- const _name = formatName(name);
1669
- const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
1670
- cases.forEach((item, idx) => {
1671
- const handlerWrapper = handler ? (ctx) => handler(item, ctx) : void 0;
1672
- if (handlerWrapper) configureProps(handlerWrapper, {
1673
- index: 1,
1674
- original: handler
1675
- });
1676
- test(formatTitle(_name, toArray(item), idx), options, handlerWrapper);
1677
- });
1678
- };
1679
- };
1680
- taskFn.skipIf = function(condition) {
1681
- return condition ? this.skip : this;
1682
- };
1683
- taskFn.runIf = function(condition) {
1684
- return condition ? this : this.skip;
1685
- };
1686
- /**
1687
- * Parse builder pattern arguments into a fixtures object.
1688
- * Handles both builder pattern (name, options?, value) and object syntax.
1689
- */
1690
- function parseBuilderFixtures(fixturesOrName, optionsOrFn, maybeFn) {
1691
- if (typeof fixturesOrName !== "string") return fixturesOrName;
1692
- const fixtureName = fixturesOrName;
1693
- let fixtureOptions;
1694
- let fixtureValue;
1695
- if (maybeFn !== void 0) {
1696
- fixtureOptions = optionsOrFn;
1697
- fixtureValue = maybeFn;
1698
- } else if (optionsOrFn !== null && typeof optionsOrFn === "object" && !Array.isArray(optionsOrFn) && TestFixtures.isFixtureOptions(optionsOrFn)) {
1699
- fixtureOptions = optionsOrFn;
1700
- fixtureValue = {};
1701
- } else {
1702
- fixtureOptions = void 0;
1703
- fixtureValue = optionsOrFn;
1704
- }
1705
- if (typeof fixtureValue === "function") {
1706
- const builderFn = fixtureValue;
1707
- const fixture = async (ctx, use) => {
1708
- let cleanup;
1709
- const onCleanup = (fn) => {
1710
- if (cleanup !== void 0) throw new Error("onCleanup can only be called once per fixture. Define separate fixtures if you need multiple cleanup functions.");
1711
- cleanup = fn;
1712
- };
1713
- await use(await builderFn(ctx, { onCleanup }));
1714
- if (cleanup) await cleanup();
1715
- };
1716
- configureProps(fixture, { original: builderFn });
1717
- if (fixtureOptions) return { [fixtureName]: [fixture, fixtureOptions] };
1718
- return { [fixtureName]: fixture };
1719
- }
1720
- if (fixtureOptions) return { [fixtureName]: [fixtureValue, fixtureOptions] };
1721
- return { [fixtureName]: fixtureValue };
1722
- }
1723
- taskFn.override = function(fixturesOrName, optionsOrFn, maybeFn) {
1724
- const userFixtures = parseBuilderFixtures(fixturesOrName, optionsOrFn, maybeFn);
1725
- getChainableContext(this).getFixtures().override(runner, userFixtures);
1726
- return this;
1727
- };
1728
- taskFn.scoped = function(fixtures) {
1729
- console.warn(`test.scoped() is deprecated and will be removed in future versions. Please use test.override() instead.`);
1730
- return this.override(fixtures);
1731
- };
1732
- taskFn.extend = function(fixturesOrName, optionsOrFn, maybeFn) {
1733
- const userFixtures = parseBuilderFixtures(fixturesOrName, optionsOrFn, maybeFn);
1734
- const fixtures = getChainableContext(this).getFixtures().extend(runner, userFixtures);
1735
- const _test = createTest(function(name, optionsOrFn, optionsOrTest) {
1736
- fn.call(this, formatName(name), optionsOrFn, optionsOrTest);
1737
- });
1738
- getChainableContext(_test).mergeContext({ fixtures });
1739
- return _test;
1740
- };
1741
- taskFn.describe = suite;
1742
- taskFn.suite = suite;
1743
- taskFn.beforeEach = beforeEach;
1744
- taskFn.afterEach = afterEach;
1745
- taskFn.beforeAll = beforeAll;
1746
- taskFn.afterAll = afterAll;
1747
- taskFn.aroundEach = aroundEach;
1748
- taskFn.aroundAll = aroundAll;
1749
- return createChainable([
1750
- "concurrent",
1751
- "sequential",
1752
- "skip",
1753
- "only",
1754
- "todo",
1755
- "fails"
1756
- ], taskFn, { fixtures: new TestFixtures() });
1757
- }
1758
- function createTest(fn) {
1759
- return createTaskCollector(fn);
1760
- }
1761
- function formatName(name) {
1762
- return typeof name === "string" ? name : typeof name === "function" ? name.name || "<anonymous>" : String(name);
1763
- }
1764
- function formatTitle(template, items, idx) {
1765
- if (template.includes("%#") || template.includes("%$")) template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/%\$/g, `${idx + 1}`).replace(/__vitest_escaped_%__/g, "%%");
1766
- const count = template.split("%").length - 1;
1767
- if (template.includes("%f")) (template.match(/%f/g) || []).forEach((_, i) => {
1768
- if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
1769
- let occurrence = 0;
1770
- template = template.replace(/%f/g, (match) => {
1771
- occurrence++;
1772
- return occurrence === i + 1 ? "-%f" : match;
1773
- });
1774
- }
1775
- });
1776
- const isObjectItem = isObject(items[0]);
1777
- function formatAttribute(s) {
1778
- return s.replace(/\$([$\w.]+)/g, (_, key) => {
1779
- const isArrayKey = /^\d+$/.test(key);
1780
- if (!isObjectItem && !isArrayKey) return `$${key}`;
1781
- const arrayElement = isArrayKey ? objectAttr(items, key) : void 0;
1782
- return objDisplay(isObjectItem ? objectAttr(items[0], key, arrayElement) : arrayElement, { truncate: runner?.config?.chaiConfig?.truncateThreshold });
1783
- });
1784
- }
1785
- let output = "";
1786
- let i = 0;
1787
- handleRegexMatch(template, formatRegExp, (match) => {
1788
- if (i < count) output += format(match[0], items[i++]);
1789
- else output += match[0];
1790
- }, (nonMatch) => {
1791
- output += formatAttribute(nonMatch);
1792
- });
1793
- return output;
1794
- }
1795
- function handleRegexMatch(input, regex, onMatch, onNonMatch) {
1796
- let lastIndex = 0;
1797
- for (const m of input.matchAll(regex)) {
1798
- if (lastIndex < m.index) onNonMatch(input.slice(lastIndex, m.index));
1799
- onMatch(m);
1800
- lastIndex = m.index + m[0].length;
1801
- }
1802
- if (lastIndex < input.length) onNonMatch(input.slice(lastIndex));
1803
- }
1804
- function formatTemplateString(cases, args) {
1805
- const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
1806
- const res = [];
1807
- for (let i = 0; i < Math.floor(args.length / header.length); i++) {
1808
- const oneCase = {};
1809
- for (let j = 0; j < header.length; j++) oneCase[header[j]] = args[i * header.length + j];
1810
- res.push(oneCase);
1811
- }
1812
- return res;
1813
- }
1814
- const now$2 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
1815
- const collectorContext = {
1816
- tasks: [],
1817
- currentSuite: null
1818
- };
1819
- function collectTask(task) {
1820
- collectorContext.currentSuite?.tasks.push(task);
1821
- }
1822
- async function runWithSuite(suite, fn) {
1823
- const prev = collectorContext.currentSuite;
1824
- collectorContext.currentSuite = suite;
1825
- await fn();
1826
- collectorContext.currentSuite = prev;
1827
- }
1828
- function withTimeout(fn, timeout, isHook = false, stackTraceError, onTimeout) {
1829
- if (timeout <= 0 || timeout === Number.POSITIVE_INFINITY) return fn;
1830
- const { setTimeout, clearTimeout } = getSafeTimers();
1831
- return (function runWithTimeout(...args) {
1832
- const startTime = now$2();
1833
- const runner = getRunner();
1834
- runner._currentTaskStartTime = startTime;
1835
- runner._currentTaskTimeout = timeout;
1836
- return new Promise((resolve_, reject_) => {
1837
- const timer = setTimeout(() => {
1838
- clearTimeout(timer);
1839
- rejectTimeoutError();
1840
- }, timeout);
1841
- timer.unref?.();
1842
- function rejectTimeoutError() {
1843
- const error = makeTimeoutError(isHook, timeout, stackTraceError);
1844
- onTimeout?.(args, error);
1845
- reject_(error);
1846
- }
1847
- function resolve(result) {
1848
- runner._currentTaskStartTime = void 0;
1849
- runner._currentTaskTimeout = void 0;
1850
- clearTimeout(timer);
1851
- if (now$2() - startTime >= timeout) {
1852
- rejectTimeoutError();
1853
- return;
1854
- }
1855
- resolve_(result);
1856
- }
1857
- function reject(error) {
1858
- runner._currentTaskStartTime = void 0;
1859
- runner._currentTaskTimeout = void 0;
1860
- clearTimeout(timer);
1861
- reject_(error);
1862
- }
1863
- try {
1864
- const result = fn(...args);
1865
- if (typeof result === "object" && result != null && typeof result.then === "function") result.then(resolve, reject);
1866
- else resolve(result);
1867
- } catch (error) {
1868
- reject(error);
1869
- }
1870
- });
1871
- });
1872
- }
1873
- function withCancel(fn, signal) {
1874
- return (function runWithCancel(...args) {
1875
- return new Promise((resolve, reject) => {
1876
- signal.addEventListener("abort", () => reject(signal.reason));
1877
- try {
1878
- const result = fn(...args);
1879
- if (typeof result === "object" && result != null && typeof result.then === "function") result.then(resolve, reject);
1880
- else resolve(result);
1881
- } catch (error) {
1882
- reject(error);
1883
- }
1884
- });
1885
- });
1886
- }
1887
- const abortControllers = /* @__PURE__ */ new WeakMap();
1888
- function abortIfTimeout([context], error) {
1889
- if (context) abortContextSignal(context, error);
1890
- }
1891
- function abortContextSignal(context, error) {
1892
- abortControllers.get(context)?.abort(error);
1893
- }
1894
- function createTestContext(test, runner) {
1895
- const context = function() {
1896
- throw new Error("done() callback is deprecated, use promise instead");
1897
- };
1898
- let abortController = abortControllers.get(context);
1899
- if (!abortController) {
1900
- abortController = new AbortController();
1901
- abortControllers.set(context, abortController);
1902
- }
1903
- context.signal = abortController.signal;
1904
- context.task = test;
1905
- context.skip = (condition, note) => {
1906
- if (condition === false) return;
1907
- test.result ??= { state: "skip" };
1908
- test.result.pending = true;
1909
- throw new PendingError("test is skipped; abort execution", test, typeof condition === "string" ? condition : note);
1910
- };
1911
- context.annotate = ((message, type, attachment) => {
1912
- if (test.result && test.result.state !== "run") throw new Error(`Cannot annotate tests outside of the test run. The test "${test.name}" finished running with the "${test.result.state}" state already.`);
1913
- const annotation = {
1914
- message,
1915
- type: typeof type === "object" || type === void 0 ? "notice" : type
1916
- };
1917
- const annotationAttachment = typeof type === "object" ? type : attachment;
1918
- if (annotationAttachment) {
1919
- annotation.attachment = annotationAttachment;
1920
- manageArtifactAttachment(annotation.attachment);
1921
- }
1922
- return recordAsyncOperation(test, recordArtifact(test, {
1923
- type: "internal:annotation",
1924
- annotation
1925
- }).then(async ({ annotation }) => {
1926
- if (!runner.onTestAnnotate) throw new Error(`Test runner doesn't support test annotations.`);
1927
- await finishSendTasksUpdate(runner);
1928
- const resolvedAnnotation = await runner.onTestAnnotate(test, annotation);
1929
- test.annotations.push(resolvedAnnotation);
1930
- return resolvedAnnotation;
1931
- }));
1932
- });
1933
- context.onTestFailed = (handler, timeout) => {
1934
- test.onFailed ||= [];
1935
- test.onFailed.push(withTimeout(handler, timeout ?? runner.config.hookTimeout, true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), (_, error) => abortController.abort(error)));
1936
- };
1937
- context.onTestFinished = (handler, timeout) => {
1938
- test.onFinished ||= [];
1939
- test.onFinished.push(withTimeout(handler, timeout ?? runner.config.hookTimeout, true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), (_, error) => abortController.abort(error)));
1940
- };
1941
- return runner.extendTaskContext?.(context) || context;
1942
- }
1943
- function makeTimeoutError(isHook, timeout, stackTraceError) {
1944
- const message = `${isHook ? "Hook" : "Test"} timed out in ${timeout}ms.\nIf this is a long-running ${isHook ? "hook" : "test"}, pass a timeout value as the last argument or configure it globally with "${isHook ? "hookTimeout" : "testTimeout"}".`;
1945
- const error = new Error(message);
1946
- if (stackTraceError?.stack) error.stack = stackTraceError.stack.replace(error.message, stackTraceError.message);
1947
- return error;
1948
- }
1949
- async function runSetupFiles(config, files, runner) {
1950
- if (config.sequence.setupFiles === "parallel") await Promise.all(files.map(async (fsPath) => {
1951
- await runner.importFile(fsPath, "setup");
1952
- }));
1953
- else for (const fsPath of files) await runner.importFile(fsPath, "setup");
1954
- }
1955
- const now$1 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
1956
- async function collectTests(specs, runner) {
1957
- const files = [];
1958
- const config = runner.config;
1959
- const $ = runner.trace;
1960
- let defaultTagsFilter;
1961
- for (const spec of specs) {
1962
- const filepath = typeof spec === "string" ? spec : spec.filepath;
1963
- await $("collect_spec", { "code.file.path": filepath }, async () => {
1964
- runner._currentSpecification = typeof spec === "string" ? { filepath: spec } : spec;
1965
- const testLocations = typeof spec === "string" ? void 0 : spec.testLocations;
1966
- const testNamePattern = typeof spec === "string" ? void 0 : spec.testNamePattern;
1967
- const testIds = typeof spec === "string" ? void 0 : spec.testIds;
1968
- const testTagsFilter = typeof spec === "object" && spec.testTagsFilter ? createTagsFilter(spec.testTagsFilter, config.tags) : void 0;
1969
- const fileTags = typeof spec === "string" ? [] : spec.fileTags || [];
1970
- const file = createFileTask(filepath, config.root, config.name, runner.pool, runner.viteEnvironment);
1971
- file.tags = fileTags;
1972
- file.shuffle = config.sequence.shuffle;
1973
- try {
1974
- validateTags(runner.config, fileTags);
1975
- runner.onCollectStart?.(file);
1976
- clearCollectorContext(file, runner);
1977
- const setupFiles = toArray(config.setupFiles);
1978
- if (setupFiles.length) {
1979
- const setupStart = now$1();
1980
- await runSetupFiles(config, setupFiles, runner);
1981
- file.setupDuration = now$1() - setupStart;
1982
- } else file.setupDuration = 0;
1983
- const collectStart = now$1();
1984
- await runner.importFile(filepath, "collect");
1985
- const durations = runner.getImportDurations?.();
1986
- if (durations) file.importDurations = durations;
1987
- const defaultTasks = await getDefaultSuite().collect(file);
1988
- const fileHooks = createSuiteHooks();
1989
- mergeHooks(fileHooks, getHooks(defaultTasks));
1990
- for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) if (c.type === "test" || c.type === "suite") file.tasks.push(c);
1991
- else if (c.type === "collector") {
1992
- const suite = await c.collect(file);
1993
- if (suite.name || suite.tasks.length) {
1994
- mergeHooks(fileHooks, getHooks(suite));
1995
- file.tasks.push(suite);
1996
- }
1997
- }
1998
- setHooks(file, fileHooks);
1999
- file.collectDuration = now$1() - collectStart;
2000
- } catch (e) {
2001
- file.result = {
2002
- state: "fail",
2003
- errors: e instanceof AggregateError ? e.errors.map((e) => processError(e, runner.config.diffOptions)) : [processError(e, runner.config.diffOptions)]
2004
- };
2005
- const durations = runner.getImportDurations?.();
2006
- if (durations) file.importDurations = durations;
2007
- }
2008
- calculateSuiteHash(file);
2009
- const hasOnlyTasks = someTasksAreOnly(file);
2010
- if (!testTagsFilter && !defaultTagsFilter && config.tagsFilter) defaultTagsFilter = createTagsFilter(config.tagsFilter, config.tags);
2011
- interpretTaskModes(file, testNamePattern ?? config.testNamePattern, testLocations, testIds, testTagsFilter ?? defaultTagsFilter, hasOnlyTasks, false, config.allowOnly);
2012
- if (file.mode === "queued") file.mode = "run";
2013
- files.push(file);
2014
- });
2015
- }
2016
- return files;
2017
- }
2018
- function mergeHooks(baseHooks, hooks) {
2019
- for (const _key in hooks) {
2020
- const key = _key;
2021
- baseHooks[key].push(...hooks[key]);
2022
- }
2023
- return baseHooks;
2024
- }
2025
- const now = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
2026
- const unixNow = Date.now;
2027
- const { clearTimeout, setTimeout } = getSafeTimers();
2028
- let limitMaxConcurrency;
2029
- /**
2030
- * Normalizes retry configuration to extract individual values.
2031
- * Handles both number and object forms.
2032
- */
2033
- function getRetryCount(retry) {
2034
- if (retry === void 0) return 0;
2035
- if (typeof retry === "number") return retry;
2036
- return retry.count ?? 0;
2037
- }
2038
- function getRetryDelay(retry) {
2039
- if (retry === void 0) return 0;
2040
- if (typeof retry === "number") return 0;
2041
- return retry.delay ?? 0;
2042
- }
2043
- function getRetryCondition(retry) {
2044
- if (retry === void 0) return;
2045
- if (typeof retry === "number") return;
2046
- return retry.condition;
2047
- }
2048
- function updateSuiteHookState(task, name, state, runner) {
2049
- if (!task.result) task.result = { state: "run" };
2050
- if (!task.result.hooks) task.result.hooks = {};
2051
- const suiteHooks = task.result.hooks;
2052
- if (suiteHooks) {
2053
- suiteHooks[name] = state;
2054
- let event = state === "run" ? "before-hook-start" : "before-hook-end";
2055
- if (name === "afterAll" || name === "afterEach") event = state === "run" ? "after-hook-start" : "after-hook-end";
2056
- updateTask(event, task, runner);
2057
- }
2058
- }
2059
- function getSuiteHooks(suite, name, sequence) {
2060
- const hooks = getHooks(suite)[name];
2061
- if (sequence === "stack" && (name === "afterAll" || name === "afterEach")) return hooks.slice().reverse();
2062
- return hooks;
2063
- }
2064
- async function callTestHooks(runner, test, hooks, sequence) {
2065
- if (sequence === "stack") hooks = hooks.slice().reverse();
2066
- if (!hooks.length) return;
2067
- const context = test.context;
2068
- const onTestFailed = test.context.onTestFailed;
2069
- const onTestFinished = test.context.onTestFinished;
2070
- context.onTestFailed = () => {
2071
- throw new Error(`Cannot call "onTestFailed" inside a test hook.`);
2072
- };
2073
- context.onTestFinished = () => {
2074
- throw new Error(`Cannot call "onTestFinished" inside a test hook.`);
2075
- };
2076
- if (sequence === "parallel") try {
2077
- await Promise.all(hooks.map((fn) => limitMaxConcurrency(() => fn(test.context))));
2078
- } catch (e) {
2079
- failTask(test.result, e, runner.config.diffOptions);
2080
- }
2081
- else for (const fn of hooks) try {
2082
- await limitMaxConcurrency(() => fn(test.context));
2083
- } catch (e) {
2084
- failTask(test.result, e, runner.config.diffOptions);
2085
- }
2086
- context.onTestFailed = onTestFailed;
2087
- context.onTestFinished = onTestFinished;
2088
- }
2089
- async function callSuiteHook(suite, currentTask, name, runner, args) {
2090
- const sequence = runner.config.sequence.hooks;
2091
- const callbacks = [];
2092
- const parentSuite = "filepath" in suite ? null : suite.suite || suite.file;
2093
- if (name === "beforeEach" && parentSuite) callbacks.push(...await callSuiteHook(parentSuite, currentTask, name, runner, args));
2094
- const hooks = getSuiteHooks(suite, name, sequence);
2095
- if (hooks.length > 0) updateSuiteHookState(currentTask, name, "run", runner);
2096
- async function runHook(hook) {
2097
- return limitMaxConcurrency(async () => {
2098
- return getBeforeHookCleanupCallback(hook, await hook(...args), name === "beforeEach" ? args[0] : void 0);
2099
- });
2100
- }
2101
- if (sequence === "parallel") callbacks.push(...await Promise.all(hooks.map((hook) => runHook(hook))));
2102
- else for (const hook of hooks) callbacks.push(await runHook(hook));
2103
- if (hooks.length > 0) updateSuiteHookState(currentTask, name, "pass", runner);
2104
- if (name === "afterEach" && parentSuite) callbacks.push(...await callSuiteHook(parentSuite, currentTask, name, runner, args));
2105
- return callbacks;
2106
- }
2107
- function getAroundEachHooks(suite) {
2108
- const hooks = [];
2109
- const parentSuite = "filepath" in suite ? null : suite.suite || suite.file;
2110
- if (parentSuite) hooks.push(...getAroundEachHooks(parentSuite));
2111
- hooks.push(...getHooks(suite).aroundEach);
2112
- return hooks;
2113
- }
2114
- function getAroundAllHooks(suite) {
2115
- return getHooks(suite).aroundAll;
2116
- }
2117
- function makeAroundHookTimeoutError(hookName, phase, timeout, stackTraceError) {
2118
- const message = `The ${phase} phase of "${hookName}" hook timed out after ${timeout}ms.`;
2119
- const error = new (phase === "setup" ? AroundHookSetupError : AroundHookTeardownError)(message);
2120
- if (stackTraceError?.stack) error.stack = stackTraceError.stack.replace(stackTraceError.message, error.message);
2121
- return error;
2122
- }
2123
- async function callAroundHooks(runInner, options) {
2124
- const { hooks, hookName, callbackName, onTimeout, invokeHook } = options;
2125
- if (!hooks.length) {
2126
- await runInner();
2127
- return;
2128
- }
2129
- const hookErrors = [];
2130
- const createTimeoutPromise = (timeout, phase, stackTraceError) => {
2131
- let timer;
2132
- let timedout = false;
2133
- const promise = new Promise((_, reject) => {
2134
- if (timeout > 0 && timeout !== Number.POSITIVE_INFINITY) {
2135
- timer = setTimeout(() => {
2136
- timedout = true;
2137
- const error = makeAroundHookTimeoutError(hookName, phase, timeout, stackTraceError);
2138
- onTimeout?.(error);
2139
- reject(error);
2140
- }, timeout);
2141
- timer.unref?.();
2142
- }
2143
- });
2144
- const clear = () => {
2145
- if (timer) {
2146
- clearTimeout(timer);
2147
- timer = void 0;
2148
- }
2149
- };
2150
- return {
2151
- promise,
2152
- clear,
2153
- isTimedOut: () => timedout
2154
- };
2155
- };
2156
- const runNextHook = async (index) => {
2157
- if (index >= hooks.length) return runInner();
2158
- const hook = hooks[index];
2159
- const timeout = getAroundHookTimeout(hook);
2160
- const stackTraceError = getAroundHookStackTrace(hook);
2161
- let useCalled = false;
2162
- let setupTimeout;
2163
- let teardownTimeout;
2164
- let setupLimitConcurrencyRelease;
2165
- let teardownLimitConcurrencyRelease;
2166
- let resolveUseCalled;
2167
- const useCalledPromise = new Promise((resolve) => {
2168
- resolveUseCalled = resolve;
2169
- });
2170
- let resolveUseReturned;
2171
- const useReturnedPromise = new Promise((resolve) => {
2172
- resolveUseReturned = resolve;
2173
- });
2174
- let resolveHookComplete;
2175
- let rejectHookComplete;
2176
- const hookCompletePromise = new Promise((resolve, reject) => {
2177
- resolveHookComplete = resolve;
2178
- rejectHookComplete = reject;
2179
- });
2180
- const use = async () => {
2181
- if (setupTimeout.isTimedOut()) throw new Error("__VITEST_INTERNAL_AROUND_HOOK_ABORT__");
2182
- if (useCalled) throw new AroundHookMultipleCallsError(`The \`${callbackName}\` callback was called multiple times in the \`${hookName}\` hook. The callback can only be called once per hook.`);
2183
- useCalled = true;
2184
- resolveUseCalled();
2185
- setupTimeout.clear();
2186
- setupLimitConcurrencyRelease?.();
2187
- await runNextHook(index + 1).catch((e) => hookErrors.push(e));
2188
- teardownLimitConcurrencyRelease = await limitMaxConcurrency.acquire();
2189
- teardownTimeout = createTimeoutPromise(timeout, "teardown", stackTraceError);
2190
- resolveUseReturned();
2191
- };
2192
- setupLimitConcurrencyRelease = await limitMaxConcurrency.acquire();
2193
- setupTimeout = createTimeoutPromise(timeout, "setup", stackTraceError);
2194
- (async () => {
2195
- try {
2196
- await invokeHook(hook, use);
2197
- if (!useCalled) throw new AroundHookSetupError(`The \`${callbackName}\` callback was not called in the \`${hookName}\` hook. Make sure to call \`${callbackName}\` to run the ${hookName === "aroundEach" ? "test" : "suite"}.`);
2198
- resolveHookComplete();
2199
- } catch (error) {
2200
- rejectHookComplete(error);
2201
- } finally {
2202
- setupLimitConcurrencyRelease?.();
2203
- teardownLimitConcurrencyRelease?.();
2204
- }
2205
- })();
2206
- try {
2207
- await Promise.race([
2208
- useCalledPromise,
2209
- hookCompletePromise,
2210
- setupTimeout.promise
2211
- ]);
2212
- } finally {
2213
- setupLimitConcurrencyRelease?.();
2214
- setupTimeout.clear();
2215
- }
2216
- await Promise.race([useReturnedPromise, hookCompletePromise]);
2217
- try {
2218
- await Promise.race([hookCompletePromise, teardownTimeout?.promise]);
2219
- } finally {
2220
- teardownLimitConcurrencyRelease?.();
2221
- teardownTimeout?.clear();
2222
- }
2223
- };
2224
- await runNextHook(0).catch((e) => hookErrors.push(e));
2225
- if (hookErrors.length > 0) throw hookErrors;
2226
- }
2227
- async function callAroundAllHooks(suite, runSuiteInner) {
2228
- await callAroundHooks(runSuiteInner, {
2229
- hooks: getAroundAllHooks(suite),
2230
- hookName: "aroundAll",
2231
- callbackName: "runSuite()",
2232
- invokeHook: (hook, use) => hook(use, suite)
2233
- });
2234
- }
2235
- async function callAroundEachHooks(suite, test, runTest) {
2236
- await callAroundHooks(() => runTest(getFixtureCleanupCount(test.context)), {
2237
- hooks: getAroundEachHooks(suite),
2238
- hookName: "aroundEach",
2239
- callbackName: "runTest()",
2240
- onTimeout: (error) => abortContextSignal(test.context, error),
2241
- invokeHook: (hook, use) => hook(use, test.context, suite)
2242
- });
2243
- }
2244
- const packs = /* @__PURE__ */ new Map();
2245
- const eventsPacks = [];
2246
- const pendingTasksUpdates = [];
2247
- function sendTasksUpdate(runner) {
2248
- if (packs.size) {
2249
- const taskPacks = Array.from(packs).map(([id, task]) => {
2250
- return [
2251
- id,
2252
- task[0],
2253
- task[1]
2254
- ];
2255
- });
2256
- const p = runner.onTaskUpdate?.(taskPacks, eventsPacks);
2257
- if (p) {
2258
- pendingTasksUpdates.push(p);
2259
- p.then(() => pendingTasksUpdates.splice(pendingTasksUpdates.indexOf(p), 1), () => {});
2260
- }
2261
- eventsPacks.length = 0;
2262
- packs.clear();
2263
- }
2264
- }
2265
- async function finishSendTasksUpdate(runner) {
2266
- sendTasksUpdate(runner);
2267
- await Promise.all(pendingTasksUpdates);
2268
- }
2269
- function throttle(fn, ms) {
2270
- let last = 0;
2271
- let pendingCall;
2272
- return function call(...args) {
2273
- const now = unixNow();
2274
- if (now - last > ms) {
2275
- last = now;
2276
- clearTimeout(pendingCall);
2277
- pendingCall = void 0;
2278
- return fn.apply(this, args);
2279
- }
2280
- pendingCall ??= setTimeout(() => call.bind(this)(...args), ms);
2281
- };
2282
- }
2283
- const sendTasksUpdateThrottled = throttle(sendTasksUpdate, 100);
2284
- function updateTask(event, task, runner) {
2285
- eventsPacks.push([
2286
- task.id,
2287
- event,
2288
- void 0
2289
- ]);
2290
- packs.set(task.id, [task.result, task.meta]);
2291
- sendTasksUpdateThrottled(runner);
2292
- }
2293
- async function callCleanupHooks(runner, cleanups) {
2294
- const sequence = runner.config.sequence.hooks;
2295
- if (sequence === "stack") cleanups = cleanups.slice().reverse();
2296
- if (sequence === "parallel") await Promise.all(cleanups.map(async (fn) => {
2297
- if (typeof fn !== "function") return;
2298
- await limitMaxConcurrency(() => fn());
2299
- }));
2300
- else for (const fn of cleanups) {
2301
- if (typeof fn !== "function") continue;
2302
- await limitMaxConcurrency(() => fn());
2303
- }
2304
- }
2305
- /**
2306
- * Determines if a test should be retried based on its retryCondition configuration
2307
- */
2308
- function passesRetryCondition(test, errors) {
2309
- const condition = getRetryCondition(test.retry);
2310
- if (!errors || errors.length === 0) return false;
2311
- if (!condition) return true;
2312
- const error = errors[errors.length - 1];
2313
- if (condition instanceof RegExp) return condition.test(error.message || "");
2314
- else if (typeof condition === "function") return condition(error);
2315
- return false;
2316
- }
2317
- async function runTest(test, runner) {
2318
- await runner.onBeforeRunTask?.(test);
2319
- if (test.mode !== "run" && test.mode !== "queued") {
2320
- updateTask("test-prepare", test, runner);
2321
- updateTask("test-finished", test, runner);
2322
- return;
2323
- }
2324
- if (test.result?.state === "fail") {
2325
- updateTask("test-failed-early", test, runner);
2326
- return;
2327
- }
2328
- const start = now();
2329
- test.result = {
2330
- state: "run",
2331
- startTime: unixNow(),
2332
- retryCount: 0
2333
- };
2334
- updateTask("test-prepare", test, runner);
2335
- const cleanupRunningTest = addRunningTest(test);
2336
- setCurrentTest(test);
2337
- const suite = test.suite || test.file;
2338
- const $ = runner.trace;
2339
- const repeats = test.repeats ?? 0;
2340
- for (let repeatCount = 0; repeatCount <= repeats; repeatCount++) {
2341
- const retry = getRetryCount(test.retry);
2342
- for (let retryCount = 0; retryCount <= retry; retryCount++) {
2343
- let beforeEachCleanups = [];
2344
- await callAroundEachHooks(suite, test, async (fixtureCheckpoint) => {
2345
- try {
2346
- await runner.onBeforeTryTask?.(test, {
2347
- retry: retryCount,
2348
- repeats: repeatCount
2349
- });
2350
- test.result.repeatCount = repeatCount;
2351
- beforeEachCleanups = await $("test.beforeEach", () => callSuiteHook(suite, test, "beforeEach", runner, [test.context, suite]));
2352
- if (runner.runTask) await $("test.callback", () => limitMaxConcurrency(() => runner.runTask(test)));
2353
- else {
2354
- const fn = getFn(test);
2355
- if (!fn) throw new Error("Test function is not found. Did you add it using `setFn`?");
2356
- await $("test.callback", () => limitMaxConcurrency(() => fn()));
2357
- }
2358
- await runner.onAfterTryTask?.(test, {
2359
- retry: retryCount,
2360
- repeats: repeatCount
2361
- });
2362
- if (test.result.state !== "fail") test.result.state = "pass";
2363
- } catch (e) {
2364
- failTask(test.result, e, runner.config.diffOptions);
2365
- }
2366
- try {
2367
- await runner.onTaskFinished?.(test);
2368
- } catch (e) {
2369
- failTask(test.result, e, runner.config.diffOptions);
2370
- }
2371
- try {
2372
- await $("test.afterEach", () => callSuiteHook(suite, test, "afterEach", runner, [test.context, suite]));
2373
- if (beforeEachCleanups.length) await $("test.cleanup", () => callCleanupHooks(runner, beforeEachCleanups));
2374
- await callFixtureCleanupFrom(test.context, fixtureCheckpoint);
2375
- } catch (e) {
2376
- failTask(test.result, e, runner.config.diffOptions);
2377
- }
2378
- if (test.onFinished?.length) await $("test.onFinished", () => callTestHooks(runner, test, test.onFinished, "stack"));
2379
- if (test.result.state === "fail" && test.onFailed?.length) await $("test.onFailed", () => callTestHooks(runner, test, test.onFailed, runner.config.sequence.hooks));
2380
- test.onFailed = void 0;
2381
- test.onFinished = void 0;
2382
- await runner.onAfterRetryTask?.(test, {
2383
- retry: retryCount,
2384
- repeats: repeatCount
2385
- });
2386
- }).catch((error) => {
2387
- failTask(test.result, error, runner.config.diffOptions);
2388
- });
2389
- try {
2390
- await callFixtureCleanup(test.context);
2391
- } catch (e) {
2392
- failTask(test.result, e, runner.config.diffOptions);
2393
- }
2394
- if (test.result?.pending || test.result?.state === "skip") {
2395
- test.mode = "skip";
2396
- test.result = {
2397
- state: "skip",
2398
- note: test.result?.note,
2399
- pending: true,
2400
- duration: now() - start
2401
- };
2402
- updateTask("test-finished", test, runner);
2403
- setCurrentTest(void 0);
2404
- cleanupRunningTest();
2405
- return;
2406
- }
2407
- if (test.result.state === "pass") break;
2408
- if (retryCount < retry) {
2409
- if (!passesRetryCondition(test, test.result.errors)) break;
2410
- test.result.state = "run";
2411
- test.result.retryCount = (test.result.retryCount ?? 0) + 1;
2412
- const delay = getRetryDelay(test.retry);
2413
- if (delay > 0) await new Promise((resolve) => setTimeout(resolve, delay));
2414
- }
2415
- updateTask("test-retried", test, runner);
2416
- }
2417
- }
2418
- if (test.fails) if (test.result.state === "pass") {
2419
- const error = processError(/* @__PURE__ */ new Error("Expect test to fail"));
2420
- test.result.state = "fail";
2421
- test.result.errors = [error];
2422
- } else {
2423
- test.result.state = "pass";
2424
- test.result.errors = void 0;
2425
- }
2426
- cleanupRunningTest();
2427
- setCurrentTest(void 0);
2428
- test.result.duration = now() - start;
2429
- await runner.onAfterRunTask?.(test);
2430
- updateTask("test-finished", test, runner);
2431
- }
2432
- function failTask(result, err, diffOptions) {
2433
- if (err instanceof PendingError) {
2434
- result.state = "skip";
2435
- result.note = err.note;
2436
- result.pending = true;
2437
- return;
2438
- }
2439
- if (err instanceof TestRunAbortError) {
2440
- result.state = "skip";
2441
- result.note = err.message;
2442
- return;
2443
- }
2444
- result.state = "fail";
2445
- const errors = Array.isArray(err) ? err : [err];
2446
- for (const e of errors) {
2447
- const errors = e instanceof AggregateError ? e.errors.map((e) => processError(e, diffOptions)) : [processError(e, diffOptions)];
2448
- result.errors ??= [];
2449
- result.errors.push(...errors);
2450
- }
2451
- }
2452
- function markTasksAsSkipped(suite, runner) {
2453
- suite.tasks.forEach((t) => {
2454
- t.mode = "skip";
2455
- t.result = {
2456
- ...t.result,
2457
- state: "skip"
2458
- };
2459
- updateTask("test-finished", t, runner);
2460
- if (t.type === "suite") markTasksAsSkipped(t, runner);
2461
- });
2462
- }
2463
- function markPendingTasksAsSkipped(suite, runner, note) {
2464
- suite.tasks.forEach((t) => {
2465
- if (!t.result || t.result.state === "run") {
2466
- t.mode = "skip";
2467
- t.result = {
2468
- ...t.result,
2469
- state: "skip",
2470
- note
2471
- };
2472
- updateTask("test-cancel", t, runner);
2473
- }
2474
- if (t.type === "suite") markPendingTasksAsSkipped(t, runner, note);
2475
- });
2476
- }
2477
- async function runSuite(suite, runner) {
2478
- await runner.onBeforeRunSuite?.(suite);
2479
- if (suite.result?.state === "fail") {
2480
- markTasksAsSkipped(suite, runner);
2481
- updateTask("suite-failed-early", suite, runner);
2482
- return;
2483
- }
2484
- const start = now();
2485
- const mode = suite.mode;
2486
- suite.result = {
2487
- state: mode === "skip" || mode === "todo" ? mode : "run",
2488
- startTime: unixNow()
2489
- };
2490
- const $ = runner.trace;
2491
- updateTask("suite-prepare", suite, runner);
2492
- let beforeAllCleanups = [];
2493
- if (suite.mode === "skip") {
2494
- suite.result.state = "skip";
2495
- updateTask("suite-finished", suite, runner);
2496
- } else if (suite.mode === "todo") {
2497
- suite.result.state = "todo";
2498
- updateTask("suite-finished", suite, runner);
2499
- } else {
2500
- let suiteRan = false;
2501
- try {
2502
- await callAroundAllHooks(suite, async () => {
2503
- suiteRan = true;
2504
- try {
2505
- try {
2506
- beforeAllCleanups = await $("suite.beforeAll", () => callSuiteHook(suite, suite, "beforeAll", runner, [suite]));
2507
- } catch (e) {
2508
- failTask(suite.result, e, runner.config.diffOptions);
2509
- markTasksAsSkipped(suite, runner);
2510
- return;
2511
- }
2512
- if (runner.runSuite) await runner.runSuite(suite);
2513
- else for (let tasksGroup of partitionSuiteChildren(suite)) if (tasksGroup[0].concurrent === true) {
2514
- const groupLimiter = limitConcurrency(runner.config.maxConcurrency);
2515
- await Promise.all(tasksGroup.map((c) => groupLimiter(() => runSuiteChild(c, runner))));
2516
- } else {
2517
- const { sequence } = runner.config;
2518
- if (suite.shuffle) tasksGroup = shuffle([tasksGroup.filter((group) => group.type === "suite"), tasksGroup.filter((group) => group.type === "test")], sequence.seed).flatMap((group) => shuffle(group, sequence.seed));
2519
- for (const c of tasksGroup) await runSuiteChild(c, runner);
2520
- }
2521
- } finally {
2522
- try {
2523
- await $("suite.afterAll", () => callSuiteHook(suite, suite, "afterAll", runner, [suite]));
2524
- if (beforeAllCleanups.length) await $("suite.cleanup", () => callCleanupHooks(runner, beforeAllCleanups));
2525
- if (suite.file === suite) {
2526
- const contexts = TestFixtures.getFileContexts(suite.file);
2527
- await Promise.all(contexts.map((context) => callFixtureCleanup(context)));
2528
- }
2529
- } catch (e) {
2530
- failTask(suite.result, e, runner.config.diffOptions);
2531
- }
2532
- }
2533
- });
2534
- } catch (e) {
2535
- if (!suiteRan) markTasksAsSkipped(suite, runner);
2536
- failTask(suite.result, e, runner.config.diffOptions);
2537
- }
2538
- if (suite.mode === "run" || suite.mode === "queued") if (!runner.config.passWithNoTests && !hasTests(suite)) {
2539
- suite.result.state = "fail";
2540
- if (!suite.result.errors?.length) {
2541
- const error = processError(/* @__PURE__ */ new Error(`No test found in suite ${suite.name}`));
2542
- suite.result.errors = [error];
2543
- }
2544
- } else if (hasFailed(suite)) suite.result.state = "fail";
2545
- else suite.result.state = "pass";
2546
- suite.result.duration = now() - start;
2547
- await runner.onAfterRunSuite?.(suite);
2548
- updateTask("suite-finished", suite, runner);
2549
- }
2550
- }
2551
- async function runSuiteChild(c, runner) {
2552
- const $ = runner.trace;
2553
- if (c.type === "test") return $("run.test", {
2554
- "vitest.test.id": c.id,
2555
- "vitest.test.name": c.name,
2556
- "vitest.test.mode": c.mode,
2557
- "vitest.test.timeout": c.timeout,
2558
- "code.file.path": c.file.filepath,
2559
- "code.line.number": c.location?.line,
2560
- "code.column.number": c.location?.column
2561
- }, () => runTest(c, runner));
2562
- else if (c.type === "suite") return $("run.suite", {
2563
- "vitest.suite.id": c.id,
2564
- "vitest.suite.name": c.name,
2565
- "vitest.suite.mode": c.mode,
2566
- "code.file.path": c.file.filepath,
2567
- "code.line.number": c.location?.line,
2568
- "code.column.number": c.location?.column
2569
- }, () => runSuite(c, runner));
2570
- }
2571
- async function runFiles(files, runner) {
2572
- limitMaxConcurrency ??= limitConcurrency(runner.config.maxConcurrency);
2573
- for (const file of files) {
2574
- if (!file.tasks.length && !runner.config.passWithNoTests) {
2575
- if (!file.result?.errors?.length) file.result = {
2576
- state: "fail",
2577
- errors: [processError(/* @__PURE__ */ new Error(`No test suite found in file ${file.filepath}`))]
2578
- };
2579
- }
2580
- await runner.trace("run.spec", {
2581
- "code.file.path": file.filepath,
2582
- "vitest.suite.tasks.length": file.tasks.length
2583
- }, () => runSuite(file, runner));
2584
- }
2585
- }
2586
- const workerRunners = /* @__PURE__ */ new WeakSet();
2587
- function defaultTrace(_, attributes, cb) {
2588
- if (typeof attributes === "function") return attributes();
2589
- return cb();
2590
- }
2591
- async function startTests(specs, runner) {
2592
- runner.trace ??= defaultTrace;
2593
- const cancel = runner.cancel?.bind(runner);
2594
- runner.cancel = (reason) => {
2595
- const error = new TestRunAbortError("The test run was aborted by the user.", reason);
2596
- getRunningTests().forEach((test) => {
2597
- abortContextSignal(test.context, error);
2598
- markPendingTasksAsSkipped(test.file, runner, error.message);
2599
- });
2600
- return cancel?.(reason);
2601
- };
2602
- if (!workerRunners.has(runner)) {
2603
- runner.onCleanupWorkerContext?.(async () => {
2604
- await Promise.all([...TestFixtures.getWorkerContexts()].map((context) => callFixtureCleanup(context))).finally(() => {
2605
- TestFixtures.clearDefinitions();
2606
- });
2607
- });
2608
- workerRunners.add(runner);
2609
- }
2610
- try {
2611
- const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
2612
- await runner.onBeforeCollect?.(paths);
2613
- const files = await collectTests(specs, runner);
2614
- await runner.onCollected?.(files);
2615
- await runner.onBeforeRunFiles?.(files);
2616
- await runFiles(files, runner);
2617
- await runner.onAfterRunFiles?.(files);
2618
- await finishSendTasksUpdate(runner);
2619
- return files;
2620
- } finally {
2621
- runner.cancel = cancel;
2622
- }
2623
- }
2624
- async function publicCollect(specs, runner) {
2625
- runner.trace ??= defaultTrace;
2626
- const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
2627
- await runner.onBeforeCollect?.(paths);
2628
- const files = await collectTests(specs, runner);
2629
- await runner.onCollected?.(files);
2630
- return files;
2631
- }
2632
- /**
2633
- * @experimental
2634
- * @advanced
2635
- *
2636
- * Records a custom test artifact during test execution.
2637
- *
2638
- * This function allows you to attach structured data, files, or metadata to a test.
2639
- *
2640
- * Vitest automatically injects the source location where the artifact was created and manages any attachments you include.
2641
- *
2642
- * **Note:** artifacts must be recorded before the task is reported. Any artifacts recorded after that will not be included in the task.
2643
- *
2644
- * @param task - The test task context, typically accessed via `this.task` in custom matchers or `context.task` in tests
2645
- * @param artifact - The artifact to record. Must extend {@linkcode TestArtifactBase}
2646
- *
2647
- * @returns A promise that resolves to the recorded artifact with location injected
2648
- *
2649
- * @throws {Error} If the test runner doesn't support artifacts
2650
- *
2651
- * @example
2652
- * ```ts
2653
- * // In a custom assertion
2654
- * async function toHaveValidSchema(this: MatcherState, actual: unknown) {
2655
- * const validation = validateSchema(actual)
2656
- *
2657
- * await recordArtifact(this.task, {
2658
- * type: 'my-plugin:schema-validation',
2659
- * passed: validation.valid,
2660
- * errors: validation.errors,
2661
- * })
2662
- *
2663
- * return { pass: validation.valid, message: () => '...' }
2664
- * }
2665
- * ```
2666
- */
2667
- async function recordArtifact(task, artifact) {
2668
- const runner = getRunner();
2669
- const stack = findTestFileStackTrace(task.file.filepath, (/* @__PURE__ */ new Error("STACK_TRACE")).stack);
2670
- if (stack) {
2671
- artifact.location = {
2672
- file: stack.file,
2673
- line: stack.line,
2674
- column: stack.column
2675
- };
2676
- if (artifact.type === "internal:annotation") artifact.annotation.location = artifact.location;
2677
- }
2678
- if (Array.isArray(artifact.attachments)) for (const attachment of artifact.attachments) manageArtifactAttachment(attachment);
2679
- if (artifact.type === "internal:annotation") return artifact;
2680
- if (!runner.onTestArtifactRecord) throw new Error(`Test runner doesn't support test artifacts.`);
2681
- await finishSendTasksUpdate(runner);
2682
- const resolvedArtifact = await runner.onTestArtifactRecord(task, artifact);
2683
- task.artifacts.push(resolvedArtifact);
2684
- return resolvedArtifact;
2685
- }
2686
- const table = [];
2687
- for (let i = 65; i < 91; i++) table.push(String.fromCharCode(i));
2688
- for (let i = 97; i < 123; i++) table.push(String.fromCharCode(i));
2689
- for (let i = 0; i < 10; i++) table.push(i.toString(10));
2690
- table.push("+", "/");
2691
- function encodeUint8Array(bytes) {
2692
- let base64 = "";
2693
- const len = bytes.byteLength;
2694
- for (let i = 0; i < len; i += 3) if (len === i + 1) {
2695
- const a = (bytes[i] & 252) >> 2;
2696
- const b = (bytes[i] & 3) << 4;
2697
- base64 += table[a];
2698
- base64 += table[b];
2699
- base64 += "==";
2700
- } else if (len === i + 2) {
2701
- const a = (bytes[i] & 252) >> 2;
2702
- const b = (bytes[i] & 3) << 4 | (bytes[i + 1] & 240) >> 4;
2703
- const c = (bytes[i + 1] & 15) << 2;
2704
- base64 += table[a];
2705
- base64 += table[b];
2706
- base64 += table[c];
2707
- base64 += "=";
2708
- } else {
2709
- const a = (bytes[i] & 252) >> 2;
2710
- const b = (bytes[i] & 3) << 4 | (bytes[i + 1] & 240) >> 4;
2711
- const c = (bytes[i + 1] & 15) << 2 | (bytes[i + 2] & 192) >> 6;
2712
- const d = bytes[i + 2] & 63;
2713
- base64 += table[a];
2714
- base64 += table[b];
2715
- base64 += table[c];
2716
- base64 += table[d];
2717
- }
2718
- return base64;
2719
- }
2720
- /**
2721
- * Records an async operation associated with a test task.
2722
- *
2723
- * This function tracks promises that should be awaited before a test completes.
2724
- * The promise is automatically removed from the test's promise list once it settles.
2725
- */
2726
- function recordAsyncOperation(test, promise) {
2727
- promise = promise.finally(() => {
2728
- if (!test.promises) return;
2729
- const index = test.promises.indexOf(promise);
2730
- if (index !== -1) test.promises.splice(index, 1);
2731
- });
2732
- if (!test.promises) test.promises = [];
2733
- test.promises.push(promise);
2734
- return promise;
2735
- }
2736
- /**
2737
- * Validates and prepares a test attachment for serialization.
2738
- *
2739
- * This function ensures attachments have either `body` or `path` set (but not both), and converts `Uint8Array` bodies to base64-encoded strings for easier serialization.
2740
- *
2741
- * @param attachment - The attachment to validate and prepare
2742
- *
2743
- * @throws {TypeError} If neither `body` nor `path` is provided
2744
- * @throws {TypeError} If both `body` and `path` are provided
2745
- */
2746
- function manageArtifactAttachment(attachment) {
2747
- if (attachment.body == null && !attachment.path) throw new TypeError(`Test attachment requires "body" or "path" to be set. Both are missing.`);
2748
- if (attachment.body && attachment.path) throw new TypeError(`Test attachment requires only one of "body" or "path" to be set. Both are specified.`);
2749
- if (attachment.path && attachment.bodyEncoding) throw new TypeError(`Test attachment with "path" should not have "bodyEncoding" specified.`);
2750
- if (attachment.body instanceof Uint8Array) attachment.body = encodeUint8Array(attachment.body);
2751
- if (attachment.body != null) attachment.bodyEncoding ??= "base64";
2752
- }
2753
- //#endregion
2754
- export { createTagsFilter as A, createTaskName as B, findTestFileStackTrace as C, generateFileHash as D, generateHash as E, getFullName as F, getNames as G, getSuites as H, getTasks as I, getTestName as J, getTests as K, hasFailed as L, hasTests as M, interpretTaskModes as N, isTestCase as O, limitConcurrency as P, matchesTags as Q, partitionSuiteChildren as R, someTasksAreOnly as S, validateTags as T, afterAll as a, afterEach as b, aroundAll as c, aroundEach as d, beforeAll as e, beforeEach as f, createTaskCollector as g, describe as h, getCurrentSuite as i, getCurrentTest as j, getFn as k, getHooks as l, it as m, onTestFinished as n, onTestFailed as o, publicCollect as p, setHooks as q, recordArtifact as r, setFn as s, startTests as t, suite as u, test as v, updateTask as w, calculateSuiteHash as x, createChainable as y, createFileTask as z };
2755
-
2756
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2h1bmstYXJ0aWZhY3QuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL0B2aXRlc3QrcnVubmVyQDQuMS4xMC9ub2RlX21vZHVsZXMvQHZpdGVzdC9ydW5uZXIvZGlzdC9jaHVuay1hcnRpZmFjdC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBwcm9jZXNzRXJyb3IgfSBmcm9tICdAdml0ZXN0L3V0aWxzL2Vycm9yJztcbmltcG9ydCB7IGlzT2JqZWN0LCBmaWx0ZXJPdXRDb21tZW50cywgb3JkaW5hbCwgY3JlYXRlRGVmZXIsIGFzc2VydFR5cGVzLCB0b0FycmF5LCBpc05lZ2F0aXZlTmFOLCB1bmlxdWUsIG9iamVjdEF0dHIsIHNodWZmbGUgfSBmcm9tICdAdml0ZXN0L3V0aWxzL2hlbHBlcnMnO1xuaW1wb3J0IHsgZ2V0U2FmZVRpbWVycyB9IGZyb20gJ0B2aXRlc3QvdXRpbHMvdGltZXJzJztcbmltcG9ydCB7IGZvcm1hdCwgZm9ybWF0UmVnRXhwLCBvYmpEaXNwbGF5IH0gZnJvbSAnQHZpdGVzdC91dGlscy9kaXNwbGF5JztcbmltcG9ydCB7IHBhcnNlU2luZ2xlU3RhY2sgfSBmcm9tICdAdml0ZXN0L3V0aWxzL3NvdXJjZS1tYXAnO1xuaW1wb3J0IHsgcmVsYXRpdmUgfSBmcm9tICdwYXRoZSc7XG5cbmNsYXNzIFBlbmRpbmdFcnJvciBleHRlbmRzIEVycm9yIHtcblx0Y29kZSA9IFwiVklURVNUX1BFTkRJTkdcIjtcblx0dGFza0lkO1xuXHRjb25zdHJ1Y3RvcihtZXNzYWdlLCB0YXNrLCBub3RlKSB7XG5cdFx0c3VwZXIobWVzc2FnZSk7XG5cdFx0dGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcblx0XHR0aGlzLm5vdGUgPSBub3RlO1xuXHRcdHRoaXMudGFza0lkID0gdGFzay5pZDtcblx0fVxufVxuY2xhc3MgVGVzdFJ1bkFib3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG5cdG5hbWUgPSBcIlRlc3RSdW5BYm9ydEVycm9yXCI7XG5cdHJlYXNvbjtcblx0Y29uc3RydWN0b3IobWVzc2FnZSwgcmVhc29uKSB7XG5cdFx0c3VwZXIobWVzc2FnZSk7XG5cdFx0dGhpcy5yZWFzb24gPSByZWFzb247XG5cdH1cbn1cbmNsYXNzIEZpeHR1cmVEZXBlbmRlbmN5RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG5cdG5hbWUgPSBcIkZpeHR1cmVEZXBlbmRlbmN5RXJyb3JcIjtcbn1cbmNsYXNzIEZpeHR1cmVBY2Nlc3NFcnJvciBleHRlbmRzIEVycm9yIHtcblx0bmFtZSA9IFwiRml4dHVyZUFjY2Vzc0Vycm9yXCI7XG59XG5jbGFzcyBGaXh0dXJlUGFyc2VFcnJvciBleHRlbmRzIEVycm9yIHtcblx0bmFtZSA9IFwiRml4dHVyZVBhcnNlRXJyb3JcIjtcbn1cbmNsYXNzIEFyb3VuZEhvb2tTZXR1cEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuXHRuYW1lID0gXCJBcm91bmRIb29rU2V0dXBFcnJvclwiO1xufVxuY2xhc3MgQXJvdW5kSG9va1RlYXJkb3duRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG5cdG5hbWUgPSBcIkFyb3VuZEhvb2tUZWFyZG93bkVycm9yXCI7XG59XG5jbGFzcyBBcm91bmRIb29rTXVsdGlwbGVDYWxsc0Vycm9yIGV4dGVuZHMgRXJyb3Ige1xuXHRuYW1lID0gXCJBcm91bmRIb29rTXVsdGlwbGVDYWxsc0Vycm9yXCI7XG59XG5cbi8vIHVzZSBXZWFrTWFwIGhlcmUgdG8gbWFrZSB0aGUgVGVzdCBhbmQgU3VpdGUgb2JqZWN0IHNlcmlhbGl6YWJsZVxuY29uc3QgZm5NYXAgPSBuZXcgV2Vha01hcCgpO1xuY29uc3QgdGVzdEZpeHR1cmVNYXAgPSBuZXcgV2Vha01hcCgpO1xuY29uc3QgaG9va3NNYXAgPSBuZXcgV2Vha01hcCgpO1xuZnVuY3Rpb24gc2V0Rm4oa2V5LCBmbikge1xuXHRmbk1hcC5zZXQoa2V5LCBmbik7XG59XG5mdW5jdGlvbiBnZXRGbihrZXkpIHtcblx0cmV0dXJuIGZuTWFwLmdldChrZXkpO1xufVxuZnVuY3Rpb24gc2V0VGVzdEZpeHR1cmUoa2V5LCBmaXh0dXJlKSB7XG5cdHRlc3RGaXh0dXJlTWFwLnNldChrZXksIGZpeHR1cmUpO1xufVxuZnVuY3Rpb24gZ2V0VGVzdEZpeHR1cmVzKGtleSkge1xuXHRyZXR1cm4gdGVzdEZpeHR1cmVNYXAuZ2V0KGtleSk7XG59XG5mdW5jdGlvbiBzZXRIb29rcyhrZXksIGhvb2tzKSB7XG5cdGhvb2tzTWFwLnNldChrZXksIGhvb2tzKTtcbn1cbmZ1bmN0aW9uIGdldEhvb2tzKGtleSkge1xuXHRyZXR1cm4gaG9va3NNYXAuZ2V0KGtleSk7XG59XG5cbmNvbnN0IEZJWFRVUkVfU1RBQ0tfVFJBQ0VfS0VZID0gU3ltYm9sLmZvcihcIlZJVEVTVF9GSVhUVVJFX1NUQUNLX1RSQUNFXCIpO1xuY2xhc3MgVGVzdEZpeHR1cmVzIHtcblx0X3N1aXRlQ29udGV4dHM7XG5cdF9vdmVycmlkZXMgPSBuZXcgV2Vha01hcCgpO1xuXHRfcmVnaXN0cmF0aW9ucztcblx0c3RhdGljIF9kZWZpbml0aW9ucyA9IFtdO1xuXHRzdGF0aWMgX2J1aWx0aW5GaXh0dXJlcyA9IFtcblx0XHRcInRhc2tcIixcblx0XHRcInNpZ25hbFwiLFxuXHRcdFwib25UZXN0RmFpbGVkXCIsXG5cdFx0XCJvblRlc3RGaW5pc2hlZFwiLFxuXHRcdFwic2tpcFwiLFxuXHRcdFwiYW5ub3RhdGVcIlxuXHRdO1xuXHRzdGF0aWMgX2ZpeHR1cmVPcHRpb25LZXlzID0gW1xuXHRcdFwiYXV0b1wiLFxuXHRcdFwiaW5qZWN0ZWRcIixcblx0XHRcInNjb3BlXCJcblx0XTtcblx0c3RhdGljIF9maXh0dXJlU2NvcGVzID0gW1xuXHRcdFwidGVzdFwiLFxuXHRcdFwiZmlsZVwiLFxuXHRcdFwid29ya2VyXCJcblx0XTtcblx0c3RhdGljIF93b3JrZXJDb250ZXh0U3VpdGUgPSB7IHR5cGU6IFwid29ya2VyXCIgfTtcblx0c3RhdGljIGNsZWFyRGVmaW5pdGlvbnMoKSB7XG5cdFx0VGVzdEZpeHR1cmVzLl9kZWZpbml0aW9ucy5sZW5ndGggPSAwO1xuXHR9XG5cdHN0YXRpYyBnZXRXb3JrZXJDb250ZXh0cygpIHtcblx0XHRyZXR1cm4gVGVzdEZpeHR1cmVzLl9kZWZpbml0aW9ucy5tYXAoKGYpID0+IGYuZ2V0V29ya2VyQ29udGV4dCgpKTtcblx0fVxuXHRzdGF0aWMgZ2V0RmlsZUNvbnRleHRzKGZpbGUpIHtcblx0XHRyZXR1cm4gVGVzdEZpeHR1cmVzLl9kZWZpbml0aW9ucy5tYXAoKGYpID0+IGYuZ2V0RmlsZUNvbnRleHQoZmlsZSkpO1xuXHR9XG5cdHN0YXRpYyBpc0ZpeHR1cmVPcHRpb25zKG9iaikge1xuXHRcdHJldHVybiBpc09iamVjdChvYmopICYmIE9iamVjdC5rZXlzKG9iaikuc29tZSgoa2V5KSA9PiBUZXN0Rml4dHVyZXMuX2ZpeHR1cmVPcHRpb25LZXlzLmluY2x1ZGVzKGtleSkpO1xuXHR9XG5cdGNvbnN0cnVjdG9yKHJlZ2lzdHJhdGlvbnMpIHtcblx0XHR0aGlzLl9yZWdpc3RyYXRpb25zID0gcmVnaXN0cmF0aW9ucyA/PyBuZXcgTWFwKCk7XG5cdFx0dGhpcy5fc3VpdGVDb250ZXh0cyA9IG5ldyBXZWFrTWFwKCk7XG5cdFx0VGVzdEZpeHR1cmVzLl9kZWZpbml0aW9ucy5wdXNoKHRoaXMpO1xuXHR9XG5cdGV4dGVuZChydW5uZXIsIHVzZXJGaXh0dXJlcykge1xuXHRcdGNvbnN0IHsgc3VpdGUgfSA9IGdldEN1cnJlbnRTdWl0ZSgpO1xuXHRcdGNvbnN0IGlzVG9wTGV2ZWwgPSAhc3VpdGUgfHwgc3VpdGUuZmlsZSA9PT0gc3VpdGU7XG5cdFx0Y29uc3QgcmVnaXN0cmF0aW9ucyA9IHRoaXMucGFyc2VVc2VyRml4dHVyZXMocnVubmVyLCB1c2VyRml4dHVyZXMsIGlzVG9wTGV2ZWwpO1xuXHRcdHJldHVybiBuZXcgVGVzdEZpeHR1cmVzKHJlZ2lzdHJhdGlvbnMpO1xuXHR9XG5cdGdldChzdWl0ZSkge1xuXHRcdGxldCBjdXJyZW50U3VpdGUgPSBzdWl0ZTtcblx0XHR3aGlsZSAoY3VycmVudFN1aXRlKSB7XG5cdFx0XHRjb25zdCBvdmVycmlkZXMgPSB0aGlzLl9vdmVycmlkZXMuZ2V0KGN1cnJlbnRTdWl0ZSk7XG5cdFx0XHQvLyByZXR1cm4gdGhlIGNsb3Nlc3Qgb3ZlcnJpZGVcblx0XHRcdGlmIChvdmVycmlkZXMpIHtcblx0XHRcdFx0cmV0dXJuIG92ZXJyaWRlcztcblx0XHRcdH1cblx0XHRcdGlmIChjdXJyZW50U3VpdGUgPT09IGN1cnJlbnRTdWl0ZS5maWxlKSB7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0Y3VycmVudFN1aXRlID0gY3VycmVudFN1aXRlLnN1aXRlIHx8IGN1cnJlbnRTdWl0ZS5maWxlO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5fcmVnaXN0cmF0aW9ucztcblx0fVxuXHRvdmVycmlkZShydW5uZXIsIHVzZXJGaXh0dXJlcykge1xuXHRcdGNvbnN0IHsgc3VpdGU6IGN1cnJlbnRTdWl0ZSwgZmlsZSB9ID0gZ2V0Q3VycmVudFN1aXRlKCk7XG5cdFx0Y29uc3Qgc3VpdGUgPSBjdXJyZW50U3VpdGUgfHwgZmlsZTtcblx0XHRjb25zdCBpc1RvcExldmVsID0gIWN1cnJlbnRTdWl0ZSB8fCBjdXJyZW50U3VpdGUuZmlsZSA9PT0gY3VycmVudFN1aXRlO1xuXHRcdC8vIENyZWF0ZSBhIGNvcHkgb2YgdGhlIGNsb3Nlc3QgcGFyZW50J3MgcmVnaXN0cmF0aW9ucyB0byBhdm9pZCBtb2RpZnlpbmcgdGhlbVxuXHRcdC8vIEZvciBjaGFpbmVkIGNhbGxzLCB0aGlzLmdldChzdWl0ZSkgcmV0dXJucyB0aGlzIHN1aXRlJ3Mgb3ZlcnJpZGVzOyBmb3IgZmlyc3QgY2FsbCwgcmV0dXJucyBwYXJlbnQnc1xuXHRcdGNvbnN0IHN1aXRlUmVnaXN0cmF0aW9ucyA9IG5ldyBNYXAodGhpcy5nZXQoc3VpdGUpKTtcblx0XHRjb25zdCByZWdpc3RyYXRpb25zID0gdGhpcy5wYXJzZVVzZXJGaXh0dXJlcyhydW5uZXIsIHVzZXJGaXh0dXJlcywgaXNUb3BMZXZlbCwgc3VpdGVSZWdpc3RyYXRpb25zKTtcblx0XHQvLyBJZiBkZWZpbmVkIGluIHRvcC1sZXZlbCwganVzdCBvdmVycmlkZSBhbGwgcmVnaXN0cmF0aW9uc1xuXHRcdC8vIFdlIGRvbid0IHN1cHBvcnQgb3ZlcnJpZGluZyBzdWl0ZS1sZXZlbCBmaXh0dXJlcyBhbnl3YXkgKGl0IHdpbGwgdGhyb3cgYW4gZXJyb3IpXG5cdFx0aWYgKGlzVG9wTGV2ZWwpIHtcblx0XHRcdHRoaXMuX3JlZ2lzdHJhdGlvbnMgPSByZWdpc3RyYXRpb25zO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9vdmVycmlkZXMuc2V0KHN1aXRlLCByZWdpc3RyYXRpb25zKTtcblx0XHR9XG5cdH1cblx0Z2V0RmlsZUNvbnRleHQoZmlsZSkge1xuXHRcdGlmICghdGhpcy5fc3VpdGVDb250ZXh0cy5oYXMoZmlsZSkpIHtcblx0XHRcdHRoaXMuX3N1aXRlQ29udGV4dHMuc2V0KGZpbGUsIE9iamVjdC5jcmVhdGUobnVsbCkpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5fc3VpdGVDb250ZXh0cy5nZXQoZmlsZSk7XG5cdH1cblx0Z2V0V29ya2VyQ29udGV4dCgpIHtcblx0XHRpZiAoIXRoaXMuX3N1aXRlQ29udGV4dHMuaGFzKFRlc3RGaXh0dXJlcy5fd29ya2VyQ29udGV4dFN1aXRlKSkge1xuXHRcdFx0dGhpcy5fc3VpdGVDb250ZXh0cy5zZXQoVGVzdEZpeHR1cmVzLl93b3JrZXJDb250ZXh0U3VpdGUsIE9iamVjdC5jcmVhdGUobnVsbCkpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5fc3VpdGVDb250ZXh0cy5nZXQoVGVzdEZpeHR1cmVzLl93b3JrZXJDb250ZXh0U3VpdGUpO1xuXHR9XG5cdHBhcnNlVXNlckZpeHR1cmVzKHJ1bm5lciwgdXNlckZpeHR1cmVzLCBzdXBwb3J0Tm9uVGVzdCwgcmVnaXN0cmF0aW9ucyA9IG5ldyBNYXAodGhpcy5fcmVnaXN0cmF0aW9ucykpIHtcblx0XHRjb25zdCBlcnJvcnMgPSBbXTtcblx0XHRPYmplY3QuZW50cmllcyh1c2VyRml4dHVyZXMpLmZvckVhY2goKFtuYW1lLCBmbl0pID0+IHtcblx0XHRcdGxldCBvcHRpb25zO1xuXHRcdFx0bGV0IHZhbHVlO1xuXHRcdFx0bGV0IF9vcHRpb25zO1xuXHRcdFx0aWYgKEFycmF5LmlzQXJyYXkoZm4pICYmIGZuLmxlbmd0aCA+PSAyICYmIFRlc3RGaXh0dXJlcy5pc0ZpeHR1cmVPcHRpb25zKGZuWzFdKSkge1xuXHRcdFx0XHRfb3B0aW9ucyA9IGZuWzFdO1xuXHRcdFx0XHRvcHRpb25zID0ge1xuXHRcdFx0XHRcdGF1dG86IF9vcHRpb25zLmF1dG8gPz8gZmFsc2UsXG5cdFx0XHRcdFx0c2NvcGU6IF9vcHRpb25zLnNjb3BlID8/IFwidGVzdFwiLFxuXHRcdFx0XHRcdGluamVjdGVkOiBfb3B0aW9ucy5pbmplY3RlZCA/PyBmYWxzZVxuXHRcdFx0XHR9O1xuXHRcdFx0XHR2YWx1ZSA9IG9wdGlvbnMuaW5qZWN0ZWQgPyBydW5uZXIuaW5qZWN0VmFsdWU/LihuYW1lKSA/PyBmblswXSA6IGZuWzBdO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFsdWUgPSBmbjtcblx0XHRcdH1cblx0XHRcdGNvbnN0IHBhcmVudCA9IHJlZ2lzdHJhdGlvbnMuZ2V0KG5hbWUpO1xuXHRcdFx0aWYgKHBhcmVudCAmJiBvcHRpb25zKSB7XG5cdFx0XHRcdGlmIChwYXJlbnQuc2NvcGUgIT09IG9wdGlvbnMuc2NvcGUpIHtcblx0XHRcdFx0XHRlcnJvcnMucHVzaChuZXcgRml4dHVyZURlcGVuZGVuY3lFcnJvcihgVGhlIFwiJHtuYW1lfVwiIGZpeHR1cmUgd2FzIGFscmVhZHkgcmVnaXN0ZXJlZCB3aXRoIGEgXCIke29wdGlvbnMuc2NvcGV9XCIgc2NvcGUuYCkpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmIChwYXJlbnQuYXV0byAhPT0gb3B0aW9ucy5hdXRvKSB7XG5cdFx0XHRcdFx0ZXJyb3JzLnB1c2gobmV3IEZpeHR1cmVEZXBlbmRlbmN5RXJyb3IoYFRoZSBcIiR7bmFtZX1cIiBmaXh0dXJlIHdhcyBhbHJlYWR5IHJlZ2lzdGVyZWQgYXMgeyBhdXRvOiAke29wdGlvbnMuYXV0b30gfS5gKSk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAocGFyZW50KSB7XG5cdFx0XHRcdG9wdGlvbnMgPSB7XG5cdFx0XHRcdFx0YXV0bzogcGFyZW50LmF1dG8sXG5cdFx0XHRcdFx0c2NvcGU6IHBhcmVudC5zY29wZSxcblx0XHRcdFx0XHRpbmplY3RlZDogcGFyZW50LmluamVjdGVkXG5cdFx0XHRcdH07XG5cdFx0XHR9IGVsc2UgaWYgKCFvcHRpb25zKSB7XG5cdFx0XHRcdG9wdGlvbnMgPSB7XG5cdFx0XHRcdFx0YXV0bzogZmFsc2UsXG5cdFx0XHRcdFx0aW5qZWN0ZWQ6IGZhbHNlLFxuXHRcdFx0XHRcdHNjb3BlOiBcInRlc3RcIlxuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdFx0aWYgKG9wdGlvbnMuc2NvcGUgJiYgIVRlc3RGaXh0dXJlcy5fZml4dHVyZVNjb3Blcy5pbmNsdWRlcyhvcHRpb25zLnNjb3BlKSkge1xuXHRcdFx0XHRlcnJvcnMucHVzaChuZXcgRml4dHVyZURlcGVuZGVuY3lFcnJvcihgVGhlIFwiJHtuYW1lfVwiIGZpeHR1cmUgaGFzIHVua25vd24gc2NvcGUgXCIke29wdGlvbnMuc2NvcGV9XCIuYCkpO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCFzdXBwb3J0Tm9uVGVzdCAmJiBvcHRpb25zLnNjb3BlICE9PSBcInRlc3RcIikge1xuXHRcdFx0XHRlcnJvcnMucHVzaChuZXcgRml4dHVyZURlcGVuZGVuY3lFcnJvcihgVGhlIFwiJHtuYW1lfVwiIGZpeHR1cmUgY2Fubm90IGJlIGRlZmluZWQgd2l0aCBhICR7b3B0aW9ucy5zY29wZX0gc2NvcGUkeyFfb3B0aW9ucz8uc2NvcGUgJiYgcGFyZW50Py5zY29wZSA/IFwiIChpbmhlcml0ZWQgZnJvbSB0aGUgYmFzZSBmaXh0dXJlKVwiIDogXCJcIn0gaW5zaWRlIHRoZSBkZXNjcmliZSBibG9jay4gRGVmaW5lIGl0IGF0IHRoZSB0b3AgbGV2ZWwgb2YgdGhlIGZpbGUgaW5zdGVhZC5gKSk7XG5cdFx0XHR9XG5cdFx0XHRjb25zdCBkZXBzID0gaXNGaXh0dXJlRnVuY3Rpb24odmFsdWUpID8gZ2V0VXNlZFByb3BzKHZhbHVlKSA6IG5ldyBTZXQoKTtcblx0XHRcdGNvbnN0IGl0ZW0gPSB7XG5cdFx0XHRcdG5hbWUsXG5cdFx0XHRcdHZhbHVlLFxuXHRcdFx0XHRhdXRvOiBvcHRpb25zLmF1dG8gPz8gZmFsc2UsXG5cdFx0XHRcdGluamVjdGVkOiBvcHRpb25zLmluamVjdGVkID8/IGZhbHNlLFxuXHRcdFx0XHRzY29wZTogb3B0aW9ucy5zY29wZSA/PyBcInRlc3RcIixcblx0XHRcdFx0ZGVwcyxcblx0XHRcdFx0cGFyZW50XG5cdFx0XHR9O1xuXHRcdFx0aWYgKGlzRml4dHVyZUZ1bmN0aW9uKHZhbHVlKSkge1xuXHRcdFx0XHRPYmplY3QuYXNzaWduKHZhbHVlLCB7IFtGSVhUVVJFX1NUQUNLX1RSQUNFX0tFWV06IG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpIH0pO1xuXHRcdFx0fVxuXHRcdFx0cmVnaXN0cmF0aW9ucy5zZXQobmFtZSwgaXRlbSk7XG5cdFx0XHRpZiAoaXRlbS5zY29wZSA9PT0gXCJ3b3JrZXJcIiAmJiAocnVubmVyLnBvb2wgPT09IFwidm1UaHJlYWRzXCIgfHwgcnVubmVyLnBvb2wgPT09IFwidm1Gb3Jrc1wiKSkge1xuXHRcdFx0XHRpdGVtLnNjb3BlID0gXCJmaWxlXCI7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Ly8gdmFsaWRhdGUgZml4dHVyZSBkZXBlbmRlbmN5IHNjb3Blc1xuXHRcdGZvciAoY29uc3QgZml4dHVyZSBvZiByZWdpc3RyYXRpb25zLnZhbHVlcygpKSB7XG5cdFx0XHRmb3IgKGNvbnN0IGRlcE5hbWUgb2YgZml4dHVyZS5kZXBzKSB7XG5cdFx0XHRcdGlmIChUZXN0Rml4dHVyZXMuX2J1aWx0aW5GaXh0dXJlcy5pbmNsdWRlcyhkZXBOYW1lKSkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGNvbnN0IGRlcCA9IHJlZ2lzdHJhdGlvbnMuZ2V0KGRlcE5hbWUpO1xuXHRcdFx0XHRpZiAoIWRlcCkge1xuXHRcdFx0XHRcdGVycm9ycy5wdXNoKG5ldyBGaXh0dXJlRGVwZW5kZW5jeUVycm9yKGBUaGUgXCIke2ZpeHR1cmUubmFtZX1cIiBmaXh0dXJlIGRlcGVuZHMgb24gdW5rbm93biBmaXh0dXJlIFwiJHtkZXBOYW1lfVwiLmApKTtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoZGVwTmFtZSA9PT0gZml4dHVyZS5uYW1lICYmICFmaXh0dXJlLnBhcmVudCkge1xuXHRcdFx0XHRcdGVycm9ycy5wdXNoKG5ldyBGaXh0dXJlRGVwZW5kZW5jeUVycm9yKGBUaGUgXCIke2ZpeHR1cmUubmFtZX1cIiBmaXh0dXJlIGRlcGVuZHMgb24gaXRzZWxmLCBidXQgZG9lcyBub3QgaGF2ZSBhIGJhc2UgaW1wbGVtZW50YXRpb24uYCkpO1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmIChUZXN0Rml4dHVyZXMuX2ZpeHR1cmVTY29wZXMuaW5kZXhPZihmaXh0dXJlLnNjb3BlKSA+IFRlc3RGaXh0dXJlcy5fZml4dHVyZVNjb3Blcy5pbmRleE9mKGRlcC5zY29wZSkpIHtcblx0XHRcdFx0XHRlcnJvcnMucHVzaChuZXcgRml4dHVyZURlcGVuZGVuY3lFcnJvcihgVGhlICR7Zml4dHVyZS5zY29wZX0gXCIke2ZpeHR1cmUubmFtZX1cIiBmaXh0dXJlIGNhbm5vdCBkZXBlbmQgb24gYSAke2RlcC5zY29wZX0gZml4dHVyZSBcIiR7ZGVwLm5hbWV9XCIuYCkpO1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmIChlcnJvcnMubGVuZ3RoID09PSAxKSB7XG5cdFx0XHR0aHJvdyBlcnJvcnNbMF07XG5cdFx0fSBlbHNlIGlmIChlcnJvcnMubGVuZ3RoID4gMSkge1xuXHRcdFx0dGhyb3cgbmV3IEFnZ3JlZ2F0ZUVycm9yKGVycm9ycywgXCJDYW5ub3QgcmVzb2x2ZSB1c2VyIGZpeHR1cmVzLiBTZWUgZXJyb3JzIGZvciBtb3JlIGluZm9ybWF0aW9uLlwiKTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlZ2lzdHJhdGlvbnM7XG5cdH1cbn1cbmNvbnN0IGNsZWFudXBGbkFycmF5TWFwID0gbmV3IFdlYWtNYXAoKTtcbmFzeW5jIGZ1bmN0aW9uIGNhbGxGaXh0dXJlQ2xlYW51cChjb250ZXh0KSB7XG5cdGNvbnN0IGNsZWFudXBGbkFycmF5ID0gY2xlYW51cEZuQXJyYXlNYXAuZ2V0KGNvbnRleHQpID8/IFtdO1xuXHRmb3IgKGNvbnN0IGNsZWFudXAgb2YgY2xlYW51cEZuQXJyYXkucmV2ZXJzZSgpKSB7XG5cdFx0YXdhaXQgY2xlYW51cCgpO1xuXHR9XG5cdGNsZWFudXBGbkFycmF5TWFwLmRlbGV0ZShjb250ZXh0KTtcbn1cbi8qKlxuKiBSZXR1cm5zIHRoZSBjdXJyZW50IG51bWJlciBvZiBjbGVhbnVwIGZ1bmN0aW9ucyByZWdpc3RlcmVkIGZvciB0aGUgY29udGV4dC5cbiogVGhpcyBjYW4gYmUgdXNlZCBhcyBhIGNoZWNrcG9pbnQgdG8gbGF0ZXIgY2xlYW4gdXAgb25seSBmaXh0dXJlcyBhZGRlZCBhZnRlciB0aGlzIHBvaW50LlxuKi9cbmZ1bmN0aW9uIGdldEZpeHR1cmVDbGVhbnVwQ291bnQoY29udGV4dCkge1xuXHRyZXR1cm4gY2xlYW51cEZuQXJyYXlNYXAuZ2V0KGNvbnRleHQpPy5sZW5ndGggPz8gMDtcbn1cbi8qKlxuKiBDbGVhbnMgdXAgb25seSBmaXh0dXJlcyB0aGF0IHdlcmUgYWRkZWQgYWZ0ZXIgdGhlIGdpdmVuIGNoZWNrcG9pbnQgaW5kZXguXG4qIFRoaXMgaXMgdXNlZCBieSBhcm91bmRFYWNoIHRvIGNsZWFuIHVwIGZpeHR1cmVzIGNyZWF0ZWQgaW5zaWRlIHJ1blRlc3QoKVxuKiB3aGlsZSBwcmVzZXJ2aW5nIGZpeHR1cmVzIHRoYXQgd2VyZSBjcmVhdGVkIGZvciBhcm91bmRFYWNoIGl0c2VsZi5cbiovXG5hc3luYyBmdW5jdGlvbiBjYWxsRml4dHVyZUNsZWFudXBGcm9tKGNvbnRleHQsIGZyb21JbmRleCkge1xuXHRjb25zdCBjbGVhbnVwRm5BcnJheSA9IGNsZWFudXBGbkFycmF5TWFwLmdldChjb250ZXh0KTtcblx0aWYgKCFjbGVhbnVwRm5BcnJheSB8fCBjbGVhbnVwRm5BcnJheS5sZW5ndGggPD0gZnJvbUluZGV4KSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdC8vIEdldCBpdGVtcyBhZGRlZCBhZnRlciB0aGUgY2hlY2twb2ludFxuXHRjb25zdCB0b0NsZWFudXAgPSBjbGVhbnVwRm5BcnJheS5zbGljZShmcm9tSW5kZXgpO1xuXHQvLyBDbGVhbiB1cCBpbiByZXZlcnNlIG9yZGVyXG5cdGZvciAoY29uc3QgY2xlYW51cCBvZiB0b0NsZWFudXAucmV2ZXJzZSgpKSB7XG5cdFx0YXdhaXQgY2xlYW51cCgpO1xuXHR9XG5cdC8vIFJlbW92ZSBjbGVhbmVkIHVwIGl0ZW1zIGZyb20gdGhlIGFycmF5LCBrZWVwaW5nIGl0ZW1zIGJlZm9yZSBjaGVja3BvaW50XG5cdGNsZWFudXBGbkFycmF5Lmxlbmd0aCA9IGZyb21JbmRleDtcbn1cbmNvbnN0IGNvbnRleHRIYXNGaXh0dXJlc0NhY2hlID0gbmV3IFdlYWtNYXAoKTtcbmZ1bmN0aW9uIHdpdGhGaXh0dXJlcyhmbiwgb3B0aW9ucykge1xuXHRjb25zdCBjb2xsZWN0b3IgPSBnZXRDdXJyZW50U3VpdGUoKTtcblx0Y29uc3Qgc3VpdGUgPSBvcHRpb25zPy5zdWl0ZSB8fCBjb2xsZWN0b3Iuc3VpdGUgfHwgY29sbGVjdG9yLmZpbGU7XG5cdHJldHVybiBhc3luYyAoaG9va0NvbnRleHQpID0+IHtcblx0XHRjb25zdCBjb250ZXh0ID0gaG9va0NvbnRleHQgfHwgb3B0aW9ucz8uY29udGV4dDtcblx0XHRpZiAoIWNvbnRleHQpIHtcblx0XHRcdGlmIChvcHRpb25zPy5zdWl0ZUhvb2spIHtcblx0XHRcdFx0dmFsaWRhdGVTdWl0ZUhvb2soZm4sIG9wdGlvbnMuc3VpdGVIb29rLCBvcHRpb25zLnN0YWNrVHJhY2VFcnJvcik7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gZm4oe30pO1xuXHRcdH1cblx0XHRjb25zdCBmaXh0dXJlcyA9IG9wdGlvbnM/LmZpeHR1cmVzIHx8IGdldFRlc3RGaXh0dXJlcyhjb250ZXh0KTtcblx0XHRpZiAoIWZpeHR1cmVzKSB7XG5cdFx0XHRyZXR1cm4gZm4oY29udGV4dCk7XG5cdFx0fVxuXHRcdGNvbnN0IHJlZ2lzdHJhdGlvbnMgPSBmaXh0dXJlcy5nZXQoc3VpdGUpO1xuXHRcdGlmICghcmVnaXN0cmF0aW9ucy5zaXplKSB7XG5cdFx0XHRyZXR1cm4gZm4oY29udGV4dCk7XG5cdFx0fVxuXHRcdGNvbnN0IHVzZWRGaXh0dXJlcyA9IFtdO1xuXHRcdGNvbnN0IHVzZWRQcm9wcyA9IGdldFVzZWRQcm9wcyhmbik7XG5cdFx0Zm9yIChjb25zdCBmaXh0dXJlIG9mIHJlZ2lzdHJhdGlvbnMudmFsdWVzKCkpIHtcblx0XHRcdGlmIChpc0F1dG9GaXh0dXJlKGZpeHR1cmUsIG9wdGlvbnMpIHx8IHVzZWRQcm9wcy5oYXMoZml4dHVyZS5uYW1lKSkge1xuXHRcdFx0XHR1c2VkRml4dHVyZXMucHVzaChmaXh0dXJlKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0aWYgKCF1c2VkRml4dHVyZXMubGVuZ3RoKSB7XG5cdFx0XHRyZXR1cm4gZm4oY29udGV4dCk7XG5cdFx0fVxuXHRcdGlmICghY2xlYW51cEZuQXJyYXlNYXAuaGFzKGNvbnRleHQpKSB7XG5cdFx0XHRjbGVhbnVwRm5BcnJheU1hcC5zZXQoY29udGV4dCwgW10pO1xuXHRcdH1cblx0XHRjb25zdCBjbGVhbnVwRm5BcnJheSA9IGNsZWFudXBGbkFycmF5TWFwLmdldChjb250ZXh0KTtcblx0XHRjb25zdCBwZW5kaW5nRml4dHVyZXMgPSByZXNvbHZlRGVwcyh1c2VkRml4dHVyZXMsIHJlZ2lzdHJhdGlvbnMpO1xuXHRcdGlmICghcGVuZGluZ0ZpeHR1cmVzLmxlbmd0aCkge1xuXHRcdFx0cmV0dXJuIGZuKGNvbnRleHQpO1xuXHRcdH1cblx0XHQvLyBDaGVjayBpZiBzdWl0ZS1sZXZlbCBob29rIGlzIHRyeWluZyB0byBhY2Nlc3MgdGVzdC1zY29wZWQgZml4dHVyZXNcblx0XHQvLyBTdWl0ZSBob29rcyAoYmVmb3JlQWxsL2FmdGVyQWxsL2Fyb3VuZEFsbCkgY2FuIG9ubHkgYWNjZXNzIGZpbGUvd29ya2VyIHNjb3BlZCBmaXh0dXJlc1xuXHRcdGlmIChvcHRpb25zPy5zdWl0ZUhvb2spIHtcblx0XHRcdGNvbnN0IHRlc3RTY29wZWRGaXh0dXJlcyA9IHBlbmRpbmdGaXh0dXJlcy5maWx0ZXIoKGYpID0+IGYuc2NvcGUgPT09IFwidGVzdFwiKTtcblx0XHRcdGlmICh0ZXN0U2NvcGVkRml4dHVyZXMubGVuZ3RoID4gMCkge1xuXHRcdFx0XHRjb25zdCBmaXh0dXJlTmFtZXMgPSB0ZXN0U2NvcGVkRml4dHVyZXMubWFwKChmKSA9PiBgXCIke2YubmFtZX1cImApLmpvaW4oXCIsIFwiKTtcblx0XHRcdFx0Y29uc3QgYWx0ZXJuYXRpdmVIb29rID0ge1xuXHRcdFx0XHRcdGFyb3VuZEFsbDogXCJhcm91bmRFYWNoXCIsXG5cdFx0XHRcdFx0YmVmb3JlQWxsOiBcImJlZm9yZUVhY2hcIixcblx0XHRcdFx0XHRhZnRlckFsbDogXCJhZnRlckVhY2hcIlxuXHRcdFx0XHR9O1xuXHRcdFx0XHRjb25zdCBlcnJvciA9IG5ldyBGaXh0dXJlRGVwZW5kZW5jeUVycm9yKGBUZXN0LXNjb3BlZCBmaXh0dXJlcyBjYW5ub3QgYmUgdXNlZCBpbnNpZGUgJHtvcHRpb25zLnN1aXRlSG9va30gaG9vay4gYCArIGBUaGUgZm9sbG93aW5nIGZpeHR1cmVzIGFyZSB0ZXN0LXNjb3BlZDogJHtmaXh0dXJlTmFtZXN9LiBgICsgYFVzZSB7IHNjb3BlOiAnZmlsZScgfSBvciB7IHNjb3BlOiAnd29ya2VyJyB9IGZpeHR1cmVzIGluc3RlYWQsIG9yIG1vdmUgdGhlIGxvZ2ljIHRvICR7YWx0ZXJuYXRpdmVIb29rW29wdGlvbnMuc3VpdGVIb29rXX0gaG9vay5gKTtcblx0XHRcdFx0Ly8gVXNlIHN0YWNrIHRyYWNlIGZyb20gaG9vayByZWdpc3RyYXRpb24gZm9yIGJldHRlciBlcnJvciBsb2NhdGlvblxuXHRcdFx0XHRpZiAob3B0aW9ucy5zdGFja1RyYWNlRXJyb3I/LnN0YWNrKSB7XG5cdFx0XHRcdFx0ZXJyb3Iuc3RhY2sgPSBlcnJvci5tZXNzYWdlICsgb3B0aW9ucy5zdGFja1RyYWNlRXJyb3Iuc3RhY2sucmVwbGFjZShvcHRpb25zLnN0YWNrVHJhY2VFcnJvci5tZXNzYWdlLCBcIlwiKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aHJvdyBlcnJvcjtcblx0XHRcdH1cblx0XHR9XG5cdFx0aWYgKCFjb250ZXh0SGFzRml4dHVyZXNDYWNoZS5oYXMoY29udGV4dCkpIHtcblx0XHRcdGNvbnRleHRIYXNGaXh0dXJlc0NhY2hlLnNldChjb250ZXh0LCBuZXcgV2Vha1NldCgpKTtcblx0XHR9XG5cdFx0Y29uc3QgY2FjaGVkRml4dHVyZXMgPSBjb250ZXh0SGFzRml4dHVyZXNDYWNoZS5nZXQoY29udGV4dCk7XG5cdFx0Zm9yIChjb25zdCBmaXh0dXJlIG9mIHBlbmRpbmdGaXh0dXJlcykge1xuXHRcdFx0aWYgKGZpeHR1cmUuc2NvcGUgPT09IFwidGVzdFwiKSB7XG5cdFx0XHRcdC8vIGZpeHR1cmUgY291bGQgYmUgYWxyZWFkeSBpbml0aWFsaXplZCBkdXJpbmcgXCJiZWZvcmVcIiBob29rXG5cdFx0XHRcdC8vIHdlIGNhbid0IGNoZWNrIFwiZml4dHVyZS5uYW1lXCIgaW4gY29udGV4dCBiZWNhdXNlIGNvbnRleHQgbWF5XG5cdFx0XHRcdC8vIGFjY2VzcyB0aGUgcGFyZW50IGZpeHR1cmUgKHsgYTogKHsgYSB9KSA9PiB7fSB9KVxuXHRcdFx0XHRpZiAoY2FjaGVkRml4dHVyZXMuaGFzKGZpeHR1cmUpKSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y2FjaGVkRml4dHVyZXMuYWRkKGZpeHR1cmUpO1xuXHRcdFx0XHRjb25zdCByZXNvbHZlZFZhbHVlID0gYXdhaXQgcmVzb2x2ZVRlc3RGaXh0dXJlVmFsdWUoZml4dHVyZSwgY29udGV4dCwgY2xlYW51cEZuQXJyYXkpO1xuXHRcdFx0XHRjb250ZXh0W2ZpeHR1cmUubmFtZV0gPSByZXNvbHZlZFZhbHVlO1xuXHRcdFx0XHRjbGVhbnVwRm5BcnJheS5wdXNoKCgpID0+IHtcblx0XHRcdFx0XHRjYWNoZWRGaXh0dXJlcy5kZWxldGUoZml4dHVyZSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y29uc3QgcmVzb2x2ZWRWYWx1ZSA9IGF3YWl0IHJlc29sdmVTY29wZUZpeHR1cmVWYWx1ZShmaXh0dXJlcywgc3VpdGUsIGZpeHR1cmUpO1xuXHRcdFx0XHRjb250ZXh0W2ZpeHR1cmUubmFtZV0gPSByZXNvbHZlZFZhbHVlO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gZm4oY29udGV4dCk7XG5cdH07XG59XG5mdW5jdGlvbiBpc0F1dG9GaXh0dXJlKGZpeHR1cmUsIG9wdGlvbnMpIHtcblx0aWYgKCFmaXh0dXJlLmF1dG8pIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblx0Ly8gc3VpdGUgaG9vayBkb2Vzbid0IGF1dG9tYXRpY2FsbHkgdHJpZ2dlciB1bnVzZWQgdGVzdC1zY29wZWQgZml4dHVyZXMuXG5cdGlmIChvcHRpb25zPy5zdWl0ZUhvb2sgJiYgZml4dHVyZS5zY29wZSA9PT0gXCJ0ZXN0XCIpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblx0cmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiBpc0ZpeHR1cmVGdW5jdGlvbih2YWx1ZSkge1xuXHRyZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCI7XG59XG5mdW5jdGlvbiByZXNvbHZlVGVzdEZpeHR1cmVWYWx1ZShmaXh0dXJlLCBjb250ZXh0LCBjbGVhbnVwRm5BcnJheSkge1xuXHRpZiAoIWlzRml4dHVyZUZ1bmN0aW9uKGZpeHR1cmUudmFsdWUpKSB7XG5cdFx0cmV0dXJuIGZpeHR1cmUudmFsdWU7XG5cdH1cblx0cmV0dXJuIHJlc29sdmVGaXh0dXJlRnVuY3Rpb24oZml4dHVyZS52YWx1ZSwgZml4dHVyZS5uYW1lLCBjb250ZXh0LCBjbGVhbnVwRm5BcnJheSk7XG59XG5jb25zdCBzY29wZWRGaXh0dXJlUHJvbWlzZUNhY2hlID0gbmV3IFdlYWtNYXAoKTtcbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVTY29wZUZpeHR1cmVWYWx1ZShmaXh0dXJlcywgc3VpdGUsIGZpeHR1cmUpIHtcblx0Y29uc3Qgd29ya2VyQ29udGV4dCA9IGZpeHR1cmVzLmdldFdvcmtlckNvbnRleHQoKTtcblx0Y29uc3QgZmlsZUNvbnRleHQgPSBmaXh0dXJlcy5nZXRGaWxlQ29udGV4dChzdWl0ZS5maWxlKTtcblx0Y29uc3QgZml4dHVyZUNvbnRleHQgPSBmaXh0dXJlLnNjb3BlID09PSBcIndvcmtlclwiID8gd29ya2VyQ29udGV4dCA6IGZpbGVDb250ZXh0O1xuXHRpZiAoIWlzRml4dHVyZUZ1bmN0aW9uKGZpeHR1cmUudmFsdWUpKSB7XG5cdFx0Zml4dHVyZUNvbnRleHRbZml4dHVyZS5uYW1lXSA9IGZpeHR1cmUudmFsdWU7XG5cdFx0cmV0dXJuIGZpeHR1cmUudmFsdWU7XG5cdH1cblx0aWYgKGZpeHR1cmUubmFtZSBpbiBmaXh0dXJlQ29udGV4dCkge1xuXHRcdHJldHVybiBmaXh0dXJlQ29udGV4dFtmaXh0dXJlLm5hbWVdO1xuXHR9XG5cdGlmIChzY29wZWRGaXh0dXJlUHJvbWlzZUNhY2hlLmhhcyhmaXh0dXJlKSkge1xuXHRcdHJldHVybiBzY29wZWRGaXh0dXJlUHJvbWlzZUNhY2hlLmdldChmaXh0dXJlKTtcblx0fVxuXHRpZiAoIWNsZWFudXBGbkFycmF5TWFwLmhhcyhmaXh0dXJlQ29udGV4dCkpIHtcblx0XHRjbGVhbnVwRm5BcnJheU1hcC5zZXQoZml4dHVyZUNvbnRleHQsIFtdKTtcblx0fVxuXHRjb25zdCBjbGVhbnVwRm5GaWxlQXJyYXkgPSBjbGVhbnVwRm5BcnJheU1hcC5nZXQoZml4dHVyZUNvbnRleHQpO1xuXHRjb25zdCBwcm9taXNlID0gcmVzb2x2ZUZpeHR1cmVGdW5jdGlvbihmaXh0dXJlLnZhbHVlLCBmaXh0dXJlLm5hbWUsIGZpeHR1cmUuc2NvcGUgPT09IFwiZmlsZVwiID8ge1xuXHRcdC4uLndvcmtlckNvbnRleHQsXG5cdFx0Li4uZmlsZUNvbnRleHRcblx0fSA6IGZpeHR1cmVDb250ZXh0LCBjbGVhbnVwRm5GaWxlQXJyYXkpLnRoZW4oKHZhbHVlKSA9PiB7XG5cdFx0Zml4dHVyZUNvbnRleHRbZml4dHVyZS5uYW1lXSA9IHZhbHVlO1xuXHRcdHNjb3BlZEZpeHR1cmVQcm9taXNlQ2FjaGUuZGVsZXRlKGZpeHR1cmUpO1xuXHRcdHJldHVybiB2YWx1ZTtcblx0fSk7XG5cdHNjb3BlZEZpeHR1cmVQcm9taXNlQ2FjaGUuc2V0KGZpeHR1cmUsIHByb21pc2UpO1xuXHRyZXR1cm4gcHJvbWlzZTtcbn1cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVGaXh0dXJlRnVuY3Rpb24oZml4dHVyZUZuLCBmaXh0dXJlTmFtZSwgY29udGV4dCwgY2xlYW51cEZuQXJyYXkpIHtcblx0Ly8gd2FpdCBmb3IgYHVzZWAgY2FsbCB0byBleHRyYWN0IGZpeHR1cmUgdmFsdWVcblx0Y29uc3QgdXNlRm5BcmdQcm9taXNlID0gY3JlYXRlRGVmZXIoKTtcblx0Y29uc3Qgc3RhY2tUcmFjZUVycm9yID0gRklYVFVSRV9TVEFDS19UUkFDRV9LRVkgaW4gZml4dHVyZUZuICYmIGZpeHR1cmVGbltGSVhUVVJFX1NUQUNLX1RSQUNFX0tFWV0gaW5zdGFuY2VvZiBFcnJvciA/IGZpeHR1cmVGbltGSVhUVVJFX1NUQUNLX1RSQUNFX0tFWV0gOiB1bmRlZmluZWQ7XG5cdGxldCBpc1VzZUZuQXJnUmVzb2x2ZWQgPSBmYWxzZTtcblx0Y29uc3QgZml4dHVyZVJldHVybiA9IGZpeHR1cmVGbihjb250ZXh0LCBhc3luYyAodXNlRm5BcmcpID0+IHtcblx0XHQvLyBleHRyYWN0IGB1c2VgIGFyZ3VtZW50XG5cdFx0aXNVc2VGbkFyZ1Jlc29sdmVkID0gdHJ1ZTtcblx0XHR1c2VGbkFyZ1Byb21pc2UucmVzb2x2ZSh1c2VGbkFyZyk7XG5cdFx0Ly8gc3VzcGVuZCBmaXh0dXJlIHRlYXJkb3duIGJ5IGhvbGRpbmcgb2ZmIGB1c2VSZXR1cm5Qcm9taXNlYCByZXNvbHV0aW9uIHVudGlsIGNsZWFudXBcblx0XHRjb25zdCB1c2VSZXR1cm5Qcm9taXNlID0gY3JlYXRlRGVmZXIoKTtcblx0XHRjbGVhbnVwRm5BcnJheS5wdXNoKGFzeW5jICgpID0+IHtcblx0XHRcdC8vIHN0YXJ0IHRlYXJkb3duIGJ5IHJlc29sdmluZyBgdXNlYCBQcm9taXNlXG5cdFx0XHR1c2VSZXR1cm5Qcm9taXNlLnJlc29sdmUoKTtcblx0XHRcdC8vIHdhaXQgZm9yIGZpbmlzaGluZyB0ZWFyZG93blxuXHRcdFx0YXdhaXQgZml4dHVyZVJldHVybjtcblx0XHR9KTtcblx0XHRhd2FpdCB1c2VSZXR1cm5Qcm9taXNlO1xuXHR9KS50aGVuKCgpID0+IHtcblx0XHQvLyBmaXh0dXJlIHJldHVybmVkIHdpdGhvdXQgY2FsbGluZyB1c2UoKVxuXHRcdGlmICghaXNVc2VGbkFyZ1Jlc29sdmVkKSB7XG5cdFx0XHRjb25zdCBlcnJvciA9IG5ldyBFcnJvcihgRml4dHVyZSBcIiR7Zml4dHVyZU5hbWV9XCIgcmV0dXJuZWQgd2l0aG91dCBjYWxsaW5nIFwidXNlXCIuIE1ha2Ugc3VyZSB0byBjYWxsIFwidXNlXCIgaW4gZXZlcnkgY29kZSBwYXRoIG9mIHRoZSBmaXh0dXJlIGZ1bmN0aW9uLmApO1xuXHRcdFx0aWYgKHN0YWNrVHJhY2VFcnJvcj8uc3RhY2spIHtcblx0XHRcdFx0ZXJyb3Iuc3RhY2sgPSBlcnJvci5tZXNzYWdlICsgc3RhY2tUcmFjZUVycm9yLnN0YWNrLnJlcGxhY2Uoc3RhY2tUcmFjZUVycm9yLm1lc3NhZ2UsIFwiXCIpO1xuXHRcdFx0fVxuXHRcdFx0dXNlRm5BcmdQcm9taXNlLnJlamVjdChlcnJvcik7XG5cdFx0fVxuXHR9KS5jYXRjaCgoZSkgPT4ge1xuXHRcdC8vIHRyZWF0IGZpeHR1cmUgc2V0dXAgZXJyb3IgYXMgdGVzdCBmYWlsdXJlXG5cdFx0aWYgKCFpc1VzZUZuQXJnUmVzb2x2ZWQpIHtcblx0XHRcdHVzZUZuQXJnUHJvbWlzZS5yZWplY3QoZSk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdC8vIG90aGVyd2lzZSByZS10aHJvdyB0byBhdm9pZCBzaWxlbmNpbmcgZXJyb3IgZHVyaW5nIGNsZWFudXBcblx0XHR0aHJvdyBlO1xuXHR9KTtcblx0cmV0dXJuIHVzZUZuQXJnUHJvbWlzZTtcbn1cbmZ1bmN0aW9uIHJlc29sdmVEZXBzKHVzZWRGaXh0dXJlcywgcmVnaXN0cmF0aW9ucywgZGVwU2V0ID0gbmV3IFNldCgpLCBwZW5kaW5nRml4dHVyZXMgPSBbXSkge1xuXHR1c2VkRml4dHVyZXMuZm9yRWFjaCgoZml4dHVyZSkgPT4ge1xuXHRcdGlmIChwZW5kaW5nRml4dHVyZXMuaW5jbHVkZXMoZml4dHVyZSkpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKCFpc0ZpeHR1cmVGdW5jdGlvbihmaXh0dXJlLnZhbHVlKSB8fCAhZml4dHVyZS5kZXBzKSB7XG5cdFx0XHRwZW5kaW5nRml4dHVyZXMucHVzaChmaXh0dXJlKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKGRlcFNldC5oYXMoZml4dHVyZSkpIHtcblx0XHRcdGlmIChmaXh0dXJlLnBhcmVudCkge1xuXHRcdFx0XHRmaXh0dXJlID0gZml4dHVyZS5wYXJlbnQ7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoYENpcmN1bGFyIGZpeHR1cmUgZGVwZW5kZW5jeSBkZXRlY3RlZDogJHtmaXh0dXJlLm5hbWV9IDwtICR7Wy4uLmRlcFNldF0ucmV2ZXJzZSgpLm1hcCgoZCkgPT4gZC5uYW1lKS5qb2luKFwiIDwtIFwiKX1gKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZGVwU2V0LmFkZChmaXh0dXJlKTtcblx0XHRyZXNvbHZlRGVwcyhbLi4uZml4dHVyZS5kZXBzXS5tYXAoKG4pID0+IG4gPT09IGZpeHR1cmUubmFtZSA/IGZpeHR1cmUucGFyZW50IDogcmVnaXN0cmF0aW9ucy5nZXQobikpLmZpbHRlcigobikgPT4gISFuKSwgcmVnaXN0cmF0aW9ucywgZGVwU2V0LCBwZW5kaW5nRml4dHVyZXMpO1xuXHRcdHBlbmRpbmdGaXh0dXJlcy5wdXNoKGZpeHR1cmUpO1xuXHRcdGRlcFNldC5jbGVhcigpO1xuXHR9KTtcblx0cmV0dXJuIHBlbmRpbmdGaXh0dXJlcztcbn1cbmZ1bmN0aW9uIHZhbGlkYXRlU3VpdGVIb29rKGZuLCBob29rLCBzdWl0ZUVycm9yKSB7XG5cdGNvbnN0IHVzZWRQcm9wcyA9IGdldFVzZWRQcm9wcyhmbiwge1xuXHRcdHNvdXJjZUVycm9yOiBzdWl0ZUVycm9yLFxuXHRcdHN1aXRlSG9vazogaG9va1xuXHR9KTtcblx0aWYgKHVzZWRQcm9wcy5zaXplKSB7XG5cdFx0Y29uc3QgZXJyb3IgPSBuZXcgRml4dHVyZUFjY2Vzc0Vycm9yKGBUaGUgJHtob29rfSBob29rIHVzZXMgZml4dHVyZXMgXCIke1suLi51c2VkUHJvcHNdLmpvaW4oXCJcXFwiLCBcXFwiXCIpfVwiLCBidXQgaGFzIG5vIGFjY2VzcyB0byBjb250ZXh0LiBgICsgYERpZCB5b3UgZm9yZ2V0IHRvIGNhbGwgaXQgYXMgXCJ0ZXN0LiR7aG9va30oKVwiIGluc3RlYWQgb2YgXCIke2hvb2t9KClcIj9cXG5gICsgYElmIHlvdSB1c2VkIGludGVybmFsIFwic3VpdGVcIiB0YXNrIGFzIHRoZSBmaXJzdCBhcmd1bWVudCBwcmV2aW91c2x5LCBhY2Nlc3MgaXQgaW4gdGhlIHNlY29uZCBhcmd1bWVudCBpbnN0ZWFkLiBgICsgYFNlZSBodHRwczovL3ZpdGVzdC5kZXYvZ3VpZGUvdGVzdC1jb250ZXh0I3N1aXRlLWxldmVsLWhvb2tzYCk7XG5cdFx0aWYgKHN1aXRlRXJyb3IpIHtcblx0XHRcdGVycm9yLnN0YWNrID0gc3VpdGVFcnJvci5zdGFjaz8ucmVwbGFjZShzdWl0ZUVycm9yLm1lc3NhZ2UsIGVycm9yLm1lc3NhZ2UpO1xuXHRcdH1cblx0XHR0aHJvdyBlcnJvcjtcblx0fVxufVxuY29uc3Qga1Byb3BzU3ltYm9sID0gU3ltYm9sKFwiJHZpdGVzdDpmaXh0dXJlLXByb3BzXCIpO1xuY29uc3Qga1Byb3BOYW1lc1N5bWJvbCA9IFN5bWJvbChcIiR2aXRlc3Q6Zml4dHVyZS1wcm9wLW5hbWVzXCIpO1xuZnVuY3Rpb24gY29uZmlndXJlUHJvcHMoZm4sIG9wdGlvbnMpIHtcblx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGZuLCBrUHJvcHNTeW1ib2wsIHtcblx0XHR2YWx1ZTogb3B0aW9ucyxcblx0XHRlbnVtZXJhYmxlOiBmYWxzZVxuXHR9KTtcbn1cbmZ1bmN0aW9uIG1lbW9Qcm9wcyhmbiwgcHJvcHMpIHtcblx0Zm5ba1Byb3BOYW1lc1N5bWJvbF0gPSBwcm9wcztcblx0cmV0dXJuIHByb3BzO1xufVxuZnVuY3Rpb24gZ2V0VXNlZFByb3BzKGZuLCB7IHNvdXJjZUVycm9yLCBzdWl0ZUhvb2sgfSA9IHt9KSB7XG5cdGlmIChrUHJvcE5hbWVzU3ltYm9sIGluIGZuKSB7XG5cdFx0cmV0dXJuIGZuW2tQcm9wTmFtZXNTeW1ib2xdO1xuXHR9XG5cdGNvbnN0IHsgaW5kZXg6IGZpeHR1cmVzSW5kZXggPSAwLCBvcmlnaW5hbDogaW1wbGVtZW50YXRpb24gPSBmbiB9ID0ga1Byb3BzU3ltYm9sIGluIGZuID8gZm5ba1Byb3BzU3ltYm9sXSA6IHt9O1xuXHRsZXQgZm5TdHJpbmcgPSBmaWx0ZXJPdXRDb21tZW50cyhpbXBsZW1lbnRhdGlvbi50b1N0cmluZygpKTtcblx0Ly8gbWF0Y2ggbG93ZXJlZCBhc3luYyBmdW5jdGlvbiBhbmQgc3RyaXAgaXQgb2ZmXG5cdC8vIGV4YW1wbGUgY29kZSBvbiBlc2J1aWxkLXRyeSBodHRwczovL2VzYnVpbGQuZ2l0aHViLmlvL3RyeS8jWWdBd0xqSTBMakFBTFMxemRYQndiM0owWldRNllYTjVibU10WVhkaGFYUTlabUZzYzJVQVpRQmxiblJ5ZVM1MGN3QmpiMjV6ZENCdklEMGdld29nSUdZeE9pQmhjM2x1WXlBb0tTQTlQaUI3ZlN3S0lDQm1Nam9nWVhONWJtTWdLR0VwSUQwK0lIdDlMQW9nSUdZek9pQmhjM2x1WXlBb1lTd2dZaWtnUFQ0Z2UzMHNDaUFnWmpRNklHRnplVzVqSUdaMWJtTjBhVzl1S0dFcElIdDlMQW9nSUdZMU9pQmhjM2x1WXlCbWRXNWpkR2x2YmlCbVppaGhLU0I3ZlN3S0lDQmhjM2x1WXlCbU5paGhLU0I3ZlN3S0NpQWdaekU2SUdGemVXNWpJQ2dwSUQwK0lIdDlMQW9nSUdjeU9pQmhjM2x1WXlBb2V5QmhJSDBwSUQwK0lIdDlMQW9nSUdjek9pQmhjM2x1WXlBb2V5QmhJSDBzSUdJcElEMCtJSHQ5TEFvZ0lHYzBPaUJoYzNsdVl5Qm1kVzVqZEdsdmJpQW9leUJoSUgwcElIdDlMQW9nSUdjMU9pQmhjM2x1WXlCbWRXNWpkR2x2YmlCblp5aDdJR0VnZlNrZ2UzMHNDaUFnWVhONWJtTWdaellvZXlCaElIMHBJSHQ5TEFvS0lDQm9NVG9nWVhONWJtTWdLQ2tnUFQ0Z2UzMHNDaUFnTHk4Z1kyOXRiV1Z1ZENCaVpYUjNaV1Z1Q2lBZ2FESTZJR0Z6ZVc1aklDaGhLU0E5UGlCN2ZTd0tmUVxuXHQvLyAgIF9fYXN5bmModGhpcywgbnVsbCwgZnVuY3Rpb24qXG5cdC8vICAgX19hc3luYyh0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uKlxuXHQvLyAgIF9fYXN5bmModGhpcywgW18wLCBfMV0sIGZ1bmN0aW9uKlxuXHRpZiAoL19fYXN5bmNcXCgoPzp0aGlzfG51bGwpLCAoPzpudWxsfGFyZ3VtZW50c3xcXFtbXzAtOSwgXSpcXF0pLCBmdW5jdGlvblxcKi8udGVzdChmblN0cmluZykpIHtcblx0XHRmblN0cmluZyA9IGZuU3RyaW5nLnNwbGl0KC9fX2FzeW5jXFwoKD86dGhpc3xudWxsKSwvKVsxXTtcblx0fVxuXHRjb25zdCBtYXRjaCA9IGZuU3RyaW5nLm1hdGNoKC9bXihdKlxcKChbXildKikvKTtcblx0aWYgKCFtYXRjaCkge1xuXHRcdHJldHVybiBtZW1vUHJvcHMoZm4sIG5ldyBTZXQoKSk7XG5cdH1cblx0Y29uc3QgYXJncyA9IHNwbGl0QnlDb21tYShtYXRjaFsxXSk7XG5cdGlmICghYXJncy5sZW5ndGgpIHtcblx0XHRyZXR1cm4gbWVtb1Byb3BzKGZuLCBuZXcgU2V0KCkpO1xuXHR9XG5cdGNvbnN0IGZpeHR1cmVzQXJndW1lbnQgPSBhcmdzW2ZpeHR1cmVzSW5kZXhdO1xuXHRpZiAoIWZpeHR1cmVzQXJndW1lbnQpIHtcblx0XHRyZXR1cm4gbWVtb1Byb3BzKGZuLCBuZXcgU2V0KCkpO1xuXHR9XG5cdGlmICghKGZpeHR1cmVzQXJndW1lbnRbMF0gPT09IFwie1wiICYmIGZpeHR1cmVzQXJndW1lbnQuZW5kc1dpdGgoXCJ9XCIpKSkge1xuXHRcdGNvbnN0IG9yZGluYWxBcmd1bWVudCA9IG9yZGluYWwoZml4dHVyZXNJbmRleCArIDEpO1xuXHRcdGNvbnN0IGVycm9yID0gbmV3IEZpeHR1cmVQYXJzZUVycm9yKGBUaGUgJHtvcmRpbmFsQXJndW1lbnR9IGFyZ3VtZW50IGluc2lkZSBhIGZpeHR1cmUgbXVzdCB1c2Ugb2JqZWN0IGRlc3RydWN0dXJpbmcgcGF0dGVybiwgZS5nLiAoeyB0YXNrIH0gPT4ge30pLiBgICsgYEluc3RlYWQsIHJlY2VpdmVkIFwiJHtmaXh0dXJlc0FyZ3VtZW50fVwiLmAgKyBgJHtzdWl0ZUhvb2sgPyBgIElmIHlvdSB1c2VkIGludGVybmFsIFwic3VpdGVcIiB0YXNrIGFzIHRoZSAke29yZGluYWxBcmd1bWVudH0gYXJndW1lbnQgcHJldmlvdXNseSwgYWNjZXNzIGl0IGluIHRoZSAke29yZGluYWwoZml4dHVyZXNJbmRleCArIDIpfSBhcmd1bWVudCBpbnN0ZWFkLmAgOiBcIlwifWApO1xuXHRcdGlmIChzb3VyY2VFcnJvcikge1xuXHRcdFx0ZXJyb3Iuc3RhY2sgPSBzb3VyY2VFcnJvci5zdGFjaz8ucmVwbGFjZShzb3VyY2VFcnJvci5tZXNzYWdlLCBlcnJvci5tZXNzYWdlKTtcblx0XHR9XG5cdFx0dGhyb3cgZXJyb3I7XG5cdH1cblx0Y29uc3QgX2ZpcnN0ID0gZml4dHVyZXNBcmd1bWVudC5zbGljZSgxLCAtMSkucmVwbGFjZSgvXFxzL2csIFwiXCIpO1xuXHRjb25zdCBwcm9wcyA9IHNwbGl0QnlDb21tYShfZmlyc3QpLm1hcCgocHJvcCkgPT4ge1xuXHRcdHJldHVybiBwcm9wLnJlcGxhY2UoLzouKnw9LiovZywgXCJcIik7XG5cdH0pO1xuXHRjb25zdCBsYXN0ID0gcHJvcHMuYXQoLTEpO1xuXHRpZiAobGFzdCAmJiBsYXN0LnN0YXJ0c1dpdGgoXCIuLi5cIikpIHtcblx0XHRjb25zdCBlcnJvciA9IG5ldyBGaXh0dXJlUGFyc2VFcnJvcihgUmVzdCBwYXJhbWV0ZXJzIGFyZSBub3Qgc3VwcG9ydGVkIGluIGZpeHR1cmVzLCByZWNlaXZlZCBcIiR7bGFzdH1cIi5gKTtcblx0XHRpZiAoc291cmNlRXJyb3IpIHtcblx0XHRcdGVycm9yLnN0YWNrID0gc291cmNlRXJyb3Iuc3RhY2s/LnJlcGxhY2Uoc291cmNlRXJyb3IubWVzc2FnZSwgZXJyb3IubWVzc2FnZSk7XG5cdFx0fVxuXHRcdHRocm93IGVycm9yO1xuXHR9XG5cdHJldHVybiBtZW1vUHJvcHMoZm4sIG5ldyBTZXQocHJvcHMpKTtcbn1cbmZ1bmN0aW9uIHNwbGl0QnlDb21tYShzKSB7XG5cdGNvbnN0IHJlc3VsdCA9IFtdO1xuXHRjb25zdCBzdGFjayA9IFtdO1xuXHRsZXQgc3RhcnQgPSAwO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IHMubGVuZ3RoOyBpKyspIHtcblx0XHRpZiAoc1tpXSA9PT0gXCJ7XCIgfHwgc1tpXSA9PT0gXCJbXCIpIHtcblx0XHRcdHN0YWNrLnB1c2goc1tpXSA9PT0gXCJ7XCIgPyBcIn1cIiA6IFwiXVwiKTtcblx0XHR9IGVsc2UgaWYgKHNbaV0gPT09IHN0YWNrLmF0KC0xKSkge1xuXHRcdFx0c3RhY2sucG9wKCk7XG5cdFx0fSBlbHNlIGlmICghc3RhY2subGVuZ3RoICYmIHNbaV0gPT09IFwiLFwiKSB7XG5cdFx0XHRjb25zdCB0b2tlbiA9IHMuc3Vic3RyaW5nKHN0YXJ0LCBpKS50cmltKCk7XG5cdFx0XHRpZiAodG9rZW4pIHtcblx0XHRcdFx0cmVzdWx0LnB1c2godG9rZW4pO1xuXHRcdFx0fVxuXHRcdFx0c3RhcnQgPSBpICsgMTtcblx0XHR9XG5cdH1cblx0Y29uc3QgbGFzdFRva2VuID0gcy5zdWJzdHJpbmcoc3RhcnQpLnRyaW0oKTtcblx0aWYgKGxhc3RUb2tlbikge1xuXHRcdHJlc3VsdC5wdXNoKGxhc3RUb2tlbik7XG5cdH1cblx0cmV0dXJuIHJlc3VsdDtcbn1cblxubGV0IF90ZXN0O1xuZnVuY3Rpb24gc2V0Q3VycmVudFRlc3QodGVzdCkge1xuXHRfdGVzdCA9IHRlc3Q7XG59XG5mdW5jdGlvbiBnZXRDdXJyZW50VGVzdCgpIHtcblx0cmV0dXJuIF90ZXN0O1xufVxuY29uc3QgdGVzdHMgPSBbXTtcbmZ1bmN0aW9uIGFkZFJ1bm5pbmdUZXN0KHRlc3QpIHtcblx0dGVzdHMucHVzaCh0ZXN0KTtcblx0cmV0dXJuICgpID0+IHtcblx0XHR0ZXN0cy5zcGxpY2UodGVzdHMuaW5kZXhPZih0ZXN0KSk7XG5cdH07XG59XG5mdW5jdGlvbiBnZXRSdW5uaW5nVGVzdHMoKSB7XG5cdHJldHVybiB0ZXN0cztcbn1cblxuY29uc3Qga0NoYWluYWJsZUNvbnRleHQgPSBTeW1ib2woXCJrQ2hhaW5hYmxlQ29udGV4dFwiKTtcbmZ1bmN0aW9uIGdldENoYWluYWJsZUNvbnRleHQoY2hhaW5hYmxlKSB7XG5cdHJldHVybiBjaGFpbmFibGU/LltrQ2hhaW5hYmxlQ29udGV4dF07XG59XG5mdW5jdGlvbiBjcmVhdGVDaGFpbmFibGUoa2V5cywgZm4sIGNvbnRleHQpIHtcblx0ZnVuY3Rpb24gY3JlYXRlKGNvbnRleHQpIHtcblx0XHRjb25zdCBjaGFpbiA9IGZ1bmN0aW9uKC4uLmFyZ3MpIHtcblx0XHRcdHJldHVybiBmbi5hcHBseShjb250ZXh0LCBhcmdzKTtcblx0XHR9O1xuXHRcdE9iamVjdC5hc3NpZ24oY2hhaW4sIGZuKTtcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoY2hhaW4sIGtDaGFpbmFibGVDb250ZXh0LCB7XG5cdFx0XHR2YWx1ZToge1xuXHRcdFx0XHR3aXRoQ29udGV4dDogKCkgPT4gY2hhaW4uYmluZChjb250ZXh0KSxcblx0XHRcdFx0Z2V0Rml4dHVyZXM6ICgpID0+IGNvbnRleHQuZml4dHVyZXMsXG5cdFx0XHRcdHNldENvbnRleHQ6IChrZXksIHZhbHVlKSA9PiB7XG5cdFx0XHRcdFx0Y29udGV4dFtrZXldID0gdmFsdWU7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdG1lcmdlQ29udGV4dDogKGN0eCkgPT4ge1xuXHRcdFx0XHRcdE9iamVjdC5hc3NpZ24oY29udGV4dCwgY3R4KTtcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdGVudW1lcmFibGU6IGZhbHNlXG5cdFx0fSk7XG5cdFx0Zm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGNoYWluLCBrZXksIHsgZ2V0KCkge1xuXHRcdFx0XHRyZXR1cm4gY3JlYXRlKHtcblx0XHRcdFx0XHQuLi5jb250ZXh0LFxuXHRcdFx0XHRcdFtrZXldOiB0cnVlXG5cdFx0XHRcdH0pO1xuXHRcdFx0fSB9KTtcblx0XHR9XG5cdFx0cmV0dXJuIGNoYWluO1xuXHR9XG5cdGNvbnN0IGNoYWluID0gY3JlYXRlKGNvbnRleHQgPz8ge30pO1xuXHRPYmplY3QuZGVmaW5lUHJvcGVydHkoY2hhaW4sIFwiZm5cIiwge1xuXHRcdHZhbHVlOiBmbixcblx0XHRlbnVtZXJhYmxlOiBmYWxzZVxuXHR9KTtcblx0cmV0dXJuIGNoYWluO1xufVxuXG5mdW5jdGlvbiBnZXREZWZhdWx0SG9va1RpbWVvdXQoKSB7XG5cdHJldHVybiBnZXRSdW5uZXIoKS5jb25maWcuaG9va1RpbWVvdXQ7XG59XG5jb25zdCBDTEVBTlVQX1RJTUVPVVRfS0VZID0gU3ltYm9sLmZvcihcIlZJVEVTVF9DTEVBTlVQX1RJTUVPVVRcIik7XG5jb25zdCBDTEVBTlVQX1NUQUNLX1RSQUNFX0tFWSA9IFN5bWJvbC5mb3IoXCJWSVRFU1RfQ0xFQU5VUF9TVEFDS19UUkFDRVwiKTtcbmNvbnN0IEFST1VORF9USU1FT1VUX0tFWSA9IFN5bWJvbC5mb3IoXCJWSVRFU1RfQVJPVU5EX1RJTUVPVVRcIik7XG5jb25zdCBBUk9VTkRfU1RBQ0tfVFJBQ0VfS0VZID0gU3ltYm9sLmZvcihcIlZJVEVTVF9BUk9VTkRfU1RBQ0tfVFJBQ0VcIik7XG5mdW5jdGlvbiBnZXRCZWZvcmVIb29rQ2xlYW51cENhbGxiYWNrKGhvb2ssIHJlc3VsdCwgY29udGV4dCkge1xuXHRpZiAodHlwZW9mIHJlc3VsdCA9PT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0Y29uc3QgdGltZW91dCA9IENMRUFOVVBfVElNRU9VVF9LRVkgaW4gaG9vayAmJiB0eXBlb2YgaG9va1tDTEVBTlVQX1RJTUVPVVRfS0VZXSA9PT0gXCJudW1iZXJcIiA/IGhvb2tbQ0xFQU5VUF9USU1FT1VUX0tFWV0gOiBnZXREZWZhdWx0SG9va1RpbWVvdXQoKTtcblx0XHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBDTEVBTlVQX1NUQUNLX1RSQUNFX0tFWSBpbiBob29rICYmIGhvb2tbQ0xFQU5VUF9TVEFDS19UUkFDRV9LRVldIGluc3RhbmNlb2YgRXJyb3IgPyBob29rW0NMRUFOVVBfU1RBQ0tfVFJBQ0VfS0VZXSA6IHVuZGVmaW5lZDtcblx0XHRyZXR1cm4gd2l0aFRpbWVvdXQocmVzdWx0LCB0aW1lb3V0LCB0cnVlLCBzdGFja1RyYWNlRXJyb3IsIChfLCBlcnJvcikgPT4ge1xuXHRcdFx0aWYgKGNvbnRleHQpIHtcblx0XHRcdFx0YWJvcnRDb250ZXh0U2lnbmFsKGNvbnRleHQsIGVycm9yKTtcblx0XHRcdH1cblx0XHR9KTtcblx0fVxufVxuLyoqXG4qIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIG9uY2UgYmVmb3JlIGFsbCB0ZXN0cyB3aXRoaW4gdGhlIGN1cnJlbnQgc3VpdGUuXG4qIFRoaXMgaG9vayBpcyB1c2VmdWwgZm9yIHNjZW5hcmlvcyB3aGVyZSB5b3UgbmVlZCB0byBwZXJmb3JtIHNldHVwIG9wZXJhdGlvbnMgdGhhdCBhcmUgY29tbW9uIHRvIGFsbCB0ZXN0cyBpbiBhIHN1aXRlLCBzdWNoIGFzIGluaXRpYWxpemluZyBhIGRhdGFiYXNlIGNvbm5lY3Rpb24gb3Igc2V0dGluZyB1cCBhIHRlc3QgZW52aXJvbm1lbnQuXG4qXG4qICoqTm90ZToqKiBUaGUgYGJlZm9yZUFsbGAgaG9va3MgYXJlIGV4ZWN1dGVkIGluIHRoZSBvcmRlciB0aGV5IGFyZSBkZWZpbmVkIG9uZSBhZnRlciBhbm90aGVyLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGJlZm9yZSBhbGwgdGVzdHMuXG4qIEBwYXJhbSB7bnVtYmVyfSBbdGltZW91dF0gLSBPcHRpb25hbCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIGhvb2suIElmIG5vdCBwcm92aWRlZCwgdGhlIGRlZmF1bHQgaG9vayB0aW1lb3V0IGZyb20gdGhlIHJ1bm5lcidzIGNvbmZpZ3VyYXRpb24gaXMgdXNlZC5cbiogQHJldHVybnMge3ZvaWR9XG4qIEBleGFtcGxlXG4qIGBgYHRzXG4qIC8vIEV4YW1wbGUgb2YgdXNpbmcgYmVmb3JlQWxsIHRvIHNldCB1cCBhIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiogYmVmb3JlQWxsKGFzeW5jICgpID0+IHtcbiogICBhd2FpdCBkYXRhYmFzZS5jb25uZWN0KCk7XG4qIH0pO1xuKiBgYGBcbiovXG5mdW5jdGlvbiBiZWZvcmVBbGwoZm4sIHRpbWVvdXQgPSBnZXREZWZhdWx0SG9va1RpbWVvdXQoKSkge1xuXHRhc3NlcnRUeXBlcyhmbiwgXCJcXFwiYmVmb3JlQWxsXFxcIiBjYWxsYmFja1wiLCBbXCJmdW5jdGlvblwiXSk7XG5cdGNvbnN0IHN0YWNrVHJhY2VFcnJvciA9IG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpO1xuXHRjb25zdCBjb250ZXh0ID0gZ2V0Q2hhaW5hYmxlQ29udGV4dCh0aGlzKTtcblx0cmV0dXJuIGdldEN1cnJlbnRTdWl0ZSgpLm9uKFwiYmVmb3JlQWxsXCIsIE9iamVjdC5hc3NpZ24od2l0aFRpbWVvdXQod2l0aFN1aXRlRml4dHVyZXMoXCJiZWZvcmVBbGxcIiwgZm4sIGNvbnRleHQsIHN0YWNrVHJhY2VFcnJvciksIHRpbWVvdXQsIHRydWUsIHN0YWNrVHJhY2VFcnJvciksIHtcblx0XHRbQ0xFQU5VUF9USU1FT1VUX0tFWV06IHRpbWVvdXQsXG5cdFx0W0NMRUFOVVBfU1RBQ0tfVFJBQ0VfS0VZXTogc3RhY2tUcmFjZUVycm9yXG5cdH0pKTtcbn1cbi8qKlxuKiBSZWdpc3RlcnMgYSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCBvbmNlIGFmdGVyIGFsbCB0ZXN0cyB3aXRoaW4gdGhlIGN1cnJlbnQgc3VpdGUgaGF2ZSBjb21wbGV0ZWQuXG4qIFRoaXMgaG9vayBpcyB1c2VmdWwgZm9yIHNjZW5hcmlvcyB3aGVyZSB5b3UgbmVlZCB0byBwZXJmb3JtIGNsZWFudXAgb3BlcmF0aW9ucyBhZnRlciBhbGwgdGVzdHMgaW4gYSBzdWl0ZSBoYXZlIHJ1biwgc3VjaCBhcyBjbG9zaW5nIGRhdGFiYXNlIGNvbm5lY3Rpb25zIG9yIGNsZWFuaW5nIHVwIHRlbXBvcmFyeSBmaWxlcy5cbipcbiogKipOb3RlOioqIFRoZSBgYWZ0ZXJBbGxgIGhvb2tzIGFyZSBydW5uaW5nIGluIHJldmVyc2Ugb3JkZXIgb2YgdGhlaXIgcmVnaXN0cmF0aW9uLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGFmdGVyIGFsbCB0ZXN0cy5cbiogQHBhcmFtIHtudW1iZXJ9IFt0aW1lb3V0XSAtIE9wdGlvbmFsIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgaG9vay4gSWYgbm90IHByb3ZpZGVkLCB0aGUgZGVmYXVsdCBob29rIHRpbWVvdXQgZnJvbSB0aGUgcnVubmVyJ3MgY29uZmlndXJhdGlvbiBpcyB1c2VkLlxuKiBAcmV0dXJucyB7dm9pZH1cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRXhhbXBsZSBvZiB1c2luZyBhZnRlckFsbCB0byBjbG9zZSBhIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiogYWZ0ZXJBbGwoYXN5bmMgKCkgPT4ge1xuKiAgIGF3YWl0IGRhdGFiYXNlLmRpc2Nvbm5lY3QoKTtcbiogfSk7XG4qIGBgYFxuKi9cbmZ1bmN0aW9uIGFmdGVyQWxsKGZuLCB0aW1lb3V0KSB7XG5cdGFzc2VydFR5cGVzKGZuLCBcIlxcXCJhZnRlckFsbFxcXCIgY2FsbGJhY2tcIiwgW1wiZnVuY3Rpb25cIl0pO1xuXHRjb25zdCBjb250ZXh0ID0gZ2V0Q2hhaW5hYmxlQ29udGV4dCh0aGlzKTtcblx0Y29uc3Qgc3RhY2tUcmFjZUVycm9yID0gbmV3IEVycm9yKFwiU1RBQ0tfVFJBQ0VfRVJST1JcIik7XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImFmdGVyQWxsXCIsIHdpdGhUaW1lb3V0KHdpdGhTdWl0ZUZpeHR1cmVzKFwiYWZ0ZXJBbGxcIiwgZm4sIGNvbnRleHQsIHN0YWNrVHJhY2VFcnJvciksIHRpbWVvdXQgPz8gZ2V0RGVmYXVsdEhvb2tUaW1lb3V0KCksIHRydWUsIHN0YWNrVHJhY2VFcnJvcikpO1xufVxuLyoqXG4qIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGJlZm9yZSBlYWNoIHRlc3Qgd2l0aGluIHRoZSBjdXJyZW50IHN1aXRlLlxuKiBUaGlzIGhvb2sgaXMgdXNlZnVsIGZvciBzY2VuYXJpb3Mgd2hlcmUgeW91IG5lZWQgdG8gcmVzZXQgb3IgcmVpbml0aWFsaXplIHRoZSB0ZXN0IGVudmlyb25tZW50IGJlZm9yZSBlYWNoIHRlc3QgcnVucywgc3VjaCBhcyByZXNldHRpbmcgZGF0YWJhc2Ugc3RhdGVzLCBjbGVhcmluZyBjYWNoZXMsIG9yIHJlaW5pdGlhbGl6aW5nIHZhcmlhYmxlcy5cbipcbiogKipOb3RlOioqIFRoZSBgYmVmb3JlRWFjaGAgaG9va3MgYXJlIGV4ZWN1dGVkIGluIHRoZSBvcmRlciB0aGV5IGFyZSBkZWZpbmVkIG9uZSBhZnRlciBhbm90aGVyLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGJlZm9yZSBlYWNoIHRlc3QuIFRoaXMgZnVuY3Rpb24gcmVjZWl2ZXMgYW4gYFRlc3RDb250ZXh0YCBwYXJhbWV0ZXIgaWYgYWRkaXRpb25hbCB0ZXN0IGNvbnRleHQgaXMgbmVlZGVkLlxuKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRdIC0gT3B0aW9uYWwgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBob29rLiBJZiBub3QgcHJvdmlkZWQsIHRoZSBkZWZhdWx0IGhvb2sgdGltZW91dCBmcm9tIHRoZSBydW5uZXIncyBjb25maWd1cmF0aW9uIGlzIHVzZWQuXG4qIEByZXR1cm5zIHt2b2lkfVxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBFeGFtcGxlIG9mIHVzaW5nIGJlZm9yZUVhY2ggdG8gcmVzZXQgYSBkYXRhYmFzZSBzdGF0ZVxuKiBiZWZvcmVFYWNoKGFzeW5jICgpID0+IHtcbiogICBhd2FpdCBkYXRhYmFzZS5yZXNldCgpO1xuKiB9KTtcbiogYGBgXG4qL1xuZnVuY3Rpb24gYmVmb3JlRWFjaChmbiwgdGltZW91dCA9IGdldERlZmF1bHRIb29rVGltZW91dCgpKSB7XG5cdGFzc2VydFR5cGVzKGZuLCBcIlxcXCJiZWZvcmVFYWNoXFxcIiBjYWxsYmFja1wiLCBbXCJmdW5jdGlvblwiXSk7XG5cdGNvbnN0IHN0YWNrVHJhY2VFcnJvciA9IG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpO1xuXHRjb25zdCB3cmFwcGVyID0gKGNvbnRleHQsIHN1aXRlKSA9PiB7XG5cdFx0Y29uc3QgZml4dHVyZVJlc29sdmVyID0gd2l0aEZpeHR1cmVzKGZuLCB7IHN1aXRlIH0pO1xuXHRcdHJldHVybiBmaXh0dXJlUmVzb2x2ZXIoY29udGV4dCk7XG5cdH07XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImJlZm9yZUVhY2hcIiwgT2JqZWN0LmFzc2lnbih3aXRoVGltZW91dCh3cmFwcGVyLCB0aW1lb3V0ID8/IGdldERlZmF1bHRIb29rVGltZW91dCgpLCB0cnVlLCBzdGFja1RyYWNlRXJyb3IsIGFib3J0SWZUaW1lb3V0KSwge1xuXHRcdFtDTEVBTlVQX1RJTUVPVVRfS0VZXTogdGltZW91dCxcblx0XHRbQ0xFQU5VUF9TVEFDS19UUkFDRV9LRVldOiBzdGFja1RyYWNlRXJyb3Jcblx0fSkpO1xufVxuLyoqXG4qIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGFmdGVyIGVhY2ggdGVzdCB3aXRoaW4gdGhlIGN1cnJlbnQgc3VpdGUgaGFzIGNvbXBsZXRlZC5cbiogVGhpcyBob29rIGlzIHVzZWZ1bCBmb3Igc2NlbmFyaW9zIHdoZXJlIHlvdSBuZWVkIHRvIGNsZWFuIHVwIG9yIHJlc2V0IHRoZSB0ZXN0IGVudmlyb25tZW50IGFmdGVyIGVhY2ggdGVzdCBydW5zLCBzdWNoIGFzIGRlbGV0aW5nIHRlbXBvcmFyeSBmaWxlcywgY2xlYXJpbmcgdGVzdC1zcGVjaWZpYyBkYXRhYmFzZSBlbnRyaWVzLCBvciByZXNldHRpbmcgbW9ja2VkIGZ1bmN0aW9ucy5cbipcbiogKipOb3RlOioqIFRoZSBgYWZ0ZXJFYWNoYCBob29rcyBhcmUgcnVubmluZyBpbiByZXZlcnNlIG9yZGVyIG9mIHRoZWlyIHJlZ2lzdHJhdGlvbi4gWW91IGNhbiBjb25maWd1cmUgdGhpcyBieSBjaGFuZ2luZyB0aGUgYHNlcXVlbmNlLmhvb2tzYCBvcHRpb24gaW4gdGhlIGNvbmZpZyBmaWxlLlxuKlxuKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCBhZnRlciBlYWNoIHRlc3QuIFRoaXMgZnVuY3Rpb24gcmVjZWl2ZXMgYW4gYFRlc3RDb250ZXh0YCBwYXJhbWV0ZXIgaWYgYWRkaXRpb25hbCB0ZXN0IGNvbnRleHQgaXMgbmVlZGVkLlxuKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRdIC0gT3B0aW9uYWwgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBob29rLiBJZiBub3QgcHJvdmlkZWQsIHRoZSBkZWZhdWx0IGhvb2sgdGltZW91dCBmcm9tIHRoZSBydW5uZXIncyBjb25maWd1cmF0aW9uIGlzIHVzZWQuXG4qIEByZXR1cm5zIHt2b2lkfVxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBFeGFtcGxlIG9mIHVzaW5nIGFmdGVyRWFjaCB0byBkZWxldGUgdGVtcG9yYXJ5IGZpbGVzIGNyZWF0ZWQgZHVyaW5nIGEgdGVzdFxuKiBhZnRlckVhY2goYXN5bmMgKCkgPT4ge1xuKiAgIGF3YWl0IGZpbGVTeXN0ZW0uZGVsZXRlVGVtcEZpbGVzKCk7XG4qIH0pO1xuKiBgYGBcbiovXG5mdW5jdGlvbiBhZnRlckVhY2goZm4sIHRpbWVvdXQpIHtcblx0YXNzZXJ0VHlwZXMoZm4sIFwiXFxcImFmdGVyRWFjaFxcXCIgY2FsbGJhY2tcIiwgW1wiZnVuY3Rpb25cIl0pO1xuXHRjb25zdCB3cmFwcGVyID0gKGNvbnRleHQsIHN1aXRlKSA9PiB7XG5cdFx0Y29uc3QgZml4dHVyZVJlc29sdmVyID0gd2l0aEZpeHR1cmVzKGZuLCB7IHN1aXRlIH0pO1xuXHRcdHJldHVybiBmaXh0dXJlUmVzb2x2ZXIoY29udGV4dCk7XG5cdH07XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImFmdGVyRWFjaFwiLCB3aXRoVGltZW91dCh3cmFwcGVyLCB0aW1lb3V0ID8/IGdldERlZmF1bHRIb29rVGltZW91dCgpLCB0cnVlLCBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKSwgYWJvcnRJZlRpbWVvdXQpKTtcbn1cbi8qKlxuKiBSZWdpc3RlcnMgYSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCB3aGVuIGEgdGVzdCBmYWlscyB3aXRoaW4gdGhlIGN1cnJlbnQgc3VpdGUuXG4qIFRoaXMgZnVuY3Rpb24gYWxsb3dzIGZvciBjdXN0b20gYWN0aW9ucyB0byBiZSBwZXJmb3JtZWQgaW4gcmVzcG9uc2UgdG8gdGVzdCBmYWlsdXJlcywgc3VjaCBhcyBsb2dnaW5nLCBjbGVhbnVwLCBvciBhZGRpdGlvbmFsIGRpYWdub3N0aWNzLlxuKlxuKiAqKk5vdGU6KiogVGhlIGBvblRlc3RGYWlsZWRgIGhvb2tzIGFyZSBydW5uaW5nIGluIHJldmVyc2Ugb3JkZXIgb2YgdGhlaXIgcmVnaXN0cmF0aW9uLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIHVwb24gYSB0ZXN0IGZhaWx1cmUuIFRoZSBmdW5jdGlvbiByZWNlaXZlcyB0aGUgdGVzdCByZXN1bHQgKGluY2x1ZGluZyBlcnJvcnMpLlxuKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRdIC0gT3B0aW9uYWwgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBob29rLiBJZiBub3QgcHJvdmlkZWQsIHRoZSBkZWZhdWx0IGhvb2sgdGltZW91dCBmcm9tIHRoZSBydW5uZXIncyBjb25maWd1cmF0aW9uIGlzIHVzZWQuXG4qIEB0aHJvd3Mge0Vycm9yfSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGZ1bmN0aW9uIGlzIG5vdCBjYWxsZWQgd2l0aGluIGEgdGVzdC5cbiogQHJldHVybnMge3ZvaWR9XG4qIEBleGFtcGxlXG4qIGBgYHRzXG4qIC8vIEV4YW1wbGUgb2YgdXNpbmcgb25UZXN0RmFpbGVkIHRvIGxvZyBmYWlsdXJlIGRldGFpbHNcbiogb25UZXN0RmFpbGVkKCh7IGVycm9ycyB9KSA9PiB7XG4qICAgY29uc29sZS5sb2coYFRlc3QgZmFpbGVkOiAke3Rlc3QubmFtZX1gLCBlcnJvcnMpO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3Qgb25UZXN0RmFpbGVkID0gY3JlYXRlVGVzdEhvb2soXCJvblRlc3RGYWlsZWRcIiwgKHRlc3QsIGhhbmRsZXIsIHRpbWVvdXQpID0+IHtcblx0dGVzdC5vbkZhaWxlZCB8fD0gW107XG5cdHRlc3Qub25GYWlsZWQucHVzaCh3aXRoVGltZW91dChoYW5kbGVyLCB0aW1lb3V0ID8/IGdldERlZmF1bHRIb29rVGltZW91dCgpLCB0cnVlLCBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKSwgYWJvcnRJZlRpbWVvdXQpKTtcbn0pO1xuLyoqXG4qIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIHdoZW4gdGhlIGN1cnJlbnQgdGVzdCBmaW5pc2hlcywgcmVnYXJkbGVzcyBvZiB0aGUgb3V0Y29tZSAocGFzcyBvciBmYWlsKS5cbiogVGhpcyBmdW5jdGlvbiBpcyBpZGVhbCBmb3IgcGVyZm9ybWluZyBhY3Rpb25zIHRoYXQgc2hvdWxkIG9jY3VyIGFmdGVyIGV2ZXJ5IHRlc3QgZXhlY3V0aW9uLCBzdWNoIGFzIGNsZWFudXAsIGxvZ2dpbmcsIG9yIHJlc2V0dGluZyBzaGFyZWQgcmVzb3VyY2VzLlxuKlxuKiBUaGlzIGhvb2sgaXMgdXNlZnVsIGlmIHlvdSBoYXZlIGFjY2VzcyB0byBhIHJlc291cmNlIGluIHRoZSB0ZXN0IGl0c2VsZiBhbmQgeW91IHdhbnQgdG8gY2xlYW4gaXQgdXAgYWZ0ZXIgdGhlIHRlc3QgZmluaXNoZXMuIEl0IGlzIGEgbW9yZSBjb21wYWN0IHdheSB0byBjbGVhbiB1cCByZXNvdXJjZXMgdGhhbiB1c2luZyB0aGUgY29tYmluYXRpb24gb2YgYGJlZm9yZUVhY2hgIGFuZCBgYWZ0ZXJFYWNoYC5cbipcbiogKipOb3RlOioqIFRoZSBgb25UZXN0RmluaXNoZWRgIGhvb2tzIGFyZSBydW5uaW5nIGluIHJldmVyc2Ugb3JkZXIgb2YgdGhlaXIgcmVnaXN0cmF0aW9uLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qICoqTm90ZToqKiBUaGUgYG9uVGVzdEZpbmlzaGVkYCBob29rIGlzIG5vdCBjYWxsZWQgaWYgdGhlIHRlc3QgaXMgY2FuY2VsZWQgd2l0aCBhIGR5bmFtaWMgYGN0eC5za2lwKClgIGNhbGwuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGFmdGVyIGEgdGVzdCBmaW5pc2hlcy4gVGhlIGZ1bmN0aW9uIGNhbiByZWNlaXZlIHBhcmFtZXRlcnMgcHJvdmlkaW5nIGRldGFpbHMgYWJvdXQgdGhlIGNvbXBsZXRlZCB0ZXN0LCBpbmNsdWRpbmcgaXRzIHN1Y2Nlc3Mgb3IgZmFpbHVyZSBzdGF0dXMuXG4qIEBwYXJhbSB7bnVtYmVyfSBbdGltZW91dF0gLSBPcHRpb25hbCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIGhvb2suIElmIG5vdCBwcm92aWRlZCwgdGhlIGRlZmF1bHQgaG9vayB0aW1lb3V0IGZyb20gdGhlIHJ1bm5lcidzIGNvbmZpZ3VyYXRpb24gaXMgdXNlZC5cbiogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgZnVuY3Rpb24gaXMgbm90IGNhbGxlZCB3aXRoaW4gYSB0ZXN0LlxuKiBAcmV0dXJucyB7dm9pZH1cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRXhhbXBsZSBvZiB1c2luZyBvblRlc3RGaW5pc2hlZCBmb3IgY2xlYW51cFxuKiBjb25zdCBkYiA9IGF3YWl0IGNvbm5lY3RUb0RhdGFiYXNlKCk7XG4qIG9uVGVzdEZpbmlzaGVkKGFzeW5jICgpID0+IHtcbiogICBhd2FpdCBkYi5kaXNjb25uZWN0KCk7XG4qIH0pO1xuKiBgYGBcbiovXG5jb25zdCBvblRlc3RGaW5pc2hlZCA9IGNyZWF0ZVRlc3RIb29rKFwib25UZXN0RmluaXNoZWRcIiwgKHRlc3QsIGhhbmRsZXIsIHRpbWVvdXQpID0+IHtcblx0dGVzdC5vbkZpbmlzaGVkIHx8PSBbXTtcblx0dGVzdC5vbkZpbmlzaGVkLnB1c2god2l0aFRpbWVvdXQoaGFuZGxlciwgdGltZW91dCA/PyBnZXREZWZhdWx0SG9va1RpbWVvdXQoKSwgdHJ1ZSwgbmV3IEVycm9yKFwiU1RBQ0tfVFJBQ0VfRVJST1JcIiksIGFib3J0SWZUaW1lb3V0KSk7XG59KTtcbi8qKlxuKiBSZWdpc3RlcnMgYSBjYWxsYmFjayBmdW5jdGlvbiB0aGF0IHdyYXBzIGFyb3VuZCBhbGwgdGVzdHMgd2l0aGluIHRoZSBjdXJyZW50IHN1aXRlLlxuKiBUaGUgY2FsbGJhY2sgcmVjZWl2ZXMgYSBgcnVuU3VpdGVgIGZ1bmN0aW9uIHRoYXQgbXVzdCBiZSBjYWxsZWQgdG8gcnVuIHRoZSBzdWl0ZSdzIHRlc3RzLlxuKiBUaGlzIGhvb2sgaXMgdXNlZnVsIGZvciBzY2VuYXJpb3Mgd2hlcmUgeW91IG5lZWQgdG8gd3JhcCBhbiBlbnRpcmUgc3VpdGUgaW4gYSBjb250ZXh0XG4qIChlLmcuLCBzdGFydGluZyBhIHNlcnZlciwgb3BlbmluZyBhIGRhdGFiYXNlIGNvbm5lY3Rpb24gdGhhdCBhbGwgdGVzdHMgc2hhcmUpLlxuKlxuKiAqKk5vdGU6KiogV2hlbiBtdWx0aXBsZSBgYXJvdW5kQWxsYCBob29rcyBhcmUgcmVnaXN0ZXJlZCwgdGhleSBhcmUgbmVzdGVkIGluc2lkZSBlYWNoIG90aGVyLlxuKiBUaGUgZmlyc3QgcmVnaXN0ZXJlZCBob29rIGlzIHRoZSBvdXRlcm1vc3Qgd3JhcHBlci5cbipcbiogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCB3cmFwcyB0aGUgc3VpdGUuIE11c3QgY2FsbCBgcnVuU3VpdGUoKWAgdG8gcnVuIHRoZSB0ZXN0cy5cbiogQHBhcmFtIHtudW1iZXJ9IFt0aW1lb3V0XSAtIE9wdGlvbmFsIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgaG9vay4gSWYgbm90IHByb3ZpZGVkLCB0aGUgZGVmYXVsdCBob29rIHRpbWVvdXQgZnJvbSB0aGUgcnVubmVyJ3MgY29uZmlndXJhdGlvbiBpcyB1c2VkLlxuKiBAcmV0dXJucyB7dm9pZH1cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRXhhbXBsZSBvZiB1c2luZyBhcm91bmRBbGwgdG8gd3JhcCBzdWl0ZSBpbiBhIHRyYWNpbmcgc3BhblxuKiBhcm91bmRBbGwoYXN5bmMgKHJ1blN1aXRlKSA9PiB7XG4qICAgYXdhaXQgdHJhY2VyLnRyYWNlKCd0ZXN0LXN1aXRlJywgcnVuU3VpdGUpO1xuKiB9KTtcbiogYGBgXG4qIEBleGFtcGxlXG4qIGBgYHRzXG4qIC8vIEV4YW1wbGUgb2YgdXNpbmcgYXJvdW5kQWxsIHdpdGggZml4dHVyZXNcbiogYXJvdW5kQWxsKGFzeW5jIChydW5TdWl0ZSwgeyBkYiB9KSA9PiB7XG4qICAgYXdhaXQgZGIudHJhbnNhY3Rpb24oKCkgPT4gcnVuU3VpdGUoKSk7XG4qIH0pO1xuKiBgYGBcbiovXG5mdW5jdGlvbiBhcm91bmRBbGwoZm4sIHRpbWVvdXQpIHtcblx0YXNzZXJ0VHlwZXMoZm4sIFwiXFxcImFyb3VuZEFsbFxcXCIgY2FsbGJhY2tcIiwgW1wiZnVuY3Rpb25cIl0pO1xuXHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKTtcblx0Y29uc3QgcmVzb2x2ZWRUaW1lb3V0ID0gdGltZW91dCA/PyBnZXREZWZhdWx0SG9va1RpbWVvdXQoKTtcblx0Y29uc3QgY29udGV4dCA9IGdldENoYWluYWJsZUNvbnRleHQodGhpcyk7XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImFyb3VuZEFsbFwiLCBPYmplY3QuYXNzaWduKHdpdGhTdWl0ZUZpeHR1cmVzKFwiYXJvdW5kQWxsXCIsIGZuLCBjb250ZXh0LCBzdGFja1RyYWNlRXJyb3IsIDEpLCB7XG5cdFx0W0FST1VORF9USU1FT1VUX0tFWV06IHJlc29sdmVkVGltZW91dCxcblx0XHRbQVJPVU5EX1NUQUNLX1RSQUNFX0tFWV06IHN0YWNrVHJhY2VFcnJvclxuXHR9KSk7XG59XG4vKipcbiogUmVnaXN0ZXJzIGEgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCB3cmFwcyBhcm91bmQgZWFjaCB0ZXN0IHdpdGhpbiB0aGUgY3VycmVudCBzdWl0ZS5cbiogVGhlIGNhbGxiYWNrIHJlY2VpdmVzIGEgYHJ1blRlc3RgIGZ1bmN0aW9uIHRoYXQgbXVzdCBiZSBjYWxsZWQgdG8gcnVuIHRoZSB0ZXN0LlxuKiBUaGlzIGhvb2sgaXMgdXNlZnVsIGZvciBzY2VuYXJpb3Mgd2hlcmUgeW91IG5lZWQgdG8gd3JhcCB0ZXN0cyBpbiBhIGNvbnRleHQgKGUuZy4sIGRhdGFiYXNlIHRyYW5zYWN0aW9ucykuXG4qXG4qICoqTm90ZToqKiBXaGVuIG11bHRpcGxlIGBhcm91bmRFYWNoYCBob29rcyBhcmUgcmVnaXN0ZXJlZCwgdGhleSBhcmUgbmVzdGVkIGluc2lkZSBlYWNoIG90aGVyLlxuKiBUaGUgZmlyc3QgcmVnaXN0ZXJlZCBob29rIGlzIHRoZSBvdXRlcm1vc3Qgd3JhcHBlci5cbipcbiogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCB3cmFwcyB0aGUgdGVzdC4gTXVzdCBjYWxsIGBydW5UZXN0KClgIHRvIHJ1biB0aGUgdGVzdC5cbiogQHBhcmFtIHtudW1iZXJ9IFt0aW1lb3V0XSAtIE9wdGlvbmFsIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgaG9vay4gSWYgbm90IHByb3ZpZGVkLCB0aGUgZGVmYXVsdCBob29rIHRpbWVvdXQgZnJvbSB0aGUgcnVubmVyJ3MgY29uZmlndXJhdGlvbiBpcyB1c2VkLlxuKiBAcmV0dXJucyB7dm9pZH1cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRXhhbXBsZSBvZiB1c2luZyBhcm91bmRFYWNoIHRvIHdyYXAgdGVzdHMgaW4gYSBkYXRhYmFzZSB0cmFuc2FjdGlvblxuKiBhcm91bmRFYWNoKGFzeW5jIChydW5UZXN0KSA9PiB7XG4qICAgYXdhaXQgZGF0YWJhc2UudHJhbnNhY3Rpb24oKCkgPT4gcnVuVGVzdCgpKTtcbiogfSk7XG4qIGBgYFxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBFeGFtcGxlIG9mIHVzaW5nIGFyb3VuZEVhY2ggd2l0aCBmaXh0dXJlc1xuKiBhcm91bmRFYWNoKGFzeW5jIChydW5UZXN0LCB7IGRiIH0pID0+IHtcbiogICBhd2FpdCBkYi50cmFuc2FjdGlvbigoKSA9PiBydW5UZXN0KCkpO1xuKiB9KTtcbiogYGBgXG4qL1xuZnVuY3Rpb24gYXJvdW5kRWFjaChmbiwgdGltZW91dCkge1xuXHRhc3NlcnRUeXBlcyhmbiwgXCJcXFwiYXJvdW5kRWFjaFxcXCIgY2FsbGJhY2tcIiwgW1wiZnVuY3Rpb25cIl0pO1xuXHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKTtcblx0Y29uc3QgcmVzb2x2ZWRUaW1lb3V0ID0gdGltZW91dCA/PyBnZXREZWZhdWx0SG9va1RpbWVvdXQoKTtcblx0Y29uc3Qgd3JhcHBlciA9IChydW5UZXN0LCBjb250ZXh0LCBzdWl0ZSkgPT4ge1xuXHRcdGNvbnN0IGlubmVyRm4gPSAoY3R4KSA9PiBmbihydW5UZXN0LCBjdHgsIHN1aXRlKTtcblx0XHRjb25maWd1cmVQcm9wcyhpbm5lckZuLCB7XG5cdFx0XHRpbmRleDogMSxcblx0XHRcdG9yaWdpbmFsOiBmblxuXHRcdH0pO1xuXHRcdGNvbnN0IGZpeHR1cmVSZXNvbHZlciA9IHdpdGhGaXh0dXJlcyhpbm5lckZuLCB7IHN1aXRlIH0pO1xuXHRcdHJldHVybiBmaXh0dXJlUmVzb2x2ZXIoY29udGV4dCk7XG5cdH07XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImFyb3VuZEVhY2hcIiwgT2JqZWN0LmFzc2lnbih3cmFwcGVyLCB7XG5cdFx0W0FST1VORF9USU1FT1VUX0tFWV06IHJlc29sdmVkVGltZW91dCxcblx0XHRbQVJPVU5EX1NUQUNLX1RSQUNFX0tFWV06IHN0YWNrVHJhY2VFcnJvclxuXHR9KSk7XG59XG5mdW5jdGlvbiB3aXRoU3VpdGVGaXh0dXJlcyhzdWl0ZUhvb2ssIGZuLCBjb250ZXh0LCBzdGFja1RyYWNlRXJyb3IsIGNvbnRleHRJbmRleCA9IDApIHtcblx0cmV0dXJuICguLi5hcmdzKSA9PiB7XG5cdFx0Y29uc3Qgc3VpdGUgPSBhcmdzLmF0KC0xKTtcblx0XHRjb25zdCBwcmVmaXggPSBhcmdzLnNsaWNlKDAsIC0xKTtcblx0XHRjb25zdCB3cmFwcGVyID0gKGN0eCkgPT4gZm4oLi4ucHJlZml4LCBjdHgsIHN1aXRlKTtcblx0XHRjb25maWd1cmVQcm9wcyh3cmFwcGVyLCB7XG5cdFx0XHRpbmRleDogY29udGV4dEluZGV4LFxuXHRcdFx0b3JpZ2luYWw6IGZuXG5cdFx0fSk7XG5cdFx0Y29uc3QgZml4dHVyZXMgPSBjb250ZXh0Py5nZXRGaXh0dXJlcygpO1xuXHRcdGNvbnN0IGZpbGVDb250ZXh0ID0gZml4dHVyZXM/LmdldEZpbGVDb250ZXh0KHN1aXRlLmZpbGUpO1xuXHRcdGNvbnN0IGZpeHR1cmVkID0gd2l0aEZpeHR1cmVzKHdyYXBwZXIsIHtcblx0XHRcdHN1aXRlSG9vayxcblx0XHRcdGZpeHR1cmVzLFxuXHRcdFx0Y29udGV4dDogZmlsZUNvbnRleHQsXG5cdFx0XHRzdGFja1RyYWNlRXJyb3Jcblx0XHR9KTtcblx0XHRyZXR1cm4gZml4dHVyZWQoKTtcblx0fTtcbn1cbmZ1bmN0aW9uIGdldEFyb3VuZEhvb2tUaW1lb3V0KGhvb2spIHtcblx0cmV0dXJuIEFST1VORF9USU1FT1VUX0tFWSBpbiBob29rICYmIHR5cGVvZiBob29rW0FST1VORF9USU1FT1VUX0tFWV0gPT09IFwibnVtYmVyXCIgPyBob29rW0FST1VORF9USU1FT1VUX0tFWV0gOiBnZXREZWZhdWx0SG9va1RpbWVvdXQoKTtcbn1cbmZ1bmN0aW9uIGdldEFyb3VuZEhvb2tTdGFja1RyYWNlKGhvb2spIHtcblx0cmV0dXJuIEFST1VORF9TVEFDS19UUkFDRV9LRVkgaW4gaG9vayAmJiBob29rW0FST1VORF9TVEFDS19UUkFDRV9LRVldIGluc3RhbmNlb2YgRXJyb3IgPyBob29rW0FST1VORF9TVEFDS19UUkFDRV9LRVldIDogdW5kZWZpbmVkO1xufVxuZnVuY3Rpb24gY3JlYXRlVGVzdEhvb2sobmFtZSwgaGFuZGxlcikge1xuXHRyZXR1cm4gKGZuLCB0aW1lb3V0KSA9PiB7XG5cdFx0YXNzZXJ0VHlwZXMoZm4sIGBcIiR7bmFtZX1cIiBjYWxsYmFja2AsIFtcImZ1bmN0aW9uXCJdKTtcblx0XHRjb25zdCBjdXJyZW50ID0gZ2V0Q3VycmVudFRlc3QoKTtcblx0XHRpZiAoIWN1cnJlbnQpIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcihgSG9vayAke25hbWV9KCkgY2FuIG9ubHkgYmUgY2FsbGVkIGluc2lkZSBhIHRlc3RgKTtcblx0XHR9XG5cdFx0cmV0dXJuIGhhbmRsZXIoY3VycmVudCwgZm4sIHRpbWVvdXQpO1xuXHR9O1xufVxuXG4vKipcbiogSWYgYW55IHRhc2tzIGJlZW4gbWFya2VkIGFzIGBvbmx5YCwgbWFyayBhbGwgb3RoZXIgdGFza3MgYXMgYHNraXBgLlxuKi9cbmZ1bmN0aW9uIGludGVycHJldFRhc2tNb2RlcyhmaWxlLCBuYW1lUGF0dGVybiwgdGVzdExvY2F0aW9ucywgdGVzdElkcywgdGVzdFRhZ3NGaWx0ZXIsIG9ubHlNb2RlLCBwYXJlbnRJc09ubHksIGFsbG93T25seSkge1xuXHRjb25zdCBtYXRjaGVkTG9jYXRpb25zID0gW107XG5cdGNvbnN0IHRyYXZlcnNlU3VpdGUgPSAoc3VpdGUsIHBhcmVudElzT25seSwgcGFyZW50TWF0Y2hlZFdpdGhMb2NhdGlvbikgPT4ge1xuXHRcdGNvbnN0IHN1aXRlSXNPbmx5ID0gcGFyZW50SXNPbmx5IHx8IHN1aXRlLm1vZGUgPT09IFwib25seVwiO1xuXHRcdC8vIENoZWNrIGlmIGFueSB0YXNrcyBpbiB0aGlzIHN1aXRlIGhhdmUgYC5vbmx5YCAtIGlmIHNvLCBvbmx5IHRob3NlIHNob3VsZCBydW5cblx0XHRjb25zdCBoYXNTb21lVGFza3NPbmx5ID0gb25seU1vZGUgJiYgc3VpdGUudGFza3Muc29tZSgodCkgPT4gdC5tb2RlID09PSBcIm9ubHlcIiB8fCB0LnR5cGUgPT09IFwic3VpdGVcIiAmJiBzb21lVGFza3NBcmVPbmx5KHQpKTtcblx0XHRzdWl0ZS50YXNrcy5mb3JFYWNoKCh0KSA9PiB7XG5cdFx0XHQvLyBDaGVjayBpZiBlaXRoZXIgdGhlIHBhcmVudCBzdWl0ZSBvciB0aGUgdGFzayBpdHNlbGYgYXJlIG1hcmtlZCBhcyBpbmNsdWRlZFxuXHRcdFx0Ly8gSWYgdGhlcmUgYXJlIHRhc2tzIHdpdGggYC5vbmx5YCBpbiB0aGlzIHN1aXRlLCBvbmx5IGluY2x1ZGUgdGhvc2UgKG5vdCBhbGwgdGFza3MgZnJvbSBkZXNjcmliZS5vbmx5KVxuXHRcdFx0Y29uc3QgaW5jbHVkZVRhc2sgPSBoYXNTb21lVGFza3NPbmx5ID8gdC5tb2RlID09PSBcIm9ubHlcIiB8fCB0LnR5cGUgPT09IFwic3VpdGVcIiAmJiBzb21lVGFza3NBcmVPbmx5KHQpIDogc3VpdGVJc09ubHkgfHwgdC5tb2RlID09PSBcIm9ubHlcIjtcblx0XHRcdGlmIChvbmx5TW9kZSkge1xuXHRcdFx0XHRpZiAodC50eXBlID09PSBcInN1aXRlXCIgJiYgKGluY2x1ZGVUYXNrIHx8IHNvbWVUYXNrc0FyZU9ubHkodCkpKSB7XG5cdFx0XHRcdFx0Ly8gRG9uJ3Qgc2tpcCB0aGlzIHN1aXRlXG5cdFx0XHRcdFx0aWYgKHQubW9kZSA9PT0gXCJvbmx5XCIpIHtcblx0XHRcdFx0XHRcdGNoZWNrQWxsb3dPbmx5KHQsIGFsbG93T25seSk7XG5cdFx0XHRcdFx0XHR0Lm1vZGUgPSBcInJ1blwiO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSBlbHNlIGlmICh0Lm1vZGUgPT09IFwicnVuXCIgJiYgIWluY2x1ZGVUYXNrKSB7XG5cdFx0XHRcdFx0dC5tb2RlID0gXCJza2lwXCI7XG5cdFx0XHRcdH0gZWxzZSBpZiAodC5tb2RlID09PSBcIm9ubHlcIikge1xuXHRcdFx0XHRcdGNoZWNrQWxsb3dPbmx5KHQsIGFsbG93T25seSk7XG5cdFx0XHRcdFx0dC5tb2RlID0gXCJydW5cIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0bGV0IGhhc0xvY2F0aW9uTWF0Y2ggPSBwYXJlbnRNYXRjaGVkV2l0aExvY2F0aW9uO1xuXHRcdFx0Ly8gTWF0Y2ggdGVzdCBsb2NhdGlvbiBhZ2FpbnN0IHByb3ZpZGVkIGxvY2F0aW9ucywgb25seSBydW4gaWYgcHJlc2VudFxuXHRcdFx0Ly8gaW4gYHRlc3RMb2NhdGlvbnNgLiBOb3RlOiBpZiBgaW5jbHVkZVRhc2tMb2NhdGlvbmAgaXMgbm90IGVuYWJsZWQsXG5cdFx0XHQvLyBhbGwgdGVzdCB3aWxsIGJlIHNraXBwZWQuXG5cdFx0XHRpZiAodGVzdExvY2F0aW9ucyAhPT0gdW5kZWZpbmVkICYmIHRlc3RMb2NhdGlvbnMubGVuZ3RoICE9PSAwKSB7XG5cdFx0XHRcdGlmICh0LmxvY2F0aW9uICYmIHRlc3RMb2NhdGlvbnM/LmluY2x1ZGVzKHQubG9jYXRpb24ubGluZSkpIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInJ1blwiO1xuXHRcdFx0XHRcdG1hdGNoZWRMb2NhdGlvbnMucHVzaCh0LmxvY2F0aW9uLmxpbmUpO1xuXHRcdFx0XHRcdGhhc0xvY2F0aW9uTWF0Y2ggPSB0cnVlO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHBhcmVudE1hdGNoZWRXaXRoTG9jYXRpb24pIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInJ1blwiO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHQudHlwZSA9PT0gXCJ0ZXN0XCIpIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInNraXBcIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYgKHQudHlwZSA9PT0gXCJ0ZXN0XCIpIHtcblx0XHRcdFx0aWYgKG5hbWVQYXR0ZXJuICYmICFnZXRUYXNrRnVsbE5hbWUodCkubWF0Y2gobmFtZVBhdHRlcm4pKSB7XG5cdFx0XHRcdFx0dC5tb2RlID0gXCJza2lwXCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKHRlc3RJZHMgJiYgIXRlc3RJZHMuaW5jbHVkZXModC5pZCkpIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInNraXBcIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAodGVzdFRhZ3NGaWx0ZXIgJiYgIXRlc3RUYWdzRmlsdGVyKHQudGFncyB8fCBbXSkpIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInNraXBcIjtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIGlmICh0LnR5cGUgPT09IFwic3VpdGVcIikge1xuXHRcdFx0XHRpZiAodC5tb2RlID09PSBcInNraXBcIikge1xuXHRcdFx0XHRcdHNraXBBbGxUYXNrcyh0KTtcblx0XHRcdFx0fSBlbHNlIGlmICh0Lm1vZGUgPT09IFwidG9kb1wiKSB7XG5cdFx0XHRcdFx0dG9kb0FsbFRhc2tzKHQpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRyYXZlcnNlU3VpdGUodCwgaW5jbHVkZVRhc2ssIGhhc0xvY2F0aW9uTWF0Y2gpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Ly8gaWYgYWxsIHN1YnRhc2tzIGFyZSBza2lwcGVkLCBtYXJrIGFzIHNraXBcblx0XHRpZiAoc3VpdGUubW9kZSA9PT0gXCJydW5cIiB8fCBzdWl0ZS5tb2RlID09PSBcInF1ZXVlZFwiKSB7XG5cdFx0XHRpZiAoc3VpdGUudGFza3MubGVuZ3RoICYmIHN1aXRlLnRhc2tzLmV2ZXJ5KChpKSA9PiBpLm1vZGUgIT09IFwicnVuXCIgJiYgaS5tb2RlICE9PSBcInF1ZXVlZFwiKSkge1xuXHRcdFx0XHRzdWl0ZS5tb2RlID0gXCJza2lwXCI7XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXHR0cmF2ZXJzZVN1aXRlKGZpbGUsIHBhcmVudElzT25seSwgZmFsc2UpO1xuXHRjb25zdCBub25NYXRjaGluZyA9IHRlc3RMb2NhdGlvbnM/LmZpbHRlcigobG9jKSA9PiAhbWF0Y2hlZExvY2F0aW9ucy5pbmNsdWRlcyhsb2MpKTtcblx0aWYgKG5vbk1hdGNoaW5nICYmIG5vbk1hdGNoaW5nLmxlbmd0aCAhPT0gMCkge1xuXHRcdGNvbnN0IG1lc3NhZ2UgPSBub25NYXRjaGluZy5sZW5ndGggPT09IDEgPyBgbGluZSAke25vbk1hdGNoaW5nWzBdfWAgOiBgbGluZXMgJHtub25NYXRjaGluZy5qb2luKFwiLCBcIil9YDtcblx0XHRpZiAoZmlsZS5yZXN1bHQgPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0ZmlsZS5yZXN1bHQgPSB7XG5cdFx0XHRcdHN0YXRlOiBcImZhaWxcIixcblx0XHRcdFx0ZXJyb3JzOiBbXVxuXHRcdFx0fTtcblx0XHR9XG5cdFx0aWYgKGZpbGUucmVzdWx0LmVycm9ycyA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRmaWxlLnJlc3VsdC5lcnJvcnMgPSBbXTtcblx0XHR9XG5cdFx0ZmlsZS5yZXN1bHQuZXJyb3JzLnB1c2gocHJvY2Vzc0Vycm9yKG5ldyBFcnJvcihgTm8gdGVzdCBmb3VuZCBpbiAke2ZpbGUubmFtZX0gaW4gJHttZXNzYWdlfWApKSk7XG5cdH1cbn1cbmZ1bmN0aW9uIGdldFRhc2tGdWxsTmFtZSh0YXNrKSB7XG5cdHJldHVybiBgJHt0YXNrLnN1aXRlID8gYCR7Z2V0VGFza0Z1bGxOYW1lKHRhc2suc3VpdGUpfSBgIDogXCJcIn0ke3Rhc2submFtZX1gO1xufVxuZnVuY3Rpb24gc29tZVRhc2tzQXJlT25seShzdWl0ZSkge1xuXHRyZXR1cm4gc3VpdGUudGFza3Muc29tZSgodCkgPT4gdC5tb2RlID09PSBcIm9ubHlcIiB8fCB0LnR5cGUgPT09IFwic3VpdGVcIiAmJiBzb21lVGFza3NBcmVPbmx5KHQpKTtcbn1cbmZ1bmN0aW9uIHNraXBBbGxUYXNrcyhzdWl0ZSkge1xuXHRzdWl0ZS50YXNrcy5mb3JFYWNoKCh0KSA9PiB7XG5cdFx0aWYgKHQubW9kZSA9PT0gXCJydW5cIiB8fCB0Lm1vZGUgPT09IFwicXVldWVkXCIpIHtcblx0XHRcdHQubW9kZSA9IFwic2tpcFwiO1xuXHRcdFx0aWYgKHQudHlwZSA9PT0gXCJzdWl0ZVwiKSB7XG5cdFx0XHRcdHNraXBBbGxUYXNrcyh0KTtcblx0XHRcdH1cblx0XHR9XG5cdH0pO1xufVxuZnVuY3Rpb24gdG9kb0FsbFRhc2tzKHN1aXRlKSB7XG5cdHN1aXRlLnRhc2tzLmZvckVhY2goKHQpID0+IHtcblx0XHRpZiAodC5tb2RlID09PSBcInJ1blwiIHx8IHQubW9kZSA9PT0gXCJxdWV1ZWRcIikge1xuXHRcdFx0dC5tb2RlID0gXCJ0b2RvXCI7XG5cdFx0XHRpZiAodC50eXBlID09PSBcInN1aXRlXCIpIHtcblx0XHRcdFx0dG9kb0FsbFRhc2tzKHQpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSk7XG59XG5mdW5jdGlvbiBjaGVja0FsbG93T25seSh0YXNrLCBhbGxvd09ubHkpIHtcblx0aWYgKGFsbG93T25seSkge1xuXHRcdHJldHVybjtcblx0fVxuXHRjb25zdCBlcnJvciA9IHByb2Nlc3NFcnJvcihuZXcgRXJyb3IoXCJbVml0ZXN0XSBVbmV4cGVjdGVkIC5vbmx5IG1vZGlmaWVyLiBSZW1vdmUgaXQgb3IgcGFzcyAtLWFsbG93T25seSBhcmd1bWVudCB0byBieXBhc3MgdGhpcyBlcnJvclwiKSk7XG5cdHRhc2sucmVzdWx0ID0ge1xuXHRcdHN0YXRlOiBcImZhaWxcIixcblx0XHRlcnJvcnM6IFtlcnJvcl1cblx0fTtcbn1cbi8qIEBfX05PX1NJREVfRUZGRUNUU19fICovXG5mdW5jdGlvbiBnZW5lcmF0ZUhhc2goc3RyKSB7XG5cdGxldCBoYXNoID0gMDtcblx0aWYgKHN0ci5sZW5ndGggPT09IDApIHtcblx0XHRyZXR1cm4gYCR7aGFzaH1gO1xuXHR9XG5cdGZvciAobGV0IGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG5cdFx0Y29uc3QgY2hhciA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuXHRcdGhhc2ggPSAoaGFzaCA8PCA1KSAtIGhhc2ggKyBjaGFyO1xuXHRcdGhhc2ggPSBoYXNoICYgaGFzaDtcblx0fVxuXHRyZXR1cm4gYCR7aGFzaH1gO1xufVxuZnVuY3Rpb24gY2FsY3VsYXRlU3VpdGVIYXNoKHBhcmVudCkge1xuXHRwYXJlbnQudGFza3MuZm9yRWFjaCgodCwgaWR4KSA9PiB7XG5cdFx0dC5pZCA9IGAke3BhcmVudC5pZH1fJHtpZHh9YDtcblx0XHRpZiAodC50eXBlID09PSBcInN1aXRlXCIpIHtcblx0XHRcdGNhbGN1bGF0ZVN1aXRlSGFzaCh0KTtcblx0XHR9XG5cdH0pO1xufVxuZnVuY3Rpb24gY3JlYXRlRmlsZVRhc2soZmlsZXBhdGgsIHJvb3QsIHByb2plY3ROYW1lLCBwb29sLCB2aXRlRW52aXJvbm1lbnQpIHtcblx0Y29uc3QgcGF0aCA9IHJlbGF0aXZlKHJvb3QsIGZpbGVwYXRoKTtcblx0Y29uc3QgZmlsZSA9IHtcblx0XHRpZDogZ2VuZXJhdGVGaWxlSGFzaChwYXRoLCBwcm9qZWN0TmFtZSksXG5cdFx0bmFtZTogcGF0aCxcblx0XHRmdWxsTmFtZTogcGF0aCxcblx0XHR0eXBlOiBcInN1aXRlXCIsXG5cdFx0bW9kZTogXCJxdWV1ZWRcIixcblx0XHRmaWxlcGF0aCxcblx0XHR0YXNrczogW10sXG5cdFx0bWV0YTogT2JqZWN0LmNyZWF0ZShudWxsKSxcblx0XHRwcm9qZWN0TmFtZSxcblx0XHRmaWxlOiB1bmRlZmluZWQsXG5cdFx0cG9vbCxcblx0XHR2aXRlRW52aXJvbm1lbnRcblx0fTtcblx0ZmlsZS5maWxlID0gZmlsZTtcblx0cmV0dXJuIGZpbGU7XG59XG4vKipcbiogR2VuZXJhdGUgYSB1bmlxdWUgSUQgZm9yIGEgZmlsZSBiYXNlZCBvbiBpdHMgcGF0aCBhbmQgcHJvamVjdCBuYW1lXG4qIEBwYXJhbSBmaWxlIEZpbGUgcmVsYXRpdmUgdG8gdGhlIHJvb3Qgb2YgdGhlIHByb2plY3QgdG8ga2VlcCBJRCB0aGUgc2FtZSBiZXR3ZWVuIGRpZmZlcmVudCBtYWNoaW5lc1xuKiBAcGFyYW0gcHJvamVjdE5hbWUgVGhlIG5hbWUgb2YgdGhlIHRlc3QgcHJvamVjdFxuKi9cbi8qIEBfX05PX1NJREVfRUZGRUNUU19fICovXG5mdW5jdGlvbiBnZW5lcmF0ZUZpbGVIYXNoKGZpbGUsIHByb2plY3ROYW1lKSB7XG5cdHJldHVybiAvKiBAX19QVVJFX18gKi8gZ2VuZXJhdGVIYXNoKGAke2ZpbGV9JHtwcm9qZWN0TmFtZSB8fCBcIlwifWApO1xufVxuZnVuY3Rpb24gZmluZFRlc3RGaWxlU3RhY2tUcmFjZSh0ZXN0RmlsZVBhdGgsIGVycm9yKSB7XG5cdC8vIGZpcnN0IGxpbmUgaXMgdGhlIGVycm9yIG1lc3NhZ2Vcblx0Y29uc3QgbGluZXMgPSBlcnJvci5zcGxpdChcIlxcblwiKS5zbGljZSgxKTtcblx0Zm9yIChjb25zdCBsaW5lIG9mIGxpbmVzKSB7XG5cdFx0Y29uc3Qgc3RhY2sgPSBwYXJzZVNpbmdsZVN0YWNrKGxpbmUpO1xuXHRcdGlmIChzdGFjayAmJiBzdGFjay5maWxlID09PSB0ZXN0RmlsZVBhdGgpIHtcblx0XHRcdHJldHVybiBzdGFjaztcblx0XHR9XG5cdH1cbn1cblxuLyoqXG4qIFJldHVybiBhIGZ1bmN0aW9uIGZvciBydW5uaW5nIG11bHRpcGxlIGFzeW5jIG9wZXJhdGlvbnMgd2l0aCBsaW1pdGVkIGNvbmN1cnJlbmN5LlxuKi9cbmZ1bmN0aW9uIGxpbWl0Q29uY3VycmVuY3koY29uY3VycmVuY3kgPSBJbmZpbml0eSkge1xuXHQvLyBUaGUgbnVtYmVyIG9mIGN1cnJlbnRseSBhY3RpdmUgKyBwZW5kaW5nIHRhc2tzLlxuXHRsZXQgY291bnQgPSAwO1xuXHQvLyBUaGUgaGVhZCBhbmQgdGFpbCBvZiB0aGUgcGVuZGluZyB0YXNrIHF1ZXVlLCBidWlsdCB1c2luZyBhIHNpbmdseSBsaW5rZWQgbGlzdC5cblx0Ly8gQm90aCBoZWFkIGFuZCB0YWlsIGFyZSBpbml0aWFsbHkgdW5kZWZpbmVkLCBzaWduaWZ5aW5nIGFuIGVtcHR5IHF1ZXVlLlxuXHQvLyBUaGV5IGJvdGggYmVjb21lIHVuZGVmaW5lZCBhZ2FpbiB3aGVuZXZlciB0aGVyZSBhcmUgbm8gcGVuZGluZyB0YXNrcy5cblx0bGV0IGhlYWQ7XG5cdGxldCB0YWlsO1xuXHQvLyBBIGJvb2trZWVwaW5nIGZ1bmN0aW9uIGV4ZWN1dGVkIHdoZW5ldmVyIGEgdGFzayBoYXMgYmVlbiBydW4gdG8gY29tcGxldGlvbi5cblx0Y29uc3QgZmluaXNoID0gKCkgPT4ge1xuXHRcdGNvdW50LS07XG5cdFx0Ly8gQ2hlY2sgaWYgdGhlcmUgYXJlIGZ1cnRoZXIgcGVuZGluZyB0YXNrcyBpbiB0aGUgcXVldWUuXG5cdFx0aWYgKGhlYWQpIHtcblx0XHRcdC8vIEFsbG93IHRoZSBuZXh0IHBlbmRpbmcgdGFzayB0byBydW4gYW5kIHBvcCBpdCBmcm9tIHRoZSBxdWV1ZS5cblx0XHRcdGhlYWRbMF0oKTtcblx0XHRcdGhlYWQgPSBoZWFkWzFdO1xuXHRcdFx0Ly8gVGhlIGhlYWQgbWF5IG5vdyBiZSB1bmRlZmluZWQgaWYgdGhlcmUgYXJlIG5vIGZ1cnRoZXIgcGVuZGluZyB0YXNrcy5cblx0XHRcdC8vIEluIHRoYXQgY2FzZSwgc2V0IHRhaWwgdG8gdW5kZWZpbmVkIGFzIHdlbGwuXG5cdFx0XHR0YWlsID0gaGVhZCAmJiB0YWlsO1xuXHRcdH1cblx0fTtcblx0Y29uc3QgYWNxdWlyZSA9ICgpID0+IHtcblx0XHRsZXQgcmVsZWFzZWQgPSBmYWxzZTtcblx0XHRjb25zdCByZWxlYXNlID0gKCkgPT4ge1xuXHRcdFx0aWYgKCFyZWxlYXNlZCkge1xuXHRcdFx0XHRyZWxlYXNlZCA9IHRydWU7XG5cdFx0XHRcdGZpbmlzaCgpO1xuXHRcdFx0fVxuXHRcdH07XG5cdFx0aWYgKGNvdW50KysgPCBjb25jdXJyZW5jeSkge1xuXHRcdFx0cmV0dXJuIHJlbGVhc2U7XG5cdFx0fVxuXHRcdHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuXHRcdFx0aWYgKHRhaWwpIHtcblx0XHRcdFx0Ly8gVGhlcmUgYXJlIHBlbmRpbmcgdGFza3MsIHNvIGFwcGVuZCB0byB0aGUgcXVldWUuXG5cdFx0XHRcdHRhaWwgPSB0YWlsWzFdID0gWygpID0+IHJlc29sdmUocmVsZWFzZSldO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly8gTm8gb3RoZXIgcGVuZGluZyB0YXNrcywgaW5pdGlhbGl6ZSB0aGUgcXVldWUgd2l0aCBhIG5ldyB0YWlsIGFuZCBoZWFkLlxuXHRcdFx0XHRoZWFkID0gdGFpbCA9IFsoKSA9PiByZXNvbHZlKHJlbGVhc2UpXTtcblx0XHRcdH1cblx0XHR9KTtcblx0fTtcblx0Y29uc3QgbGltaXRlckZuID0gKGZ1bmMsIC4uLmFyZ3MpID0+IHtcblx0XHRmdW5jdGlvbiBydW4ocmVsZWFzZSkge1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0Y29uc3QgcmVzdWx0ID0gZnVuYyguLi5hcmdzKTtcblx0XHRcdFx0aWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHtcblx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0LmZpbmFsbHkocmVsZWFzZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmVsZWFzZSgpO1xuXHRcdFx0XHRyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHJlc3VsdCk7XG5cdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0XHRyZWxlYXNlKCk7XG5cdFx0XHRcdHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvcik7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGNvbnN0IHJlbGVhc2UgPSBhY3F1aXJlKCk7XG5cdFx0cmV0dXJuIHJlbGVhc2UgaW5zdGFuY2VvZiBQcm9taXNlID8gcmVsZWFzZS50aGVuKHJ1bikgOiBydW4ocmVsZWFzZSk7XG5cdH07XG5cdHJldHVybiBPYmplY3QuYXNzaWduKGxpbWl0ZXJGbiwgeyBhY3F1aXJlIH0pO1xufVxuXG4vKipcbiogUGFydGl0aW9uIGluIHRhc2tzIGdyb3VwcyBieSBjb25zZWN1dGl2ZSBjb25jdXJyZW50XG4qL1xuZnVuY3Rpb24gcGFydGl0aW9uU3VpdGVDaGlsZHJlbihzdWl0ZSkge1xuXHRsZXQgdGFza3NHcm91cCA9IFtdO1xuXHRjb25zdCB0YXNrc0dyb3VwcyA9IFtdO1xuXHRmb3IgKGNvbnN0IGMgb2Ygc3VpdGUudGFza3MpIHtcblx0XHRpZiAodGFza3NHcm91cC5sZW5ndGggPT09IDAgfHwgYy5jb25jdXJyZW50ID09PSB0YXNrc0dyb3VwWzBdLmNvbmN1cnJlbnQpIHtcblx0XHRcdHRhc2tzR3JvdXAucHVzaChjKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGFza3NHcm91cHMucHVzaCh0YXNrc0dyb3VwKTtcblx0XHRcdHRhc2tzR3JvdXAgPSBbY107XG5cdFx0fVxuXHR9XG5cdGlmICh0YXNrc0dyb3VwLmxlbmd0aCA+IDApIHtcblx0XHR0YXNrc0dyb3Vwcy5wdXNoKHRhc2tzR3JvdXApO1xuXHR9XG5cdHJldHVybiB0YXNrc0dyb3Vwcztcbn1cblxuY29uc3QgZmlsdGVyTWFwID0gbmV3IFdlYWtNYXAoKTtcbi8qKlxuKiBAZXhwZXJpbWVudGFsXG4qL1xuZnVuY3Rpb24gbWF0Y2hlc1RhZ3ModGVzdFRhZ3MpIHtcblx0Y29uc3QgcnVubmVyID0gZ2V0UnVubmVyKCk7XG5cdGNvbnN0IHRhZ3NGaWx0ZXIgPSBydW5uZXIuX2N1cnJlbnRTcGVjaWZpY2F0aW9uPy50ZXN0VGFnc0ZpbHRlciA/PyBydW5uZXIuY29uZmlnLnRhZ3NGaWx0ZXI7XG5cdGlmICghdGFnc0ZpbHRlcikge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cdGxldCB0YWdzRmlsdGVyUHJlZGljYXRlID0gZmlsdGVyTWFwLmdldCh0YWdzRmlsdGVyKTtcblx0aWYgKCF0YWdzRmlsdGVyUHJlZGljYXRlKSB7XG5cdFx0dGFnc0ZpbHRlclByZWRpY2F0ZSA9IGNyZWF0ZVRhZ3NGaWx0ZXIodGFnc0ZpbHRlciwgcnVubmVyLmNvbmZpZy50YWdzKTtcblx0XHRmaWx0ZXJNYXAuc2V0KHRhZ3NGaWx0ZXIsIHRhZ3NGaWx0ZXJQcmVkaWNhdGUpO1xuXHR9XG5cdHJldHVybiB0YWdzRmlsdGVyUHJlZGljYXRlKHRlc3RUYWdzKTtcbn1cbmZ1bmN0aW9uIHZhbGlkYXRlVGFncyhjb25maWcsIHRhZ3MpIHtcblx0aWYgKCFjb25maWcuc3RyaWN0VGFncykge1xuXHRcdHJldHVybjtcblx0fVxuXHRjb25zdCBhdmFpbGFibGVUYWdzID0gbmV3IFNldChjb25maWcudGFncy5tYXAoKHRhZykgPT4gdGFnLm5hbWUpKTtcblx0Zm9yIChjb25zdCB0YWcgb2YgdGFncykge1xuXHRcdGlmICghYXZhaWxhYmxlVGFncy5oYXModGFnKSkge1xuXHRcdFx0dGhyb3cgY3JlYXRlTm9UYWdzRXJyb3IoY29uZmlnLnRhZ3MsIHRhZyk7XG5cdFx0fVxuXHR9XG59XG5mdW5jdGlvbiBjcmVhdGVOb1RhZ3NFcnJvcihhdmFpbGFibGVUYWdzLCB0YWcsIHByZWZpeCA9IFwidGFnXCIpIHtcblx0aWYgKCFhdmFpbGFibGVUYWdzLmxlbmd0aCkge1xuXHRcdHRocm93IG5ldyBFcnJvcihgVGhlIFZpdGVzdCBjb25maWcgZG9lcyd0IGRlZmluZSBhbnkgXCJ0YWdzXCIsIGNhbm5vdCBhcHBseSBcIiR7dGFnfVwiICR7cHJlZml4fSBmb3IgdGhpcyB0ZXN0LiBTZWU6IGh0dHBzOi8vdml0ZXN0LmRldi9ndWlkZS90ZXN0LXRhZ3NgKTtcblx0fVxuXHR0aHJvdyBuZXcgRXJyb3IoYFRoZSAke3ByZWZpeH0gXCIke3RhZ31cIiBpcyBub3QgZGVmaW5lZCBpbiB0aGUgY29uZmlndXJhdGlvbi4gQXZhaWxhYmxlIHRhZ3MgYXJlOlxcbiR7YXZhaWxhYmxlVGFncy5tYXAoKHQpID0+IGAtICR7dC5uYW1lfSR7dC5kZXNjcmlwdGlvbiA/IGA6ICR7dC5kZXNjcmlwdGlvbn1gIDogXCJcIn1gKS5qb2luKFwiXFxuXCIpfWApO1xufVxuZnVuY3Rpb24gY3JlYXRlVGFnc0ZpbHRlcih0YWdzRXhwciwgYXZhaWxhYmxlVGFncykge1xuXHRjb25zdCBtYXRjaGVycyA9IHRhZ3NFeHByLm1hcCgoZXhwcikgPT4gcGFyc2VUYWdzRXhwcmVzc2lvbihleHByLCBhdmFpbGFibGVUYWdzKSk7XG5cdHJldHVybiAodGVzdFRhZ3MpID0+IHtcblx0XHRyZXR1cm4gbWF0Y2hlcnMuZXZlcnkoKG1hdGNoZXIpID0+IG1hdGNoZXIodGVzdFRhZ3MpKTtcblx0fTtcbn1cbmZ1bmN0aW9uIHBhcnNlVGFnc0V4cHJlc3Npb24oZXhwciwgYXZhaWxhYmxlVGFncykge1xuXHRjb25zdCB0b2tlbnMgPSB0b2tlbml6ZShleHByKTtcblx0Y29uc3Qgc3RyZWFtID0gbmV3IFRva2VuU3RyZWFtKHRva2VucywgZXhwcik7XG5cdGNvbnN0IGFzdCA9IHBhcnNlT3JFeHByZXNzaW9uKHN0cmVhbSwgYXZhaWxhYmxlVGFncyk7XG5cdGlmIChzdHJlYW0ucGVlaygpLnR5cGUgIT09IFwiRU9GXCIpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdGFncyBleHByZXNzaW9uOiB1bmV4cGVjdGVkIFwiJHtmb3JtYXRUb2tlbihzdHJlYW0ucGVlaygpKX1cIiBpbiBcIiR7ZXhwcn1cImApO1xuXHR9XG5cdHJldHVybiAodGFncykgPT4gZXZhbHVhdGVOb2RlKGFzdCwgdGFncyk7XG59XG5mdW5jdGlvbiBmb3JtYXRUb2tlbih0b2tlbikge1xuXHRzd2l0Y2ggKHRva2VuLnR5cGUpIHtcblx0XHRjYXNlIFwiVEFHXCI6IHJldHVybiB0b2tlbi52YWx1ZTtcblx0XHRkZWZhdWx0OiByZXR1cm4gZm9ybWF0VG9rZW5UeXBlKHRva2VuLnR5cGUpO1xuXHR9XG59XG5mdW5jdGlvbiB0b2tlbml6ZShleHByKSB7XG5cdGNvbnN0IHRva2VucyA9IFtdO1xuXHRsZXQgaSA9IDA7XG5cdHdoaWxlIChpIDwgZXhwci5sZW5ndGgpIHtcblx0XHRpZiAoZXhwcltpXSA9PT0gXCIgXCIgfHwgZXhwcltpXSA9PT0gXCJcdFwiKSB7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKGV4cHJbaV0gPT09IFwiKFwiKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiTFBBUkVOXCIgfSk7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKGV4cHJbaV0gPT09IFwiKVwiKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiUlBBUkVOXCIgfSk7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKGV4cHJbaV0gPT09IFwiIVwiKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiTk9UXCIgfSk7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKGV4cHIuc2xpY2UoaSwgaSArIDIpID09PSBcIiYmXCIpIHtcblx0XHRcdHRva2Vucy5wdXNoKHsgdHlwZTogXCJBTkRcIiB9KTtcblx0XHRcdGkgKz0gMjtcblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblx0XHRpZiAoZXhwci5zbGljZShpLCBpICsgMikgPT09IFwifHxcIikge1xuXHRcdFx0dG9rZW5zLnB1c2goeyB0eXBlOiBcIk9SXCIgfSk7XG5cdFx0XHRpICs9IDI7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKC9eYW5kKD86XFxzfFxcKXwkKS9pLnRlc3QoZXhwci5zbGljZShpKSkpIHtcblx0XHRcdHRva2Vucy5wdXNoKHsgdHlwZTogXCJBTkRcIiB9KTtcblx0XHRcdGkgKz0gMztcblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblx0XHRpZiAoL15vcig/Olxcc3xcXCl8JCkvaS50ZXN0KGV4cHIuc2xpY2UoaSkpKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiT1JcIiB9KTtcblx0XHRcdGkgKz0gMjtcblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblx0XHRpZiAoL15ub3RcXHMvaS50ZXN0KGV4cHIuc2xpY2UoaSkpKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiTk9UXCIgfSk7XG5cdFx0XHRpICs9IDM7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0bGV0IHRhZyA9IFwiXCI7XG5cdFx0d2hpbGUgKGkgPCBleHByLmxlbmd0aCAmJiBleHByW2ldICE9PSBcIiBcIiAmJiBleHByW2ldICE9PSBcIlx0XCIgJiYgZXhwcltpXSAhPT0gXCIoXCIgJiYgZXhwcltpXSAhPT0gXCIpXCIgJiYgZXhwcltpXSAhPT0gXCIhXCIgJiYgZXhwcltpXSAhPT0gXCImXCIgJiYgZXhwcltpXSAhPT0gXCJ8XCIpIHtcblx0XHRcdGNvbnN0IHJlbWFpbmluZyA9IGV4cHIuc2xpY2UoaSk7XG5cdFx0XHQvLyBPbmx5IHRyZWF0IGFuZC9vci9ub3QgYXMgb3BlcmF0b3JzIGlmIHdlJ3JlIGF0IHRoZSBzdGFydCBvZiBhIHRhZyAoYWZ0ZXIgd2hpdGVzcGFjZSlcblx0XHRcdC8vIFRoaXMgYWxsb3dzIHRhZ3MgbGlrZSBcImRlbWFuZFwiLCBcImVkaXRvclwiLCBcImNhbm5vdFwiIHRvIHdvcmsgY29ycmVjdGx5XG5cdFx0XHRpZiAodGFnID09PSBcIlwiICYmICgvXmFuZCg/Olxcc3xcXCl8JCkvaS50ZXN0KHJlbWFpbmluZykgfHwgL15vcig/Olxcc3xcXCl8JCkvaS50ZXN0KHJlbWFpbmluZykgfHwgL15ub3RcXHMvaS50ZXN0KHJlbWFpbmluZykpKSB7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0dGFnICs9IGV4cHJbaV07XG5cdFx0XHRpKys7XG5cdFx0fVxuXHRcdGlmICh0YWcpIHtcblx0XHRcdHRva2Vucy5wdXNoKHtcblx0XHRcdFx0dHlwZTogXCJUQUdcIixcblx0XHRcdFx0dmFsdWU6IHRhZ1xuXHRcdFx0fSk7XG5cdFx0fVxuXHR9XG5cdHRva2Vucy5wdXNoKHsgdHlwZTogXCJFT0ZcIiB9KTtcblx0cmV0dXJuIHRva2Vucztcbn1cbmNsYXNzIFRva2VuU3RyZWFtIHtcblx0cG9zID0gMDtcblx0Y29uc3RydWN0b3IodG9rZW5zLCBleHByKSB7XG5cdFx0dGhpcy50b2tlbnMgPSB0b2tlbnM7XG5cdFx0dGhpcy5leHByID0gZXhwcjtcblx0fVxuXHRwZWVrKCkge1xuXHRcdHJldHVybiB0aGlzLnRva2Vuc1t0aGlzLnBvc107XG5cdH1cblx0bmV4dCgpIHtcblx0XHRyZXR1cm4gdGhpcy50b2tlbnNbdGhpcy5wb3MrK107XG5cdH1cblx0ZXhwZWN0KHR5cGUpIHtcblx0XHRjb25zdCB0b2tlbiA9IHRoaXMubmV4dCgpO1xuXHRcdGlmICh0b2tlbi50eXBlICE9PSB0eXBlKSB7XG5cdFx0XHRpZiAodHlwZSA9PT0gXCJSUEFSRU5cIiAmJiB0b2tlbi50eXBlID09PSBcIkVPRlwiKSB7XG5cdFx0XHRcdHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB0YWdzIGV4cHJlc3Npb246IG1pc3NpbmcgY2xvc2luZyBcIilcIiBpbiBcIiR7dGhpcy5leHByfVwiYCk7XG5cdFx0XHR9XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdGFncyBleHByZXNzaW9uOiBleHBlY3RlZCBcIiR7Zm9ybWF0VG9rZW5UeXBlKHR5cGUpfVwiIGJ1dCBnb3QgXCIke2Zvcm1hdFRva2VuKHRva2VuKX1cIiBpbiBcIiR7dGhpcy5leHByfVwiYCk7XG5cdFx0fVxuXHRcdHJldHVybiB0b2tlbjtcblx0fVxuXHR1bmV4cGVjdGVkVG9rZW4oKSB7XG5cdFx0Y29uc3QgdG9rZW4gPSB0aGlzLnBlZWsoKTtcblx0XHRpZiAodG9rZW4udHlwZSA9PT0gXCJFT0ZcIikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHRhZ3MgZXhwcmVzc2lvbjogdW5leHBlY3RlZCBlbmQgb2YgZXhwcmVzc2lvbiBpbiBcIiR7dGhpcy5leHByfVwiYCk7XG5cdFx0fVxuXHRcdHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB0YWdzIGV4cHJlc3Npb246IHVuZXhwZWN0ZWQgXCIke2Zvcm1hdFRva2VuKHRva2VuKX1cIiBpbiBcIiR7dGhpcy5leHByfVwiYCk7XG5cdH1cbn1cbmZ1bmN0aW9uIGZvcm1hdFRva2VuVHlwZSh0eXBlKSB7XG5cdHN3aXRjaCAodHlwZSkge1xuXHRcdGNhc2UgXCJUQUdcIjogcmV0dXJuIFwidGFnXCI7XG5cdFx0Y2FzZSBcIkFORFwiOiByZXR1cm4gXCJhbmRcIjtcblx0XHRjYXNlIFwiT1JcIjogcmV0dXJuIFwib3JcIjtcblx0XHRjYXNlIFwiTk9UXCI6IHJldHVybiBcIm5vdFwiO1xuXHRcdGNhc2UgXCJMUEFSRU5cIjogcmV0dXJuIFwiKFwiO1xuXHRcdGNhc2UgXCJSUEFSRU5cIjogcmV0dXJuIFwiKVwiO1xuXHRcdGNhc2UgXCJFT0ZcIjogcmV0dXJuIFwiZW5kIG9mIGV4cHJlc3Npb25cIjtcblx0fVxufVxuZnVuY3Rpb24gcGFyc2VPckV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKSB7XG5cdGxldCBsZWZ0ID0gcGFyc2VBbmRFeHByZXNzaW9uKHN0cmVhbSwgYXZhaWxhYmxlVGFncyk7XG5cdHdoaWxlIChzdHJlYW0ucGVlaygpLnR5cGUgPT09IFwiT1JcIikge1xuXHRcdHN0cmVhbS5uZXh0KCk7XG5cdFx0Y29uc3QgcmlnaHQgPSBwYXJzZUFuZEV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKTtcblx0XHRsZWZ0ID0ge1xuXHRcdFx0dHlwZTogXCJvclwiLFxuXHRcdFx0bGVmdCxcblx0XHRcdHJpZ2h0XG5cdFx0fTtcblx0fVxuXHRyZXR1cm4gbGVmdDtcbn1cbmZ1bmN0aW9uIHBhcnNlQW5kRXhwcmVzc2lvbihzdHJlYW0sIGF2YWlsYWJsZVRhZ3MpIHtcblx0bGV0IGxlZnQgPSBwYXJzZVVuYXJ5RXhwcmVzc2lvbihzdHJlYW0sIGF2YWlsYWJsZVRhZ3MpO1xuXHR3aGlsZSAoc3RyZWFtLnBlZWsoKS50eXBlID09PSBcIkFORFwiKSB7XG5cdFx0c3RyZWFtLm5leHQoKTtcblx0XHRjb25zdCByaWdodCA9IHBhcnNlVW5hcnlFeHByZXNzaW9uKHN0cmVhbSwgYXZhaWxhYmxlVGFncyk7XG5cdFx0bGVmdCA9IHtcblx0XHRcdHR5cGU6IFwiYW5kXCIsXG5cdFx0XHRsZWZ0LFxuXHRcdFx0cmlnaHRcblx0XHR9O1xuXHR9XG5cdHJldHVybiBsZWZ0O1xufVxuZnVuY3Rpb24gcGFyc2VVbmFyeUV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKSB7XG5cdGlmIChzdHJlYW0ucGVlaygpLnR5cGUgPT09IFwiTk9UXCIpIHtcblx0XHRzdHJlYW0ubmV4dCgpO1xuXHRcdGNvbnN0IG9wZXJhbmQgPSBwYXJzZVVuYXJ5RXhwcmVzc2lvbihzdHJlYW0sIGF2YWlsYWJsZVRhZ3MpO1xuXHRcdHJldHVybiB7XG5cdFx0XHR0eXBlOiBcIm5vdFwiLFxuXHRcdFx0b3BlcmFuZFxuXHRcdH07XG5cdH1cblx0cmV0dXJuIHBhcnNlUHJpbWFyeUV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKTtcbn1cbmZ1bmN0aW9uIHBhcnNlUHJpbWFyeUV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKSB7XG5cdGNvbnN0IHRva2VuID0gc3RyZWFtLnBlZWsoKTtcblx0aWYgKHRva2VuLnR5cGUgPT09IFwiTFBBUkVOXCIpIHtcblx0XHRzdHJlYW0ubmV4dCgpO1xuXHRcdGNvbnN0IGV4cHIgPSBwYXJzZU9yRXhwcmVzc2lvbihzdHJlYW0sIGF2YWlsYWJsZVRhZ3MpO1xuXHRcdHN0cmVhbS5leHBlY3QoXCJSUEFSRU5cIik7XG5cdFx0cmV0dXJuIGV4cHI7XG5cdH1cblx0aWYgKHRva2VuLnR5cGUgPT09IFwiVEFHXCIpIHtcblx0XHRzdHJlYW0ubmV4dCgpO1xuXHRcdGNvbnN0IHRhZ1ZhbHVlID0gdG9rZW4udmFsdWU7XG5cdFx0Y29uc3QgcGF0dGVybiA9IHJlc29sdmVUYWdQYXR0ZXJuKHRhZ1ZhbHVlLCBhdmFpbGFibGVUYWdzKTtcblx0XHRyZXR1cm4ge1xuXHRcdFx0dHlwZTogXCJ0YWdcIixcblx0XHRcdHZhbHVlOiB0YWdWYWx1ZSxcblx0XHRcdHBhdHRlcm5cblx0XHR9O1xuXHR9XG5cdHN0cmVhbS51bmV4cGVjdGVkVG9rZW4oKTtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVdpbGRjYXJkUmVnZXgocGF0dGVybikge1xuXHRyZXR1cm4gbmV3IFJlZ0V4cChgXiR7cGF0dGVybi5yZXBsYWNlKC9bLis/XiR7fSgpfFtcXF1cXFxcXS9nLCBcIlxcXFwkJlwiKS5yZXBsYWNlKC9cXCovZywgXCIuKlwiKX0kYCk7XG59XG5mdW5jdGlvbiByZXNvbHZlVGFnUGF0dGVybih0YWdQYXR0ZXJuLCBhdmFpbGFibGVUYWdzKSB7XG5cdGlmICh0YWdQYXR0ZXJuLmluY2x1ZGVzKFwiKlwiKSkge1xuXHRcdGNvbnN0IHJlZ2V4ID0gY3JlYXRlV2lsZGNhcmRSZWdleCh0YWdQYXR0ZXJuKTtcblx0XHRjb25zdCBoYXNNYXRjaCA9IGF2YWlsYWJsZVRhZ3Muc29tZSgodGFnKSA9PiByZWdleC50ZXN0KHRhZy5uYW1lKSk7XG5cdFx0aWYgKCFoYXNNYXRjaCkge1xuXHRcdFx0dGhyb3cgY3JlYXRlTm9UYWdzRXJyb3IoYXZhaWxhYmxlVGFncywgdGFnUGF0dGVybiwgXCJ0YWcgcGF0dGVyblwiKTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlZ2V4O1xuXHR9XG5cdGlmICghYXZhaWxhYmxlVGFncy5sZW5ndGggfHwgIWF2YWlsYWJsZVRhZ3Muc29tZSgodGFnKSA9PiB0YWcubmFtZSA9PT0gdGFnUGF0dGVybikpIHtcblx0XHR0aHJvdyBjcmVhdGVOb1RhZ3NFcnJvcihhdmFpbGFibGVUYWdzLCB0YWdQYXR0ZXJuLCBcInRhZyBwYXR0ZXJuXCIpO1xuXHR9XG5cdHJldHVybiBudWxsO1xufVxuZnVuY3Rpb24gZXZhbHVhdGVOb2RlKG5vZGUsIHRhZ3MpIHtcblx0c3dpdGNoIChub2RlLnR5cGUpIHtcblx0XHRjYXNlIFwidGFnXCI6XG5cdFx0XHRpZiAobm9kZS5wYXR0ZXJuKSB7XG5cdFx0XHRcdHJldHVybiB0YWdzLnNvbWUoKHRhZykgPT4gbm9kZS5wYXR0ZXJuLnRlc3QodGFnKSk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdGFncy5pbmNsdWRlcyhub2RlLnZhbHVlKTtcblx0XHRjYXNlIFwibm90XCI6IHJldHVybiAhZXZhbHVhdGVOb2RlKG5vZGUub3BlcmFuZCwgdGFncyk7XG5cdFx0Y2FzZSBcImFuZFwiOiByZXR1cm4gZXZhbHVhdGVOb2RlKG5vZGUubGVmdCwgdGFncykgJiYgZXZhbHVhdGVOb2RlKG5vZGUucmlnaHQsIHRhZ3MpO1xuXHRcdGNhc2UgXCJvclwiOiByZXR1cm4gZXZhbHVhdGVOb2RlKG5vZGUubGVmdCwgdGFncykgfHwgZXZhbHVhdGVOb2RlKG5vZGUucmlnaHQsIHRhZ3MpO1xuXHR9XG59XG5cbmZ1bmN0aW9uIGlzVGVzdENhc2Uocykge1xuXHRyZXR1cm4gcy50eXBlID09PSBcInRlc3RcIjtcbn1cbmZ1bmN0aW9uIGdldFRlc3RzKHN1aXRlKSB7XG5cdGNvbnN0IHRlc3RzID0gW107XG5cdGNvbnN0IGFycmF5U3VpdGVzID0gdG9BcnJheShzdWl0ZSk7XG5cdGZvciAoY29uc3QgcyBvZiBhcnJheVN1aXRlcykge1xuXHRcdGlmIChpc1Rlc3RDYXNlKHMpKSB7XG5cdFx0XHR0ZXN0cy5wdXNoKHMpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRmb3IgKGNvbnN0IHRhc2sgb2Ygcy50YXNrcykge1xuXHRcdFx0XHRpZiAoaXNUZXN0Q2FzZSh0YXNrKSkge1xuXHRcdFx0XHRcdHRlc3RzLnB1c2godGFzayk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Y29uc3QgdGFza1Rlc3RzID0gZ2V0VGVzdHModGFzayk7XG5cdFx0XHRcdFx0Zm9yIChjb25zdCB0ZXN0IG9mIHRhc2tUZXN0cykge1xuXHRcdFx0XHRcdFx0dGVzdHMucHVzaCh0ZXN0KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblx0cmV0dXJuIHRlc3RzO1xufVxuZnVuY3Rpb24gZ2V0VGFza3ModGFza3MgPSBbXSkge1xuXHRyZXR1cm4gdG9BcnJheSh0YXNrcykuZmxhdE1hcCgocykgPT4gaXNUZXN0Q2FzZShzKSA/IFtzXSA6IFtzLCAuLi5nZXRUYXNrcyhzLnRhc2tzKV0pO1xufVxuZnVuY3Rpb24gZ2V0U3VpdGVzKHN1aXRlKSB7XG5cdHJldHVybiB0b0FycmF5KHN1aXRlKS5mbGF0TWFwKChzKSA9PiBzLnR5cGUgPT09IFwic3VpdGVcIiA/IFtzLCAuLi5nZXRTdWl0ZXMocy50YXNrcyldIDogW10pO1xufVxuZnVuY3Rpb24gaGFzVGVzdHMoc3VpdGUpIHtcblx0cmV0dXJuIHRvQXJyYXkoc3VpdGUpLnNvbWUoKHMpID0+IHMudGFza3Muc29tZSgoYykgPT4gaXNUZXN0Q2FzZShjKSB8fCBoYXNUZXN0cyhjKSkpO1xufVxuZnVuY3Rpb24gaGFzRmFpbGVkKHN1aXRlKSB7XG5cdHJldHVybiB0b0FycmF5KHN1aXRlKS5zb21lKChzKSA9PiBzLnJlc3VsdD8uc3RhdGUgPT09IFwiZmFpbFwiIHx8IHMudHlwZSA9PT0gXCJzdWl0ZVwiICYmIGhhc0ZhaWxlZChzLnRhc2tzKSk7XG59XG5mdW5jdGlvbiBnZXROYW1lcyh0YXNrKSB7XG5cdGNvbnN0IG5hbWVzID0gW3Rhc2submFtZV07XG5cdGxldCBjdXJyZW50ID0gdGFzaztcblx0d2hpbGUgKGN1cnJlbnQ/LnN1aXRlKSB7XG5cdFx0Y3VycmVudCA9IGN1cnJlbnQuc3VpdGU7XG5cdFx0aWYgKGN1cnJlbnQ/Lm5hbWUpIHtcblx0XHRcdG5hbWVzLnVuc2hpZnQoY3VycmVudC5uYW1lKTtcblx0XHR9XG5cdH1cblx0aWYgKGN1cnJlbnQgIT09IHRhc2suZmlsZSkge1xuXHRcdG5hbWVzLnVuc2hpZnQodGFzay5maWxlLm5hbWUpO1xuXHR9XG5cdHJldHVybiBuYW1lcztcbn1cbmZ1bmN0aW9uIGdldEZ1bGxOYW1lKHRhc2ssIHNlcGFyYXRvciA9IFwiID4gXCIpIHtcblx0cmV0dXJuIGdldE5hbWVzKHRhc2spLmpvaW4oc2VwYXJhdG9yKTtcbn1cbmZ1bmN0aW9uIGdldFRlc3ROYW1lKHRhc2ssIHNlcGFyYXRvciA9IFwiID4gXCIpIHtcblx0cmV0dXJuIGdldE5hbWVzKHRhc2spLnNsaWNlKDEpLmpvaW4oc2VwYXJhdG9yKTtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVRhc2tOYW1lKG5hbWVzLCBzZXBhcmF0b3IgPSBcIiA+IFwiKSB7XG5cdHJldHVybiBuYW1lcy5maWx0ZXIoKG5hbWUpID0+IG5hbWUgIT09IHVuZGVmaW5lZCkuam9pbihzZXBhcmF0b3IpO1xufVxuXG4vKipcbiogQ3JlYXRlcyBhIHN1aXRlIG9mIHRlc3RzLCBhbGxvd2luZyBmb3IgZ3JvdXBpbmcgYW5kIGhpZXJhcmNoaWNhbCBvcmdhbml6YXRpb24gb2YgdGVzdHMuXG4qIFN1aXRlcyBjYW4gY29udGFpbiBib3RoIHRlc3RzIGFuZCBvdGhlciBzdWl0ZXMsIGVuYWJsaW5nIGNvbXBsZXggdGVzdCBzdHJ1Y3R1cmVzLlxuKlxuKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBzdWl0ZSwgdXNlZCBmb3IgaWRlbnRpZmljYXRpb24gYW5kIHJlcG9ydGluZy5cbiogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBBIGZ1bmN0aW9uIHRoYXQgZGVmaW5lcyB0aGUgdGVzdHMgYW5kIHN1aXRlcyB3aXRoaW4gdGhpcyBzdWl0ZS5cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIGEgc3VpdGUgd2l0aCB0d28gdGVzdHNcbiogc3VpdGUoJ01hdGggb3BlcmF0aW9ucycsICgpID0+IHtcbiogICB0ZXN0KCdzaG91bGQgYWRkIHR3byBudW1iZXJzJywgKCkgPT4ge1xuKiAgICAgZXhwZWN0KGFkZCgxLCAyKSkudG9CZSgzKTtcbiogICB9KTtcbipcbiogICB0ZXN0KCdzaG91bGQgc3VidHJhY3QgdHdvIG51bWJlcnMnLCAoKSA9PiB7XG4qICAgICBleHBlY3Qoc3VidHJhY3QoNSwgMikpLnRvQmUoMyk7XG4qICAgfSk7XG4qIH0pO1xuKiBgYGBcbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIG5lc3RlZCBzdWl0ZXNcbiogc3VpdGUoJ1N0cmluZyBvcGVyYXRpb25zJywgKCkgPT4ge1xuKiAgIHN1aXRlKCdUcmltbWluZycsICgpID0+IHtcbiogICAgIHRlc3QoJ3Nob3VsZCB0cmltIHdoaXRlc3BhY2UgZnJvbSBzdGFydCBhbmQgZW5kJywgKCkgPT4ge1xuKiAgICAgICBleHBlY3QoJyAgaGVsbG8gICcudHJpbSgpKS50b0JlKCdoZWxsbycpO1xuKiAgICAgfSk7XG4qICAgfSk7XG4qXG4qICAgc3VpdGUoJ0NvbmNhdGVuYXRpb24nLCAoKSA9PiB7XG4qICAgICB0ZXN0KCdzaG91bGQgY29uY2F0ZW5hdGUgdHdvIHN0cmluZ3MnLCAoKSA9PiB7XG4qICAgICAgIGV4cGVjdCgnaGVsbG8nICsgJyAnICsgJ3dvcmxkJykudG9CZSgnaGVsbG8gd29ybGQnKTtcbiogICAgIH0pO1xuKiAgIH0pO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3Qgc3VpdGUgPSBjcmVhdGVTdWl0ZSgpO1xuLyoqXG4qIERlZmluZXMgYSB0ZXN0IGNhc2Ugd2l0aCBhIGdpdmVuIG5hbWUgYW5kIHRlc3QgZnVuY3Rpb24uIFRoZSB0ZXN0IGZ1bmN0aW9uIGNhbiBvcHRpb25hbGx5IGJlIGNvbmZpZ3VyZWQgd2l0aCB0ZXN0IG9wdGlvbnMuXG4qXG4qIEBwYXJhbSB7c3RyaW5nIHwgRnVuY3Rpb259IG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGVzdCBvciBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSB1c2VkIGFzIGEgdGVzdCBuYW1lLlxuKiBAcGFyYW0ge1Rlc3RPcHRpb25zIHwgVGVzdEZ1bmN0aW9ufSBbb3B0aW9uc09yRm5dIC0gT3B0aW9uYWwuIFRoZSB0ZXN0IG9wdGlvbnMgb3IgdGhlIHRlc3QgZnVuY3Rpb24gaWYgbm8gZXhwbGljaXQgbmFtZSBpcyBwcm92aWRlZC5cbiogQHBhcmFtIHtudW1iZXIgfCBUZXN0T3B0aW9ucyB8IFRlc3RGdW5jdGlvbn0gW29wdGlvbnNPclRlc3RdIC0gT3B0aW9uYWwuIFRoZSB0ZXN0IGZ1bmN0aW9uIG9yIG9wdGlvbnMsIGRlcGVuZGluZyBvbiB0aGUgcHJldmlvdXMgcGFyYW1ldGVycy5cbiogQHRocm93cyB7RXJyb3J9IElmIGNhbGxlZCBpbnNpZGUgYW5vdGhlciB0ZXN0IGZ1bmN0aW9uLlxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBEZWZpbmUgYSBzaW1wbGUgdGVzdFxuKiB0ZXN0KCdzaG91bGQgYWRkIHR3byBudW1iZXJzJywgKCkgPT4ge1xuKiAgIGV4cGVjdChhZGQoMSwgMikpLnRvQmUoMyk7XG4qIH0pO1xuKiBgYGBcbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIGEgdGVzdCB3aXRoIG9wdGlvbnNcbiogdGVzdCgnc2hvdWxkIHN1YnRyYWN0IHR3byBudW1iZXJzJywgeyByZXRyeTogMyB9LCAoKSA9PiB7XG4qICAgZXhwZWN0KHN1YnRyYWN0KDUsIDIpKS50b0JlKDMpO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3QgdGVzdCA9IGNyZWF0ZVRlc3QoZnVuY3Rpb24obmFtZSwgb3B0aW9uc09yRm4sIG9wdGlvbnNPclRlc3QpIHtcblx0aWYgKGdldEN1cnJlbnRUZXN0KCkpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoXCJDYWxsaW5nIHRoZSB0ZXN0IGZ1bmN0aW9uIGluc2lkZSBhbm90aGVyIHRlc3QgZnVuY3Rpb24gaXMgbm90IGFsbG93ZWQuIFBsZWFzZSBwdXQgaXQgaW5zaWRlIFxcXCJkZXNjcmliZVxcXCIgb3IgXFxcInN1aXRlXFxcIiBzbyBpdCBjYW4gYmUgcHJvcGVybHkgY29sbGVjdGVkLlwiKTtcblx0fVxuXHRnZXRDdXJyZW50U3VpdGUoKS50ZXN0LmZuLmNhbGwodGhpcywgZm9ybWF0TmFtZShuYW1lKSwgb3B0aW9uc09yRm4sIG9wdGlvbnNPclRlc3QpO1xufSk7XG4vKipcbiogQ3JlYXRlcyBhIHN1aXRlIG9mIHRlc3RzLCBhbGxvd2luZyBmb3IgZ3JvdXBpbmcgYW5kIGhpZXJhcmNoaWNhbCBvcmdhbml6YXRpb24gb2YgdGVzdHMuXG4qIFN1aXRlcyBjYW4gY29udGFpbiBib3RoIHRlc3RzIGFuZCBvdGhlciBzdWl0ZXMsIGVuYWJsaW5nIGNvbXBsZXggdGVzdCBzdHJ1Y3R1cmVzLlxuKlxuKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBzdWl0ZSwgdXNlZCBmb3IgaWRlbnRpZmljYXRpb24gYW5kIHJlcG9ydGluZy5cbiogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBBIGZ1bmN0aW9uIHRoYXQgZGVmaW5lcyB0aGUgdGVzdHMgYW5kIHN1aXRlcyB3aXRoaW4gdGhpcyBzdWl0ZS5cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIGEgc3VpdGUgd2l0aCB0d28gdGVzdHNcbiogZGVzY3JpYmUoJ01hdGggb3BlcmF0aW9ucycsICgpID0+IHtcbiogICB0ZXN0KCdzaG91bGQgYWRkIHR3byBudW1iZXJzJywgKCkgPT4ge1xuKiAgICAgZXhwZWN0KGFkZCgxLCAyKSkudG9CZSgzKTtcbiogICB9KTtcbipcbiogICB0ZXN0KCdzaG91bGQgc3VidHJhY3QgdHdvIG51bWJlcnMnLCAoKSA9PiB7XG4qICAgICBleHBlY3Qoc3VidHJhY3QoNSwgMikpLnRvQmUoMyk7XG4qICAgfSk7XG4qIH0pO1xuKiBgYGBcbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIG5lc3RlZCBzdWl0ZXNcbiogZGVzY3JpYmUoJ1N0cmluZyBvcGVyYXRpb25zJywgKCkgPT4ge1xuKiAgIGRlc2NyaWJlKCdUcmltbWluZycsICgpID0+IHtcbiogICAgIHRlc3QoJ3Nob3VsZCB0cmltIHdoaXRlc3BhY2UgZnJvbSBzdGFydCBhbmQgZW5kJywgKCkgPT4ge1xuKiAgICAgICBleHBlY3QoJyAgaGVsbG8gICcudHJpbSgpKS50b0JlKCdoZWxsbycpO1xuKiAgICAgfSk7XG4qICAgfSk7XG4qXG4qICAgZGVzY3JpYmUoJ0NvbmNhdGVuYXRpb24nLCAoKSA9PiB7XG4qICAgICB0ZXN0KCdzaG91bGQgY29uY2F0ZW5hdGUgdHdvIHN0cmluZ3MnLCAoKSA9PiB7XG4qICAgICAgIGV4cGVjdCgnaGVsbG8nICsgJyAnICsgJ3dvcmxkJykudG9CZSgnaGVsbG8gd29ybGQnKTtcbiogICAgIH0pO1xuKiAgIH0pO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3QgZGVzY3JpYmUgPSBzdWl0ZTtcbi8qKlxuKiBEZWZpbmVzIGEgdGVzdCBjYXNlIHdpdGggYSBnaXZlbiBuYW1lIGFuZCB0ZXN0IGZ1bmN0aW9uLiBUaGUgdGVzdCBmdW5jdGlvbiBjYW4gb3B0aW9uYWxseSBiZSBjb25maWd1cmVkIHdpdGggdGVzdCBvcHRpb25zLlxuKlxuKiBAcGFyYW0ge3N0cmluZyB8IEZ1bmN0aW9ufSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRlc3Qgb3IgYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgdXNlZCBhcyBhIHRlc3QgbmFtZS5cbiogQHBhcmFtIHtUZXN0T3B0aW9ucyB8IFRlc3RGdW5jdGlvbn0gW29wdGlvbnNPckZuXSAtIE9wdGlvbmFsLiBUaGUgdGVzdCBvcHRpb25zIG9yIHRoZSB0ZXN0IGZ1bmN0aW9uIGlmIG5vIGV4cGxpY2l0IG5hbWUgaXMgcHJvdmlkZWQuXG4qIEBwYXJhbSB7bnVtYmVyIHwgVGVzdE9wdGlvbnMgfCBUZXN0RnVuY3Rpb259IFtvcHRpb25zT3JUZXN0XSAtIE9wdGlvbmFsLiBUaGUgdGVzdCBmdW5jdGlvbiBvciBvcHRpb25zLCBkZXBlbmRpbmcgb24gdGhlIHByZXZpb3VzIHBhcmFtZXRlcnMuXG4qIEB0aHJvd3Mge0Vycm9yfSBJZiBjYWxsZWQgaW5zaWRlIGFub3RoZXIgdGVzdCBmdW5jdGlvbi5cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIGEgc2ltcGxlIHRlc3RcbiogaXQoJ2FkZHMgdHdvIG51bWJlcnMnLCAoKSA9PiB7XG4qICAgZXhwZWN0KGFkZCgxLCAyKSkudG9CZSgzKTtcbiogfSk7XG4qIGBgYFxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBEZWZpbmUgYSB0ZXN0IHdpdGggb3B0aW9uc1xuKiBpdCgnc3VidHJhY3RzIHR3byBudW1iZXJzJywgeyByZXRyeTogMyB9LCAoKSA9PiB7XG4qICAgZXhwZWN0KHN1YnRyYWN0KDUsIDIpKS50b0JlKDMpO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3QgaXQgPSB0ZXN0O1xubGV0IHJ1bm5lcjtcbmxldCBkZWZhdWx0U3VpdGU7XG5sZXQgY3VycmVudFRlc3RGaWxlcGF0aDtcbmZ1bmN0aW9uIGFzc2VydChjb25kaXRpb24sIG1lc3NhZ2UpIHtcblx0aWYgKCFjb25kaXRpb24pIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYFZpdGVzdCBmYWlsZWQgdG8gZmluZCAke21lc3NhZ2V9LiBPbmUgb2YgdGhlIGZvbGxvd2luZyBpcyBwb3NzaWJsZTpgICsgXCJcXG4tIFxcXCJ2aXRlc3RcXFwiIGlzIGltcG9ydGVkIGRpcmVjdGx5IHdpdGhvdXQgcnVubmluZyBcXFwidml0ZXN0XFxcIiBjb21tYW5kXCIgKyBcIlxcbi0gXFxcInZpdGVzdFxcXCIgaXMgaW1wb3J0ZWQgaW5zaWRlIFxcXCJnbG9iYWxTZXR1cFxcXCIgKHRvIGZpeCB0aGlzLCB1c2UgXFxcInNldHVwRmlsZXNcXFwiIGluc3RlYWQsIGJlY2F1c2UgXFxcImdsb2JhbFNldHVwXFxcIiBydW5zIGluIGEgZGlmZmVyZW50IGNvbnRleHQpXCIgKyBcIlxcbi0gXFxcInZpdGVzdFxcXCIgaXMgaW1wb3J0ZWQgaW5zaWRlIFZpdGUgLyBWaXRlc3QgY29uZmlnIGZpbGVcIiArIFwiXFxuLSBPdGhlcndpc2UsIGl0IG1pZ2h0IGJlIGEgVml0ZXN0IGJ1Zy4gUGxlYXNlIHJlcG9ydCBpdCB0byBodHRwczovL2dpdGh1Yi5jb20vdml0ZXN0LWRldi92aXRlc3QvaXNzdWVzXFxuXCIpO1xuXHR9XG59XG5mdW5jdGlvbiBnZXREZWZhdWx0U3VpdGUoKSB7XG5cdGFzc2VydChkZWZhdWx0U3VpdGUsIFwidGhlIGRlZmF1bHQgc3VpdGVcIik7XG5cdHJldHVybiBkZWZhdWx0U3VpdGU7XG59XG5mdW5jdGlvbiBnZXRSdW5uZXIoKSB7XG5cdGFzc2VydChydW5uZXIsIFwidGhlIHJ1bm5lclwiKTtcblx0cmV0dXJuIHJ1bm5lcjtcbn1cbmZ1bmN0aW9uIGNyZWF0ZURlZmF1bHRTdWl0ZShydW5uZXIpIHtcblx0Y29uc3QgY29uZmlnID0gcnVubmVyLmNvbmZpZy5zZXF1ZW5jZTtcblx0Y29uc3Qgb3B0aW9ucyA9IHt9O1xuXHRpZiAoY29uZmlnLmNvbmN1cnJlbnQgIT0gbnVsbCkge1xuXHRcdG9wdGlvbnMuY29uY3VycmVudCA9IGNvbmZpZy5jb25jdXJyZW50O1xuXHR9XG5cdGNvbnN0IGNvbGxlY3RvciA9IHN1aXRlKFwiXCIsIG9wdGlvbnMsICgpID0+IHt9KTtcblx0Ly8gbm8gcGFyZW50IHN1aXRlIGZvciB0b3AtbGV2ZWwgdGVzdHNcblx0ZGVsZXRlIGNvbGxlY3Rvci5zdWl0ZTtcblx0cmV0dXJuIGNvbGxlY3Rvcjtcbn1cbmZ1bmN0aW9uIGNsZWFyQ29sbGVjdG9yQ29udGV4dChmaWxlLCBjdXJyZW50UnVubmVyKSB7XG5cdGN1cnJlbnRUZXN0RmlsZXBhdGggPSBmaWxlLmZpbGVwYXRoO1xuXHRydW5uZXIgPSBjdXJyZW50UnVubmVyO1xuXHRpZiAoIWRlZmF1bHRTdWl0ZSkge1xuXHRcdGRlZmF1bHRTdWl0ZSA9IGNyZWF0ZURlZmF1bHRTdWl0ZShjdXJyZW50UnVubmVyKTtcblx0fVxuXHRkZWZhdWx0U3VpdGUuZmlsZSA9IGZpbGU7XG5cdGNvbGxlY3RvckNvbnRleHQudGFza3MubGVuZ3RoID0gMDtcblx0ZGVmYXVsdFN1aXRlLmNsZWFyKCk7XG5cdGNvbGxlY3RvckNvbnRleHQuY3VycmVudFN1aXRlID0gZGVmYXVsdFN1aXRlO1xufVxuZnVuY3Rpb24gZ2V0Q3VycmVudFN1aXRlKCkge1xuXHRjb25zdCBjdXJyZW50U3VpdGUgPSBjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZSB8fCBkZWZhdWx0U3VpdGU7XG5cdGFzc2VydChjdXJyZW50U3VpdGUsIFwidGhlIGN1cnJlbnQgc3VpdGVcIik7XG5cdHJldHVybiBjdXJyZW50U3VpdGU7XG59XG5mdW5jdGlvbiBjcmVhdGVTdWl0ZUhvb2tzKCkge1xuXHRyZXR1cm4ge1xuXHRcdGJlZm9yZUFsbDogW10sXG5cdFx0YWZ0ZXJBbGw6IFtdLFxuXHRcdGJlZm9yZUVhY2g6IFtdLFxuXHRcdGFmdGVyRWFjaDogW10sXG5cdFx0YXJvdW5kRWFjaDogW10sXG5cdFx0YXJvdW5kQWxsOiBbXVxuXHR9O1xufVxuY29uc3QgUE9TSVRJVkVfSU5GSU5JVFkgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7XG5mdW5jdGlvbiBwYXJzZUFyZ3VtZW50cyhvcHRpb25zT3JGbiwgdGltZW91dE9yVGVzdCkge1xuXHRpZiAodGltZW91dE9yVGVzdCAhPSBudWxsICYmIHR5cGVvZiB0aW1lb3V0T3JUZXN0ID09PSBcIm9iamVjdFwiKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcihgU2lnbmF0dXJlIFwidGVzdChuYW1lLCBmbiwgeyAuLi4gfSlcIiB3YXMgZGVwcmVjYXRlZCBpbiBWaXRlc3QgMyBhbmQgcmVtb3ZlZCBpbiBWaXRlc3QgNC4gUGxlYXNlLCBwcm92aWRlIG9wdGlvbnMgYXMgYSBzZWNvbmQgYXJndW1lbnQgaW5zdGVhZC5gKTtcblx0fVxuXHRsZXQgb3B0aW9ucyA9IHt9O1xuXHRsZXQgZm47XG5cdC8vIGl0KCcnLCAoKSA9PiB7fSwgMTAwMClcblx0aWYgKHR5cGVvZiB0aW1lb3V0T3JUZXN0ID09PSBcIm51bWJlclwiKSB7XG5cdFx0b3B0aW9ucyA9IHsgdGltZW91dDogdGltZW91dE9yVGVzdCB9O1xuXHR9IGVsc2UgaWYgKHR5cGVvZiBvcHRpb25zT3JGbiA9PT0gXCJvYmplY3RcIikge1xuXHRcdG9wdGlvbnMgPSBvcHRpb25zT3JGbjtcblx0fVxuXHRpZiAodHlwZW9mIG9wdGlvbnNPckZuID09PSBcImZ1bmN0aW9uXCIpIHtcblx0XHRpZiAodHlwZW9mIHRpbWVvdXRPclRlc3QgPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdFx0dGhyb3cgbmV3IFR5cGVFcnJvcihcIkNhbm5vdCB1c2UgdHdvIGZ1bmN0aW9ucyBhcyBhcmd1bWVudHMuIFBsZWFzZSB1c2UgdGhlIHNlY29uZCBhcmd1bWVudCBmb3Igb3B0aW9ucy5cIik7XG5cdFx0fVxuXHRcdGZuID0gb3B0aW9uc09yRm47XG5cdH0gZWxzZSBpZiAodHlwZW9mIHRpbWVvdXRPclRlc3QgPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdGZuID0gdGltZW91dE9yVGVzdDtcblx0fVxuXHRyZXR1cm4ge1xuXHRcdG9wdGlvbnMsXG5cdFx0aGFuZGxlcjogZm5cblx0fTtcbn1cbi8vIGltcGxlbWVudGF0aW9uc1xuZnVuY3Rpb24gY3JlYXRlU3VpdGVDb2xsZWN0b3IobmFtZSwgZmFjdG9yeSA9ICgpID0+IHt9LCBtb2RlLCBlYWNoLCBzdWl0ZU9wdGlvbnMpIHtcblx0Y29uc3QgdGFza3MgPSBbXTtcblx0bGV0IHN1aXRlO1xuXHRpbml0U3VpdGUodHJ1ZSk7XG5cdGNvbnN0IHRhc2sgPSBmdW5jdGlvbihuYW1lID0gXCJcIiwgb3B0aW9ucyA9IHt9KSB7XG5cdFx0Y29uc3QgY3VycmVudFN1aXRlID0gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LnN1aXRlO1xuXHRcdGNvbnN0IHBhcmVudFRhc2sgPSBjdXJyZW50U3VpdGUgPz8gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LmZpbGU7XG5cdFx0Y29uc3QgcGFyZW50VGFncyA9IHBhcmVudFRhc2s/LnRhZ3MgfHwgW107XG5cdFx0Y29uc3QgdGVzdFRhZ3MgPSB1bmlxdWUoWy4uLnBhcmVudFRhZ3MsIC4uLnRvQXJyYXkob3B0aW9ucy50YWdzKV0pO1xuXHRcdGNvbnN0IHRhZ3NPcHRpb25zID0gdGVzdFRhZ3MubWFwKCh0YWcpID0+IHtcblx0XHRcdGNvbnN0IHRhZ0RlZmluaXRpb24gPSBydW5uZXIuY29uZmlnLnRhZ3M/LmZpbmQoKHQpID0+IHQubmFtZSA9PT0gdGFnKTtcblx0XHRcdGlmICghdGFnRGVmaW5pdGlvbiAmJiBydW5uZXIuY29uZmlnLnN0cmljdFRhZ3MpIHtcblx0XHRcdFx0dGhyb3cgY3JlYXRlTm9UYWdzRXJyb3IocnVubmVyLmNvbmZpZy50YWdzLCB0YWcpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRhZ0RlZmluaXRpb247XG5cdFx0fSkuZmlsdGVyKChyKSA9PiByICE9IG51bGwpLnNvcnQoKHRhZzEsIHRhZzIpID0+ICh0YWcyLnByaW9yaXR5ID8/IFBPU0lUSVZFX0lORklOSVRZKSAtICh0YWcxLnByaW9yaXR5ID8/IFBPU0lUSVZFX0lORklOSVRZKSkucmVkdWNlKChhY2MsIHRhZykgPT4ge1xuXHRcdFx0Y29uc3QgeyBuYW1lLCBkZXNjcmlwdGlvbiwgcHJpb3JpdHksIG1ldGEsIC4uLm9wdGlvbnMgfSA9IHRhZztcblx0XHRcdE9iamVjdC5hc3NpZ24oYWNjLCBvcHRpb25zKTtcblx0XHRcdGlmIChtZXRhKSB7XG5cdFx0XHRcdGFjYy5tZXRhID0gT2JqZWN0LmFzc2lnbihhY2MubWV0YSA/PyBPYmplY3QuY3JlYXRlKG51bGwpLCBtZXRhKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBhY2M7XG5cdFx0fSwge30pO1xuXHRcdGNvbnN0IHRlc3RPd25NZXRhID0gb3B0aW9ucy5tZXRhO1xuXHRcdG9wdGlvbnMgPSB7XG5cdFx0XHQuLi50YWdzT3B0aW9ucyxcblx0XHRcdC4uLm9wdGlvbnNcblx0XHR9O1xuXHRcdGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgPz8gcnVubmVyLmNvbmZpZy50ZXN0VGltZW91dDtcblx0XHRjb25zdCBwYXJlbnRNZXRhID0gY3VycmVudFN1aXRlPy5tZXRhO1xuXHRcdGNvbnN0IHRhZ01ldGEgPSB0YWdzT3B0aW9ucy5tZXRhO1xuXHRcdGNvbnN0IHRlc3RNZXRhID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcblx0XHRpZiAodGFnTWV0YSkge1xuXHRcdFx0T2JqZWN0LmFzc2lnbih0ZXN0TWV0YSwgdGFnTWV0YSk7XG5cdFx0fVxuXHRcdGlmIChwYXJlbnRNZXRhKSB7XG5cdFx0XHRPYmplY3QuYXNzaWduKHRlc3RNZXRhLCBwYXJlbnRNZXRhKTtcblx0XHR9XG5cdFx0aWYgKHRlc3RPd25NZXRhKSB7XG5cdFx0XHRPYmplY3QuYXNzaWduKHRlc3RNZXRhLCB0ZXN0T3duTWV0YSk7XG5cdFx0fVxuXHRcdGNvbnN0IHRhc2sgPSB7XG5cdFx0XHRpZDogXCJcIixcblx0XHRcdG5hbWUsXG5cdFx0XHRmdWxsTmFtZTogY3JlYXRlVGFza05hbWUoW2N1cnJlbnRTdWl0ZT8uZnVsbE5hbWUgPz8gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LmZpbGU/LmZ1bGxOYW1lLCBuYW1lXSksXG5cdFx0XHRmdWxsVGVzdE5hbWU6IGNyZWF0ZVRhc2tOYW1lKFtjdXJyZW50U3VpdGU/LmZ1bGxUZXN0TmFtZSwgbmFtZV0pLFxuXHRcdFx0c3VpdGU6IGN1cnJlbnRTdWl0ZSxcblx0XHRcdGVhY2g6IG9wdGlvbnMuZWFjaCxcblx0XHRcdGZhaWxzOiBvcHRpb25zLmZhaWxzLFxuXHRcdFx0Y29udGV4dDogdW5kZWZpbmVkLFxuXHRcdFx0dHlwZTogXCJ0ZXN0XCIsXG5cdFx0XHRmaWxlOiBjdXJyZW50U3VpdGU/LmZpbGUgPz8gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LmZpbGUsXG5cdFx0XHR0aW1lb3V0LFxuXHRcdFx0cmV0cnk6IG9wdGlvbnMucmV0cnkgPz8gcnVubmVyLmNvbmZpZy5yZXRyeSxcblx0XHRcdHJlcGVhdHM6IG9wdGlvbnMucmVwZWF0cyxcblx0XHRcdG1vZGU6IG9wdGlvbnMub25seSA/IFwib25seVwiIDogb3B0aW9ucy5za2lwID8gXCJza2lwXCIgOiBvcHRpb25zLnRvZG8gPyBcInRvZG9cIiA6IFwicnVuXCIsXG5cdFx0XHRtZXRhOiB0ZXN0TWV0YSxcblx0XHRcdGFubm90YXRpb25zOiBbXSxcblx0XHRcdGFydGlmYWN0czogW10sXG5cdFx0XHR0YWdzOiB0ZXN0VGFnc1xuXHRcdH07XG5cdFx0Y29uc3QgaGFuZGxlciA9IG9wdGlvbnMuaGFuZGxlcjtcblx0XHRpZiAodGFzay5tb2RlID09PSBcInJ1blwiICYmICFoYW5kbGVyKSB7XG5cdFx0XHR0YXNrLm1vZGUgPSBcInRvZG9cIjtcblx0XHR9XG5cdFx0aWYgKG9wdGlvbnMuY29uY3VycmVudCA/PyAoIW9wdGlvbnMuc2VxdWVudGlhbCAmJiBydW5uZXIuY29uZmlnLnNlcXVlbmNlLmNvbmN1cnJlbnQpKSB7XG5cdFx0XHR0YXNrLmNvbmN1cnJlbnQgPSB0cnVlO1xuXHRcdH1cblx0XHR0YXNrLnNodWZmbGUgPSBzdWl0ZU9wdGlvbnM/LnNodWZmbGU7XG5cdFx0Y29uc3QgY29udGV4dCA9IGNyZWF0ZVRlc3RDb250ZXh0KHRhc2ssIHJ1bm5lcik7XG5cdFx0Ly8gY3JlYXRlIHRlc3QgY29udGV4dFxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXNrLCBcImNvbnRleHRcIiwge1xuXHRcdFx0dmFsdWU6IGNvbnRleHQsXG5cdFx0XHRlbnVtZXJhYmxlOiBmYWxzZVxuXHRcdH0pO1xuXHRcdHNldFRlc3RGaXh0dXJlKGNvbnRleHQsIG9wdGlvbnMuZml4dHVyZXMgPz8gbmV3IFRlc3RGaXh0dXJlcygpKTtcblx0XHRjb25zdCBsaW1pdCA9IEVycm9yLnN0YWNrVHJhY2VMaW1pdDtcblx0XHRFcnJvci5zdGFja1RyYWNlTGltaXQgPSAxMDtcblx0XHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKTtcblx0XHRFcnJvci5zdGFja1RyYWNlTGltaXQgPSBsaW1pdDtcblx0XHRpZiAoaGFuZGxlcikge1xuXHRcdFx0c2V0Rm4odGFzaywgd2l0aFRpbWVvdXQod2l0aENhbmNlbCh3aXRoQXdhaXRBc3luY0Fzc2VydGlvbnMod2l0aEZpeHR1cmVzKGhhbmRsZXIsIHsgY29udGV4dCB9KSwgdGFzayksIHRhc2suY29udGV4dC5zaWduYWwpLCB0aW1lb3V0LCBmYWxzZSwgc3RhY2tUcmFjZUVycm9yLCAoXywgZXJyb3IpID0+IGFib3J0SWZUaW1lb3V0KFtjb250ZXh0XSwgZXJyb3IpKSk7XG5cdFx0fVxuXHRcdGlmIChydW5uZXIuY29uZmlnLmluY2x1ZGVUYXNrTG9jYXRpb24pIHtcblx0XHRcdGNvbnN0IGVycm9yID0gc3RhY2tUcmFjZUVycm9yLnN0YWNrO1xuXHRcdFx0Y29uc3Qgc3RhY2sgPSBmaW5kVGVzdEZpbGVTdGFja1RyYWNlKGN1cnJlbnRUZXN0RmlsZXBhdGgsIGVycm9yKTtcblx0XHRcdGlmIChzdGFjaykge1xuXHRcdFx0XHR0YXNrLmxvY2F0aW9uID0ge1xuXHRcdFx0XHRcdGxpbmU6IHN0YWNrLmxpbmUsXG5cdFx0XHRcdFx0Y29sdW1uOiBzdGFjay5jb2x1bW5cblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGFza3MucHVzaCh0YXNrKTtcblx0XHRyZXR1cm4gdGFzaztcblx0fTtcblx0Y29uc3QgdGVzdCA9IGNyZWF0ZVRlc3QoZnVuY3Rpb24obmFtZSwgb3B0aW9uc09yRm4sIHRpbWVvdXRPclRlc3QpIHtcblx0XHRsZXQgeyBvcHRpb25zLCBoYW5kbGVyIH0gPSBwYXJzZUFyZ3VtZW50cyhvcHRpb25zT3JGbiwgdGltZW91dE9yVGVzdCk7XG5cdFx0Ly8gaW5oZXJpdCByZXBlYXRzLCByZXRyeSwgdGltZW91dCBmcm9tIHN1aXRlXG5cdFx0aWYgKHR5cGVvZiBzdWl0ZU9wdGlvbnMgPT09IFwib2JqZWN0XCIpIHtcblx0XHRcdG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKHt9LCBzdWl0ZU9wdGlvbnMsIG9wdGlvbnMpO1xuXHRcdH1cblx0XHQvLyBpbmhlcml0IGNvbmN1cnJlbnQgLyBzZXF1ZW50aWFsIGZyb20gc3VpdGVcblx0XHRjb25zdCBjb25jdXJyZW50ID0gdGhpcy5jb25jdXJyZW50ID8/ICghdGhpcy5zZXF1ZW50aWFsICYmIG9wdGlvbnM/LmNvbmN1cnJlbnQpO1xuXHRcdGlmIChvcHRpb25zLmNvbmN1cnJlbnQgIT0gbnVsbCAmJiBjb25jdXJyZW50ICE9IG51bGwpIHtcblx0XHRcdG9wdGlvbnMuY29uY3VycmVudCA9IGNvbmN1cnJlbnQ7XG5cdFx0fVxuXHRcdGNvbnN0IHNlcXVlbnRpYWwgPSB0aGlzLnNlcXVlbnRpYWwgPz8gKCF0aGlzLmNvbmN1cnJlbnQgJiYgb3B0aW9ucz8uc2VxdWVudGlhbCk7XG5cdFx0aWYgKG9wdGlvbnMuc2VxdWVudGlhbCAhPSBudWxsICYmIHNlcXVlbnRpYWwgIT0gbnVsbCkge1xuXHRcdFx0b3B0aW9ucy5zZXF1ZW50aWFsID0gc2VxdWVudGlhbDtcblx0XHR9XG5cdFx0Y29uc3QgdGVzdCA9IHRhc2soZm9ybWF0TmFtZShuYW1lKSwge1xuXHRcdFx0Li4udGhpcyxcblx0XHRcdC4uLm9wdGlvbnMsXG5cdFx0XHRoYW5kbGVyXG5cdFx0fSk7XG5cdFx0dGVzdC50eXBlID0gXCJ0ZXN0XCI7XG5cdH0pO1xuXHRjb25zdCBjb2xsZWN0b3IgPSB7XG5cdFx0dHlwZTogXCJjb2xsZWN0b3JcIixcblx0XHRuYW1lLFxuXHRcdG1vZGUsXG5cdFx0c3VpdGUsXG5cdFx0b3B0aW9uczogc3VpdGVPcHRpb25zLFxuXHRcdHRlc3QsXG5cdFx0ZmlsZTogc3VpdGUuZmlsZSxcblx0XHR0YXNrcyxcblx0XHRjb2xsZWN0LFxuXHRcdHRhc2ssXG5cdFx0Y2xlYXIsXG5cdFx0b246IGFkZEhvb2tcblx0fTtcblx0ZnVuY3Rpb24gYWRkSG9vayhuYW1lLCAuLi5mbikge1xuXHRcdGdldEhvb2tzKHN1aXRlKVtuYW1lXS5wdXNoKC4uLmZuKTtcblx0fVxuXHRmdW5jdGlvbiBpbml0U3VpdGUoaW5jbHVkZUxvY2F0aW9uKSB7XG5cdFx0aWYgKHR5cGVvZiBzdWl0ZU9wdGlvbnMgPT09IFwibnVtYmVyXCIpIHtcblx0XHRcdHN1aXRlT3B0aW9ucyA9IHsgdGltZW91dDogc3VpdGVPcHRpb25zIH07XG5cdFx0fVxuXHRcdGNvbnN0IGN1cnJlbnRTdWl0ZSA9IGNvbGxlY3RvckNvbnRleHQuY3VycmVudFN1aXRlPy5zdWl0ZTtcblx0XHRjb25zdCBwYXJlbnRUYXNrID0gY3VycmVudFN1aXRlID8/IGNvbGxlY3RvckNvbnRleHQuY3VycmVudFN1aXRlPy5maWxlO1xuXHRcdGNvbnN0IHN1aXRlVGFncyA9IHRvQXJyYXkoc3VpdGVPcHRpb25zPy50YWdzKTtcblx0XHR2YWxpZGF0ZVRhZ3MocnVubmVyLmNvbmZpZywgc3VpdGVUYWdzKTtcblx0XHRzdWl0ZSA9IHtcblx0XHRcdGlkOiBcIlwiLFxuXHRcdFx0dHlwZTogXCJzdWl0ZVwiLFxuXHRcdFx0bmFtZSxcblx0XHRcdGZ1bGxOYW1lOiBjcmVhdGVUYXNrTmFtZShbY3VycmVudFN1aXRlPy5mdWxsTmFtZSA/PyBjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZT8uZmlsZT8uZnVsbE5hbWUsIG5hbWVdKSxcblx0XHRcdGZ1bGxUZXN0TmFtZTogY3JlYXRlVGFza05hbWUoW2N1cnJlbnRTdWl0ZT8uZnVsbFRlc3ROYW1lLCBuYW1lXSksXG5cdFx0XHRzdWl0ZTogY3VycmVudFN1aXRlLFxuXHRcdFx0bW9kZSxcblx0XHRcdGVhY2gsXG5cdFx0XHRmaWxlOiBjdXJyZW50U3VpdGU/LmZpbGUgPz8gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LmZpbGUsXG5cdFx0XHRzaHVmZmxlOiBzdWl0ZU9wdGlvbnM/LnNodWZmbGUsXG5cdFx0XHR0YXNrczogW10sXG5cdFx0XHRtZXRhOiBzdWl0ZU9wdGlvbnM/Lm1ldGEgPz8gT2JqZWN0LmNyZWF0ZShudWxsKSxcblx0XHRcdGNvbmN1cnJlbnQ6IHN1aXRlT3B0aW9ucz8uY29uY3VycmVudCxcblx0XHRcdHRhZ3M6IHVuaXF1ZShbLi4ucGFyZW50VGFzaz8udGFncyB8fCBbXSwgLi4uc3VpdGVUYWdzXSlcblx0XHR9O1xuXHRcdGlmIChydW5uZXIgJiYgaW5jbHVkZUxvY2F0aW9uICYmIHJ1bm5lci5jb25maWcuaW5jbHVkZVRhc2tMb2NhdGlvbikge1xuXHRcdFx0Y29uc3QgbGltaXQgPSBFcnJvci5zdGFja1RyYWNlTGltaXQ7XG5cdFx0XHRFcnJvci5zdGFja1RyYWNlTGltaXQgPSAxNTtcblx0XHRcdGNvbnN0IGVycm9yID0gbmV3IEVycm9yKFwic3RhY2t0cmFjZVwiKS5zdGFjaztcblx0XHRcdEVycm9yLnN0YWNrVHJhY2VMaW1pdCA9IGxpbWl0O1xuXHRcdFx0Y29uc3Qgc3RhY2sgPSBmaW5kVGVzdEZpbGVTdGFja1RyYWNlKGN1cnJlbnRUZXN0RmlsZXBhdGgsIGVycm9yKTtcblx0XHRcdGlmIChzdGFjaykge1xuXHRcdFx0XHRzdWl0ZS5sb2NhdGlvbiA9IHtcblx0XHRcdFx0XHRsaW5lOiBzdGFjay5saW5lLFxuXHRcdFx0XHRcdGNvbHVtbjogc3RhY2suY29sdW1uXG5cdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHNldEhvb2tzKHN1aXRlLCBjcmVhdGVTdWl0ZUhvb2tzKCkpO1xuXHR9XG5cdGZ1bmN0aW9uIGNsZWFyKCkge1xuXHRcdHRhc2tzLmxlbmd0aCA9IDA7XG5cdFx0aW5pdFN1aXRlKGZhbHNlKTtcblx0fVxuXHRhc3luYyBmdW5jdGlvbiBjb2xsZWN0KGZpbGUpIHtcblx0XHRpZiAoIWZpbGUpIHtcblx0XHRcdHRocm93IG5ldyBUeXBlRXJyb3IoXCJGaWxlIGlzIHJlcXVpcmVkIHRvIGNvbGxlY3QgdGFza3MuXCIpO1xuXHRcdH1cblx0XHRpZiAoZmFjdG9yeSkge1xuXHRcdFx0YXdhaXQgcnVuV2l0aFN1aXRlKGNvbGxlY3RvciwgKCkgPT4gZmFjdG9yeSh0ZXN0KSk7XG5cdFx0fVxuXHRcdGNvbnN0IGFsbENoaWxkcmVuID0gW107XG5cdFx0Zm9yIChjb25zdCBpIG9mIHRhc2tzKSB7XG5cdFx0XHRhbGxDaGlsZHJlbi5wdXNoKGkudHlwZSA9PT0gXCJjb2xsZWN0b3JcIiA/IGF3YWl0IGkuY29sbGVjdChmaWxlKSA6IGkpO1xuXHRcdH1cblx0XHRzdWl0ZS50YXNrcyA9IGFsbENoaWxkcmVuO1xuXHRcdHJldHVybiBzdWl0ZTtcblx0fVxuXHRjb2xsZWN0VGFzayhjb2xsZWN0b3IpO1xuXHRyZXR1cm4gY29sbGVjdG9yO1xufVxuZnVuY3Rpb24gd2l0aEF3YWl0QXN5bmNBc3NlcnRpb25zKGZuLCB0YXNrKSB7XG5cdHJldHVybiAoYXN5bmMgKC4uLmFyZ3MpID0+IHtcblx0XHRjb25zdCBmblJlc3VsdCA9IGF3YWl0IGZuKC4uLmFyZ3MpO1xuXHRcdC8vIHNvbWUgYXN5bmMgZXhwZWN0IHdpbGwgYmUgYWRkZWQgdG8gdGhpcyBhcnJheSwgaW4gY2FzZSB1c2VyIGZvcmdldCB0byBhd2FpdCB0aGVtXG5cdFx0aWYgKHRhc2sucHJvbWlzZXMpIHtcblx0XHRcdGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZCh0YXNrLnByb21pc2VzKTtcblx0XHRcdGNvbnN0IGVycm9ycyA9IHJlc3VsdC5tYXAoKHIpID0+IHIuc3RhdHVzID09PSBcInJlamVjdGVkXCIgPyByLnJlYXNvbiA6IHVuZGVmaW5lZCkuZmlsdGVyKEJvb2xlYW4pO1xuXHRcdFx0aWYgKGVycm9ycy5sZW5ndGgpIHtcblx0XHRcdFx0dGhyb3cgZXJyb3JzO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gZm5SZXN1bHQ7XG5cdH0pO1xufVxuZnVuY3Rpb24gY3JlYXRlU3VpdGUoKSB7XG5cdGZ1bmN0aW9uIHN1aXRlRm4obmFtZSwgZmFjdG9yeU9yT3B0aW9ucywgb3B0aW9uc09yRmFjdG9yeSkge1xuXHRcdGlmIChnZXRDdXJyZW50VGVzdCgpKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJDYWxsaW5nIHRoZSBzdWl0ZSBmdW5jdGlvbiBpbnNpZGUgdGVzdCBmdW5jdGlvbiBpcyBub3QgYWxsb3dlZC4gSXQgY2FuIGJlIG9ubHkgY2FsbGVkIGF0IHRoZSB0b3AgbGV2ZWwgb3IgaW5zaWRlIGFub3RoZXIgc3VpdGUgZnVuY3Rpb24uXCIpO1xuXHRcdH1cblx0XHRjb25zdCBjdXJyZW50U3VpdGUgPSBjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZSB8fCBkZWZhdWx0U3VpdGU7XG5cdFx0bGV0IHsgb3B0aW9ucywgaGFuZGxlcjogZmFjdG9yeSB9ID0gcGFyc2VBcmd1bWVudHMoZmFjdG9yeU9yT3B0aW9ucywgb3B0aW9uc09yRmFjdG9yeSk7XG5cdFx0Y29uc3QgaXNDb25jdXJyZW50U3BlY2lmaWVkID0gb3B0aW9ucy5jb25jdXJyZW50IHx8IHRoaXMuY29uY3VycmVudCB8fCBvcHRpb25zLnNlcXVlbnRpYWwgPT09IGZhbHNlO1xuXHRcdGNvbnN0IGlzU2VxdWVudGlhbFNwZWNpZmllZCA9IG9wdGlvbnMuc2VxdWVudGlhbCB8fCB0aGlzLnNlcXVlbnRpYWwgfHwgb3B0aW9ucy5jb25jdXJyZW50ID09PSBmYWxzZTtcblx0XHRjb25zdCB7IG1ldGE6IHBhcmVudE1ldGEsIC4uLnBhcmVudE9wdGlvbnMgfSA9IGN1cnJlbnRTdWl0ZT8ub3B0aW9ucyB8fCB7fTtcblx0XHQvLyBpbmhlcml0IG9wdGlvbnMgZnJvbSBjdXJyZW50IHN1aXRlXG5cdFx0b3B0aW9ucyA9IHtcblx0XHRcdC4uLnBhcmVudE9wdGlvbnMsXG5cdFx0XHQuLi5vcHRpb25zXG5cdFx0fTtcblx0XHRjb25zdCBzaHVmZmxlID0gdGhpcy5zaHVmZmxlID8/IG9wdGlvbnMuc2h1ZmZsZSA/PyBjdXJyZW50U3VpdGU/Lm9wdGlvbnM/LnNodWZmbGUgPz8gcnVubmVyPy5jb25maWcuc2VxdWVuY2Uuc2h1ZmZsZTtcblx0XHRpZiAoc2h1ZmZsZSAhPSBudWxsKSB7XG5cdFx0XHRvcHRpb25zLnNodWZmbGUgPSBzaHVmZmxlO1xuXHRcdH1cblx0XHRsZXQgbW9kZSA9IHRoaXMub25seSA/PyBvcHRpb25zLm9ubHkgPyBcIm9ubHlcIiA6IHRoaXMuc2tpcCA/PyBvcHRpb25zLnNraXAgPyBcInNraXBcIiA6IHRoaXMudG9kbyA/PyBvcHRpb25zLnRvZG8gPyBcInRvZG9cIiA6IFwicnVuXCI7XG5cdFx0Ly8gcGFzc2VkIGFzIHRlc3QobmFtZSksIGFzc3VtZSBpdCdzIGEgXCJ0b2RvXCJcblx0XHRpZiAobW9kZSA9PT0gXCJydW5cIiAmJiAhZmFjdG9yeSkge1xuXHRcdFx0bW9kZSA9IFwidG9kb1wiO1xuXHRcdH1cblx0XHQvLyBpbmhlcml0IGNvbmN1cnJlbnQgLyBzZXF1ZW50aWFsIGZyb20gc3VpdGVcblx0XHRjb25zdCBpc0NvbmN1cnJlbnQgPSBpc0NvbmN1cnJlbnRTcGVjaWZpZWQgfHwgb3B0aW9ucy5jb25jdXJyZW50ICYmICFpc1NlcXVlbnRpYWxTcGVjaWZpZWQ7XG5cdFx0Y29uc3QgaXNTZXF1ZW50aWFsID0gaXNTZXF1ZW50aWFsU3BlY2lmaWVkIHx8IG9wdGlvbnMuc2VxdWVudGlhbCAmJiAhaXNDb25jdXJyZW50U3BlY2lmaWVkO1xuXHRcdGlmIChpc0NvbmN1cnJlbnQgIT0gbnVsbCkge1xuXHRcdFx0b3B0aW9ucy5jb25jdXJyZW50ID0gaXNDb25jdXJyZW50ICYmICFpc1NlcXVlbnRpYWw7XG5cdFx0fVxuXHRcdGlmIChpc1NlcXVlbnRpYWwgIT0gbnVsbCkge1xuXHRcdFx0b3B0aW9ucy5zZXF1ZW50aWFsID0gaXNTZXF1ZW50aWFsICYmICFpc0NvbmN1cnJlbnQ7XG5cdFx0fVxuXHRcdGlmIChwYXJlbnRNZXRhKSB7XG5cdFx0XHRvcHRpb25zLm1ldGEgPSBPYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUobnVsbCksIHBhcmVudE1ldGEsIG9wdGlvbnMubWV0YSk7XG5cdFx0fVxuXHRcdHJldHVybiBjcmVhdGVTdWl0ZUNvbGxlY3Rvcihmb3JtYXROYW1lKG5hbWUpLCBmYWN0b3J5LCBtb2RlLCB0aGlzLmVhY2gsIG9wdGlvbnMpO1xuXHR9XG5cdHN1aXRlRm4uZWFjaCA9IGZ1bmN0aW9uKGNhc2VzLCAuLi5hcmdzKSB7XG5cdFx0Y29uc3QgY29udGV4dCA9IGdldENoYWluYWJsZUNvbnRleHQodGhpcyk7XG5cdFx0Y29uc3Qgc3VpdGUgPSBjb250ZXh0LndpdGhDb250ZXh0KCk7XG5cdFx0Y29udGV4dC5zZXRDb250ZXh0KFwiZWFjaFwiLCB0cnVlKTtcblx0XHRpZiAoQXJyYXkuaXNBcnJheShjYXNlcykgJiYgYXJncy5sZW5ndGgpIHtcblx0XHRcdGNhc2VzID0gZm9ybWF0VGVtcGxhdGVTdHJpbmcoY2FzZXMsIGFyZ3MpO1xuXHRcdH1cblx0XHRyZXR1cm4gKG5hbWUsIG9wdGlvbnNPckZuLCBmbk9yT3B0aW9ucykgPT4ge1xuXHRcdFx0Y29uc3QgX25hbWUgPSBmb3JtYXROYW1lKG5hbWUpO1xuXHRcdFx0Y29uc3QgYXJyYXlPbmx5Q2FzZXMgPSBjYXNlcy5ldmVyeShBcnJheS5pc0FycmF5KTtcblx0XHRcdGNvbnN0IHsgb3B0aW9ucywgaGFuZGxlciB9ID0gcGFyc2VBcmd1bWVudHMob3B0aW9uc09yRm4sIGZuT3JPcHRpb25zKTtcblx0XHRcdGNvbnN0IGZuRmlyc3QgPSB0eXBlb2Ygb3B0aW9uc09yRm4gPT09IFwiZnVuY3Rpb25cIjtcblx0XHRcdGNhc2VzLmZvckVhY2goKGksIGlkeCkgPT4ge1xuXHRcdFx0XHRjb25zdCBpdGVtcyA9IEFycmF5LmlzQXJyYXkoaSkgPyBpIDogW2ldO1xuXHRcdFx0XHRpZiAoZm5GaXJzdCkge1xuXHRcdFx0XHRcdGlmIChhcnJheU9ubHlDYXNlcykge1xuXHRcdFx0XHRcdFx0c3VpdGUoZm9ybWF0VGl0bGUoX25hbWUsIGl0ZW1zLCBpZHgpLCBoYW5kbGVyID8gKCkgPT4gaGFuZGxlciguLi5pdGVtcykgOiB1bmRlZmluZWQsIG9wdGlvbnMudGltZW91dCk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHN1aXRlKGZvcm1hdFRpdGxlKF9uYW1lLCBpdGVtcywgaWR4KSwgaGFuZGxlciA/ICgpID0+IGhhbmRsZXIoaSkgOiB1bmRlZmluZWQsIG9wdGlvbnMudGltZW91dCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmIChhcnJheU9ubHlDYXNlcykge1xuXHRcdFx0XHRcdFx0c3VpdGUoZm9ybWF0VGl0bGUoX25hbWUsIGl0ZW1zLCBpZHgpLCBvcHRpb25zLCBoYW5kbGVyID8gKCkgPT4gaGFuZGxlciguLi5pdGVtcykgOiB1bmRlZmluZWQpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRzdWl0ZShmb3JtYXRUaXRsZShfbmFtZSwgaXRlbXMsIGlkeCksIG9wdGlvbnMsIGhhbmRsZXIgPyAoKSA9PiBoYW5kbGVyKGkpIDogdW5kZWZpbmVkKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdFx0Y29udGV4dC5zZXRDb250ZXh0KFwiZWFjaFwiLCB1bmRlZmluZWQpO1xuXHRcdH07XG5cdH07XG5cdHN1aXRlRm4uZm9yID0gZnVuY3Rpb24oY2FzZXMsIC4uLmFyZ3MpIHtcblx0XHRpZiAoQXJyYXkuaXNBcnJheShjYXNlcykgJiYgYXJncy5sZW5ndGgpIHtcblx0XHRcdGNhc2VzID0gZm9ybWF0VGVtcGxhdGVTdHJpbmcoY2FzZXMsIGFyZ3MpO1xuXHRcdH1cblx0XHRyZXR1cm4gKG5hbWUsIG9wdGlvbnNPckZuLCBmbk9yT3B0aW9ucykgPT4ge1xuXHRcdFx0Y29uc3QgbmFtZV8gPSBmb3JtYXROYW1lKG5hbWUpO1xuXHRcdFx0Y29uc3QgeyBvcHRpb25zLCBoYW5kbGVyIH0gPSBwYXJzZUFyZ3VtZW50cyhvcHRpb25zT3JGbiwgZm5Pck9wdGlvbnMpO1xuXHRcdFx0Y2FzZXMuZm9yRWFjaCgoaXRlbSwgaWR4KSA9PiB7XG5cdFx0XHRcdHN1aXRlKGZvcm1hdFRpdGxlKG5hbWVfLCB0b0FycmF5KGl0ZW0pLCBpZHgpLCBvcHRpb25zLCBoYW5kbGVyID8gKCkgPT4gaGFuZGxlcihpdGVtKSA6IHVuZGVmaW5lZCk7XG5cdFx0XHR9KTtcblx0XHR9O1xuXHR9O1xuXHRzdWl0ZUZuLnNraXBJZiA9IChjb25kaXRpb24pID0+IGNvbmRpdGlvbiA/IHN1aXRlLnNraXAgOiBzdWl0ZTtcblx0c3VpdGVGbi5ydW5JZiA9IChjb25kaXRpb24pID0+IGNvbmRpdGlvbiA/IHN1aXRlIDogc3VpdGUuc2tpcDtcblx0cmV0dXJuIGNyZWF0ZUNoYWluYWJsZShbXG5cdFx0XCJjb25jdXJyZW50XCIsXG5cdFx0XCJzZXF1ZW50aWFsXCIsXG5cdFx0XCJzaHVmZmxlXCIsXG5cdFx0XCJza2lwXCIsXG5cdFx0XCJvbmx5XCIsXG5cdFx0XCJ0b2RvXCJcblx0XSwgc3VpdGVGbik7XG59XG5mdW5jdGlvbiBjcmVhdGVUYXNrQ29sbGVjdG9yKGZuKSB7XG5cdGNvbnN0IHRhc2tGbiA9IGZuO1xuXHR0YXNrRm4uZWFjaCA9IGZ1bmN0aW9uKGNhc2VzLCAuLi5hcmdzKSB7XG5cdFx0Y29uc3QgY29udGV4dCA9IGdldENoYWluYWJsZUNvbnRleHQodGhpcyk7XG5cdFx0Y29uc3QgdGVzdCA9IGNvbnRleHQud2l0aENvbnRleHQoKTtcblx0XHRjb250ZXh0LnNldENvbnRleHQoXCJlYWNoXCIsIHRydWUpO1xuXHRcdGlmIChBcnJheS5pc0FycmF5KGNhc2VzKSAmJiBhcmdzLmxlbmd0aCkge1xuXHRcdFx0Y2FzZXMgPSBmb3JtYXRUZW1wbGF0ZVN0cmluZyhjYXNlcywgYXJncyk7XG5cdFx0fVxuXHRcdHJldHVybiAobmFtZSwgb3B0aW9uc09yRm4sIGZuT3JPcHRpb25zKSA9PiB7XG5cdFx0XHRjb25zdCBfbmFtZSA9IGZvcm1hdE5hbWUobmFtZSk7XG5cdFx0XHRjb25zdCBhcnJheU9ubHlDYXNlcyA9IGNhc2VzLmV2ZXJ5KEFycmF5LmlzQXJyYXkpO1xuXHRcdFx0Y29uc3QgeyBvcHRpb25zLCBoYW5kbGVyIH0gPSBwYXJzZUFyZ3VtZW50cyhvcHRpb25zT3JGbiwgZm5Pck9wdGlvbnMpO1xuXHRcdFx0Y29uc3QgZm5GaXJzdCA9IHR5cGVvZiBvcHRpb25zT3JGbiA9PT0gXCJmdW5jdGlvblwiO1xuXHRcdFx0Y2FzZXMuZm9yRWFjaCgoaSwgaWR4KSA9PiB7XG5cdFx0XHRcdGNvbnN0IGl0ZW1zID0gQXJyYXkuaXNBcnJheShpKSA/IGkgOiBbaV07XG5cdFx0XHRcdGlmIChmbkZpcnN0KSB7XG5cdFx0XHRcdFx0aWYgKGFycmF5T25seUNhc2VzKSB7XG5cdFx0XHRcdFx0XHR0ZXN0KGZvcm1hdFRpdGxlKF9uYW1lLCBpdGVtcywgaWR4KSwgaGFuZGxlciA/ICgpID0+IGhhbmRsZXIoLi4uaXRlbXMpIDogdW5kZWZpbmVkLCBvcHRpb25zLnRpbWVvdXQpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR0ZXN0KGZvcm1hdFRpdGxlKF9uYW1lLCBpdGVtcywgaWR4KSwgaGFuZGxlciA/ICgpID0+IGhhbmRsZXIoaSkgOiB1bmRlZmluZWQsIG9wdGlvbnMudGltZW91dCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmIChhcnJheU9ubHlDYXNlcykge1xuXHRcdFx0XHRcdFx0dGVzdChmb3JtYXRUaXRsZShfbmFtZSwgaXRlbXMsIGlkeCksIG9wdGlvbnMsIGhhbmRsZXIgPyAoKSA9PiBoYW5kbGVyKC4uLml0ZW1zKSA6IHVuZGVmaW5lZCk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRlc3QoZm9ybWF0VGl0bGUoX25hbWUsIGl0ZW1zLCBpZHgpLCBvcHRpb25zLCBoYW5kbGVyID8gKCkgPT4gaGFuZGxlcihpKSA6IHVuZGVmaW5lZCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHRcdGNvbnRleHQuc2V0Q29udGV4dChcImVhY2hcIiwgdW5kZWZpbmVkKTtcblx0XHR9O1xuXHR9O1xuXHR0YXNrRm4uZm9yID0gZnVuY3Rpb24oY2FzZXMsIC4uLmFyZ3MpIHtcblx0XHRjb25zdCBjb250ZXh0ID0gZ2V0Q2hhaW5hYmxlQ29udGV4dCh0aGlzKTtcblx0XHRjb25zdCB0ZXN0ID0gY29udGV4dC53aXRoQ29udGV4dCgpO1xuXHRcdGlmIChBcnJheS5pc0FycmF5KGNhc2VzKSAmJiBhcmdzLmxlbmd0aCkge1xuXHRcdFx0Y2FzZXMgPSBmb3JtYXRUZW1wbGF0ZVN0cmluZyhjYXNlcywgYXJncyk7XG5cdFx0fVxuXHRcdHJldHVybiAobmFtZSwgb3B0aW9uc09yRm4sIGZuT3JPcHRpb25zKSA9PiB7XG5cdFx0XHRjb25zdCBfbmFtZSA9IGZvcm1hdE5hbWUobmFtZSk7XG5cdFx0XHRjb25zdCB7IG9wdGlvbnMsIGhhbmRsZXIgfSA9IHBhcnNlQXJndW1lbnRzKG9wdGlvbnNPckZuLCBmbk9yT3B0aW9ucyk7XG5cdFx0XHRjYXNlcy5mb3JFYWNoKChpdGVtLCBpZHgpID0+IHtcblx0XHRcdFx0Ly8gbW9ua2V5LXBhdGNoIGhhbmRsZXIgdG8gYWxsb3cgcGFyc2luZyBmaXh0dXJlXG5cdFx0XHRcdGNvbnN0IGhhbmRsZXJXcmFwcGVyID0gaGFuZGxlciA/IChjdHgpID0+IGhhbmRsZXIoaXRlbSwgY3R4KSA6IHVuZGVmaW5lZDtcblx0XHRcdFx0aWYgKGhhbmRsZXJXcmFwcGVyKSB7XG5cdFx0XHRcdFx0Y29uZmlndXJlUHJvcHMoaGFuZGxlcldyYXBwZXIsIHtcblx0XHRcdFx0XHRcdGluZGV4OiAxLFxuXHRcdFx0XHRcdFx0b3JpZ2luYWw6IGhhbmRsZXJcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0ZXN0KGZvcm1hdFRpdGxlKF9uYW1lLCB0b0FycmF5KGl0ZW0pLCBpZHgpLCBvcHRpb25zLCBoYW5kbGVyV3JhcHBlcik7XG5cdFx0XHR9KTtcblx0XHR9O1xuXHR9O1xuXHR0YXNrRm4uc2tpcElmID0gZnVuY3Rpb24oY29uZGl0aW9uKSB7XG5cdFx0cmV0dXJuIGNvbmRpdGlvbiA/IHRoaXMuc2tpcCA6IHRoaXM7XG5cdH07XG5cdHRhc2tGbi5ydW5JZiA9IGZ1bmN0aW9uKGNvbmRpdGlvbikge1xuXHRcdHJldHVybiBjb25kaXRpb24gPyB0aGlzIDogdGhpcy5za2lwO1xuXHR9O1xuXHQvKipcblx0KiBQYXJzZSBidWlsZGVyIHBhdHRlcm4gYXJndW1lbnRzIGludG8gYSBmaXh0dXJlcyBvYmplY3QuXG5cdCogSGFuZGxlcyBib3RoIGJ1aWxkZXIgcGF0dGVybiAobmFtZSwgb3B0aW9ucz8sIHZhbHVlKSBhbmQgb2JqZWN0IHN5bnRheC5cblx0Ki9cblx0ZnVuY3Rpb24gcGFyc2VCdWlsZGVyRml4dHVyZXMoZml4dHVyZXNPck5hbWUsIG9wdGlvbnNPckZuLCBtYXliZUZuKSB7XG5cdFx0Ly8gT2JqZWN0IHN5bnRheDoganVzdCByZXR1cm4gYXMtaXNcblx0XHRpZiAodHlwZW9mIGZpeHR1cmVzT3JOYW1lICE9PSBcInN0cmluZ1wiKSB7XG5cdFx0XHRyZXR1cm4gZml4dHVyZXNPck5hbWU7XG5cdFx0fVxuXHRcdGNvbnN0IGZpeHR1cmVOYW1lID0gZml4dHVyZXNPck5hbWU7XG5cdFx0bGV0IGZpeHR1cmVPcHRpb25zO1xuXHRcdGxldCBmaXh0dXJlVmFsdWU7XG5cdFx0aWYgKG1heWJlRm4gIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0Ly8gKG5hbWUsIG9wdGlvbnMsIHZhbHVlKSBvciAobmFtZSwgb3B0aW9ucywgZm4pXG5cdFx0XHRmaXh0dXJlT3B0aW9ucyA9IG9wdGlvbnNPckZuO1xuXHRcdFx0Zml4dHVyZVZhbHVlID0gbWF5YmVGbjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gKG5hbWUsIHZhbHVlKSBvciAobmFtZSwgZm4pXG5cdFx0XHQvLyBDaGVjayBpZiBvcHRpb25zT3JGbiBsb29rcyBsaWtlIGZpeHR1cmUgb3B0aW9ucyAoaGFzIHNjb3BlIG9yIGF1dG8pXG5cdFx0XHRpZiAob3B0aW9uc09yRm4gIT09IG51bGwgJiYgdHlwZW9mIG9wdGlvbnNPckZuID09PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KG9wdGlvbnNPckZuKSAmJiBUZXN0Rml4dHVyZXMuaXNGaXh0dXJlT3B0aW9ucyhvcHRpb25zT3JGbikpIHtcblx0XHRcdFx0Ly8gKG5hbWUsIG9wdGlvbnMpIHdpdGggbm8gdmFsdWUgLSB0cmVhdCBhcyBlbXB0eSBvYmplY3QgZml4dHVyZVxuXHRcdFx0XHRmaXh0dXJlT3B0aW9ucyA9IG9wdGlvbnNPckZuO1xuXHRcdFx0XHRmaXh0dXJlVmFsdWUgPSB7fTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIChuYW1lLCB2YWx1ZSkgb3IgKG5hbWUsIGZuKVxuXHRcdFx0XHRmaXh0dXJlT3B0aW9ucyA9IHVuZGVmaW5lZDtcblx0XHRcdFx0Zml4dHVyZVZhbHVlID0gb3B0aW9uc09yRm47XG5cdFx0XHR9XG5cdFx0fVxuXHRcdC8vIEZ1bmN0aW9uIHZhbHVlOiB3cmFwIHdpdGggb25DbGVhbnVwIHBhdHRlcm5cblx0XHRpZiAodHlwZW9mIGZpeHR1cmVWYWx1ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0XHRjb25zdCBidWlsZGVyRm4gPSBmaXh0dXJlVmFsdWU7XG5cdFx0XHQvLyBXcmFwIGJ1aWxkZXIgcGF0dGVybiBmdW5jdGlvbiAocmV0dXJucyB2YWx1ZSkgdG8gdXNlKCkgcGF0dGVyblxuXHRcdFx0Y29uc3QgZml4dHVyZSA9IGFzeW5jIChjdHgsIHVzZSkgPT4ge1xuXHRcdFx0XHRsZXQgY2xlYW51cDtcblx0XHRcdFx0Y29uc3Qgb25DbGVhbnVwID0gKGZuKSA9PiB7XG5cdFx0XHRcdFx0aWYgKGNsZWFudXAgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKGBvbkNsZWFudXAgY2FuIG9ubHkgYmUgY2FsbGVkIG9uY2UgcGVyIGZpeHR1cmUuIGAgKyBgRGVmaW5lIHNlcGFyYXRlIGZpeHR1cmVzIGlmIHlvdSBuZWVkIG11bHRpcGxlIGNsZWFudXAgZnVuY3Rpb25zLmApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRjbGVhbnVwID0gZm47XG5cdFx0XHRcdH07XG5cdFx0XHRcdGNvbnN0IHZhbHVlID0gYXdhaXQgYnVpbGRlckZuKGN0eCwgeyBvbkNsZWFudXAgfSk7XG5cdFx0XHRcdGF3YWl0IHVzZSh2YWx1ZSk7XG5cdFx0XHRcdGlmIChjbGVhbnVwKSB7XG5cdFx0XHRcdFx0YXdhaXQgY2xlYW51cCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdFx0Y29uZmlndXJlUHJvcHMoZml4dHVyZSwgeyBvcmlnaW5hbDogYnVpbGRlckZuIH0pO1xuXHRcdFx0aWYgKGZpeHR1cmVPcHRpb25zKSB7XG5cdFx0XHRcdHJldHVybiB7IFtmaXh0dXJlTmFtZV06IFtmaXh0dXJlLCBmaXh0dXJlT3B0aW9uc10gfTtcblx0XHRcdH1cblx0XHRcdHJldHVybiB7IFtmaXh0dXJlTmFtZV06IGZpeHR1cmUgfTtcblx0XHR9XG5cdFx0Ly8gTm9uLWZ1bmN0aW9uIHZhbHVlOiB1c2UgZGlyZWN0bHlcblx0XHRpZiAoZml4dHVyZU9wdGlvbnMpIHtcblx0XHRcdHJldHVybiB7IFtmaXh0dXJlTmFtZV06IFtmaXh0dXJlVmFsdWUsIGZpeHR1cmVPcHRpb25zXSB9O1xuXHRcdH1cblx0XHRyZXR1cm4geyBbZml4dHVyZU5hbWVdOiBmaXh0dXJlVmFsdWUgfTtcblx0fVxuXHR0YXNrRm4ub3ZlcnJpZGUgPSBmdW5jdGlvbihmaXh0dXJlc09yTmFtZSwgb3B0aW9uc09yRm4sIG1heWJlRm4pIHtcblx0XHRjb25zdCB1c2VyRml4dHVyZXMgPSBwYXJzZUJ1aWxkZXJGaXh0dXJlcyhmaXh0dXJlc09yTmFtZSwgb3B0aW9uc09yRm4sIG1heWJlRm4pO1xuXHRcdGdldENoYWluYWJsZUNvbnRleHQodGhpcykuZ2V0Rml4dHVyZXMoKS5vdmVycmlkZShydW5uZXIsIHVzZXJGaXh0dXJlcyk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH07XG5cdHRhc2tGbi5zY29wZWQgPSBmdW5jdGlvbihmaXh0dXJlcykge1xuXHRcdGNvbnNvbGUud2FybihgdGVzdC5zY29wZWQoKSBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gZnV0dXJlIHZlcnNpb25zLiBQbGVhc2UgdXNlIHRlc3Qub3ZlcnJpZGUoKSBpbnN0ZWFkLmApO1xuXHRcdHJldHVybiB0aGlzLm92ZXJyaWRlKGZpeHR1cmVzKTtcblx0fTtcblx0dGFza0ZuLmV4dGVuZCA9IGZ1bmN0aW9uKGZpeHR1cmVzT3JOYW1lLCBvcHRpb25zT3JGbiwgbWF5YmVGbikge1xuXHRcdGNvbnN0IHVzZXJGaXh0dXJlcyA9IHBhcnNlQnVpbGRlckZpeHR1cmVzKGZpeHR1cmVzT3JOYW1lLCBvcHRpb25zT3JGbiwgbWF5YmVGbik7XG5cdFx0Y29uc3QgZml4dHVyZXMgPSBnZXRDaGFpbmFibGVDb250ZXh0KHRoaXMpLmdldEZpeHR1cmVzKCkuZXh0ZW5kKHJ1bm5lciwgdXNlckZpeHR1cmVzKTtcblx0XHRjb25zdCBfdGVzdCA9IGNyZWF0ZVRlc3QoZnVuY3Rpb24obmFtZSwgb3B0aW9uc09yRm4sIG9wdGlvbnNPclRlc3QpIHtcblx0XHRcdGZuLmNhbGwodGhpcywgZm9ybWF0TmFtZShuYW1lKSwgb3B0aW9uc09yRm4sIG9wdGlvbnNPclRlc3QpO1xuXHRcdH0pO1xuXHRcdGdldENoYWluYWJsZUNvbnRleHQoX3Rlc3QpLm1lcmdlQ29udGV4dCh7IGZpeHR1cmVzIH0pO1xuXHRcdHJldHVybiBfdGVzdDtcblx0fTtcblx0dGFza0ZuLmRlc2NyaWJlID0gc3VpdGU7XG5cdHRhc2tGbi5zdWl0ZSA9IHN1aXRlO1xuXHR0YXNrRm4uYmVmb3JlRWFjaCA9IGJlZm9yZUVhY2g7XG5cdHRhc2tGbi5hZnRlckVhY2ggPSBhZnRlckVhY2g7XG5cdHRhc2tGbi5iZWZvcmVBbGwgPSBiZWZvcmVBbGw7XG5cdHRhc2tGbi5hZnRlckFsbCA9IGFmdGVyQWxsO1xuXHR0YXNrRm4uYXJvdW5kRWFjaCA9IGFyb3VuZEVhY2g7XG5cdHRhc2tGbi5hcm91bmRBbGwgPSBhcm91bmRBbGw7XG5cdGNvbnN0IF90ZXN0ID0gY3JlYXRlQ2hhaW5hYmxlKFtcblx0XHRcImNvbmN1cnJlbnRcIixcblx0XHRcInNlcXVlbnRpYWxcIixcblx0XHRcInNraXBcIixcblx0XHRcIm9ubHlcIixcblx0XHRcInRvZG9cIixcblx0XHRcImZhaWxzXCJcblx0XSwgdGFza0ZuLCB7IGZpeHR1cmVzOiBuZXcgVGVzdEZpeHR1cmVzKCkgfSk7XG5cdHJldHVybiBfdGVzdDtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVRlc3QoZm4pIHtcblx0cmV0dXJuIGNyZWF0ZVRhc2tDb2xsZWN0b3IoZm4pO1xufVxuZnVuY3Rpb24gZm9ybWF0TmFtZShuYW1lKSB7XG5cdHJldHVybiB0eXBlb2YgbmFtZSA9PT0gXCJzdHJpbmdcIiA/IG5hbWUgOiB0eXBlb2YgbmFtZSA9PT0gXCJmdW5jdGlvblwiID8gbmFtZS5uYW1lIHx8IFwiPGFub255bW91cz5cIiA6IFN0cmluZyhuYW1lKTtcbn1cbmZ1bmN0aW9uIGZvcm1hdFRpdGxlKHRlbXBsYXRlLCBpdGVtcywgaWR4KSB7XG5cdGlmICh0ZW1wbGF0ZS5pbmNsdWRlcyhcIiUjXCIpIHx8IHRlbXBsYXRlLmluY2x1ZGVzKFwiJSRcIikpIHtcblx0XHQvLyAnJSMnIG1hdGNoIGluZGV4IG9mIHRoZSB0ZXN0IGNhc2Vcblx0XHR0ZW1wbGF0ZSA9IHRlbXBsYXRlLnJlcGxhY2UoLyUlL2csIFwiX192aXRlc3RfZXNjYXBlZF8lX19cIikucmVwbGFjZSgvJSMvZywgYCR7aWR4fWApLnJlcGxhY2UoLyVcXCQvZywgYCR7aWR4ICsgMX1gKS5yZXBsYWNlKC9fX3ZpdGVzdF9lc2NhcGVkXyVfXy9nLCBcIiUlXCIpO1xuXHR9XG5cdGNvbnN0IGNvdW50ID0gdGVtcGxhdGUuc3BsaXQoXCIlXCIpLmxlbmd0aCAtIDE7XG5cdGlmICh0ZW1wbGF0ZS5pbmNsdWRlcyhcIiVmXCIpKSB7XG5cdFx0Y29uc3QgcGxhY2Vob2xkZXJzID0gdGVtcGxhdGUubWF0Y2goLyVmL2cpIHx8IFtdO1xuXHRcdHBsYWNlaG9sZGVycy5mb3JFYWNoKChfLCBpKSA9PiB7XG5cdFx0XHRpZiAoaXNOZWdhdGl2ZU5hTihpdGVtc1tpXSkgfHwgT2JqZWN0LmlzKGl0ZW1zW2ldLCAtMCkpIHtcblx0XHRcdFx0Ly8gUmVwbGFjZSB0aGUgaS10aCBvY2N1cnJlbmNlIG9mICclZicgd2l0aCAnLSVmJ1xuXHRcdFx0XHRsZXQgb2NjdXJyZW5jZSA9IDA7XG5cdFx0XHRcdHRlbXBsYXRlID0gdGVtcGxhdGUucmVwbGFjZSgvJWYvZywgKG1hdGNoKSA9PiB7XG5cdFx0XHRcdFx0b2NjdXJyZW5jZSsrO1xuXHRcdFx0XHRcdHJldHVybiBvY2N1cnJlbmNlID09PSBpICsgMSA/IFwiLSVmXCIgOiBtYXRjaDtcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblx0Y29uc3QgaXNPYmplY3RJdGVtID0gaXNPYmplY3QoaXRlbXNbMF0pO1xuXHRmdW5jdGlvbiBmb3JtYXRBdHRyaWJ1dGUocykge1xuXHRcdHJldHVybiBzLnJlcGxhY2UoL1xcJChbJFxcdy5dKykvZywgKF8sIGtleSkgPT4ge1xuXHRcdFx0Y29uc3QgaXNBcnJheUtleSA9IC9eXFxkKyQvLnRlc3Qoa2V5KTtcblx0XHRcdGlmICghaXNPYmplY3RJdGVtICYmICFpc0FycmF5S2V5KSB7XG5cdFx0XHRcdHJldHVybiBgJCR7a2V5fWA7XG5cdFx0XHR9XG5cdFx0XHRjb25zdCBhcnJheUVsZW1lbnQgPSBpc0FycmF5S2V5ID8gb2JqZWN0QXR0cihpdGVtcywga2V5KSA6IHVuZGVmaW5lZDtcblx0XHRcdGNvbnN0IHZhbHVlID0gaXNPYmplY3RJdGVtID8gb2JqZWN0QXR0cihpdGVtc1swXSwga2V5LCBhcnJheUVsZW1lbnQpIDogYXJyYXlFbGVtZW50O1xuXHRcdFx0cmV0dXJuIG9iakRpc3BsYXkodmFsdWUsIHsgdHJ1bmNhdGU6IHJ1bm5lcj8uY29uZmlnPy5jaGFpQ29uZmlnPy50cnVuY2F0ZVRocmVzaG9sZCB9KTtcblx0XHR9KTtcblx0fVxuXHRsZXQgb3V0cHV0ID0gXCJcIjtcblx0bGV0IGkgPSAwO1xuXHRoYW5kbGVSZWdleE1hdGNoKFxuXHRcdHRlbXBsYXRlLFxuXHRcdGZvcm1hdFJlZ0V4cCxcblx0XHQvLyBmb3JtYXQgXCIlXCJcblx0XHQobWF0Y2gpID0+IHtcblx0XHRcdGlmIChpIDwgY291bnQpIHtcblx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdChtYXRjaFswXSwgaXRlbXNbaSsrXSk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRvdXRwdXQgKz0gbWF0Y2hbMF07XG5cdFx0XHR9XG5cdFx0fSxcblx0XHQvLyBmb3JtYXQgXCIkXCJcblx0XHQobm9uTWF0Y2gpID0+IHtcblx0XHRcdG91dHB1dCArPSBmb3JtYXRBdHRyaWJ1dGUobm9uTWF0Y2gpO1xuXHRcdH1cblx0KTtcblx0cmV0dXJuIG91dHB1dDtcbn1cbi8vIGJhc2VkIG9uIGh0dHBzOi8vZ2l0aHViLmNvbS91bm9jc3MvdW5vY3NzL2Jsb2IvMmU3NGIzMTYyNWJiZTNiOWM4MzUxNTcwNzQ5YWEyZDNmNzk5ZDkxOS9wYWNrYWdlcy9hdXRvY29tcGxldGUvc3JjL3BhcnNlLnRzI0wxMVxuZnVuY3Rpb24gaGFuZGxlUmVnZXhNYXRjaChpbnB1dCwgcmVnZXgsIG9uTWF0Y2gsIG9uTm9uTWF0Y2gpIHtcblx0bGV0IGxhc3RJbmRleCA9IDA7XG5cdGZvciAoY29uc3QgbSBvZiBpbnB1dC5tYXRjaEFsbChyZWdleCkpIHtcblx0XHRpZiAobGFzdEluZGV4IDwgbS5pbmRleCkge1xuXHRcdFx0b25Ob25NYXRjaChpbnB1dC5zbGljZShsYXN0SW5kZXgsIG0uaW5kZXgpKTtcblx0XHR9XG5cdFx0b25NYXRjaChtKTtcblx0XHRsYXN0SW5kZXggPSBtLmluZGV4ICsgbVswXS5sZW5ndGg7XG5cdH1cblx0aWYgKGxhc3RJbmRleCA8IGlucHV0Lmxlbmd0aCkge1xuXHRcdG9uTm9uTWF0Y2goaW5wdXQuc2xpY2UobGFzdEluZGV4KSk7XG5cdH1cbn1cbmZ1bmN0aW9uIGZvcm1hdFRlbXBsYXRlU3RyaW5nKGNhc2VzLCBhcmdzKSB7XG5cdGNvbnN0IGhlYWRlciA9IGNhc2VzLmpvaW4oXCJcIikudHJpbSgpLnJlcGxhY2UoLyAvZywgXCJcIikuc3BsaXQoXCJcXG5cIikubWFwKChpKSA9PiBpLnNwbGl0KFwifFwiKSlbMF07XG5cdGNvbnN0IHJlcyA9IFtdO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IE1hdGguZmxvb3IoYXJncy5sZW5ndGggLyBoZWFkZXIubGVuZ3RoKTsgaSsrKSB7XG5cdFx0Y29uc3Qgb25lQ2FzZSA9IHt9O1xuXHRcdGZvciAobGV0IGogPSAwOyBqIDwgaGVhZGVyLmxlbmd0aDsgaisrKSB7XG5cdFx0XHRvbmVDYXNlW2hlYWRlcltqXV0gPSBhcmdzW2kgKiBoZWFkZXIubGVuZ3RoICsgal07XG5cdFx0fVxuXHRcdHJlcy5wdXNoKG9uZUNhc2UpO1xuXHR9XG5cdHJldHVybiByZXM7XG59XG5cbmNvbnN0IG5vdyQyID0gZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZSA/IGdsb2JhbFRoaXMucGVyZm9ybWFuY2Uubm93LmJpbmQoZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZSkgOiBEYXRlLm5vdztcbmNvbnN0IGNvbGxlY3RvckNvbnRleHQgPSB7XG5cdHRhc2tzOiBbXSxcblx0Y3VycmVudFN1aXRlOiBudWxsXG59O1xuZnVuY3Rpb24gY29sbGVjdFRhc2sodGFzaykge1xuXHRjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZT8udGFza3MucHVzaCh0YXNrKTtcbn1cbmFzeW5jIGZ1bmN0aW9uIHJ1bldpdGhTdWl0ZShzdWl0ZSwgZm4pIHtcblx0Y29uc3QgcHJldiA9IGNvbGxlY3RvckNvbnRleHQuY3VycmVudFN1aXRlO1xuXHRjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZSA9IHN1aXRlO1xuXHRhd2FpdCBmbigpO1xuXHRjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZSA9IHByZXY7XG59XG5mdW5jdGlvbiB3aXRoVGltZW91dChmbiwgdGltZW91dCwgaXNIb29rID0gZmFsc2UsIHN0YWNrVHJhY2VFcnJvciwgb25UaW1lb3V0KSB7XG5cdGlmICh0aW1lb3V0IDw9IDAgfHwgdGltZW91dCA9PT0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZKSB7XG5cdFx0cmV0dXJuIGZuO1xuXHR9XG5cdGNvbnN0IHsgc2V0VGltZW91dCwgY2xlYXJUaW1lb3V0IH0gPSBnZXRTYWZlVGltZXJzKCk7XG5cdC8vIHRoaXMgZnVuY3Rpb24gbmFtZSBpcyB1c2VkIHRvIGZpbHRlciBlcnJvciBpbiB0ZXN0L2NsaS90ZXN0L2ZhaWxzLnRlc3QudHNcblx0cmV0dXJuIChmdW5jdGlvbiBydW5XaXRoVGltZW91dCguLi5hcmdzKSB7XG5cdFx0Y29uc3Qgc3RhcnRUaW1lID0gbm93JDIoKTtcblx0XHRjb25zdCBydW5uZXIgPSBnZXRSdW5uZXIoKTtcblx0XHRydW5uZXIuX2N1cnJlbnRUYXNrU3RhcnRUaW1lID0gc3RhcnRUaW1lO1xuXHRcdHJ1bm5lci5fY3VycmVudFRhc2tUaW1lb3V0ID0gdGltZW91dDtcblx0XHRyZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmVfLCByZWplY3RfKSA9PiB7XG5cdFx0XHRjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0XHRjbGVhclRpbWVvdXQodGltZXIpO1xuXHRcdFx0XHRyZWplY3RUaW1lb3V0RXJyb3IoKTtcblx0XHRcdH0sIHRpbWVvdXQpO1xuXHRcdFx0Ly8gYHVucmVmYCBtaWdodCBub3QgZXhpc3QgaW4gYnJvd3NlclxuXHRcdFx0dGltZXIudW5yZWY/LigpO1xuXHRcdFx0ZnVuY3Rpb24gcmVqZWN0VGltZW91dEVycm9yKCkge1xuXHRcdFx0XHRjb25zdCBlcnJvciA9IG1ha2VUaW1lb3V0RXJyb3IoaXNIb29rLCB0aW1lb3V0LCBzdGFja1RyYWNlRXJyb3IpO1xuXHRcdFx0XHRvblRpbWVvdXQ/LihhcmdzLCBlcnJvcik7XG5cdFx0XHRcdHJlamVjdF8oZXJyb3IpO1xuXHRcdFx0fVxuXHRcdFx0ZnVuY3Rpb24gcmVzb2x2ZShyZXN1bHQpIHtcblx0XHRcdFx0cnVubmVyLl9jdXJyZW50VGFza1N0YXJ0VGltZSA9IHVuZGVmaW5lZDtcblx0XHRcdFx0cnVubmVyLl9jdXJyZW50VGFza1RpbWVvdXQgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdGNsZWFyVGltZW91dCh0aW1lcik7XG5cdFx0XHRcdC8vIGlmIHRlc3QvaG9vayB0b29rIHRvbyBsb25nIGluIG1pY3JvdGFzaywgc2V0VGltZW91dCB3b24ndCBiZSB0cmlnZ2VyZWQsXG5cdFx0XHRcdC8vIGJ1dCB3ZSBzdGlsbCBuZWVkIHRvIGZhaWwgdGhlIHRlc3QsIHNlZVxuXHRcdFx0XHQvLyBodHRwczovL2dpdGh1Yi5jb20vdml0ZXN0LWRldi92aXRlc3QvaXNzdWVzLzI5MjBcblx0XHRcdFx0aWYgKG5vdyQyKCkgLSBzdGFydFRpbWUgPj0gdGltZW91dCkge1xuXHRcdFx0XHRcdHJlamVjdFRpbWVvdXRFcnJvcigpO1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXNvbHZlXyhyZXN1bHQpO1xuXHRcdFx0fVxuXHRcdFx0ZnVuY3Rpb24gcmVqZWN0KGVycm9yKSB7XG5cdFx0XHRcdHJ1bm5lci5fY3VycmVudFRhc2tTdGFydFRpbWUgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdHJ1bm5lci5fY3VycmVudFRhc2tUaW1lb3V0ID0gdW5kZWZpbmVkO1xuXHRcdFx0XHRjbGVhclRpbWVvdXQodGltZXIpO1xuXHRcdFx0XHRyZWplY3RfKGVycm9yKTtcblx0XHRcdH1cblx0XHRcdC8vIHN5bmMgdGVzdC9ob29rIHdpbGwgYmUgY2F1Z2h0IGJ5IHRyeS9jYXRjaFxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0Y29uc3QgcmVzdWx0ID0gZm4oLi4uYXJncyk7XG5cdFx0XHRcdC8vIHRoZSByZXN1bHQgaXMgYSB0aGVuYWJsZSwgd2UgZG9uJ3Qgd3JhcCB0aGlzIGluIFByb21pc2UucmVzb2x2ZVxuXHRcdFx0XHQvLyB0byBhdm9pZCBjcmVhdGluZyBuZXcgcHJvbWlzZXNcblx0XHRcdFx0aWYgKHR5cGVvZiByZXN1bHQgPT09IFwib2JqZWN0XCIgJiYgcmVzdWx0ICE9IG51bGwgJiYgdHlwZW9mIHJlc3VsdC50aGVuID09PSBcImZ1bmN0aW9uXCIpIHtcblx0XHRcdFx0XHRyZXN1bHQudGhlbihyZXNvbHZlLCByZWplY3QpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHJlc29sdmUocmVzdWx0KTtcblx0XHRcdFx0fVxuXHRcdFx0fSBcblx0XHRcdC8vIHVzZXIgc3luYyB0ZXN0L2hvb2sgdGhyb3dzIGFuIGVycm9yXG5jYXRjaCAoZXJyb3IpIHtcblx0XHRcdFx0cmVqZWN0KGVycm9yKTtcblx0XHRcdH1cblx0XHR9KTtcblx0fSk7XG59XG5mdW5jdGlvbiB3aXRoQ2FuY2VsKGZuLCBzaWduYWwpIHtcblx0cmV0dXJuIChmdW5jdGlvbiBydW5XaXRoQ2FuY2VsKC4uLmFyZ3MpIHtcblx0XHRyZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuXHRcdFx0c2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCAoKSA9PiByZWplY3Qoc2lnbmFsLnJlYXNvbikpO1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0Y29uc3QgcmVzdWx0ID0gZm4oLi4uYXJncyk7XG5cdFx0XHRcdGlmICh0eXBlb2YgcmVzdWx0ID09PSBcIm9iamVjdFwiICYmIHJlc3VsdCAhPSBudWxsICYmIHR5cGVvZiByZXN1bHQudGhlbiA9PT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0XHRcdFx0cmVzdWx0LnRoZW4ocmVzb2x2ZSwgcmVqZWN0KTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRyZXNvbHZlKHJlc3VsdCk7XG5cdFx0XHRcdH1cblx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdHJlamVjdChlcnJvcik7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH0pO1xufVxuY29uc3QgYWJvcnRDb250cm9sbGVycyA9IG5ldyBXZWFrTWFwKCk7XG5mdW5jdGlvbiBhYm9ydElmVGltZW91dChbY29udGV4dF0sIGVycm9yKSB7XG5cdGlmIChjb250ZXh0KSB7XG5cdFx0YWJvcnRDb250ZXh0U2lnbmFsKGNvbnRleHQsIGVycm9yKTtcblx0fVxufVxuZnVuY3Rpb24gYWJvcnRDb250ZXh0U2lnbmFsKGNvbnRleHQsIGVycm9yKSB7XG5cdGNvbnN0IGFib3J0Q29udHJvbGxlciA9IGFib3J0Q29udHJvbGxlcnMuZ2V0KGNvbnRleHQpO1xuXHRhYm9ydENvbnRyb2xsZXI/LmFib3J0KGVycm9yKTtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVRlc3RDb250ZXh0KHRlc3QsIHJ1bm5lcikge1xuXHRjb25zdCBjb250ZXh0ID0gZnVuY3Rpb24oKSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKFwiZG9uZSgpIGNhbGxiYWNrIGlzIGRlcHJlY2F0ZWQsIHVzZSBwcm9taXNlIGluc3RlYWRcIik7XG5cdH07XG5cdGxldCBhYm9ydENvbnRyb2xsZXIgPSBhYm9ydENvbnRyb2xsZXJzLmdldChjb250ZXh0KTtcblx0aWYgKCFhYm9ydENvbnRyb2xsZXIpIHtcblx0XHRhYm9ydENvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG5cdFx0YWJvcnRDb250cm9sbGVycy5zZXQoY29udGV4dCwgYWJvcnRDb250cm9sbGVyKTtcblx0fVxuXHRjb250ZXh0LnNpZ25hbCA9IGFib3J0Q29udHJvbGxlci5zaWduYWw7XG5cdGNvbnRleHQudGFzayA9IHRlc3Q7XG5cdGNvbnRleHQuc2tpcCA9IChjb25kaXRpb24sIG5vdGUpID0+IHtcblx0XHRpZiAoY29uZGl0aW9uID09PSBmYWxzZSkge1xuXHRcdFx0Ly8gZG8gbm90aGluZ1xuXHRcdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0XHR9XG5cdFx0dGVzdC5yZXN1bHQgPz89IHsgc3RhdGU6IFwic2tpcFwiIH07XG5cdFx0dGVzdC5yZXN1bHQucGVuZGluZyA9IHRydWU7XG5cdFx0dGhyb3cgbmV3IFBlbmRpbmdFcnJvcihcInRlc3QgaXMgc2tpcHBlZDsgYWJvcnQgZXhlY3V0aW9uXCIsIHRlc3QsIHR5cGVvZiBjb25kaXRpb24gPT09IFwic3RyaW5nXCIgPyBjb25kaXRpb24gOiBub3RlKTtcblx0fTtcblx0Y29udGV4dC5hbm5vdGF0ZSA9ICgobWVzc2FnZSwgdHlwZSwgYXR0YWNobWVudCkgPT4ge1xuXHRcdGlmICh0ZXN0LnJlc3VsdCAmJiB0ZXN0LnJlc3VsdC5zdGF0ZSAhPT0gXCJydW5cIikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgYW5ub3RhdGUgdGVzdHMgb3V0c2lkZSBvZiB0aGUgdGVzdCBydW4uIFRoZSB0ZXN0IFwiJHt0ZXN0Lm5hbWV9XCIgZmluaXNoZWQgcnVubmluZyB3aXRoIHRoZSBcIiR7dGVzdC5yZXN1bHQuc3RhdGV9XCIgc3RhdGUgYWxyZWFkeS5gKTtcblx0XHR9XG5cdFx0Y29uc3QgYW5ub3RhdGlvbiA9IHtcblx0XHRcdG1lc3NhZ2UsXG5cdFx0XHR0eXBlOiB0eXBlb2YgdHlwZSA9PT0gXCJvYmplY3RcIiB8fCB0eXBlID09PSB1bmRlZmluZWQgPyBcIm5vdGljZVwiIDogdHlwZVxuXHRcdH07XG5cdFx0Y29uc3QgYW5ub3RhdGlvbkF0dGFjaG1lbnQgPSB0eXBlb2YgdHlwZSA9PT0gXCJvYmplY3RcIiA/IHR5cGUgOiBhdHRhY2htZW50O1xuXHRcdGlmIChhbm5vdGF0aW9uQXR0YWNobWVudCkge1xuXHRcdFx0YW5ub3RhdGlvbi5hdHRhY2htZW50ID0gYW5ub3RhdGlvbkF0dGFjaG1lbnQ7XG5cdFx0XHRtYW5hZ2VBcnRpZmFjdEF0dGFjaG1lbnQoYW5ub3RhdGlvbi5hdHRhY2htZW50KTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlY29yZEFzeW5jT3BlcmF0aW9uKHRlc3QsIHJlY29yZEFydGlmYWN0KHRlc3QsIHtcblx0XHRcdHR5cGU6IFwiaW50ZXJuYWw6YW5ub3RhdGlvblwiLFxuXHRcdFx0YW5ub3RhdGlvblxuXHRcdH0pLnRoZW4oYXN5bmMgKHsgYW5ub3RhdGlvbiB9KSA9PiB7XG5cdFx0XHRpZiAoIXJ1bm5lci5vblRlc3RBbm5vdGF0ZSkge1xuXHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoYFRlc3QgcnVubmVyIGRvZXNuJ3Qgc3VwcG9ydCB0ZXN0IGFubm90YXRpb25zLmApO1xuXHRcdFx0fVxuXHRcdFx0YXdhaXQgZmluaXNoU2VuZFRhc2tzVXBkYXRlKHJ1bm5lcik7XG5cdFx0XHRjb25zdCByZXNvbHZlZEFubm90YXRpb24gPSBhd2FpdCBydW5uZXIub25UZXN0QW5ub3RhdGUodGVzdCwgYW5ub3RhdGlvbik7XG5cdFx0XHR0ZXN0LmFubm90YXRpb25zLnB1c2gocmVzb2x2ZWRBbm5vdGF0aW9uKTtcblx0XHRcdHJldHVybiByZXNvbHZlZEFubm90YXRpb247XG5cdFx0fSkpO1xuXHR9KTtcblx0Y29udGV4dC5vblRlc3RGYWlsZWQgPSAoaGFuZGxlciwgdGltZW91dCkgPT4ge1xuXHRcdHRlc3Qub25GYWlsZWQgfHw9IFtdO1xuXHRcdHRlc3Qub25GYWlsZWQucHVzaCh3aXRoVGltZW91dChoYW5kbGVyLCB0aW1lb3V0ID8/IHJ1bm5lci5jb25maWcuaG9va1RpbWVvdXQsIHRydWUsIG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpLCAoXywgZXJyb3IpID0+IGFib3J0Q29udHJvbGxlci5hYm9ydChlcnJvcikpKTtcblx0fTtcblx0Y29udGV4dC5vblRlc3RGaW5pc2hlZCA9IChoYW5kbGVyLCB0aW1lb3V0KSA9PiB7XG5cdFx0dGVzdC5vbkZpbmlzaGVkIHx8PSBbXTtcblx0XHR0ZXN0Lm9uRmluaXNoZWQucHVzaCh3aXRoVGltZW91dChoYW5kbGVyLCB0aW1lb3V0ID8/IHJ1bm5lci5jb25maWcuaG9va1RpbWVvdXQsIHRydWUsIG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpLCAoXywgZXJyb3IpID0+IGFib3J0Q29udHJvbGxlci5hYm9ydChlcnJvcikpKTtcblx0fTtcblx0cmV0dXJuIHJ1bm5lci5leHRlbmRUYXNrQ29udGV4dD8uKGNvbnRleHQpIHx8IGNvbnRleHQ7XG59XG5mdW5jdGlvbiBtYWtlVGltZW91dEVycm9yKGlzSG9vaywgdGltZW91dCwgc3RhY2tUcmFjZUVycm9yKSB7XG5cdGNvbnN0IG1lc3NhZ2UgPSBgJHtpc0hvb2sgPyBcIkhvb2tcIiA6IFwiVGVzdFwifSB0aW1lZCBvdXQgaW4gJHt0aW1lb3V0fW1zLlxcbklmIHRoaXMgaXMgYSBsb25nLXJ1bm5pbmcgJHtpc0hvb2sgPyBcImhvb2tcIiA6IFwidGVzdFwifSwgcGFzcyBhIHRpbWVvdXQgdmFsdWUgYXMgdGhlIGxhc3QgYXJndW1lbnQgb3IgY29uZmlndXJlIGl0IGdsb2JhbGx5IHdpdGggXCIke2lzSG9vayA/IFwiaG9va1RpbWVvdXRcIiA6IFwidGVzdFRpbWVvdXRcIn1cIi5gO1xuXHRjb25zdCBlcnJvciA9IG5ldyBFcnJvcihtZXNzYWdlKTtcblx0aWYgKHN0YWNrVHJhY2VFcnJvcj8uc3RhY2spIHtcblx0XHRlcnJvci5zdGFjayA9IHN0YWNrVHJhY2VFcnJvci5zdGFjay5yZXBsYWNlKGVycm9yLm1lc3NhZ2UsIHN0YWNrVHJhY2VFcnJvci5tZXNzYWdlKTtcblx0fVxuXHRyZXR1cm4gZXJyb3I7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1blNldHVwRmlsZXMoY29uZmlnLCBmaWxlcywgcnVubmVyKSB7XG5cdGlmIChjb25maWcuc2VxdWVuY2Uuc2V0dXBGaWxlcyA9PT0gXCJwYXJhbGxlbFwiKSB7XG5cdFx0YXdhaXQgUHJvbWlzZS5hbGwoZmlsZXMubWFwKGFzeW5jIChmc1BhdGgpID0+IHtcblx0XHRcdGF3YWl0IHJ1bm5lci5pbXBvcnRGaWxlKGZzUGF0aCwgXCJzZXR1cFwiKTtcblx0XHR9KSk7XG5cdH0gZWxzZSB7XG5cdFx0Zm9yIChjb25zdCBmc1BhdGggb2YgZmlsZXMpIHtcblx0XHRcdGF3YWl0IHJ1bm5lci5pbXBvcnRGaWxlKGZzUGF0aCwgXCJzZXR1cFwiKTtcblx0XHR9XG5cdH1cbn1cblxuY29uc3Qgbm93JDEgPSBnbG9iYWxUaGlzLnBlcmZvcm1hbmNlID8gZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZS5ub3cuYmluZChnbG9iYWxUaGlzLnBlcmZvcm1hbmNlKSA6IERhdGUubm93O1xuYXN5bmMgZnVuY3Rpb24gY29sbGVjdFRlc3RzKHNwZWNzLCBydW5uZXIpIHtcblx0Y29uc3QgZmlsZXMgPSBbXTtcblx0Y29uc3QgY29uZmlnID0gcnVubmVyLmNvbmZpZztcblx0Y29uc3QgJCA9IHJ1bm5lci50cmFjZTtcblx0bGV0IGRlZmF1bHRUYWdzRmlsdGVyO1xuXHRmb3IgKGNvbnN0IHNwZWMgb2Ygc3BlY3MpIHtcblx0XHRjb25zdCBmaWxlcGF0aCA9IHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiID8gc3BlYyA6IHNwZWMuZmlsZXBhdGg7XG5cdFx0YXdhaXQgJChcImNvbGxlY3Rfc3BlY1wiLCB7IFwiY29kZS5maWxlLnBhdGhcIjogZmlsZXBhdGggfSwgYXN5bmMgKCkgPT4ge1xuXHRcdFx0cnVubmVyLl9jdXJyZW50U3BlY2lmaWNhdGlvbiA9IHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiID8geyBmaWxlcGF0aDogc3BlYyB9IDogc3BlYztcblx0XHRcdGNvbnN0IHRlc3RMb2NhdGlvbnMgPSB0eXBlb2Ygc3BlYyA9PT0gXCJzdHJpbmdcIiA/IHVuZGVmaW5lZCA6IHNwZWMudGVzdExvY2F0aW9ucztcblx0XHRcdGNvbnN0IHRlc3ROYW1lUGF0dGVybiA9IHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiID8gdW5kZWZpbmVkIDogc3BlYy50ZXN0TmFtZVBhdHRlcm47XG5cdFx0XHRjb25zdCB0ZXN0SWRzID0gdHlwZW9mIHNwZWMgPT09IFwic3RyaW5nXCIgPyB1bmRlZmluZWQgOiBzcGVjLnRlc3RJZHM7XG5cdFx0XHRjb25zdCB0ZXN0VGFnc0ZpbHRlciA9IHR5cGVvZiBzcGVjID09PSBcIm9iamVjdFwiICYmIHNwZWMudGVzdFRhZ3NGaWx0ZXIgPyBjcmVhdGVUYWdzRmlsdGVyKHNwZWMudGVzdFRhZ3NGaWx0ZXIsIGNvbmZpZy50YWdzKSA6IHVuZGVmaW5lZDtcblx0XHRcdGNvbnN0IGZpbGVUYWdzID0gdHlwZW9mIHNwZWMgPT09IFwic3RyaW5nXCIgPyBbXSA6IHNwZWMuZmlsZVRhZ3MgfHwgW107XG5cdFx0XHRjb25zdCBmaWxlID0gY3JlYXRlRmlsZVRhc2soZmlsZXBhdGgsIGNvbmZpZy5yb290LCBjb25maWcubmFtZSwgcnVubmVyLnBvb2wsIHJ1bm5lci52aXRlRW52aXJvbm1lbnQpO1xuXHRcdFx0ZmlsZS50YWdzID0gZmlsZVRhZ3M7XG5cdFx0XHRmaWxlLnNodWZmbGUgPSBjb25maWcuc2VxdWVuY2Uuc2h1ZmZsZTtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdHZhbGlkYXRlVGFncyhydW5uZXIuY29uZmlnLCBmaWxlVGFncyk7XG5cdFx0XHRcdHJ1bm5lci5vbkNvbGxlY3RTdGFydD8uKGZpbGUpO1xuXHRcdFx0XHRjbGVhckNvbGxlY3RvckNvbnRleHQoZmlsZSwgcnVubmVyKTtcblx0XHRcdFx0Y29uc3Qgc2V0dXBGaWxlcyA9IHRvQXJyYXkoY29uZmlnLnNldHVwRmlsZXMpO1xuXHRcdFx0XHRpZiAoc2V0dXBGaWxlcy5sZW5ndGgpIHtcblx0XHRcdFx0XHRjb25zdCBzZXR1cFN0YXJ0ID0gbm93JDEoKTtcblx0XHRcdFx0XHRhd2FpdCBydW5TZXR1cEZpbGVzKGNvbmZpZywgc2V0dXBGaWxlcywgcnVubmVyKTtcblx0XHRcdFx0XHRjb25zdCBzZXR1cEVuZCA9IG5vdyQxKCk7XG5cdFx0XHRcdFx0ZmlsZS5zZXR1cER1cmF0aW9uID0gc2V0dXBFbmQgLSBzZXR1cFN0YXJ0O1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGZpbGUuc2V0dXBEdXJhdGlvbiA9IDA7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y29uc3QgY29sbGVjdFN0YXJ0ID0gbm93JDEoKTtcblx0XHRcdFx0YXdhaXQgcnVubmVyLmltcG9ydEZpbGUoZmlsZXBhdGgsIFwiY29sbGVjdFwiKTtcblx0XHRcdFx0Y29uc3QgZHVyYXRpb25zID0gcnVubmVyLmdldEltcG9ydER1cmF0aW9ucz8uKCk7XG5cdFx0XHRcdGlmIChkdXJhdGlvbnMpIHtcblx0XHRcdFx0XHRmaWxlLmltcG9ydER1cmF0aW9ucyA9IGR1cmF0aW9ucztcblx0XHRcdFx0fVxuXHRcdFx0XHRjb25zdCBkZWZhdWx0VGFza3MgPSBhd2FpdCBnZXREZWZhdWx0U3VpdGUoKS5jb2xsZWN0KGZpbGUpO1xuXHRcdFx0XHRjb25zdCBmaWxlSG9va3MgPSBjcmVhdGVTdWl0ZUhvb2tzKCk7XG5cdFx0XHRcdG1lcmdlSG9va3MoZmlsZUhvb2tzLCBnZXRIb29rcyhkZWZhdWx0VGFza3MpKTtcblx0XHRcdFx0Zm9yIChjb25zdCBjIG9mIFsuLi5kZWZhdWx0VGFza3MudGFza3MsIC4uLmNvbGxlY3RvckNvbnRleHQudGFza3NdKSB7XG5cdFx0XHRcdFx0aWYgKGMudHlwZSA9PT0gXCJ0ZXN0XCIgfHwgYy50eXBlID09PSBcInN1aXRlXCIpIHtcblx0XHRcdFx0XHRcdGZpbGUudGFza3MucHVzaChjKTtcblx0XHRcdFx0XHR9IGVsc2UgaWYgKGMudHlwZSA9PT0gXCJjb2xsZWN0b3JcIikge1xuXHRcdFx0XHRcdFx0Y29uc3Qgc3VpdGUgPSBhd2FpdCBjLmNvbGxlY3QoZmlsZSk7XG5cdFx0XHRcdFx0XHRpZiAoc3VpdGUubmFtZSB8fCBzdWl0ZS50YXNrcy5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0bWVyZ2VIb29rcyhmaWxlSG9va3MsIGdldEhvb2tzKHN1aXRlKSk7XG5cdFx0XHRcdFx0XHRcdGZpbGUudGFza3MucHVzaChzdWl0ZSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdC8vIGNoZWNrIHRoYXQgdHlwZXMgYXJlIGV4aGF1c3RlZFxuXHRcdFx0XHRcdFx0Yztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0c2V0SG9va3MoZmlsZSwgZmlsZUhvb2tzKTtcblx0XHRcdFx0ZmlsZS5jb2xsZWN0RHVyYXRpb24gPSBub3ckMSgpIC0gY29sbGVjdFN0YXJ0O1xuXHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRjb25zdCBlcnJvcnMgPSBlIGluc3RhbmNlb2YgQWdncmVnYXRlRXJyb3IgPyBlLmVycm9ycy5tYXAoKGUpID0+IHByb2Nlc3NFcnJvcihlLCBydW5uZXIuY29uZmlnLmRpZmZPcHRpb25zKSkgOiBbcHJvY2Vzc0Vycm9yKGUsIHJ1bm5lci5jb25maWcuZGlmZk9wdGlvbnMpXTtcblx0XHRcdFx0ZmlsZS5yZXN1bHQgPSB7XG5cdFx0XHRcdFx0c3RhdGU6IFwiZmFpbFwiLFxuXHRcdFx0XHRcdGVycm9yc1xuXHRcdFx0XHR9O1xuXHRcdFx0XHRjb25zdCBkdXJhdGlvbnMgPSBydW5uZXIuZ2V0SW1wb3J0RHVyYXRpb25zPy4oKTtcblx0XHRcdFx0aWYgKGR1cmF0aW9ucykge1xuXHRcdFx0XHRcdGZpbGUuaW1wb3J0RHVyYXRpb25zID0gZHVyYXRpb25zO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRjYWxjdWxhdGVTdWl0ZUhhc2goZmlsZSk7XG5cdFx0XHRjb25zdCBoYXNPbmx5VGFza3MgPSBzb21lVGFza3NBcmVPbmx5KGZpbGUpO1xuXHRcdFx0aWYgKCF0ZXN0VGFnc0ZpbHRlciAmJiAhZGVmYXVsdFRhZ3NGaWx0ZXIgJiYgY29uZmlnLnRhZ3NGaWx0ZXIpIHtcblx0XHRcdFx0ZGVmYXVsdFRhZ3NGaWx0ZXIgPSBjcmVhdGVUYWdzRmlsdGVyKGNvbmZpZy50YWdzRmlsdGVyLCBjb25maWcudGFncyk7XG5cdFx0XHR9XG5cdFx0XHRpbnRlcnByZXRUYXNrTW9kZXMoZmlsZSwgdGVzdE5hbWVQYXR0ZXJuID8/IGNvbmZpZy50ZXN0TmFtZVBhdHRlcm4sIHRlc3RMb2NhdGlvbnMsIHRlc3RJZHMsIHRlc3RUYWdzRmlsdGVyID8/IGRlZmF1bHRUYWdzRmlsdGVyLCBoYXNPbmx5VGFza3MsIGZhbHNlLCBjb25maWcuYWxsb3dPbmx5KTtcblx0XHRcdGlmIChmaWxlLm1vZGUgPT09IFwicXVldWVkXCIpIHtcblx0XHRcdFx0ZmlsZS5tb2RlID0gXCJydW5cIjtcblx0XHRcdH1cblx0XHRcdGZpbGVzLnB1c2goZmlsZSk7XG5cdFx0fSk7XG5cdH1cblx0cmV0dXJuIGZpbGVzO1xufVxuZnVuY3Rpb24gbWVyZ2VIb29rcyhiYXNlSG9va3MsIGhvb2tzKSB7XG5cdGZvciAoY29uc3QgX2tleSBpbiBob29rcykge1xuXHRcdGNvbnN0IGtleSA9IF9rZXk7XG5cdFx0YmFzZUhvb2tzW2tleV0ucHVzaCguLi5ob29rc1trZXldKTtcblx0fVxuXHRyZXR1cm4gYmFzZUhvb2tzO1xufVxuXG5jb25zdCBub3cgPSBnbG9iYWxUaGlzLnBlcmZvcm1hbmNlID8gZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZS5ub3cuYmluZChnbG9iYWxUaGlzLnBlcmZvcm1hbmNlKSA6IERhdGUubm93O1xuY29uc3QgdW5peE5vdyA9IERhdGUubm93O1xuY29uc3QgeyBjbGVhclRpbWVvdXQsIHNldFRpbWVvdXQgfSA9IGdldFNhZmVUaW1lcnMoKTtcbmxldCBsaW1pdE1heENvbmN1cnJlbmN5O1xuLyoqXG4qIE5vcm1hbGl6ZXMgcmV0cnkgY29uZmlndXJhdGlvbiB0byBleHRyYWN0IGluZGl2aWR1YWwgdmFsdWVzLlxuKiBIYW5kbGVzIGJvdGggbnVtYmVyIGFuZCBvYmplY3QgZm9ybXMuXG4qL1xuZnVuY3Rpb24gZ2V0UmV0cnlDb3VudChyZXRyeSkge1xuXHRpZiAocmV0cnkgPT09IHVuZGVmaW5lZCkge1xuXHRcdHJldHVybiAwO1xuXHR9XG5cdGlmICh0eXBlb2YgcmV0cnkgPT09IFwibnVtYmVyXCIpIHtcblx0XHRyZXR1cm4gcmV0cnk7XG5cdH1cblx0cmV0dXJuIHJldHJ5LmNvdW50ID8/IDA7XG59XG5mdW5jdGlvbiBnZXRSZXRyeURlbGF5KHJldHJ5KSB7XG5cdGlmIChyZXRyeSA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0cmV0dXJuIDA7XG5cdH1cblx0aWYgKHR5cGVvZiByZXRyeSA9PT0gXCJudW1iZXJcIikge1xuXHRcdHJldHVybiAwO1xuXHR9XG5cdHJldHVybiByZXRyeS5kZWxheSA/PyAwO1xufVxuZnVuY3Rpb24gZ2V0UmV0cnlDb25kaXRpb24ocmV0cnkpIHtcblx0aWYgKHJldHJ5ID09PSB1bmRlZmluZWQpIHtcblx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHR9XG5cdGlmICh0eXBlb2YgcmV0cnkgPT09IFwibnVtYmVyXCIpIHtcblx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHR9XG5cdHJldHVybiByZXRyeS5jb25kaXRpb247XG59XG5mdW5jdGlvbiB1cGRhdGVTdWl0ZUhvb2tTdGF0ZSh0YXNrLCBuYW1lLCBzdGF0ZSwgcnVubmVyKSB7XG5cdGlmICghdGFzay5yZXN1bHQpIHtcblx0XHR0YXNrLnJlc3VsdCA9IHsgc3RhdGU6IFwicnVuXCIgfTtcblx0fVxuXHRpZiAoIXRhc2sucmVzdWx0Lmhvb2tzKSB7XG5cdFx0dGFzay5yZXN1bHQuaG9va3MgPSB7fTtcblx0fVxuXHRjb25zdCBzdWl0ZUhvb2tzID0gdGFzay5yZXN1bHQuaG9va3M7XG5cdGlmIChzdWl0ZUhvb2tzKSB7XG5cdFx0c3VpdGVIb29rc1tuYW1lXSA9IHN0YXRlO1xuXHRcdGxldCBldmVudCA9IHN0YXRlID09PSBcInJ1blwiID8gXCJiZWZvcmUtaG9vay1zdGFydFwiIDogXCJiZWZvcmUtaG9vay1lbmRcIjtcblx0XHRpZiAobmFtZSA9PT0gXCJhZnRlckFsbFwiIHx8IG5hbWUgPT09IFwiYWZ0ZXJFYWNoXCIpIHtcblx0XHRcdGV2ZW50ID0gc3RhdGUgPT09IFwicnVuXCIgPyBcImFmdGVyLWhvb2stc3RhcnRcIiA6IFwiYWZ0ZXItaG9vay1lbmRcIjtcblx0XHR9XG5cdFx0dXBkYXRlVGFzayhldmVudCwgdGFzaywgcnVubmVyKTtcblx0fVxufVxuZnVuY3Rpb24gZ2V0U3VpdGVIb29rcyhzdWl0ZSwgbmFtZSwgc2VxdWVuY2UpIHtcblx0Y29uc3QgaG9va3MgPSBnZXRIb29rcyhzdWl0ZSlbbmFtZV07XG5cdGlmIChzZXF1ZW5jZSA9PT0gXCJzdGFja1wiICYmIChuYW1lID09PSBcImFmdGVyQWxsXCIgfHwgbmFtZSA9PT0gXCJhZnRlckVhY2hcIikpIHtcblx0XHRyZXR1cm4gaG9va3Muc2xpY2UoKS5yZXZlcnNlKCk7XG5cdH1cblx0cmV0dXJuIGhvb2tzO1xufVxuYXN5bmMgZnVuY3Rpb24gY2FsbFRlc3RIb29rcyhydW5uZXIsIHRlc3QsIGhvb2tzLCBzZXF1ZW5jZSkge1xuXHRpZiAoc2VxdWVuY2UgPT09IFwic3RhY2tcIikge1xuXHRcdGhvb2tzID0gaG9va3Muc2xpY2UoKS5yZXZlcnNlKCk7XG5cdH1cblx0aWYgKCFob29rcy5sZW5ndGgpIHtcblx0XHRyZXR1cm47XG5cdH1cblx0Y29uc3QgY29udGV4dCA9IHRlc3QuY29udGV4dDtcblx0Y29uc3Qgb25UZXN0RmFpbGVkID0gdGVzdC5jb250ZXh0Lm9uVGVzdEZhaWxlZDtcblx0Y29uc3Qgb25UZXN0RmluaXNoZWQgPSB0ZXN0LmNvbnRleHQub25UZXN0RmluaXNoZWQ7XG5cdGNvbnRleHQub25UZXN0RmFpbGVkID0gKCkgPT4ge1xuXHRcdHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGNhbGwgXCJvblRlc3RGYWlsZWRcIiBpbnNpZGUgYSB0ZXN0IGhvb2suYCk7XG5cdH07XG5cdGNvbnRleHQub25UZXN0RmluaXNoZWQgPSAoKSA9PiB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgY2FsbCBcIm9uVGVzdEZpbmlzaGVkXCIgaW5zaWRlIGEgdGVzdCBob29rLmApO1xuXHR9O1xuXHRpZiAoc2VxdWVuY2UgPT09IFwicGFyYWxsZWxcIikge1xuXHRcdHRyeSB7XG5cdFx0XHRhd2FpdCBQcm9taXNlLmFsbChob29rcy5tYXAoKGZuKSA9PiBsaW1pdE1heENvbmN1cnJlbmN5KCgpID0+IGZuKHRlc3QuY29udGV4dCkpKSk7XG5cdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0ZmFpbFRhc2sodGVzdC5yZXN1bHQsIGUsIHJ1bm5lci5jb25maWcuZGlmZk9wdGlvbnMpO1xuXHRcdH1cblx0fSBlbHNlIHtcblx0XHRmb3IgKGNvbnN0IGZuIG9mIGhvb2tzKSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRhd2FpdCBsaW1pdE1heENvbmN1cnJlbmN5KCgpID0+IGZuKHRlc3QuY29udGV4dCkpO1xuXHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRmYWlsVGFzayh0ZXN0LnJlc3VsdCwgZSwgcnVubmVyLmNvbmZpZy5kaWZmT3B0aW9ucyk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdGNvbnRleHQub25UZXN0RmFpbGVkID0gb25UZXN0RmFpbGVkO1xuXHRjb250ZXh0Lm9uVGVzdEZpbmlzaGVkID0gb25UZXN0RmluaXNoZWQ7XG59XG5hc3luYyBmdW5jdGlvbiBjYWxsU3VpdGVIb29rKHN1aXRlLCBjdXJyZW50VGFzaywgbmFtZSwgcnVubmVyLCBhcmdzKSB7XG5cdGNvbnN0IHNlcXVlbmNlID0gcnVubmVyLmNvbmZpZy5zZXF1ZW5jZS5ob29rcztcblx0Y29uc3QgY2FsbGJhY2tzID0gW107XG5cdC8vIHN0b3AgYXQgZmlsZSBsZXZlbFxuXHRjb25zdCBwYXJlbnRTdWl0ZSA9IFwiZmlsZXBhdGhcIiBpbiBzdWl0ZSA/IG51bGwgOiBzdWl0ZS5zdWl0ZSB8fCBzdWl0ZS5maWxlO1xuXHRpZiAobmFtZSA9PT0gXCJiZWZvcmVFYWNoXCIgJiYgcGFyZW50U3VpdGUpIHtcblx0XHRjYWxsYmFja3MucHVzaCguLi5hd2FpdCBjYWxsU3VpdGVIb29rKHBhcmVudFN1aXRlLCBjdXJyZW50VGFzaywgbmFtZSwgcnVubmVyLCBhcmdzKSk7XG5cdH1cblx0Y29uc3QgaG9va3MgPSBnZXRTdWl0ZUhvb2tzKHN1aXRlLCBuYW1lLCBzZXF1ZW5jZSk7XG5cdGlmIChob29rcy5sZW5ndGggPiAwKSB7XG5cdFx0dXBkYXRlU3VpdGVIb29rU3RhdGUoY3VycmVudFRhc2ssIG5hbWUsIFwicnVuXCIsIHJ1bm5lcik7XG5cdH1cblx0YXN5bmMgZnVuY3Rpb24gcnVuSG9vayhob29rKSB7XG5cdFx0cmV0dXJuIGxpbWl0TWF4Q29uY3VycmVuY3koYXN5bmMgKCkgPT4ge1xuXHRcdFx0cmV0dXJuIGdldEJlZm9yZUhvb2tDbGVhbnVwQ2FsbGJhY2soaG9vaywgYXdhaXQgaG9vayguLi5hcmdzKSwgbmFtZSA9PT0gXCJiZWZvcmVFYWNoXCIgPyBhcmdzWzBdIDogdW5kZWZpbmVkKTtcblx0XHR9KTtcblx0fVxuXHRpZiAoc2VxdWVuY2UgPT09IFwicGFyYWxsZWxcIikge1xuXHRcdGNhbGxiYWNrcy5wdXNoKC4uLmF3YWl0IFByb21pc2UuYWxsKGhvb2tzLm1hcCgoaG9vaykgPT4gcnVuSG9vayhob29rKSkpKTtcblx0fSBlbHNlIHtcblx0XHRmb3IgKGNvbnN0IGhvb2sgb2YgaG9va3MpIHtcblx0XHRcdGNhbGxiYWNrcy5wdXNoKGF3YWl0IHJ1bkhvb2soaG9vaykpO1xuXHRcdH1cblx0fVxuXHRpZiAoaG9va3MubGVuZ3RoID4gMCkge1xuXHRcdHVwZGF0ZVN1aXRlSG9va1N0YXRlKGN1cnJlbnRUYXNrLCBuYW1lLCBcInBhc3NcIiwgcnVubmVyKTtcblx0fVxuXHRpZiAobmFtZSA9PT0gXCJhZnRlckVhY2hcIiAmJiBwYXJlbnRTdWl0ZSkge1xuXHRcdGNhbGxiYWNrcy5wdXNoKC4uLmF3YWl0IGNhbGxTdWl0ZUhvb2socGFyZW50U3VpdGUsIGN1cnJlbnRUYXNrLCBuYW1lLCBydW5uZXIsIGFyZ3MpKTtcblx0fVxuXHRyZXR1cm4gY2FsbGJhY2tzO1xufVxuZnVuY3Rpb24gZ2V0QXJvdW5kRWFjaEhvb2tzKHN1aXRlKSB7XG5cdGNvbnN0IGhvb2tzID0gW107XG5cdGNvbnN0IHBhcmVudFN1aXRlID0gXCJmaWxlcGF0aFwiIGluIHN1aXRlID8gbnVsbCA6IHN1aXRlLnN1aXRlIHx8IHN1aXRlLmZpbGU7XG5cdGlmIChwYXJlbnRTdWl0ZSkge1xuXHRcdGhvb2tzLnB1c2goLi4uZ2V0QXJvdW5kRWFjaEhvb2tzKHBhcmVudFN1aXRlKSk7XG5cdH1cblx0aG9va3MucHVzaCguLi5nZXRIb29rcyhzdWl0ZSkuYXJvdW5kRWFjaCk7XG5cdHJldHVybiBob29rcztcbn1cbmZ1bmN0aW9uIGdldEFyb3VuZEFsbEhvb2tzKHN1aXRlKSB7XG5cdHJldHVybiBnZXRIb29rcyhzdWl0ZSkuYXJvdW5kQWxsO1xufVxuZnVuY3Rpb24gbWFrZUFyb3VuZEhvb2tUaW1lb3V0RXJyb3IoaG9va05hbWUsIHBoYXNlLCB0aW1lb3V0LCBzdGFja1RyYWNlRXJyb3IpIHtcblx0Y29uc3QgbWVzc2FnZSA9IGBUaGUgJHtwaGFzZX0gcGhhc2Ugb2YgXCIke2hvb2tOYW1lfVwiIGhvb2sgdGltZWQgb3V0IGFmdGVyICR7dGltZW91dH1tcy5gO1xuXHRjb25zdCBFcnJvckNsYXNzID0gcGhhc2UgPT09IFwic2V0dXBcIiA/IEFyb3VuZEhvb2tTZXR1cEVycm9yIDogQXJvdW5kSG9va1RlYXJkb3duRXJyb3I7XG5cdGNvbnN0IGVycm9yID0gbmV3IEVycm9yQ2xhc3MobWVzc2FnZSk7XG5cdGlmIChzdGFja1RyYWNlRXJyb3I/LnN0YWNrKSB7XG5cdFx0ZXJyb3Iuc3RhY2sgPSBzdGFja1RyYWNlRXJyb3Iuc3RhY2sucmVwbGFjZShzdGFja1RyYWNlRXJyb3IubWVzc2FnZSwgZXJyb3IubWVzc2FnZSk7XG5cdH1cblx0cmV0dXJuIGVycm9yO1xufVxuYXN5bmMgZnVuY3Rpb24gY2FsbEFyb3VuZEhvb2tzKHJ1bklubmVyLCBvcHRpb25zKSB7XG5cdGNvbnN0IHsgaG9va3MsIGhvb2tOYW1lLCBjYWxsYmFja05hbWUsIG9uVGltZW91dCwgaW52b2tlSG9vayB9ID0gb3B0aW9ucztcblx0aWYgKCFob29rcy5sZW5ndGgpIHtcblx0XHRhd2FpdCBydW5Jbm5lcigpO1xuXHRcdHJldHVybjtcblx0fVxuXHRjb25zdCBob29rRXJyb3JzID0gW107XG5cdGNvbnN0IGNyZWF0ZVRpbWVvdXRQcm9taXNlID0gKHRpbWVvdXQsIHBoYXNlLCBzdGFja1RyYWNlRXJyb3IpID0+IHtcblx0XHRsZXQgdGltZXI7XG5cdFx0bGV0IHRpbWVkb3V0ID0gZmFsc2U7XG5cdFx0Y29uc3QgcHJvbWlzZSA9IG5ldyBQcm9taXNlKChfLCByZWplY3QpID0+IHtcblx0XHRcdGlmICh0aW1lb3V0ID4gMCAmJiB0aW1lb3V0ICE9PSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkpIHtcblx0XHRcdFx0dGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdFx0XHR0aW1lZG91dCA9IHRydWU7XG5cdFx0XHRcdFx0Y29uc3QgZXJyb3IgPSBtYWtlQXJvdW5kSG9va1RpbWVvdXRFcnJvcihob29rTmFtZSwgcGhhc2UsIHRpbWVvdXQsIHN0YWNrVHJhY2VFcnJvcik7XG5cdFx0XHRcdFx0b25UaW1lb3V0Py4oZXJyb3IpO1xuXHRcdFx0XHRcdHJlamVjdChlcnJvcik7XG5cdFx0XHRcdH0sIHRpbWVvdXQpO1xuXHRcdFx0XHR0aW1lci51bnJlZj8uKCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Y29uc3QgY2xlYXIgPSAoKSA9PiB7XG5cdFx0XHRpZiAodGltZXIpIHtcblx0XHRcdFx0Y2xlYXJUaW1lb3V0KHRpbWVyKTtcblx0XHRcdFx0dGltZXIgPSB1bmRlZmluZWQ7XG5cdFx0XHR9XG5cdFx0fTtcblx0XHRyZXR1cm4ge1xuXHRcdFx0cHJvbWlzZSxcblx0XHRcdGNsZWFyLFxuXHRcdFx0aXNUaW1lZE91dDogKCkgPT4gdGltZWRvdXRcblx0XHR9O1xuXHR9O1xuXHRjb25zdCBydW5OZXh0SG9vayA9IGFzeW5jIChpbmRleCkgPT4ge1xuXHRcdGlmIChpbmRleCA+PSBob29rcy5sZW5ndGgpIHtcblx0XHRcdHJldHVybiBydW5Jbm5lcigpO1xuXHRcdH1cblx0XHRjb25zdCBob29rID0gaG9va3NbaW5kZXhdO1xuXHRcdGNvbnN0IHRpbWVvdXQgPSBnZXRBcm91bmRIb29rVGltZW91dChob29rKTtcblx0XHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBnZXRBcm91bmRIb29rU3RhY2tUcmFjZShob29rKTtcblx0XHRsZXQgdXNlQ2FsbGVkID0gZmFsc2U7XG5cdFx0bGV0IHNldHVwVGltZW91dDtcblx0XHRsZXQgdGVhcmRvd25UaW1lb3V0O1xuXHRcdGxldCBzZXR1cExpbWl0Q29uY3VycmVuY3lSZWxlYXNlO1xuXHRcdGxldCB0ZWFyZG93bkxpbWl0Q29uY3VycmVuY3lSZWxlYXNlO1xuXHRcdC8vIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHVzZSgpIGlzIGNhbGxlZCAoc2V0dXAgcGhhc2UgY29tcGxldGUpXG5cdFx0bGV0IHJlc29sdmVVc2VDYWxsZWQ7XG5cdFx0Y29uc3QgdXNlQ2FsbGVkUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG5cdFx0XHRyZXNvbHZlVXNlQ2FsbGVkID0gcmVzb2x2ZTtcblx0XHR9KTtcblx0XHQvLyBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB1c2UoKSByZXR1cm5zIChpbm5lciBob29rcyBjb21wbGV0ZSwgdGVhcmRvd24gcGhhc2Ugc3RhcnRzKVxuXHRcdGxldCByZXNvbHZlVXNlUmV0dXJuZWQ7XG5cdFx0Y29uc3QgdXNlUmV0dXJuZWRQcm9taXNlID0gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcblx0XHRcdHJlc29sdmVVc2VSZXR1cm5lZCA9IHJlc29sdmU7XG5cdFx0fSk7XG5cdFx0Ly8gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gaG9vayBjb21wbGV0ZXNcblx0XHRsZXQgcmVzb2x2ZUhvb2tDb21wbGV0ZTtcblx0XHRsZXQgcmVqZWN0SG9va0NvbXBsZXRlO1xuXHRcdGNvbnN0IGhvb2tDb21wbGV0ZVByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG5cdFx0XHRyZXNvbHZlSG9va0NvbXBsZXRlID0gcmVzb2x2ZTtcblx0XHRcdHJlamVjdEhvb2tDb21wbGV0ZSA9IHJlamVjdDtcblx0XHR9KTtcblx0XHRjb25zdCB1c2UgPSBhc3luYyAoKSA9PiB7XG5cdFx0XHQvLyBzaG91bGRuJ3QgY29udGludWUgdG8gbmV4dCAocnVuVGVzdC9TdWl0ZSBvciBpbm5lciBhcm91bmRFYWNoL0FsbCkgd2hlbiBhcm91bmRFYWNoL0FsbCBzZXR1cCB0aW1lZCBvdXQuXG5cdFx0XHRpZiAoc2V0dXBUaW1lb3V0LmlzVGltZWRPdXQoKSkge1xuXHRcdFx0XHQvLyB3ZSBjYW4gdGhyb3cgYW55IGVycm9yIHRvIGJhaWwgb3V0LlxuXHRcdFx0XHQvLyB0aGlzIGVycm9yIGlzIG5vdCBzZWVuIGJ5IGVuZCB1c2VycyBzaW5jZSBgcnVuTmV4dEhvb2tgIGFscmVhZHkgcmVqZWN0ZWQgd2l0aCB0aW1lb3V0IGVycm9yXG5cdFx0XHRcdC8vIGFuZCB0aGlzIGVycm9yIGlzIGNhdWdodCBieSBgcmVqZWN0SG9va0NvbXBsZXRlYC5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKFwiX19WSVRFU1RfSU5URVJOQUxfQVJPVU5EX0hPT0tfQUJPUlRfX1wiKTtcblx0XHRcdH1cblx0XHRcdGlmICh1c2VDYWxsZWQpIHtcblx0XHRcdFx0dGhyb3cgbmV3IEFyb3VuZEhvb2tNdWx0aXBsZUNhbGxzRXJyb3IoYFRoZSBcXGAke2NhbGxiYWNrTmFtZX1cXGAgY2FsbGJhY2sgd2FzIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyBpbiB0aGUgXFxgJHtob29rTmFtZX1cXGAgaG9vay4gYCArIGBUaGUgY2FsbGJhY2sgY2FuIG9ubHkgYmUgY2FsbGVkIG9uY2UgcGVyIGhvb2suYCk7XG5cdFx0XHR9XG5cdFx0XHR1c2VDYWxsZWQgPSB0cnVlO1xuXHRcdFx0cmVzb2x2ZVVzZUNhbGxlZCgpO1xuXHRcdFx0Ly8gU2V0dXAgcGhhc2UgY29tcGxldGVkIC0gY2xlYXIgc2V0dXAgdGltZXJcblx0XHRcdHNldHVwVGltZW91dC5jbGVhcigpO1xuXHRcdFx0c2V0dXBMaW1pdENvbmN1cnJlbmN5UmVsZWFzZT8uKCk7XG5cdFx0XHQvLyBSdW4gaW5uZXIgaG9va3MgLSBkb24ndCB0aW1lIHRoaXMgYWdhaW5zdCBvdXIgdGVhcmRvd24gdGltZW91dFxuXHRcdFx0YXdhaXQgcnVuTmV4dEhvb2soaW5kZXggKyAxKS5jYXRjaCgoZSkgPT4gaG9va0Vycm9ycy5wdXNoKGUpKTtcblx0XHRcdHRlYXJkb3duTGltaXRDb25jdXJyZW5jeVJlbGVhc2UgPSBhd2FpdCBsaW1pdE1heENvbmN1cnJlbmN5LmFjcXVpcmUoKTtcblx0XHRcdC8vIFN0YXJ0IHRlYXJkb3duIHRpbWVyIGFmdGVyIGlubmVyIGhvb2tzIGNvbXBsZXRlIC0gb25seSB0aW1lcyB0aGlzIGhvb2sncyB0ZWFyZG93biBjb2RlXG5cdFx0XHR0ZWFyZG93blRpbWVvdXQgPSBjcmVhdGVUaW1lb3V0UHJvbWlzZSh0aW1lb3V0LCBcInRlYXJkb3duXCIsIHN0YWNrVHJhY2VFcnJvcik7XG5cdFx0XHQvLyBTaWduYWwgdGhhdCB1c2UoKSBpcyByZXR1cm5pbmcgKHRlYXJkb3duIHBoYXNlIHN0YXJ0aW5nKVxuXHRcdFx0cmVzb2x2ZVVzZVJldHVybmVkKCk7XG5cdFx0fTtcblx0XHRzZXR1cExpbWl0Q29uY3VycmVuY3lSZWxlYXNlID0gYXdhaXQgbGltaXRNYXhDb25jdXJyZW5jeS5hY3F1aXJlKCk7XG5cdFx0Ly8gU3RhcnQgc2V0dXAgdGltZW91dFxuXHRcdHNldHVwVGltZW91dCA9IGNyZWF0ZVRpbWVvdXRQcm9taXNlKHRpbWVvdXQsIFwic2V0dXBcIiwgc3RhY2tUcmFjZUVycm9yKTtcblx0XHQoYXN5bmMgKCkgPT4ge1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0YXdhaXQgaW52b2tlSG9vayhob29rLCB1c2UpO1xuXHRcdFx0XHRpZiAoIXVzZUNhbGxlZCkge1xuXHRcdFx0XHRcdHRocm93IG5ldyBBcm91bmRIb29rU2V0dXBFcnJvcihgVGhlIFxcYCR7Y2FsbGJhY2tOYW1lfVxcYCBjYWxsYmFjayB3YXMgbm90IGNhbGxlZCBpbiB0aGUgXFxgJHtob29rTmFtZX1cXGAgaG9vay4gYCArIGBNYWtlIHN1cmUgdG8gY2FsbCBcXGAke2NhbGxiYWNrTmFtZX1cXGAgdG8gcnVuIHRoZSAke2hvb2tOYW1lID09PSBcImFyb3VuZEVhY2hcIiA/IFwidGVzdFwiIDogXCJzdWl0ZVwifS5gKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXNvbHZlSG9va0NvbXBsZXRlKCk7XG5cdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0XHRyZWplY3RIb29rQ29tcGxldGUoZXJyb3IpO1xuXHRcdFx0fSBmaW5hbGx5IHtcblx0XHRcdFx0c2V0dXBMaW1pdENvbmN1cnJlbmN5UmVsZWFzZT8uKCk7XG5cdFx0XHRcdHRlYXJkb3duTGltaXRDb25jdXJyZW5jeVJlbGVhc2U/LigpO1xuXHRcdFx0fVxuXHRcdH0pKCk7XG5cdFx0Ly8gV2FpdCBmb3IgZWl0aGVyOiB1c2UoKSB0byBiZSBjYWxsZWQgT1IgaG9vayB0byBjb21wbGV0ZSAoZXJyb3IpIE9SIHNldHVwIHRpbWVvdXRcblx0XHR0cnkge1xuXHRcdFx0YXdhaXQgUHJvbWlzZS5yYWNlKFtcblx0XHRcdFx0dXNlQ2FsbGVkUHJvbWlzZSxcblx0XHRcdFx0aG9va0NvbXBsZXRlUHJvbWlzZSxcblx0XHRcdFx0c2V0dXBUaW1lb3V0LnByb21pc2Vcblx0XHRcdF0pO1xuXHRcdH0gZmluYWxseSB7XG5cdFx0XHRzZXR1cExpbWl0Q29uY3VycmVuY3lSZWxlYXNlPy4oKTtcblx0XHRcdHNldHVwVGltZW91dC5jbGVhcigpO1xuXHRcdH1cblx0XHQvLyBXYWl0IGZvciB1c2UoKSB0byByZXR1cm4gKGlubmVyIGhvb2tzIGNvbXBsZXRlKSBPUiBob29rIHRvIGNvbXBsZXRlIChlcnJvciBkdXJpbmcgaW5uZXIgaG9va3MpXG5cdFx0YXdhaXQgUHJvbWlzZS5yYWNlKFt1c2VSZXR1cm5lZFByb21pc2UsIGhvb2tDb21wbGV0ZVByb21pc2VdKTtcblx0XHQvLyBOb3cgdGVhcmRvd25UaW1lb3V0IGlzIGd1YXJhbnRlZWQgdG8gYmUgc2V0XG5cdFx0Ly8gV2FpdCBmb3IgaG9vayB0byBjb21wbGV0ZSAodGVhcmRvd24pIE9SIHRlYXJkb3duIHRpbWVvdXRcblx0XHR0cnkge1xuXHRcdFx0YXdhaXQgUHJvbWlzZS5yYWNlKFtob29rQ29tcGxldGVQcm9taXNlLCB0ZWFyZG93blRpbWVvdXQ/LnByb21pc2VdKTtcblx0XHR9IGZpbmFsbHkge1xuXHRcdFx0dGVhcmRvd25MaW1pdENvbmN1cnJlbmN5UmVsZWFzZT8uKCk7XG5cdFx0XHR0ZWFyZG93blRpbWVvdXQ/LmNsZWFyKCk7XG5cdFx0fVxuXHR9O1xuXHRhd2FpdCBydW5OZXh0SG9vaygwKS5jYXRjaCgoZSkgPT4gaG9va0Vycm9ycy5wdXNoKGUpKTtcblx0aWYgKGhvb2tFcnJvcnMubGVuZ3RoID4gMCkge1xuXHRcdHRocm93IGhvb2tFcnJvcnM7XG5cdH1cbn1cbmFzeW5jIGZ1bmN0aW9uIGNhbGxBcm91bmRBbGxIb29rcyhzdWl0ZSwgcnVuU3VpdGVJbm5lcikge1xuXHRhd2FpdCBjYWxsQXJvdW5kSG9va3MocnVuU3VpdGVJbm5lciwge1xuXHRcdGhvb2tzOiBnZXRBcm91bmRBbGxIb29rcyhzdWl0ZSksXG5cdFx0aG9va05hbWU6IFwiYXJvdW5kQWxsXCIsXG5cdFx0Y2FsbGJhY2tOYW1lOiBcInJ1blN1aXRlKClcIixcblx0XHRpbnZva2VIb29rOiAoaG9vaywgdXNlKSA9PiBob29rKHVzZSwgc3VpdGUpXG5cdH0pO1xufVxuYXN5bmMgZnVuY3Rpb24gY2FsbEFyb3VuZEVhY2hIb29rcyhzdWl0ZSwgdGVzdCwgcnVuVGVzdCkge1xuXHRhd2FpdCBjYWxsQXJvdW5kSG9va3MoXG5cdFx0Ly8gVGFrZSBjaGVja3BvaW50IHJpZ2h0IGJlZm9yZSBydW5UZXN0IC0gYXQgdGhpcyBwb2ludCBhbGwgYXJvdW5kRWFjaCBmaXh0dXJlc1xuXHRcdC8vIGhhdmUgYmVlbiByZXNvbHZlZCwgc28gd2UgY2FuIGNvcnJlY3RseSBpZGVudGlmeSB3aGljaCBmaXh0dXJlcyBiZWxvbmcgdG9cblx0XHQvLyBhcm91bmRFYWNoIChiZWZvcmUgY2hlY2twb2ludCkgdnMgaW5zaWRlIHJ1blRlc3QgKGFmdGVyIGNoZWNrcG9pbnQpXG5cdFx0KCkgPT4gcnVuVGVzdChnZXRGaXh0dXJlQ2xlYW51cENvdW50KHRlc3QuY29udGV4dCkpLFxuXHRcdHtcblx0XHRcdGhvb2tzOiBnZXRBcm91bmRFYWNoSG9va3Moc3VpdGUpLFxuXHRcdFx0aG9va05hbWU6IFwiYXJvdW5kRWFjaFwiLFxuXHRcdFx0Y2FsbGJhY2tOYW1lOiBcInJ1blRlc3QoKVwiLFxuXHRcdFx0b25UaW1lb3V0OiAoZXJyb3IpID0+IGFib3J0Q29udGV4dFNpZ25hbCh0ZXN0LmNvbnRleHQsIGVycm9yKSxcblx0XHRcdGludm9rZUhvb2s6IChob29rLCB1c2UpID0+IGhvb2sodXNlLCB0ZXN0LmNvbnRleHQsIHN1aXRlKVxuXHRcdH1cblx0KTtcbn1cbmNvbnN0IHBhY2tzID0gbmV3IE1hcCgpO1xuY29uc3QgZXZlbnRzUGFja3MgPSBbXTtcbmNvbnN0IHBlbmRpbmdUYXNrc1VwZGF0ZXMgPSBbXTtcbmZ1bmN0aW9uIHNlbmRUYXNrc1VwZGF0ZShydW5uZXIpIHtcblx0aWYgKHBhY2tzLnNpemUpIHtcblx0XHRjb25zdCB0YXNrUGFja3MgPSBBcnJheS5mcm9tKHBhY2tzKS5tYXAoKFtpZCwgdGFza10pID0+IHtcblx0XHRcdHJldHVybiBbXG5cdFx0XHRcdGlkLFxuXHRcdFx0XHR0YXNrWzBdLFxuXHRcdFx0XHR0YXNrWzFdXG5cdFx0XHRdO1xuXHRcdH0pO1xuXHRcdGNvbnN0IHAgPSBydW5uZXIub25UYXNrVXBkYXRlPy4odGFza1BhY2tzLCBldmVudHNQYWNrcyk7XG5cdFx0aWYgKHApIHtcblx0XHRcdHBlbmRpbmdUYXNrc1VwZGF0ZXMucHVzaChwKTtcblx0XHRcdC8vIHJlbW92ZSBzdWNjZXNzZnVsIHByb21pc2UgdG8gbm90IGdyb3cgYXJyYXkgaW5kZWZpbml0ZWx5LFxuXHRcdFx0Ly8gYnV0IGtlZXAgcmVqZWN0aW9ucyBzbyBmaW5pc2hTZW5kVGFza3NVcGRhdGUgY2FuIGhhbmRsZSB0aGVtXG5cdFx0XHRwLnRoZW4oKCkgPT4gcGVuZGluZ1Rhc2tzVXBkYXRlcy5zcGxpY2UocGVuZGluZ1Rhc2tzVXBkYXRlcy5pbmRleE9mKHApLCAxKSwgKCkgPT4ge30pO1xuXHRcdH1cblx0XHRldmVudHNQYWNrcy5sZW5ndGggPSAwO1xuXHRcdHBhY2tzLmNsZWFyKCk7XG5cdH1cbn1cbmFzeW5jIGZ1bmN0aW9uIGZpbmlzaFNlbmRUYXNrc1VwZGF0ZShydW5uZXIpIHtcblx0c2VuZFRhc2tzVXBkYXRlKHJ1bm5lcik7XG5cdGF3YWl0IFByb21pc2UuYWxsKHBlbmRpbmdUYXNrc1VwZGF0ZXMpO1xufVxuZnVuY3Rpb24gdGhyb3R0bGUoZm4sIG1zKSB7XG5cdGxldCBsYXN0ID0gMDtcblx0bGV0IHBlbmRpbmdDYWxsO1xuXHRyZXR1cm4gZnVuY3Rpb24gY2FsbCguLi5hcmdzKSB7XG5cdFx0Y29uc3Qgbm93ID0gdW5peE5vdygpO1xuXHRcdGlmIChub3cgLSBsYXN0ID4gbXMpIHtcblx0XHRcdGxhc3QgPSBub3c7XG5cdFx0XHRjbGVhclRpbWVvdXQocGVuZGluZ0NhbGwpO1xuXHRcdFx0cGVuZGluZ0NhbGwgPSB1bmRlZmluZWQ7XG5cdFx0XHRyZXR1cm4gZm4uYXBwbHkodGhpcywgYXJncyk7XG5cdFx0fVxuXHRcdC8vIE1ha2Ugc3VyZSBmbiBpcyBzdGlsbCBjYWxsZWQgZXZlbiBpZiB0aGVyZSBhcmUgbm8gZnVydGhlciBjYWxsc1xuXHRcdHBlbmRpbmdDYWxsID8/PSBzZXRUaW1lb3V0KCgpID0+IGNhbGwuYmluZCh0aGlzKSguLi5hcmdzKSwgbXMpO1xuXHR9O1xufVxuLy8gdGhyb3R0bGUgYmFzZWQgb24gc3VtbWFyeSByZXBvcnRlcidzIERVUkFUSU9OX1VQREFURV9JTlRFUlZBTF9NU1xuY29uc3Qgc2VuZFRhc2tzVXBkYXRlVGhyb3R0bGVkID0gdGhyb3R0bGUoc2VuZFRhc2tzVXBkYXRlLCAxMDApO1xuZnVuY3Rpb24gdXBkYXRlVGFzayhldmVudCwgdGFzaywgcnVubmVyKSB7XG5cdGV2ZW50c1BhY2tzLnB1c2goW1xuXHRcdHRhc2suaWQsXG5cdFx0ZXZlbnQsXG5cdFx0dW5kZWZpbmVkXG5cdF0pO1xuXHRwYWNrcy5zZXQodGFzay5pZCwgW3Rhc2sucmVzdWx0LCB0YXNrLm1ldGFdKTtcblx0c2VuZFRhc2tzVXBkYXRlVGhyb3R0bGVkKHJ1bm5lcik7XG59XG5hc3luYyBmdW5jdGlvbiBjYWxsQ2xlYW51cEhvb2tzKHJ1bm5lciwgY2xlYW51cHMpIHtcblx0Y29uc3Qgc2VxdWVuY2UgPSBydW5uZXIuY29uZmlnLnNlcXVlbmNlLmhvb2tzO1xuXHRpZiAoc2VxdWVuY2UgPT09IFwic3RhY2tcIikge1xuXHRcdGNsZWFudXBzID0gY2xlYW51cHMuc2xpY2UoKS5yZXZlcnNlKCk7XG5cdH1cblx0aWYgKHNlcXVlbmNlID09PSBcInBhcmFsbGVsXCIpIHtcblx0XHRhd2FpdCBQcm9taXNlLmFsbChjbGVhbnVwcy5tYXAoYXN5bmMgKGZuKSA9PiB7XG5cdFx0XHRpZiAodHlwZW9mIGZuICE9PSBcImZ1bmN0aW9uXCIpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0YXdhaXQgbGltaXRNYXhDb25jdXJyZW5jeSgoKSA9PiBmbigpKTtcblx0XHR9KSk7XG5cdH0gZWxzZSB7XG5cdFx0Zm9yIChjb25zdCBmbiBvZiBjbGVhbnVwcykge1xuXHRcdFx0aWYgKHR5cGVvZiBmbiAhPT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXHRcdFx0YXdhaXQgbGltaXRNYXhDb25jdXJyZW5jeSgoKSA9PiBmbigpKTtcblx0XHR9XG5cdH1cbn1cbi8qKlxuKiBEZXRlcm1pbmVzIGlmIGEgdGVzdCBzaG91bGQgYmUgcmV0cmllZCBiYXNlZCBvbiBpdHMgcmV0cnlDb25kaXRpb24gY29uZmlndXJhdGlvblxuKi9cbmZ1bmN0aW9uIHBhc3Nlc1JldHJ5Q29uZGl0aW9uKHRlc3QsIGVycm9ycykge1xuXHRjb25zdCBjb25kaXRpb24gPSBnZXRSZXRyeUNvbmRpdGlvbih0ZXN0LnJldHJ5KTtcblx0aWYgKCFlcnJvcnMgfHwgZXJyb3JzLmxlbmd0aCA9PT0gMCkge1xuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXHRpZiAoIWNvbmRpdGlvbikge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cdGNvbnN0IGVycm9yID0gZXJyb3JzW2Vycm9ycy5sZW5ndGggLSAxXTtcblx0aWYgKGNvbmRpdGlvbiBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuXHRcdHJldHVybiBjb25kaXRpb24udGVzdChlcnJvci5tZXNzYWdlIHx8IFwiXCIpO1xuXHR9IGVsc2UgaWYgKHR5cGVvZiBjb25kaXRpb24gPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdHJldHVybiBjb25kaXRpb24oZXJyb3IpO1xuXHR9XG5cdHJldHVybiBmYWxzZTtcbn1cbmFzeW5jIGZ1bmN0aW9uIHJ1blRlc3QodGVzdCwgcnVubmVyKSB7XG5cdGF3YWl0IHJ1bm5lci5vbkJlZm9yZVJ1blRhc2s/Lih0ZXN0KTtcblx0aWYgKHRlc3QubW9kZSAhPT0gXCJydW5cIiAmJiB0ZXN0Lm1vZGUgIT09IFwicXVldWVkXCIpIHtcblx0XHR1cGRhdGVUYXNrKFwidGVzdC1wcmVwYXJlXCIsIHRlc3QsIHJ1bm5lcik7XG5cdFx0dXBkYXRlVGFzayhcInRlc3QtZmluaXNoZWRcIiwgdGVzdCwgcnVubmVyKTtcblx0XHRyZXR1cm47XG5cdH1cblx0aWYgKHRlc3QucmVzdWx0Py5zdGF0ZSA9PT0gXCJmYWlsXCIpIHtcblx0XHQvLyBzaG91bGQgbm90IGJlIHBvc3NpYmxlIHRvIGdldCBoZXJlLCBJIHRoaW5rIHRoaXMgaXMganVzdCBjb3B5IHBhc3RlZCBmcm9tIHN1aXRlXG5cdFx0Ly8gVE9ETzogbWF5YmUgc29tZW9uZSBmYWlscyB0ZXN0cyBpbiBgYmVmb3JlQWxsYCBob29rcz9cblx0XHQvLyBodHRwczovL2dpdGh1Yi5jb20vdml0ZXN0LWRldi92aXRlc3QvcHVsbC83MDY5XG5cdFx0dXBkYXRlVGFzayhcInRlc3QtZmFpbGVkLWVhcmx5XCIsIHRlc3QsIHJ1bm5lcik7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdGNvbnN0IHN0YXJ0ID0gbm93KCk7XG5cdHRlc3QucmVzdWx0ID0ge1xuXHRcdHN0YXRlOiBcInJ1blwiLFxuXHRcdHN0YXJ0VGltZTogdW5peE5vdygpLFxuXHRcdHJldHJ5Q291bnQ6IDBcblx0fTtcblx0dXBkYXRlVGFzayhcInRlc3QtcHJlcGFyZVwiLCB0ZXN0LCBydW5uZXIpO1xuXHRjb25zdCBjbGVhbnVwUnVubmluZ1Rlc3QgPSBhZGRSdW5uaW5nVGVzdCh0ZXN0KTtcblx0c2V0Q3VycmVudFRlc3QodGVzdCk7XG5cdGNvbnN0IHN1aXRlID0gdGVzdC5zdWl0ZSB8fCB0ZXN0LmZpbGU7XG5cdGNvbnN0ICQgPSBydW5uZXIudHJhY2U7XG5cdGNvbnN0IHJlcGVhdHMgPSB0ZXN0LnJlcGVhdHMgPz8gMDtcblx0Zm9yIChsZXQgcmVwZWF0Q291bnQgPSAwOyByZXBlYXRDb3VudCA8PSByZXBlYXRzOyByZXBlYXRDb3VudCsrKSB7XG5cdFx0Y29uc3QgcmV0cnkgPSBnZXRSZXRyeUNvdW50KHRlc3QucmV0cnkpO1xuXHRcdGZvciAobGV0IHJldHJ5Q291bnQgPSAwOyByZXRyeUNvdW50IDw9IHJldHJ5OyByZXRyeUNvdW50KyspIHtcblx0XHRcdGxldCBiZWZvcmVFYWNoQ2xlYW51cHMgPSBbXTtcblx0XHRcdC8vIGZpeHR1cmVDaGVja3BvaW50IGlzIHBhc3NlZCBieSBjYWxsQXJvdW5kRWFjaEhvb2tzIC0gaXQgcmVwcmVzZW50cyB0aGUgY291bnRcblx0XHRcdC8vIG9mIGZpeHR1cmUgY2xlYW51cCBmdW5jdGlvbnMgQUZURVIgYWxsIGFyb3VuZEVhY2ggZml4dHVyZXMgaGF2ZSBiZWVuIHJlc29sdmVkXG5cdFx0XHQvLyBidXQgQkVGT1JFIHRoZSB0ZXN0IHJ1bnMuIFRoaXMgYWxsb3dzIHVzIHRvIGNsZWFuIHVwIG9ubHkgZml4dHVyZXMgY3JlYXRlZFxuXHRcdFx0Ly8gaW5zaWRlIHJ1blRlc3Qgd2hpbGUgcHJlc2VydmluZyBhcm91bmRFYWNoIGZpeHR1cmVzIGZvciB0ZWFyZG93bi5cblx0XHRcdGF3YWl0IGNhbGxBcm91bmRFYWNoSG9va3Moc3VpdGUsIHRlc3QsIGFzeW5jIChmaXh0dXJlQ2hlY2twb2ludCkgPT4ge1xuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdGF3YWl0IHJ1bm5lci5vbkJlZm9yZVRyeVRhc2s/Lih0ZXN0LCB7XG5cdFx0XHRcdFx0XHRyZXRyeTogcmV0cnlDb3VudCxcblx0XHRcdFx0XHRcdHJlcGVhdHM6IHJlcGVhdENvdW50XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0dGVzdC5yZXN1bHQucmVwZWF0Q291bnQgPSByZXBlYXRDb3VudDtcblx0XHRcdFx0XHRiZWZvcmVFYWNoQ2xlYW51cHMgPSBhd2FpdCAkKFwidGVzdC5iZWZvcmVFYWNoXCIsICgpID0+IGNhbGxTdWl0ZUhvb2soc3VpdGUsIHRlc3QsIFwiYmVmb3JlRWFjaFwiLCBydW5uZXIsIFt0ZXN0LmNvbnRleHQsIHN1aXRlXSkpO1xuXHRcdFx0XHRcdGlmIChydW5uZXIucnVuVGFzaykge1xuXHRcdFx0XHRcdFx0YXdhaXQgJChcInRlc3QuY2FsbGJhY2tcIiwgKCkgPT4gbGltaXRNYXhDb25jdXJyZW5jeSgoKSA9PiBydW5uZXIucnVuVGFzayh0ZXN0KSkpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRjb25zdCBmbiA9IGdldEZuKHRlc3QpO1xuXHRcdFx0XHRcdFx0aWYgKCFmbikge1xuXHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJUZXN0IGZ1bmN0aW9uIGlzIG5vdCBmb3VuZC4gRGlkIHlvdSBhZGQgaXQgdXNpbmcgYHNldEZuYD9cIik7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRhd2FpdCAkKFwidGVzdC5jYWxsYmFja1wiLCAoKSA9PiBsaW1pdE1heENvbmN1cnJlbmN5KCgpID0+IGZuKCkpKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YXdhaXQgcnVubmVyLm9uQWZ0ZXJUcnlUYXNrPy4odGVzdCwge1xuXHRcdFx0XHRcdFx0cmV0cnk6IHJldHJ5Q291bnQsXG5cdFx0XHRcdFx0XHRyZXBlYXRzOiByZXBlYXRDb3VudFxuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdGlmICh0ZXN0LnJlc3VsdC5zdGF0ZSAhPT0gXCJmYWlsXCIpIHtcblx0XHRcdFx0XHRcdHRlc3QucmVzdWx0LnN0YXRlID0gXCJwYXNzXCI7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGNhdGNoIChlKSB7XG5cdFx0XHRcdFx0ZmFpbFRhc2sodGVzdC5yZXN1bHQsIGUsIHJ1bm5lci5jb25maWcuZGlmZk9wdGlvbnMpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0YXdhaXQgcnVubmVyLm9uVGFza0ZpbmlzaGVkPy4odGVzdCk7XG5cdFx0XHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdFx0XHRmYWlsVGFzayh0ZXN0LnJlc3VsdCwgZSwgcnVubmVyLmNvbmZpZy5kaWZmT3B0aW9ucyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRhd2FpdCAkKFwidGVzdC5hZnRlckVhY2hcIiwgKCkgPT4gY2FsbFN1aXRlSG9vayhzdWl0ZSwgdGVzdCwgXCJhZnRlckVhY2hcIiwgcnVubmVyLCBbdGVzdC5jb250ZXh0LCBzdWl0ZV0pKTtcblx0XHRcdFx0XHRpZiAoYmVmb3JlRWFjaENsZWFudXBzLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0YXdhaXQgJChcInRlc3QuY2xlYW51cFwiLCAoKSA9PiBjYWxsQ2xlYW51cEhvb2tzKHJ1bm5lciwgYmVmb3JlRWFjaENsZWFudXBzKSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdC8vIE9ubHkgY2xlYW4gdXAgZml4dHVyZXMgY3JlYXRlZCBpbnNpZGUgcnVuVGVzdCAoYWZ0ZXIgdGhlIGNoZWNrcG9pbnQpXG5cdFx0XHRcdFx0Ly8gRml4dHVyZXMgY3JlYXRlZCBmb3IgYXJvdW5kRWFjaCB3aWxsIGJlIGNsZWFuZWQgdXAgYWZ0ZXIgYXJvdW5kRWFjaCB0ZWFyZG93blxuXHRcdFx0XHRcdGF3YWl0IGNhbGxGaXh0dXJlQ2xlYW51cEZyb20odGVzdC5jb250ZXh0LCBmaXh0dXJlQ2hlY2twb2ludCk7XG5cdFx0XHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdFx0XHRmYWlsVGFzayh0ZXN0LnJlc3VsdCwgZSwgcnVubmVyLmNvbmZpZy5kaWZmT3B0aW9ucyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKHRlc3Qub25GaW5pc2hlZD8ubGVuZ3RoKSB7XG5cdFx0XHRcdFx0YXdhaXQgJChcInRlc3Qub25GaW5pc2hlZFwiLCAoKSA9PiBjYWxsVGVzdEhvb2tzKHJ1bm5lciwgdGVzdCwgdGVzdC5vbkZpbmlzaGVkLCBcInN0YWNrXCIpKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAodGVzdC5yZXN1bHQuc3RhdGUgPT09IFwiZmFpbFwiICYmIHRlc3Qub25GYWlsZWQ/Lmxlbmd0aCkge1xuXHRcdFx0XHRcdGF3YWl0ICQoXCJ0ZXN0Lm9uRmFpbGVkXCIsICgpID0+IGNhbGxUZXN0SG9va3MocnVubmVyLCB0ZXN0LCB0ZXN0Lm9uRmFpbGVkLCBydW5uZXIuY29uZmlnLnNlcXVlbmNlLmhvb2tzKSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGVzdC5vbkZhaWxlZCA9IHVuZGVmaW5lZDtcblx0XHRcdFx0dGVzdC5vbkZpbmlzaGVkID0gdW5kZWZpbmVkO1xuXHRcdFx0XHRhd2FpdCBydW5uZXIub25BZnRlclJldHJ5VGFzaz8uKHRlc3QsIHtcblx0XHRcdFx0XHRyZXRyeTogcmV0cnlDb3VudCxcblx0XHRcdFx0XHRyZXBlYXRzOiByZXBlYXRDb3VudFxuXHRcdFx0XHR9KTtcblx0XHRcdH0pLmNhdGNoKChlcnJvcikgPT4ge1xuXHRcdFx0XHRmYWlsVGFzayh0ZXN0LnJlc3VsdCwgZXJyb3IsIHJ1bm5lci5jb25maWcuZGlmZk9wdGlvbnMpO1xuXHRcdFx0fSk7XG5cdFx0XHQvLyBDbGVhbiB1cCBmaXh0dXJlcyB0aGF0IHdlcmUgY3JlYXRlZCBmb3IgYXJvdW5kRWFjaCAoYmVmb3JlIHRoZSBjaGVja3BvaW50KVxuXHRcdFx0Ly8gVGhpcyBydW5zIGFmdGVyIGFyb3VuZEVhY2ggdGVhcmRvd24gaGFzIGNvbXBsZXRlZFxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0YXdhaXQgY2FsbEZpeHR1cmVDbGVhbnVwKHRlc3QuY29udGV4dCk7XG5cdFx0XHR9IGNhdGNoIChlKSB7XG5cdFx0XHRcdGZhaWxUYXNrKHRlc3QucmVzdWx0LCBlLCBydW5uZXIuY29uZmlnLmRpZmZPcHRpb25zKTtcblx0XHRcdH1cblx0XHRcdC8vIHNraXBwZWQgd2l0aCBuZXcgUGVuZGluZ0Vycm9yXG5cdFx0XHRpZiAodGVzdC5yZXN1bHQ/LnBlbmRpbmcgfHwgdGVzdC5yZXN1bHQ/LnN0YXRlID09PSBcInNraXBcIikge1xuXHRcdFx0XHR0ZXN0Lm1vZGUgPSBcInNraXBcIjtcblx0XHRcdFx0dGVzdC5yZXN1bHQgPSB7XG5cdFx0XHRcdFx0c3RhdGU6IFwic2tpcFwiLFxuXHRcdFx0XHRcdG5vdGU6IHRlc3QucmVzdWx0Py5ub3RlLFxuXHRcdFx0XHRcdHBlbmRpbmc6IHRydWUsXG5cdFx0XHRcdFx0ZHVyYXRpb246IG5vdygpIC0gc3RhcnRcblx0XHRcdFx0fTtcblx0XHRcdFx0dXBkYXRlVGFzayhcInRlc3QtZmluaXNoZWRcIiwgdGVzdCwgcnVubmVyKTtcblx0XHRcdFx0c2V0Q3VycmVudFRlc3QodW5kZWZpbmVkKTtcblx0XHRcdFx0Y2xlYW51cFJ1bm5pbmdUZXN0KCk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHRcdGlmICh0ZXN0LnJlc3VsdC5zdGF0ZSA9PT0gXCJwYXNzXCIpIHtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRpZiAocmV0cnlDb3VudCA8IHJldHJ5KSB7XG5cdFx0XHRcdGNvbnN0IHNob3VsZFJldHJ5ID0gcGFzc2VzUmV0cnlDb25kaXRpb24odGVzdCwgdGVzdC5yZXN1bHQuZXJyb3JzKTtcblx0XHRcdFx0aWYgKCFzaG91bGRSZXRyeSkge1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRlc3QucmVzdWx0LnN0YXRlID0gXCJydW5cIjtcblx0XHRcdFx0dGVzdC5yZXN1bHQucmV0cnlDb3VudCA9ICh0ZXN0LnJlc3VsdC5yZXRyeUNvdW50ID8/IDApICsgMTtcblx0XHRcdFx0Y29uc3QgZGVsYXkgPSBnZXRSZXRyeURlbGF5KHRlc3QucmV0cnkpO1xuXHRcdFx0XHRpZiAoZGVsYXkgPiAwKSB7XG5cdFx0XHRcdFx0YXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgZGVsYXkpKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0Ly8gdXBkYXRlIHJldHJ5IGluZm9cblx0XHRcdHVwZGF0ZVRhc2soXCJ0ZXN0LXJldHJpZWRcIiwgdGVzdCwgcnVubmVyKTtcblx0XHR9XG5cdH1cblx0Ly8gaWYgdGVzdCBpcyBtYXJrZWQgdG8gYmUgZmFpbGVkLCBmbGlwIHRoZSByZXN1bHRcblx0aWYgKHRlc3QuZmFpbHMpIHtcblx0XHRpZiAodGVzdC5yZXN1bHQuc3RhdGUgPT09IFwicGFzc1wiKSB7XG5cdFx0XHRjb25zdCBlcnJvciA9IHByb2Nlc3NFcnJvcihuZXcgRXJyb3IoXCJFeHBlY3QgdGVzdCB0byBmYWlsXCIpKTtcblx0XHRcdHRlc3QucmVzdWx0LnN0YXRlID0gXCJmYWlsXCI7XG5cdFx0XHR0ZXN0LnJlc3VsdC5lcnJvcnMgPSBbZXJyb3JdO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0ZXN0LnJlc3VsdC5zdGF0ZSA9IFwicGFzc1wiO1xuXHRcdFx0dGVzdC5yZXN1bHQuZXJyb3JzID0gdW5kZWZpbmVkO1xuXHRcdH1cblx0fVxuXHRjbGVhbnVwUnVubmluZ1Rlc3QoKTtcblx0c2V0Q3VycmVudFRlc3QodW5kZWZpbmVkKTtcblx0dGVzdC5yZXN1bHQuZHVyYXRpb24gPSBub3coKSAtIHN0YXJ0O1xuXHRhd2FpdCBydW5uZXIub25BZnRlclJ1blRhc2s/Lih0ZXN0KTtcblx0dXBkYXRlVGFzayhcInRlc3QtZmluaXNoZWRcIiwgdGVzdCwgcnVubmVyKTtcbn1cbmZ1bmN0aW9uIGZhaWxUYXNrKHJlc3VsdCwgZXJyLCBkaWZmT3B0aW9ucykge1xuXHRpZiAoZXJyIGluc3RhbmNlb2YgUGVuZGluZ0Vycm9yKSB7XG5cdFx0cmVzdWx0LnN0YXRlID0gXCJza2lwXCI7XG5cdFx0cmVzdWx0Lm5vdGUgPSBlcnIubm90ZTtcblx0XHRyZXN1bHQucGVuZGluZyA9IHRydWU7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdGlmIChlcnIgaW5zdGFuY2VvZiBUZXN0UnVuQWJvcnRFcnJvcikge1xuXHRcdHJlc3VsdC5zdGF0ZSA9IFwic2tpcFwiO1xuXHRcdHJlc3VsdC5ub3RlID0gZXJyLm1lc3NhZ2U7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdHJlc3VsdC5zdGF0ZSA9IFwiZmFpbFwiO1xuXHRjb25zdCBlcnJvcnMgPSBBcnJheS5pc0FycmF5KGVycikgPyBlcnIgOiBbZXJyXTtcblx0Zm9yIChjb25zdCBlIG9mIGVycm9ycykge1xuXHRcdGNvbnN0IGVycm9ycyA9IGUgaW5zdGFuY2VvZiBBZ2dyZWdhdGVFcnJvciA/IGUuZXJyb3JzLm1hcCgoZSkgPT4gcHJvY2Vzc0Vycm9yKGUsIGRpZmZPcHRpb25zKSkgOiBbcHJvY2Vzc0Vycm9yKGUsIGRpZmZPcHRpb25zKV07XG5cdFx0cmVzdWx0LmVycm9ycyA/Pz0gW107XG5cdFx0cmVzdWx0LmVycm9ycy5wdXNoKC4uLmVycm9ycyk7XG5cdH1cbn1cbmZ1bmN0aW9uIG1hcmtUYXNrc0FzU2tpcHBlZChzdWl0ZSwgcnVubmVyKSB7XG5cdHN1aXRlLnRhc2tzLmZvckVhY2goKHQpID0+IHtcblx0XHR0Lm1vZGUgPSBcInNraXBcIjtcblx0XHR0LnJlc3VsdCA9IHtcblx0XHRcdC4uLnQucmVzdWx0LFxuXHRcdFx0c3RhdGU6IFwic2tpcFwiXG5cdFx0fTtcblx0XHR1cGRhdGVUYXNrKFwidGVzdC1maW5pc2hlZFwiLCB0LCBydW5uZXIpO1xuXHRcdGlmICh0LnR5cGUgPT09IFwic3VpdGVcIikge1xuXHRcdFx0bWFya1Rhc2tzQXNTa2lwcGVkKHQsIHJ1bm5lcik7XG5cdFx0fVxuXHR9KTtcbn1cbmZ1bmN0aW9uIG1hcmtQZW5kaW5nVGFza3NBc1NraXBwZWQoc3VpdGUsIHJ1bm5lciwgbm90ZSkge1xuXHRzdWl0ZS50YXNrcy5mb3JFYWNoKCh0KSA9PiB7XG5cdFx0aWYgKCF0LnJlc3VsdCB8fCB0LnJlc3VsdC5zdGF0ZSA9PT0gXCJydW5cIikge1xuXHRcdFx0dC5tb2RlID0gXCJza2lwXCI7XG5cdFx0XHR0LnJlc3VsdCA9IHtcblx0XHRcdFx0Li4udC5yZXN1bHQsXG5cdFx0XHRcdHN0YXRlOiBcInNraXBcIixcblx0XHRcdFx0bm90ZVxuXHRcdFx0fTtcblx0XHRcdHVwZGF0ZVRhc2soXCJ0ZXN0LWNhbmNlbFwiLCB0LCBydW5uZXIpO1xuXHRcdH1cblx0XHRpZiAodC50eXBlID09PSBcInN1aXRlXCIpIHtcblx0XHRcdG1hcmtQZW5kaW5nVGFza3NBc1NraXBwZWQodCwgcnVubmVyLCBub3RlKTtcblx0XHR9XG5cdH0pO1xufVxuYXN5bmMgZnVuY3Rpb24gcnVuU3VpdGUoc3VpdGUsIHJ1bm5lcikge1xuXHRhd2FpdCBydW5uZXIub25CZWZvcmVSdW5TdWl0ZT8uKHN1aXRlKTtcblx0aWYgKHN1aXRlLnJlc3VsdD8uc3RhdGUgPT09IFwiZmFpbFwiKSB7XG5cdFx0bWFya1Rhc2tzQXNTa2lwcGVkKHN1aXRlLCBydW5uZXIpO1xuXHRcdC8vIGZhaWxlZCBkdXJpbmcgY29sbGVjdGlvblxuXHRcdHVwZGF0ZVRhc2soXCJzdWl0ZS1mYWlsZWQtZWFybHlcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdGNvbnN0IHN0YXJ0ID0gbm93KCk7XG5cdGNvbnN0IG1vZGUgPSBzdWl0ZS5tb2RlO1xuXHRzdWl0ZS5yZXN1bHQgPSB7XG5cdFx0c3RhdGU6IG1vZGUgPT09IFwic2tpcFwiIHx8IG1vZGUgPT09IFwidG9kb1wiID8gbW9kZSA6IFwicnVuXCIsXG5cdFx0c3RhcnRUaW1lOiB1bml4Tm93KClcblx0fTtcblx0Y29uc3QgJCA9IHJ1bm5lci50cmFjZTtcblx0dXBkYXRlVGFzayhcInN1aXRlLXByZXBhcmVcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdGxldCBiZWZvcmVBbGxDbGVhbnVwcyA9IFtdO1xuXHRpZiAoc3VpdGUubW9kZSA9PT0gXCJza2lwXCIpIHtcblx0XHRzdWl0ZS5yZXN1bHQuc3RhdGUgPSBcInNraXBcIjtcblx0XHR1cGRhdGVUYXNrKFwic3VpdGUtZmluaXNoZWRcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdH0gZWxzZSBpZiAoc3VpdGUubW9kZSA9PT0gXCJ0b2RvXCIpIHtcblx0XHRzdWl0ZS5yZXN1bHQuc3RhdGUgPSBcInRvZG9cIjtcblx0XHR1cGRhdGVUYXNrKFwic3VpdGUtZmluaXNoZWRcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdH0gZWxzZSB7XG5cdFx0bGV0IHN1aXRlUmFuID0gZmFsc2U7XG5cdFx0dHJ5IHtcblx0XHRcdGF3YWl0IGNhbGxBcm91bmRBbGxIb29rcyhzdWl0ZSwgYXN5bmMgKCkgPT4ge1xuXHRcdFx0XHRzdWl0ZVJhbiA9IHRydWU7XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0Ly8gYmVmb3JlQWxsXG5cdFx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRcdGJlZm9yZUFsbENsZWFudXBzID0gYXdhaXQgJChcInN1aXRlLmJlZm9yZUFsbFwiLCAoKSA9PiBjYWxsU3VpdGVIb29rKHN1aXRlLCBzdWl0ZSwgXCJiZWZvcmVBbGxcIiwgcnVubmVyLCBbc3VpdGVdKSk7XG5cdFx0XHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRcdFx0ZmFpbFRhc2soc3VpdGUucmVzdWx0LCBlLCBydW5uZXIuY29uZmlnLmRpZmZPcHRpb25zKTtcblx0XHRcdFx0XHRcdG1hcmtUYXNrc0FzU2tpcHBlZChzdWl0ZSwgcnVubmVyKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Ly8gcnVuIHN1aXRlIGNoaWxkcmVuXG5cdFx0XHRcdFx0aWYgKHJ1bm5lci5ydW5TdWl0ZSkge1xuXHRcdFx0XHRcdFx0YXdhaXQgcnVubmVyLnJ1blN1aXRlKHN1aXRlKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0Zm9yIChsZXQgdGFza3NHcm91cCBvZiBwYXJ0aXRpb25TdWl0ZUNoaWxkcmVuKHN1aXRlKSkge1xuXHRcdFx0XHRcdFx0XHRpZiAodGFza3NHcm91cFswXS5jb25jdXJyZW50ID09PSB0cnVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgZ3JvdXBMaW1pdGVyID0gbGltaXRDb25jdXJyZW5jeShydW5uZXIuY29uZmlnLm1heENvbmN1cnJlbmN5KTtcblx0XHRcdFx0XHRcdFx0XHRhd2FpdCBQcm9taXNlLmFsbCh0YXNrc0dyb3VwLm1hcCgoYykgPT4gZ3JvdXBMaW1pdGVyKCgpID0+IHJ1blN1aXRlQ2hpbGQoYywgcnVubmVyKSkpKTtcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRjb25zdCB7IHNlcXVlbmNlIH0gPSBydW5uZXIuY29uZmlnO1xuXHRcdFx0XHRcdFx0XHRcdGlmIChzdWl0ZS5zaHVmZmxlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBydW4gZGVzY3JpYmUgYmxvY2sgaW5kZXBlbmRlbnRseSBmcm9tIHRlc3RzXG5cdFx0XHRcdFx0XHRcdFx0XHRjb25zdCBzdWl0ZXMgPSB0YXNrc0dyb3VwLmZpbHRlcigoZ3JvdXApID0+IGdyb3VwLnR5cGUgPT09IFwic3VpdGVcIik7XG5cdFx0XHRcdFx0XHRcdFx0XHRjb25zdCB0ZXN0cyA9IHRhc2tzR3JvdXAuZmlsdGVyKChncm91cCkgPT4gZ3JvdXAudHlwZSA9PT0gXCJ0ZXN0XCIpO1xuXHRcdFx0XHRcdFx0XHRcdFx0Y29uc3QgZ3JvdXBzID0gc2h1ZmZsZShbc3VpdGVzLCB0ZXN0c10sIHNlcXVlbmNlLnNlZWQpO1xuXHRcdFx0XHRcdFx0XHRcdFx0dGFza3NHcm91cCA9IGdyb3Vwcy5mbGF0TWFwKChncm91cCkgPT4gc2h1ZmZsZShncm91cCwgc2VxdWVuY2Uuc2VlZCkpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRmb3IgKGNvbnN0IGMgb2YgdGFza3NHcm91cCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0YXdhaXQgcnVuU3VpdGVDaGlsZChjLCBydW5uZXIpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSBmaW5hbGx5IHtcblx0XHRcdFx0XHQvLyBhZnRlckFsbCBydW5zIGV2ZW4gaWYgYmVmb3JlQWxsIG9yIHN1aXRlIGNoaWxkcmVuIGZhaWxcblx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0YXdhaXQgJChcInN1aXRlLmFmdGVyQWxsXCIsICgpID0+IGNhbGxTdWl0ZUhvb2soc3VpdGUsIHN1aXRlLCBcImFmdGVyQWxsXCIsIHJ1bm5lciwgW3N1aXRlXSkpO1xuXHRcdFx0XHRcdFx0aWYgKGJlZm9yZUFsbENsZWFudXBzLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRhd2FpdCAkKFwic3VpdGUuY2xlYW51cFwiLCAoKSA9PiBjYWxsQ2xlYW51cEhvb2tzKHJ1bm5lciwgYmVmb3JlQWxsQ2xlYW51cHMpKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmIChzdWl0ZS5maWxlID09PSBzdWl0ZSkge1xuXHRcdFx0XHRcdFx0XHRjb25zdCBjb250ZXh0cyA9IFRlc3RGaXh0dXJlcy5nZXRGaWxlQ29udGV4dHMoc3VpdGUuZmlsZSk7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IFByb21pc2UuYWxsKGNvbnRleHRzLm1hcCgoY29udGV4dCkgPT4gY2FsbEZpeHR1cmVDbGVhbnVwKGNvbnRleHQpKSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRcdFx0ZmFpbFRhc2soc3VpdGUucmVzdWx0LCBlLCBydW5uZXIuY29uZmlnLmRpZmZPcHRpb25zKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdC8vIG1hcmsgdGFza3MgYXMgc2tpcHBlZCBpZiBhcm91bmRBbGwgZmFpbGVkIGJlZm9yZSB0aGUgc3VpdGUgY2FsbGJhY2sgd2FzIGV4ZWN1dGVkXG5cdFx0XHRpZiAoIXN1aXRlUmFuKSB7XG5cdFx0XHRcdG1hcmtUYXNrc0FzU2tpcHBlZChzdWl0ZSwgcnVubmVyKTtcblx0XHRcdH1cblx0XHRcdGZhaWxUYXNrKHN1aXRlLnJlc3VsdCwgZSwgcnVubmVyLmNvbmZpZy5kaWZmT3B0aW9ucyk7XG5cdFx0fVxuXHRcdGlmIChzdWl0ZS5tb2RlID09PSBcInJ1blwiIHx8IHN1aXRlLm1vZGUgPT09IFwicXVldWVkXCIpIHtcblx0XHRcdGlmICghcnVubmVyLmNvbmZpZy5wYXNzV2l0aE5vVGVzdHMgJiYgIWhhc1Rlc3RzKHN1aXRlKSkge1xuXHRcdFx0XHRzdWl0ZS5yZXN1bHQuc3RhdGUgPSBcImZhaWxcIjtcblx0XHRcdFx0aWYgKCFzdWl0ZS5yZXN1bHQuZXJyb3JzPy5sZW5ndGgpIHtcblx0XHRcdFx0XHRjb25zdCBlcnJvciA9IHByb2Nlc3NFcnJvcihuZXcgRXJyb3IoYE5vIHRlc3QgZm91bmQgaW4gc3VpdGUgJHtzdWl0ZS5uYW1lfWApKTtcblx0XHRcdFx0XHRzdWl0ZS5yZXN1bHQuZXJyb3JzID0gW2Vycm9yXTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIGlmIChoYXNGYWlsZWQoc3VpdGUpKSB7XG5cdFx0XHRcdHN1aXRlLnJlc3VsdC5zdGF0ZSA9IFwiZmFpbFwiO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0c3VpdGUucmVzdWx0LnN0YXRlID0gXCJwYXNzXCI7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHN1aXRlLnJlc3VsdC5kdXJhdGlvbiA9IG5vdygpIC0gc3RhcnQ7XG5cdFx0YXdhaXQgcnVubmVyLm9uQWZ0ZXJSdW5TdWl0ZT8uKHN1aXRlKTtcblx0XHR1cGRhdGVUYXNrKFwic3VpdGUtZmluaXNoZWRcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdH1cbn1cbmFzeW5jIGZ1bmN0aW9uIHJ1blN1aXRlQ2hpbGQoYywgcnVubmVyKSB7XG5cdGNvbnN0ICQgPSBydW5uZXIudHJhY2U7XG5cdGlmIChjLnR5cGUgPT09IFwidGVzdFwiKSB7XG5cdFx0cmV0dXJuICQoXCJydW4udGVzdFwiLCB7XG5cdFx0XHRcInZpdGVzdC50ZXN0LmlkXCI6IGMuaWQsXG5cdFx0XHRcInZpdGVzdC50ZXN0Lm5hbWVcIjogYy5uYW1lLFxuXHRcdFx0XCJ2aXRlc3QudGVzdC5tb2RlXCI6IGMubW9kZSxcblx0XHRcdFwidml0ZXN0LnRlc3QudGltZW91dFwiOiBjLnRpbWVvdXQsXG5cdFx0XHRcImNvZGUuZmlsZS5wYXRoXCI6IGMuZmlsZS5maWxlcGF0aCxcblx0XHRcdFwiY29kZS5saW5lLm51bWJlclwiOiBjLmxvY2F0aW9uPy5saW5lLFxuXHRcdFx0XCJjb2RlLmNvbHVtbi5udW1iZXJcIjogYy5sb2NhdGlvbj8uY29sdW1uXG5cdFx0fSwgKCkgPT4gcnVuVGVzdChjLCBydW5uZXIpKTtcblx0fSBlbHNlIGlmIChjLnR5cGUgPT09IFwic3VpdGVcIikge1xuXHRcdHJldHVybiAkKFwicnVuLnN1aXRlXCIsIHtcblx0XHRcdFwidml0ZXN0LnN1aXRlLmlkXCI6IGMuaWQsXG5cdFx0XHRcInZpdGVzdC5zdWl0ZS5uYW1lXCI6IGMubmFtZSxcblx0XHRcdFwidml0ZXN0LnN1aXRlLm1vZGVcIjogYy5tb2RlLFxuXHRcdFx0XCJjb2RlLmZpbGUucGF0aFwiOiBjLmZpbGUuZmlsZXBhdGgsXG5cdFx0XHRcImNvZGUubGluZS5udW1iZXJcIjogYy5sb2NhdGlvbj8ubGluZSxcblx0XHRcdFwiY29kZS5jb2x1bW4ubnVtYmVyXCI6IGMubG9jYXRpb24/LmNvbHVtblxuXHRcdH0sICgpID0+IHJ1blN1aXRlKGMsIHJ1bm5lcikpO1xuXHR9XG59XG5hc3luYyBmdW5jdGlvbiBydW5GaWxlcyhmaWxlcywgcnVubmVyKSB7XG5cdGxpbWl0TWF4Q29uY3VycmVuY3kgPz89IGxpbWl0Q29uY3VycmVuY3kocnVubmVyLmNvbmZpZy5tYXhDb25jdXJyZW5jeSk7XG5cdGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuXHRcdGlmICghZmlsZS50YXNrcy5sZW5ndGggJiYgIXJ1bm5lci5jb25maWcucGFzc1dpdGhOb1Rlc3RzKSB7XG5cdFx0XHRpZiAoIWZpbGUucmVzdWx0Py5lcnJvcnM/Lmxlbmd0aCkge1xuXHRcdFx0XHRjb25zdCBlcnJvciA9IHByb2Nlc3NFcnJvcihuZXcgRXJyb3IoYE5vIHRlc3Qgc3VpdGUgZm91bmQgaW4gZmlsZSAke2ZpbGUuZmlsZXBhdGh9YCkpO1xuXHRcdFx0XHRmaWxlLnJlc3VsdCA9IHtcblx0XHRcdFx0XHRzdGF0ZTogXCJmYWlsXCIsXG5cdFx0XHRcdFx0ZXJyb3JzOiBbZXJyb3JdXG5cdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGF3YWl0IHJ1bm5lci50cmFjZShcInJ1bi5zcGVjXCIsIHtcblx0XHRcdFwiY29kZS5maWxlLnBhdGhcIjogZmlsZS5maWxlcGF0aCxcblx0XHRcdFwidml0ZXN0LnN1aXRlLnRhc2tzLmxlbmd0aFwiOiBmaWxlLnRhc2tzLmxlbmd0aFxuXHRcdH0sICgpID0+IHJ1blN1aXRlKGZpbGUsIHJ1bm5lcikpO1xuXHR9XG59XG5jb25zdCB3b3JrZXJSdW5uZXJzID0gbmV3IFdlYWtTZXQoKTtcbmZ1bmN0aW9uIGRlZmF1bHRUcmFjZShfLCBhdHRyaWJ1dGVzLCBjYikge1xuXHRpZiAodHlwZW9mIGF0dHJpYnV0ZXMgPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdHJldHVybiBhdHRyaWJ1dGVzKCk7XG5cdH1cblx0cmV0dXJuIGNiKCk7XG59XG5hc3luYyBmdW5jdGlvbiBzdGFydFRlc3RzKHNwZWNzLCBydW5uZXIpIHtcblx0cnVubmVyLnRyYWNlID8/PSBkZWZhdWx0VHJhY2U7XG5cdGNvbnN0IGNhbmNlbCA9IHJ1bm5lci5jYW5jZWw/LmJpbmQocnVubmVyKTtcblx0Ly8gSWRlYWxseSwgd2UgbmVlZCB0byBoYXZlIGFuIGV2ZW50IGxpc3RlbmVyIGZvciB0aGlzLCBidXQgb25seSBoYXZlIGEgcnVubmVyIGhlcmUuXG5cdC8vIEFkZGluZyBhbm90aGVyIG9uQ2FuY2VsIGZlbHQgd3JvbmcgKG1heWJlIGl0IG5lZWRzIHRvIGJlIHJlZmFjdG9yZWQpXG5cdHJ1bm5lci5jYW5jZWwgPSAocmVhc29uKSA9PiB7XG5cdFx0Ly8gV2UgaW50ZW50aW9uYWxseSBjcmVhdGUgb25seSBvbmUgZXJyb3Igc2luY2UgdGhlcmUgaXMgb25seSBvbmUgdGVzdCBydW4gdGhhdCBjYW4gYmUgY2FuY2VsbGVkXG5cdFx0Y29uc3QgZXJyb3IgPSBuZXcgVGVzdFJ1bkFib3J0RXJyb3IoXCJUaGUgdGVzdCBydW4gd2FzIGFib3J0ZWQgYnkgdGhlIHVzZXIuXCIsIHJlYXNvbik7XG5cdFx0Z2V0UnVubmluZ1Rlc3RzKCkuZm9yRWFjaCgodGVzdCkgPT4ge1xuXHRcdFx0YWJvcnRDb250ZXh0U2lnbmFsKHRlc3QuY29udGV4dCwgZXJyb3IpO1xuXHRcdFx0bWFya1BlbmRpbmdUYXNrc0FzU2tpcHBlZCh0ZXN0LmZpbGUsIHJ1bm5lciwgZXJyb3IubWVzc2FnZSk7XG5cdFx0fSk7XG5cdFx0cmV0dXJuIGNhbmNlbD8uKHJlYXNvbik7XG5cdH07XG5cdGlmICghd29ya2VyUnVubmVycy5oYXMocnVubmVyKSkge1xuXHRcdHJ1bm5lci5vbkNsZWFudXBXb3JrZXJDb250ZXh0Py4oYXN5bmMgKCkgPT4ge1xuXHRcdFx0YXdhaXQgUHJvbWlzZS5hbGwoWy4uLlRlc3RGaXh0dXJlcy5nZXRXb3JrZXJDb250ZXh0cygpXS5tYXAoKGNvbnRleHQpID0+IGNhbGxGaXh0dXJlQ2xlYW51cChjb250ZXh0KSkpLmZpbmFsbHkoKCkgPT4ge1xuXHRcdFx0XHRUZXN0Rml4dHVyZXMuY2xlYXJEZWZpbml0aW9ucygpO1xuXHRcdFx0fSk7XG5cdFx0fSk7XG5cdFx0d29ya2VyUnVubmVycy5hZGQocnVubmVyKTtcblx0fVxuXHR0cnkge1xuXHRcdGNvbnN0IHBhdGhzID0gc3BlY3MubWFwKChmKSA9PiB0eXBlb2YgZiA9PT0gXCJzdHJpbmdcIiA/IGYgOiBmLmZpbGVwYXRoKTtcblx0XHRhd2FpdCBydW5uZXIub25CZWZvcmVDb2xsZWN0Py4ocGF0aHMpO1xuXHRcdGNvbnN0IGZpbGVzID0gYXdhaXQgY29sbGVjdFRlc3RzKHNwZWNzLCBydW5uZXIpO1xuXHRcdGF3YWl0IHJ1bm5lci5vbkNvbGxlY3RlZD8uKGZpbGVzKTtcblx0XHRhd2FpdCBydW5uZXIub25CZWZvcmVSdW5GaWxlcz8uKGZpbGVzKTtcblx0XHRhd2FpdCBydW5GaWxlcyhmaWxlcywgcnVubmVyKTtcblx0XHRhd2FpdCBydW5uZXIub25BZnRlclJ1bkZpbGVzPy4oZmlsZXMpO1xuXHRcdGF3YWl0IGZpbmlzaFNlbmRUYXNrc1VwZGF0ZShydW5uZXIpO1xuXHRcdHJldHVybiBmaWxlcztcblx0fSBmaW5hbGx5IHtcblx0XHRydW5uZXIuY2FuY2VsID0gY2FuY2VsO1xuXHR9XG59XG5hc3luYyBmdW5jdGlvbiBwdWJsaWNDb2xsZWN0KHNwZWNzLCBydW5uZXIpIHtcblx0cnVubmVyLnRyYWNlID8/PSBkZWZhdWx0VHJhY2U7XG5cdGNvbnN0IHBhdGhzID0gc3BlY3MubWFwKChmKSA9PiB0eXBlb2YgZiA9PT0gXCJzdHJpbmdcIiA/IGYgOiBmLmZpbGVwYXRoKTtcblx0YXdhaXQgcnVubmVyLm9uQmVmb3JlQ29sbGVjdD8uKHBhdGhzKTtcblx0Y29uc3QgZmlsZXMgPSBhd2FpdCBjb2xsZWN0VGVzdHMoc3BlY3MsIHJ1bm5lcik7XG5cdGF3YWl0IHJ1bm5lci5vbkNvbGxlY3RlZD8uKGZpbGVzKTtcblx0cmV0dXJuIGZpbGVzO1xufVxuXG4vKipcbiogQGV4cGVyaW1lbnRhbFxuKiBAYWR2YW5jZWRcbipcbiogUmVjb3JkcyBhIGN1c3RvbSB0ZXN0IGFydGlmYWN0IGR1cmluZyB0ZXN0IGV4ZWN1dGlvbi5cbipcbiogVGhpcyBmdW5jdGlvbiBhbGxvd3MgeW91IHRvIGF0dGFjaCBzdHJ1Y3R1cmVkIGRhdGEsIGZpbGVzLCBvciBtZXRhZGF0YSB0byBhIHRlc3QuXG4qXG4qIFZpdGVzdCBhdXRvbWF0aWNhbGx5IGluamVjdHMgdGhlIHNvdXJjZSBsb2NhdGlvbiB3aGVyZSB0aGUgYXJ0aWZhY3Qgd2FzIGNyZWF0ZWQgYW5kIG1hbmFnZXMgYW55IGF0dGFjaG1lbnRzIHlvdSBpbmNsdWRlLlxuKlxuKiAqKk5vdGU6KiogYXJ0aWZhY3RzIG11c3QgYmUgcmVjb3JkZWQgYmVmb3JlIHRoZSB0YXNrIGlzIHJlcG9ydGVkLiBBbnkgYXJ0aWZhY3RzIHJlY29yZGVkIGFmdGVyIHRoYXQgd2lsbCBub3QgYmUgaW5jbHVkZWQgaW4gdGhlIHRhc2suXG4qXG4qIEBwYXJhbSB0YXNrIC0gVGhlIHRlc3QgdGFzayBjb250ZXh0LCB0eXBpY2FsbHkgYWNjZXNzZWQgdmlhIGB0aGlzLnRhc2tgIGluIGN1c3RvbSBtYXRjaGVycyBvciBgY29udGV4dC50YXNrYCBpbiB0ZXN0c1xuKiBAcGFyYW0gYXJ0aWZhY3QgLSBUaGUgYXJ0aWZhY3QgdG8gcmVjb3JkLiBNdXN0IGV4dGVuZCB7QGxpbmtjb2RlIFRlc3RBcnRpZmFjdEJhc2V9XG4qXG4qIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZWNvcmRlZCBhcnRpZmFjdCB3aXRoIGxvY2F0aW9uIGluamVjdGVkXG4qXG4qIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdGVzdCBydW5uZXIgZG9lc24ndCBzdXBwb3J0IGFydGlmYWN0c1xuKlxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBJbiBhIGN1c3RvbSBhc3NlcnRpb25cbiogYXN5bmMgZnVuY3Rpb24gdG9IYXZlVmFsaWRTY2hlbWEodGhpczogTWF0Y2hlclN0YXRlLCBhY3R1YWw6IHVua25vd24pIHtcbiogICBjb25zdCB2YWxpZGF0aW9uID0gdmFsaWRhdGVTY2hlbWEoYWN0dWFsKVxuKlxuKiAgIGF3YWl0IHJlY29yZEFydGlmYWN0KHRoaXMudGFzaywge1xuKiAgICAgdHlwZTogJ215LXBsdWdpbjpzY2hlbWEtdmFsaWRhdGlvbicsXG4qICAgICBwYXNzZWQ6IHZhbGlkYXRpb24udmFsaWQsXG4qICAgICBlcnJvcnM6IHZhbGlkYXRpb24uZXJyb3JzLFxuKiAgIH0pXG4qXG4qICAgcmV0dXJuIHsgcGFzczogdmFsaWRhdGlvbi52YWxpZCwgbWVzc2FnZTogKCkgPT4gJy4uLicgfVxuKiB9XG4qIGBgYFxuKi9cbmFzeW5jIGZ1bmN0aW9uIHJlY29yZEFydGlmYWN0KHRhc2ssIGFydGlmYWN0KSB7XG5cdGNvbnN0IHJ1bm5lciA9IGdldFJ1bm5lcigpO1xuXHRjb25zdCBzdGFjayA9IGZpbmRUZXN0RmlsZVN0YWNrVHJhY2UodGFzay5maWxlLmZpbGVwYXRoLCBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRVwiKS5zdGFjayk7XG5cdGlmIChzdGFjaykge1xuXHRcdGFydGlmYWN0LmxvY2F0aW9uID0ge1xuXHRcdFx0ZmlsZTogc3RhY2suZmlsZSxcblx0XHRcdGxpbmU6IHN0YWNrLmxpbmUsXG5cdFx0XHRjb2x1bW46IHN0YWNrLmNvbHVtblxuXHRcdH07XG5cdFx0aWYgKGFydGlmYWN0LnR5cGUgPT09IFwiaW50ZXJuYWw6YW5ub3RhdGlvblwiKSB7XG5cdFx0XHRhcnRpZmFjdC5hbm5vdGF0aW9uLmxvY2F0aW9uID0gYXJ0aWZhY3QubG9jYXRpb247XG5cdFx0fVxuXHR9XG5cdGlmIChBcnJheS5pc0FycmF5KGFydGlmYWN0LmF0dGFjaG1lbnRzKSkge1xuXHRcdGZvciAoY29uc3QgYXR0YWNobWVudCBvZiBhcnRpZmFjdC5hdHRhY2htZW50cykge1xuXHRcdFx0bWFuYWdlQXJ0aWZhY3RBdHRhY2htZW50KGF0dGFjaG1lbnQpO1xuXHRcdH1cblx0fVxuXHQvLyBhbm5vdGF0aW9ucyB3b24ndCByZXNvbHZlIGFzIGFydGlmYWN0cyBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkgdW50aWwgbmV4dCBtYWpvclxuXHRpZiAoYXJ0aWZhY3QudHlwZSA9PT0gXCJpbnRlcm5hbDphbm5vdGF0aW9uXCIpIHtcblx0XHRyZXR1cm4gYXJ0aWZhY3Q7XG5cdH1cblx0aWYgKCFydW5uZXIub25UZXN0QXJ0aWZhY3RSZWNvcmQpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYFRlc3QgcnVubmVyIGRvZXNuJ3Qgc3VwcG9ydCB0ZXN0IGFydGlmYWN0cy5gKTtcblx0fVxuXHRhd2FpdCBmaW5pc2hTZW5kVGFza3NVcGRhdGUocnVubmVyKTtcblx0Y29uc3QgcmVzb2x2ZWRBcnRpZmFjdCA9IGF3YWl0IHJ1bm5lci5vblRlc3RBcnRpZmFjdFJlY29yZCh0YXNrLCBhcnRpZmFjdCk7XG5cdHRhc2suYXJ0aWZhY3RzLnB1c2gocmVzb2x2ZWRBcnRpZmFjdCk7XG5cdHJldHVybiByZXNvbHZlZEFydGlmYWN0O1xufVxuY29uc3QgdGFibGUgPSBbXTtcbmZvciAobGV0IGkgPSA2NTsgaSA8IDkxOyBpKyspIHtcblx0dGFibGUucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGkpKTtcbn1cbmZvciAobGV0IGkgPSA5NzsgaSA8IDEyMzsgaSsrKSB7XG5cdHRhYmxlLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShpKSk7XG59XG5mb3IgKGxldCBpID0gMDsgaSA8IDEwOyBpKyspIHtcblx0dGFibGUucHVzaChpLnRvU3RyaW5nKDEwKSk7XG59XG50YWJsZS5wdXNoKFwiK1wiLCBcIi9cIik7XG5mdW5jdGlvbiBlbmNvZGVVaW50OEFycmF5KGJ5dGVzKSB7XG5cdGxldCBiYXNlNjQgPSBcIlwiO1xuXHRjb25zdCBsZW4gPSBieXRlcy5ieXRlTGVuZ3RoO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IGxlbjsgaSArPSAzKSB7XG5cdFx0aWYgKGxlbiA9PT0gaSArIDEpIHtcblx0XHRcdGNvbnN0IGEgPSAoYnl0ZXNbaV0gJiAyNTIpID4+IDI7XG5cdFx0XHRjb25zdCBiID0gKGJ5dGVzW2ldICYgMykgPDwgNDtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVthXTtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVtiXTtcblx0XHRcdGJhc2U2NCArPSBcIj09XCI7XG5cdFx0fSBlbHNlIGlmIChsZW4gPT09IGkgKyAyKSB7XG5cdFx0XHRjb25zdCBhID0gKGJ5dGVzW2ldICYgMjUyKSA+PiAyO1xuXHRcdFx0Y29uc3QgYiA9IChieXRlc1tpXSAmIDMpIDw8IDQgfCAoYnl0ZXNbaSArIDFdICYgMjQwKSA+PiA0O1xuXHRcdFx0Y29uc3QgYyA9IChieXRlc1tpICsgMV0gJiAxNSkgPDwgMjtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVthXTtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVtiXTtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVtjXTtcblx0XHRcdGJhc2U2NCArPSBcIj1cIjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y29uc3QgYSA9IChieXRlc1tpXSAmIDI1MikgPj4gMjtcblx0XHRcdGNvbnN0IGIgPSAoYnl0ZXNbaV0gJiAzKSA8PCA0IHwgKGJ5dGVzW2kgKyAxXSAmIDI0MCkgPj4gNDtcblx0XHRcdGNvbnN0IGMgPSAoYnl0ZXNbaSArIDFdICYgMTUpIDw8IDIgfCAoYnl0ZXNbaSArIDJdICYgMTkyKSA+PiA2O1xuXHRcdFx0Y29uc3QgZCA9IGJ5dGVzW2kgKyAyXSAmIDYzO1xuXHRcdFx0YmFzZTY0ICs9IHRhYmxlW2FdO1xuXHRcdFx0YmFzZTY0ICs9IHRhYmxlW2JdO1xuXHRcdFx0YmFzZTY0ICs9IHRhYmxlW2NdO1xuXHRcdFx0YmFzZTY0ICs9IHRhYmxlW2RdO1xuXHRcdH1cblx0fVxuXHRyZXR1cm4gYmFzZTY0O1xufVxuLyoqXG4qIFJlY29yZHMgYW4gYXN5bmMgb3BlcmF0aW9uIGFzc29jaWF0ZWQgd2l0aCBhIHRlc3QgdGFzay5cbipcbiogVGhpcyBmdW5jdGlvbiB0cmFja3MgcHJvbWlzZXMgdGhhdCBzaG91bGQgYmUgYXdhaXRlZCBiZWZvcmUgYSB0ZXN0IGNvbXBsZXRlcy5cbiogVGhlIHByb21pc2UgaXMgYXV0b21hdGljYWxseSByZW1vdmVkIGZyb20gdGhlIHRlc3QncyBwcm9taXNlIGxpc3Qgb25jZSBpdCBzZXR0bGVzLlxuKi9cbmZ1bmN0aW9uIHJlY29yZEFzeW5jT3BlcmF0aW9uKHRlc3QsIHByb21pc2UpIHtcblx0Ly8gaWYgcHJvbWlzZSBpcyBleHBsaWNpdGx5IGF3YWl0ZWQsIHJlbW92ZSBpdCBmcm9tIHRoZSBsaXN0XG5cdHByb21pc2UgPSBwcm9taXNlLmZpbmFsbHkoKCkgPT4ge1xuXHRcdGlmICghdGVzdC5wcm9taXNlcykge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRjb25zdCBpbmRleCA9IHRlc3QucHJvbWlzZXMuaW5kZXhPZihwcm9taXNlKTtcblx0XHRpZiAoaW5kZXggIT09IC0xKSB7XG5cdFx0XHR0ZXN0LnByb21pc2VzLnNwbGljZShpbmRleCwgMSk7XG5cdFx0fVxuXHR9KTtcblx0Ly8gcmVjb3JkIHByb21pc2Vcblx0aWYgKCF0ZXN0LnByb21pc2VzKSB7XG5cdFx0dGVzdC5wcm9taXNlcyA9IFtdO1xuXHR9XG5cdHRlc3QucHJvbWlzZXMucHVzaChwcm9taXNlKTtcblx0cmV0dXJuIHByb21pc2U7XG59XG4vKipcbiogVmFsaWRhdGVzIGFuZCBwcmVwYXJlcyBhIHRlc3QgYXR0YWNobWVudCBmb3Igc2VyaWFsaXphdGlvbi5cbipcbiogVGhpcyBmdW5jdGlvbiBlbnN1cmVzIGF0dGFjaG1lbnRzIGhhdmUgZWl0aGVyIGBib2R5YCBvciBgcGF0aGAgc2V0IChidXQgbm90IGJvdGgpLCBhbmQgY29udmVydHMgYFVpbnQ4QXJyYXlgIGJvZGllcyB0byBiYXNlNjQtZW5jb2RlZCBzdHJpbmdzIGZvciBlYXNpZXIgc2VyaWFsaXphdGlvbi5cbipcbiogQHBhcmFtIGF0dGFjaG1lbnQgLSBUaGUgYXR0YWNobWVudCB0byB2YWxpZGF0ZSBhbmQgcHJlcGFyZVxuKlxuKiBAdGhyb3dzIHtUeXBlRXJyb3J9IElmIG5laXRoZXIgYGJvZHlgIG5vciBgcGF0aGAgaXMgcHJvdmlkZWRcbiogQHRocm93cyB7VHlwZUVycm9yfSBJZiBib3RoIGBib2R5YCBhbmQgYHBhdGhgIGFyZSBwcm92aWRlZFxuKi9cbmZ1bmN0aW9uIG1hbmFnZUFydGlmYWN0QXR0YWNobWVudChhdHRhY2htZW50KSB7XG5cdGlmIChhdHRhY2htZW50LmJvZHkgPT0gbnVsbCAmJiAhYXR0YWNobWVudC5wYXRoKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcihgVGVzdCBhdHRhY2htZW50IHJlcXVpcmVzIFwiYm9keVwiIG9yIFwicGF0aFwiIHRvIGJlIHNldC4gQm90aCBhcmUgbWlzc2luZy5gKTtcblx0fVxuXHRpZiAoYXR0YWNobWVudC5ib2R5ICYmIGF0dGFjaG1lbnQucGF0aCkge1xuXHRcdHRocm93IG5ldyBUeXBlRXJyb3IoYFRlc3QgYXR0YWNobWVudCByZXF1aXJlcyBvbmx5IG9uZSBvZiBcImJvZHlcIiBvciBcInBhdGhcIiB0byBiZSBzZXQuIEJvdGggYXJlIHNwZWNpZmllZC5gKTtcblx0fVxuXHRpZiAoYXR0YWNobWVudC5wYXRoICYmIGF0dGFjaG1lbnQuYm9keUVuY29kaW5nKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcihgVGVzdCBhdHRhY2htZW50IHdpdGggXCJwYXRoXCIgc2hvdWxkIG5vdCBoYXZlIFwiYm9keUVuY29kaW5nXCIgc3BlY2lmaWVkLmApO1xuXHR9XG5cdC8vIGNvbnZlcnQgdG8gYSBzdHJpbmcgc28gaXQncyBlYXNpZXIgdG8gc2VyaWFsaXNlXG5cdGlmIChhdHRhY2htZW50LmJvZHkgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG5cdFx0YXR0YWNobWVudC5ib2R5ID0gZW5jb2RlVWludDhBcnJheShhdHRhY2htZW50LmJvZHkpO1xuXHR9XG5cdGlmIChhdHRhY2htZW50LmJvZHkgIT0gbnVsbCkge1xuXHRcdGF0dGFjaG1lbnQuYm9keUVuY29kaW5nID8/PSBcImJhc2U2NFwiO1xuXHR9XG59XG5cbmV4cG9ydCB7IGNyZWF0ZVRhZ3NGaWx0ZXIgYXMgQSwgY3JlYXRlVGFza05hbWUgYXMgQiwgZmluZFRlc3RGaWxlU3RhY2tUcmFjZSBhcyBDLCBnZW5lcmF0ZUZpbGVIYXNoIGFzIEQsIGdlbmVyYXRlSGFzaCBhcyBFLCBnZXRGdWxsTmFtZSBhcyBGLCBnZXROYW1lcyBhcyBHLCBnZXRTdWl0ZXMgYXMgSCwgZ2V0VGFza3MgYXMgSSwgZ2V0VGVzdE5hbWUgYXMgSiwgZ2V0VGVzdHMgYXMgSywgaGFzRmFpbGVkIGFzIEwsIGhhc1Rlc3RzIGFzIE0sIGludGVycHJldFRhc2tNb2RlcyBhcyBOLCBpc1Rlc3RDYXNlIGFzIE8sIGxpbWl0Q29uY3VycmVuY3kgYXMgUCwgbWF0Y2hlc1RhZ3MgYXMgUSwgcGFydGl0aW9uU3VpdGVDaGlsZHJlbiBhcyBSLCBzb21lVGFza3NBcmVPbmx5IGFzIFMsIHZhbGlkYXRlVGFncyBhcyBULCBhZnRlckFsbCBhcyBhLCBhZnRlckVhY2ggYXMgYiwgYXJvdW5kQWxsIGFzIGMsIGFyb3VuZEVhY2ggYXMgZCwgYmVmb3JlQWxsIGFzIGUsIGJlZm9yZUVhY2ggYXMgZiwgY3JlYXRlVGFza0NvbGxlY3RvciBhcyBnLCBkZXNjcmliZSBhcyBoLCBnZXRDdXJyZW50U3VpdGUgYXMgaSwgZ2V0Q3VycmVudFRlc3QgYXMgaiwgZ2V0Rm4gYXMgaywgZ2V0SG9va3MgYXMgbCwgaXQgYXMgbSwgb25UZXN0RmluaXNoZWQgYXMgbiwgb25UZXN0RmFpbGVkIGFzIG8sIHB1YmxpY0NvbGxlY3QgYXMgcCwgc2V0SG9va3MgYXMgcSwgcmVjb3JkQXJ0aWZhY3QgYXMgciwgc2V0Rm4gYXMgcywgc3RhcnRUZXN0cyBhcyB0LCBzdWl0ZSBhcyB1LCB0ZXN0IGFzIHYsIHVwZGF0ZVRhc2sgYXMgdywgY2FsY3VsYXRlU3VpdGVIYXNoIGFzIHgsIGNyZWF0ZUNoYWluYWJsZSBhcyB5LCBjcmVhdGVGaWxlVGFzayBhcyB6IH07XG4iXSwieF9nb29nbGVfaWdub3JlTGlzdCI6WzBdLCJtYXBwaW5n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