@mnaoumov/obsidian-dev-toolkit 0.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -1
  3. package/bundlers/esbuild/package.json +6 -0
  4. package/bundlers/esbuild-impl/copy-to-obsidian-plugins-folder-plugin/package.json +6 -0
  5. package/bundlers/esbuild-impl/dependency/package.json +6 -0
  6. package/bundlers/esbuild-impl/fix-source-maps-plugin/package.json +6 -0
  7. package/bundlers/esbuild-impl/index/package.json +6 -0
  8. package/bundlers/esbuild-impl/obsidian-plugin-builder/package.json +6 -0
  9. package/bundlers/esbuild-impl/package.json +6 -0
  10. package/bundlers/esbuild-impl/preprocess-plugin/package.json +6 -0
  11. package/bundlers/esbuild-impl/rename-css-plugin/package.json +6 -0
  12. package/bundlers/index/package.json +6 -0
  13. package/bundlers/package.json +6 -0
  14. package/dist/demo-vault-helper/main.js +1264 -0
  15. package/dist/demo-vault-helper/manifest.json +9 -0
  16. package/dist/integration-test-plugin/main.js +54167 -0
  17. package/dist/integration-test-plugin/manifest.json +8 -0
  18. package/dist/lib/cjs/bundlers/esbuild-impl/copy-to-obsidian-plugins-folder-plugin.cjs +322 -0
  19. package/dist/lib/cjs/bundlers/esbuild-impl/copy-to-obsidian-plugins-folder-plugin.d.cts +38 -0
  20. package/dist/lib/cjs/bundlers/esbuild-impl/dependency.cjs +240 -0
  21. package/dist/lib/cjs/bundlers/esbuild-impl/dependency.d.cts +20 -0
  22. package/dist/lib/cjs/bundlers/esbuild-impl/fix-source-maps-plugin.cjs +213 -0
  23. package/dist/lib/cjs/bundlers/esbuild-impl/fix-source-maps-plugin.d.cts +34 -0
  24. package/dist/lib/cjs/bundlers/esbuild-impl/index.cjs +179 -0
  25. package/dist/lib/cjs/bundlers/esbuild-impl/index.d.cts +7 -0
  26. package/dist/lib/cjs/bundlers/esbuild-impl/obsidian-plugin-builder.cjs +362 -0
  27. package/dist/lib/cjs/bundlers/esbuild-impl/obsidian-plugin-builder.d.cts +98 -0
  28. package/dist/lib/cjs/bundlers/esbuild-impl/preprocess-plugin.cjs +234 -0
  29. package/dist/lib/cjs/bundlers/esbuild-impl/preprocess-plugin.d.cts +30 -0
  30. package/dist/lib/cjs/bundlers/esbuild-impl/rename-css-plugin.cjs +171 -0
  31. package/dist/lib/cjs/bundlers/esbuild-impl/rename-css-plugin.d.cts +14 -0
  32. package/dist/lib/cjs/bundlers/esbuild.cjs +164 -0
  33. package/dist/lib/cjs/bundlers/esbuild.d.cts +11 -0
  34. package/dist/lib/cjs/bundlers/index.cjs +167 -0
  35. package/dist/lib/cjs/bundlers/index.d.cts +3 -0
  36. package/dist/lib/cjs/demo-vault-app-json.cjs +186 -0
  37. package/dist/lib/cjs/demo-vault-app-json.d.cts +93 -0
  38. package/dist/lib/cjs/demo-vault-buttons.cjs +567 -0
  39. package/dist/lib/cjs/demo-vault-buttons.d.cts +259 -0
  40. package/dist/lib/cjs/demo-vault-coverage.cjs +713 -0
  41. package/dist/lib/cjs/demo-vault-coverage.d.cts +533 -0
  42. package/dist/lib/cjs/demo-vault.cjs +296 -0
  43. package/dist/lib/cjs/demo-vault.d.cts +33 -0
  44. package/dist/lib/cjs/formatters/dprint.cjs +160 -0
  45. package/dist/lib/cjs/formatters/dprint.d.cts +15 -0
  46. package/dist/lib/cjs/formatters/index.cjs +164 -0
  47. package/dist/lib/cjs/formatters/index.d.cts +2 -0
  48. package/dist/lib/cjs/index.cjs +194 -0
  49. package/dist/lib/cjs/index.d.cts +16 -0
  50. package/dist/lib/cjs/integration-test-setup.cjs +129 -0
  51. package/dist/lib/cjs/integration-test-setup.d.cts +33 -0
  52. package/dist/lib/cjs/integration-test-vitest-global-setup.cjs +163 -0
  53. package/dist/lib/cjs/integration-test-vitest-global-setup.d.cts +39 -0
  54. package/dist/lib/cjs/jest-setup.cjs +134 -0
  55. package/dist/lib/cjs/jest-setup.d.cts +13 -0
  56. package/dist/lib/cjs/linters/eslint-config.cjs +403 -0
  57. package/dist/lib/cjs/linters/eslint-config.d.cts +25 -0
  58. package/dist/lib/cjs/linters/eslint-rules/index.cjs +200 -0
  59. package/dist/lib/cjs/linters/eslint-rules/index.d.cts +14 -0
  60. package/dist/lib/cjs/linters/eslint-rules/manifest-description.cjs +255 -0
  61. package/dist/lib/cjs/linters/eslint-rules/manifest-description.d.cts +54 -0
  62. package/dist/lib/cjs/linters/eslint-rules/manifest-helpers.cjs +218 -0
  63. package/dist/lib/cjs/linters/eslint-rules/manifest-helpers.d.cts +141 -0
  64. package/dist/lib/cjs/linters/eslint-rules/manifest-id.cjs +215 -0
  65. package/dist/lib/cjs/linters/eslint-rules/manifest-id.d.cts +32 -0
  66. package/dist/lib/cjs/linters/eslint-rules/manifest-name.cjs +216 -0
  67. package/dist/lib/cjs/linters/eslint-rules/manifest-name.d.cts +30 -0
  68. package/dist/lib/cjs/linters/eslint-rules/manifest-schema.cjs +316 -0
  69. package/dist/lib/cjs/linters/eslint-rules/manifest-schema.d.cts +45 -0
  70. package/dist/lib/cjs/linters/eslint-rules/no-local-obsidian-internals.cjs +259 -0
  71. package/dist/lib/cjs/linters/eslint-rules/no-local-obsidian-internals.d.cts +10 -0
  72. package/dist/lib/cjs/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian.cjs +657 -0
  73. package/dist/lib/cjs/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian.d.cts +10 -0
  74. package/dist/lib/cjs/linters/eslint-rules/no-untrusted-input-events.cjs +247 -0
  75. package/dist/lib/cjs/linters/eslint-rules/no-untrusted-input-events.d.cts +10 -0
  76. package/dist/lib/cjs/linters/eslint-rules/obsidian-dev-utils-plugin.cjs +181 -0
  77. package/dist/lib/cjs/linters/eslint-rules/obsidian-dev-utils-plugin.d.cts +13 -0
  78. package/dist/lib/cjs/linters/eslint-rules/plugin-name-as-code-in-ui.cjs +263 -0
  79. package/dist/lib/cjs/linters/eslint-rules/plugin-name-as-code-in-ui.d.cts +30 -0
  80. package/dist/lib/cjs/linters/eslint-rules/plugin-name-as-code.cjs +215 -0
  81. package/dist/lib/cjs/linters/eslint-rules/plugin-name-as-code.d.cts +29 -0
  82. package/dist/lib/cjs/linters/eslint-rules/require-component-suffix.cjs +278 -0
  83. package/dist/lib/cjs/linters/eslint-rules/require-component-suffix.d.cts +18 -0
  84. package/dist/lib/cjs/linters/eslint-rules/require-plugin-api-contract-schemas.cjs +306 -0
  85. package/dist/lib/cjs/linters/eslint-rules/require-plugin-api-contract-schemas.d.cts +10 -0
  86. package/dist/lib/cjs/linters/eslint.cjs +160 -0
  87. package/dist/lib/cjs/linters/eslint.d.cts +15 -0
  88. package/dist/lib/cjs/linters/index.cjs +185 -0
  89. package/dist/lib/cjs/linters/index.d.cts +9 -0
  90. package/dist/lib/cjs/linters/markdownlint-cli2-config.cjs +171 -0
  91. package/dist/lib/cjs/linters/markdownlint-cli2-config.d.cts +12 -0
  92. package/dist/lib/cjs/linters/markdownlint-rules/index.cjs +164 -0
  93. package/dist/lib/cjs/linters/markdownlint-rules/index.d.cts +2 -0
  94. package/dist/lib/cjs/linters/markdownlint-rules/plugin-name-as-code.cjs +246 -0
  95. package/dist/lib/cjs/linters/markdownlint-rules/plugin-name-as-code.d.cts +32 -0
  96. package/dist/lib/cjs/linters/markdownlint.cjs +160 -0
  97. package/dist/lib/cjs/linters/markdownlint.d.cts +15 -0
  98. package/dist/lib/cjs/linters/obsidianmd-rule-custom-message.cjs +176 -0
  99. package/dist/lib/cjs/linters/obsidianmd-rule-custom-message.d.cts +40 -0
  100. package/dist/lib/cjs/linters/plugin-names.cjs +249 -0
  101. package/dist/lib/cjs/linters/plugin-names.d.cts +81 -0
  102. package/dist/lib/cjs/obsidian-plugin-repo-paths.cjs +216 -0
  103. package/dist/lib/cjs/obsidian-plugin-repo-paths.d.cts +253 -0
  104. package/dist/lib/cjs/setup.cjs +163 -0
  105. package/dist/lib/cjs/setup.d.cts +21 -0
  106. package/dist/lib/cjs/templates.cjs +172 -0
  107. package/dist/lib/cjs/templates.d.cts +13 -0
  108. package/dist/lib/cjs/test-runners/index.cjs +170 -0
  109. package/dist/lib/cjs/test-runners/index.d.cts +4 -0
  110. package/dist/lib/cjs/test-runners/integration-test-plugin.cjs +211 -0
  111. package/dist/lib/cjs/test-runners/integration-test-plugin.d.cts +44 -0
  112. package/dist/lib/cjs/test-runners/performance-eval-cap.cjs +157 -0
  113. package/dist/lib/cjs/test-runners/performance-eval-cap.d.cts +27 -0
  114. package/dist/lib/cjs/test-runners/stale-build-global-setup.cjs +217 -0
  115. package/dist/lib/cjs/test-runners/stale-build-global-setup.d.cts +86 -0
  116. package/dist/lib/cjs/test-runners/vitest-config.cjs +484 -0
  117. package/dist/lib/cjs/test-runners/vitest-config.d.cts +200 -0
  118. package/dist/lib/cjs/version.cjs +262 -0
  119. package/dist/lib/cjs/version.d.cts +92 -0
  120. package/dist/lib/cjs/vitest-setup.cjs +134 -0
  121. package/dist/lib/cjs/vitest-setup.d.cts +11 -0
  122. package/dist/lib/esm/bundlers/esbuild-impl/copy-to-obsidian-plugins-folder-plugin.d.mts +38 -0
  123. package/dist/lib/esm/bundlers/esbuild-impl/copy-to-obsidian-plugins-folder-plugin.mjs +218 -0
  124. package/dist/lib/esm/bundlers/esbuild-impl/dependency.d.mts +20 -0
  125. package/dist/lib/esm/bundlers/esbuild-impl/dependency.mjs +130 -0
  126. package/dist/lib/esm/bundlers/esbuild-impl/fix-source-maps-plugin.d.mts +34 -0
  127. package/dist/lib/esm/bundlers/esbuild-impl/fix-source-maps-plugin.mjs +108 -0
  128. package/dist/lib/esm/bundlers/esbuild-impl/index.d.mts +7 -0
  129. package/dist/lib/esm/bundlers/esbuild-impl/index.mjs +56 -0
  130. package/dist/lib/esm/bundlers/esbuild-impl/obsidian-plugin-builder.d.mts +98 -0
  131. package/dist/lib/esm/bundlers/esbuild-impl/obsidian-plugin-builder.mjs +247 -0
  132. package/dist/lib/esm/bundlers/esbuild-impl/preprocess-plugin.d.mts +30 -0
  133. package/dist/lib/esm/bundlers/esbuild-impl/preprocess-plugin.mjs +126 -0
  134. package/dist/lib/esm/bundlers/esbuild-impl/rename-css-plugin.d.mts +14 -0
  135. package/dist/lib/esm/bundlers/esbuild-impl/rename-css-plugin.mjs +63 -0
  136. package/dist/lib/esm/bundlers/esbuild.d.mts +11 -0
  137. package/dist/lib/esm/bundlers/esbuild.mjs +58 -0
  138. package/dist/lib/esm/bundlers/index.d.mts +3 -0
  139. package/dist/lib/esm/bundlers/index.mjs +48 -0
  140. package/dist/lib/esm/demo-vault-app-json.d.mts +93 -0
  141. package/dist/lib/esm/demo-vault-app-json.mjs +75 -0
  142. package/dist/lib/esm/demo-vault-buttons.d.mts +259 -0
  143. package/dist/lib/esm/demo-vault-buttons.mjs +452 -0
  144. package/dist/lib/esm/demo-vault-coverage.d.mts +533 -0
  145. package/dist/lib/esm/demo-vault-coverage.mjs +619 -0
  146. package/dist/lib/esm/demo-vault.d.mts +33 -0
  147. package/dist/lib/esm/demo-vault.mjs +197 -0
  148. package/dist/lib/esm/formatters/dprint.d.mts +15 -0
  149. package/dist/lib/esm/formatters/dprint.mjs +52 -0
  150. package/dist/lib/esm/formatters/index.d.mts +2 -0
  151. package/dist/lib/esm/formatters/index.mjs +46 -0
  152. package/dist/lib/esm/index.d.mts +16 -0
  153. package/dist/lib/esm/index.mjs +66 -0
  154. package/dist/lib/esm/integration-test-setup.d.mts +33 -0
  155. package/dist/lib/esm/integration-test-setup.mjs +44 -0
  156. package/dist/lib/esm/integration-test-vitest-global-setup.d.mts +39 -0
  157. package/dist/lib/esm/integration-test-vitest-global-setup.mjs +57 -0
  158. package/dist/lib/esm/jest-setup.d.mts +13 -0
  159. package/dist/lib/esm/jest-setup.mjs +53 -0
  160. package/dist/lib/esm/linters/eslint-config.d.mts +25 -0
  161. package/dist/lib/esm/linters/eslint-config.mjs +290 -0
  162. package/dist/lib/esm/linters/eslint-rules/index.d.mts +14 -0
  163. package/dist/lib/esm/linters/eslint-rules/index.mjs +70 -0
  164. package/dist/lib/esm/linters/eslint-rules/manifest-description.d.mts +54 -0
  165. package/dist/lib/esm/linters/eslint-rules/manifest-description.mjs +146 -0
  166. package/dist/lib/esm/linters/eslint-rules/manifest-helpers.d.mts +141 -0
  167. package/dist/lib/esm/linters/eslint-rules/manifest-helpers.mjs +90 -0
  168. package/dist/lib/esm/linters/eslint-rules/manifest-id.d.mts +32 -0
  169. package/dist/lib/esm/linters/eslint-rules/manifest-id.mjs +109 -0
  170. package/dist/lib/esm/linters/eslint-rules/manifest-name.d.mts +30 -0
  171. package/dist/lib/esm/linters/eslint-rules/manifest-name.mjs +110 -0
  172. package/dist/lib/esm/linters/eslint-rules/manifest-schema.d.mts +45 -0
  173. package/dist/lib/esm/linters/eslint-rules/manifest-schema.mjs +212 -0
  174. package/dist/lib/esm/linters/eslint-rules/no-local-obsidian-internals.d.mts +10 -0
  175. package/dist/lib/esm/linters/eslint-rules/no-local-obsidian-internals.mjs +150 -0
  176. package/dist/lib/esm/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian.d.mts +10 -0
  177. package/dist/lib/esm/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian.mjs +551 -0
  178. package/dist/lib/esm/linters/eslint-rules/no-untrusted-input-events.d.mts +10 -0
  179. package/dist/lib/esm/linters/eslint-rules/no-untrusted-input-events.mjs +138 -0
  180. package/dist/lib/esm/linters/eslint-rules/obsidian-dev-utils-plugin.d.mts +13 -0
  181. package/dist/lib/esm/linters/eslint-rules/obsidian-dev-utils-plugin.mjs +73 -0
  182. package/dist/lib/esm/linters/eslint-rules/plugin-name-as-code-in-ui.d.mts +30 -0
  183. package/dist/lib/esm/linters/eslint-rules/plugin-name-as-code-in-ui.mjs +157 -0
  184. package/dist/lib/esm/linters/eslint-rules/plugin-name-as-code.d.mts +29 -0
  185. package/dist/lib/esm/linters/eslint-rules/plugin-name-as-code.mjs +108 -0
  186. package/dist/lib/esm/linters/eslint-rules/require-component-suffix.d.mts +18 -0
  187. package/dist/lib/esm/linters/eslint-rules/require-component-suffix.mjs +167 -0
  188. package/dist/lib/esm/linters/eslint-rules/require-plugin-api-contract-schemas.d.mts +10 -0
  189. package/dist/lib/esm/linters/eslint-rules/require-plugin-api-contract-schemas.mjs +197 -0
  190. package/dist/lib/esm/linters/eslint.d.mts +15 -0
  191. package/dist/lib/esm/linters/eslint.mjs +52 -0
  192. package/dist/lib/esm/linters/index.d.mts +9 -0
  193. package/dist/lib/esm/linters/index.mjs +60 -0
  194. package/dist/lib/esm/linters/markdownlint-cli2-config.d.mts +12 -0
  195. package/dist/lib/esm/linters/markdownlint-cli2-config.mjs +66 -0
  196. package/dist/lib/esm/linters/markdownlint-rules/index.d.mts +2 -0
  197. package/dist/lib/esm/linters/markdownlint-rules/index.mjs +46 -0
  198. package/dist/lib/esm/linters/markdownlint-rules/plugin-name-as-code.d.mts +32 -0
  199. package/dist/lib/esm/linters/markdownlint-rules/plugin-name-as-code.mjs +130 -0
  200. package/dist/lib/esm/linters/markdownlint.d.mts +15 -0
  201. package/dist/lib/esm/linters/markdownlint.mjs +52 -0
  202. package/dist/lib/esm/linters/obsidianmd-rule-custom-message.d.mts +40 -0
  203. package/dist/lib/esm/linters/obsidianmd-rule-custom-message.mjs +67 -0
  204. package/dist/lib/esm/linters/plugin-names.d.mts +81 -0
  205. package/dist/lib/esm/linters/plugin-names.mjs +141 -0
  206. package/dist/lib/esm/obsidian-plugin-repo-paths.d.mts +253 -0
  207. package/dist/lib/esm/obsidian-plugin-repo-paths.mjs +108 -0
  208. package/dist/lib/esm/setup.d.mts +21 -0
  209. package/dist/lib/esm/setup.mjs +55 -0
  210. package/dist/lib/esm/templates.d.mts +13 -0
  211. package/dist/lib/esm/templates.mjs +57 -0
  212. package/dist/lib/esm/test-runners/index.d.mts +4 -0
  213. package/dist/lib/esm/test-runners/index.mjs +50 -0
  214. package/dist/lib/esm/test-runners/integration-test-plugin.d.mts +44 -0
  215. package/dist/lib/esm/test-runners/integration-test-plugin.mjs +94 -0
  216. package/dist/lib/esm/test-runners/performance-eval-cap.d.mts +27 -0
  217. package/dist/lib/esm/test-runners/performance-eval-cap.mjs +48 -0
  218. package/dist/lib/esm/test-runners/stale-build-global-setup.d.mts +86 -0
  219. package/dist/lib/esm/test-runners/stale-build-global-setup.mjs +115 -0
  220. package/dist/lib/esm/test-runners/vitest-config.d.mts +200 -0
  221. package/dist/lib/esm/test-runners/vitest-config.mjs +369 -0
  222. package/dist/lib/esm/version.d.mts +92 -0
  223. package/dist/lib/esm/version.mjs +160 -0
  224. package/dist/lib/esm/vitest-setup.d.mts +11 -0
  225. package/dist/lib/esm/vitest-setup.mjs +53 -0
  226. package/dist/templates/.markdownlint-cli2.mjs +4 -0
  227. package/dist/templates/.nano-staged.mjs +4 -0
  228. package/dist/templates/commitlint.config.ts +3 -0
  229. package/dist/templates/dprint.json +26 -0
  230. package/dist/templates/eslint.config.mts +3 -0
  231. package/dist/templates/scripts/build/build-clean.ts +4 -0
  232. package/dist/templates/scripts/build/build-compile-svelte.ts +4 -0
  233. package/dist/templates/scripts/build/build-compile-typescript.ts +4 -0
  234. package/dist/templates/scripts/build/build-compile.ts +4 -0
  235. package/dist/templates/scripts/build/build-templates.ts +4 -0
  236. package/dist/templates/scripts/bundlers/esbuild/build.ts +4 -0
  237. package/dist/templates/scripts/bundlers/esbuild/dev.ts +4 -0
  238. package/dist/templates/scripts/commitlint-config.ts +3 -0
  239. package/dist/templates/scripts/eslint-config.ts +10 -0
  240. package/dist/templates/scripts/formatters/dprint/format-check.ts +8 -0
  241. package/dist/templates/scripts/formatters/dprint/format.ts +8 -0
  242. package/dist/templates/scripts/gate/gate.ts +10 -0
  243. package/dist/templates/scripts/linters/cspell/spellcheck.ts +8 -0
  244. package/dist/templates/scripts/linters/eslint/lint-fix.ts +8 -0
  245. package/dist/templates/scripts/linters/eslint/lint.ts +8 -0
  246. package/dist/templates/scripts/linters/markdownlint/lint-md-fix.ts +8 -0
  247. package/dist/templates/scripts/linters/markdownlint/lint-md.ts +8 -0
  248. package/dist/templates/scripts/linters/over-exposure/find-overexposed-fix.ts +25 -0
  249. package/dist/templates/scripts/linters/over-exposure/find-overexposed.ts +15 -0
  250. package/dist/templates/scripts/markdownlint-cli2-config.ts +3 -0
  251. package/dist/templates/scripts/nano-staged-config.ts +3 -0
  252. package/dist/templates/scripts/test-runners/vitest/test-coverage.ts +4 -0
  253. package/dist/templates/scripts/test-runners/vitest/test-watch.ts +4 -0
  254. package/dist/templates/scripts/test-runners/vitest/test.ts +4 -0
  255. package/dist/templates/scripts/version/version.ts +10 -0
  256. package/dist/templates/scripts/vitest-config.ts +3 -0
  257. package/dist/templates/vitest.config.ts +3 -0
  258. package/formatters/dprint/package.json +6 -0
  259. package/formatters/index/package.json +6 -0
  260. package/formatters/package.json +6 -0
  261. package/linters/eslint/package.json +6 -0
  262. package/linters/eslint-config/package.json +6 -0
  263. package/linters/eslint-rules/index/package.json +6 -0
  264. package/linters/eslint-rules/manifest-description/package.json +6 -0
  265. package/linters/eslint-rules/manifest-helpers/package.json +6 -0
  266. package/linters/eslint-rules/manifest-id/package.json +6 -0
  267. package/linters/eslint-rules/manifest-name/package.json +6 -0
  268. package/linters/eslint-rules/manifest-schema/package.json +6 -0
  269. package/linters/eslint-rules/no-local-obsidian-internals/package.json +6 -0
  270. package/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian/package.json +6 -0
  271. package/linters/eslint-rules/no-untrusted-input-events/package.json +6 -0
  272. package/linters/eslint-rules/obsidian-dev-utils-plugin/package.json +6 -0
  273. package/linters/eslint-rules/package.json +6 -0
  274. package/linters/eslint-rules/plugin-name-as-code/package.json +6 -0
  275. package/linters/eslint-rules/plugin-name-as-code-in-ui/package.json +6 -0
  276. package/linters/eslint-rules/require-component-suffix/package.json +6 -0
  277. package/linters/eslint-rules/require-plugin-api-contract-schemas/package.json +6 -0
  278. package/linters/index/package.json +6 -0
  279. package/linters/markdownlint/package.json +6 -0
  280. package/linters/markdownlint-cli2-config/package.json +6 -0
  281. package/linters/markdownlint-rules/index/package.json +6 -0
  282. package/linters/markdownlint-rules/package.json +6 -0
  283. package/linters/markdownlint-rules/plugin-name-as-code/package.json +6 -0
  284. package/linters/obsidianmd-rule-custom-message/package.json +6 -0
  285. package/linters/package.json +6 -0
  286. package/linters/plugin-names/package.json +6 -0
  287. package/package.json +302 -13
  288. package/test-runners/index/package.json +6 -0
  289. package/test-runners/integration-test-plugin/package.json +6 -0
  290. package/test-runners/package.json +6 -0
  291. package/test-runners/performance-eval-cap/package.json +6 -0
  292. package/test-runners/stale-build-global-setup/package.json +6 -0
  293. package/test-runners/vitest-config/package.json +6 -0
@@ -0,0 +1,452 @@
1
+ /*
2
+ THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
3
+ if you want to view the source, please visit the github repository of this plugin
4
+ */
5
+
6
+ (function () {
7
+ function ensureDisposeSymbols(symbolConstructor = Symbol) {
8
+ symbolConstructor.asyncDispose ??= symbolConstructor.for("Symbol.asyncDispose");
9
+ symbolConstructor.dispose ??= symbolConstructor.for("Symbol.dispose");
10
+ }
11
+
12
+ function ensureBrowserProcess() {
13
+ const browserProcess = {
14
+ browser: true,
15
+ cwd() {
16
+ return "/";
17
+ },
18
+ env: {},
19
+ platform: "android"
20
+ };
21
+ const existingProcess = globalThis.process;
22
+ if (!existingProcess) {
23
+ globalThis.process = browserProcess;
24
+ return;
25
+ }
26
+ if (existingProcess.versions?.node) {
27
+ return;
28
+ }
29
+ const existingProcessRecord = existingProcess;
30
+ for (const [key, value] of Object.entries(browserProcess)) {
31
+ existingProcessRecord[key] ??= value;
32
+ }
33
+ existingProcessRecord["browser"] = true;
34
+ }
35
+
36
+ (function initEsm() {
37
+ ensureDisposeSymbols();
38
+ ensureBrowserProcess();
39
+ })();
40
+ })();
41
+
42
+ import { getRootFolder } from "@mnaoumov/typescript-dev-toolkit/root";
43
+ import {
44
+ readdirSync,
45
+ readFileSync
46
+ } from "node:fs";
47
+ import { join } from "node:path";
48
+ import process from "node:process";
49
+ import {
50
+ DEFAULT_EVAL_CAP_IN_MILLISECONDS,
51
+ evalInObsidian
52
+ } from "obsidian-integration-testing";
53
+ import { getTemporaryVault } from "obsidian-integration-testing/vitest-global-setup-plugin";
54
+ import {
55
+ beforeAll,
56
+ describe,
57
+ expect,
58
+ it
59
+ } from "vitest";
60
+ const CODE_SCRIPT_TOOLKIT_PLUGIN_ID = "fix-require-modules";
61
+ const DEFAULT_BUTTON_RESULT_TIMEOUT_IN_MILLISECONDS = 1e4;
62
+ const DEFAULT_SETTLE_TIMEOUT_IN_MILLISECONDS = 12e3;
63
+ const POLL_INTERVAL_IN_MILLISECONDS = 100;
64
+ const OUTPUT_EXCERPT_LENGTH = 400;
65
+ const DEFAULT_EXCLUDED_NOTES = ["README.md"];
66
+ const FENCE_REG_EXP = /^(?<indent>\s*)(?<marker>`{3,}|~{3,})(?<info>.*)$/;
67
+ const CODE_BUTTON_FENCE_INFO = "code-button";
68
+ const FRONT_MATTER_DELIMITER = "---";
69
+ const RAW_MODE_CONFIG_REG_EXP = /^isRaw:\s*true\s*$/m;
70
+ const CAPTION_CONFIG_REG_EXP = /^caption:(?<value>.*)$/m;
71
+ const PLAIN_SCALAR_COMMENT_REG_EXP = /\s+#.*$/;
72
+ const SINGLE_QUOTED_SCALAR_REG_EXP = /^'(?<content>.*)'$/;
73
+ const DOUBLE_QUOTED_SCALAR_REG_EXP = /^"(?<content>.*)"$/;
74
+ const DEFAULT_CODE_BUTTON_CAPTION = "(no caption)";
75
+ function assertClickBudgetsFitTransportCap(timeouts) {
76
+ const totalInMilliseconds = timeouts.settleTimeoutInMilliseconds + timeouts.buttonResultTimeoutInMilliseconds;
77
+ if (totalInMilliseconds < DEFAULT_EVAL_CAP_IN_MILLISECONDS) {
78
+ return;
79
+ }
80
+ throw new Error(
81
+ `One demo-vault button click spends settleTimeoutInMilliseconds (${String(timeouts.settleTimeoutInMilliseconds)} ms) and buttonResultTimeoutInMilliseconds (${String(timeouts.buttonResultTimeoutInMilliseconds)} ms) inside a single transport call, so their sum of ${String(totalInMilliseconds)} ms is at or over the transport's ${String(DEFAULT_EVAL_CAP_IN_MILLISECONDS)} ms script timeout and can never be honoured. Lower either budget in RegisterDemoVaultButtonSuiteOptions.`
82
+ );
83
+ }
84
+ function countRenderedButtons(source) {
85
+ return listRenderedButtonCaptions(source).length;
86
+ }
87
+ function findDuplicateCaptions(captions) {
88
+ const seenCaptions = /* @__PURE__ */ new Set();
89
+ const duplicateCaptions = /* @__PURE__ */ new Set();
90
+ for (const caption of captions) {
91
+ if (seenCaptions.has(caption)) {
92
+ duplicateCaptions.add(caption);
93
+ }
94
+ seenCaptions.add(caption);
95
+ }
96
+ return [...duplicateCaptions];
97
+ }
98
+ function formatFailures(noteName, failures) {
99
+ if (failures.length === 0) {
100
+ return "";
101
+ }
102
+ const details = failures.map((failure) => ` - "${failure.caption}" [${failure.status}]: ${failure.output.replaceAll(/\s+/g, " ").trim()}`).join("\n");
103
+ return `${String(failures.length)} button(s) in ${noteName} did not run cleanly:
104
+ ${details}`;
105
+ }
106
+ function listRenderedButtonCaptions(source) {
107
+ const captions = [];
108
+ let openMarker = "";
109
+ let isCodeButtonFence = false;
110
+ let fenceBody = [];
111
+ let fenceIndentLength = 0;
112
+ function closeFence() {
113
+ if (isCodeButtonFence && !isRawFence(fenceBody)) {
114
+ captions.push(readCaption(fenceBody));
115
+ }
116
+ openMarker = "";
117
+ }
118
+ for (const line of source.split(/\r?\n/)) {
119
+ const match = FENCE_REG_EXP.exec(line);
120
+ const indent = match?.groups?.["indent"] ?? "";
121
+ const marker = match?.groups?.["marker"] ?? "";
122
+ const info = (match?.groups?.["info"] ?? "").trim();
123
+ if (openMarker === "") {
124
+ if (match) {
125
+ openMarker = marker;
126
+ isCodeButtonFence = info === CODE_BUTTON_FENCE_INFO;
127
+ fenceBody = [];
128
+ fenceIndentLength = indent.length;
129
+ }
130
+ continue;
131
+ }
132
+ if (marker.startsWith(openMarker.charAt(0)) && marker.length >= openMarker.length && info === "") {
133
+ closeFence();
134
+ continue;
135
+ }
136
+ fenceBody.push(line.slice(Math.min(fenceIndentLength, line.length - line.trimStart().length)));
137
+ }
138
+ if (openMarker !== "") {
139
+ closeFence();
140
+ }
141
+ return captions;
142
+ }
143
+ function selectUnexpectedFailures(noteName, results, expectedNonOkButtons) {
144
+ return results.filter(
145
+ (result) => result.status !== "ok" && expectedNonOkButtons.every(
146
+ (expected) => !(expected.note === noteName && expected.status === result.status && result.caption.includes(expected.captionIncludes))
147
+ )
148
+ );
149
+ }
150
+ function isRawFence(fenceBody) {
151
+ const config = readConfigBlock(fenceBody);
152
+ return config !== null && RAW_MODE_CONFIG_REG_EXP.test(config);
153
+ }
154
+ function readCaption(fenceBody) {
155
+ const config = readConfigBlock(fenceBody);
156
+ const rawValue = config === null ? void 0 : CAPTION_CONFIG_REG_EXP.exec(config)?.groups?.["value"];
157
+ if (rawValue === void 0) {
158
+ return DEFAULT_CODE_BUTTON_CAPTION;
159
+ }
160
+ const value = rawValue.trim();
161
+ const singleQuotedContent = SINGLE_QUOTED_SCALAR_REG_EXP.exec(value)?.groups?.["content"];
162
+ if (singleQuotedContent !== void 0) {
163
+ return singleQuotedContent.replaceAll("''", "'");
164
+ }
165
+ const doubleQuotedContent = DOUBLE_QUOTED_SCALAR_REG_EXP.exec(value)?.groups?.["content"];
166
+ if (doubleQuotedContent !== void 0) {
167
+ try {
168
+ return JSON.parse(value);
169
+ } catch {
170
+ return doubleQuotedContent;
171
+ }
172
+ }
173
+ return value.replace(PLAIN_SCALAR_COMMENT_REG_EXP, "");
174
+ }
175
+ function readConfigBlock(fenceBody) {
176
+ if (fenceBody[0]?.trim() !== FRONT_MATTER_DELIMITER) {
177
+ return null;
178
+ }
179
+ const endIndex = fenceBody.findIndex((line, index) => index > 0 && line.trim() === FRONT_MATTER_DELIMITER);
180
+ return endIndex === -1 ? null : fenceBody.slice(1, endIndex).join("\n");
181
+ }
182
+ const NON_WALKTHROUGH_FOLDERS = /* @__PURE__ */ new Set(["Materials"]);
183
+ function listNotesWithButtons(demoVaultPath, excludedNotes, excludedFolders = /* @__PURE__ */ new Set()) {
184
+ const notes = [];
185
+ function walk(folder, relativeFolder) {
186
+ for (const entry of readdirSync(folder, { withFileTypes: true })) {
187
+ const relativePath = relativeFolder === "" ? entry.name : `${relativeFolder}/${entry.name}`;
188
+ if (entry.isDirectory()) {
189
+ if (!entry.name.startsWith(".") && !entry.name.startsWith("_") && !NON_WALKTHROUGH_FOLDERS.has(entry.name) && !excludedFolders.has(entry.name) && !excludedFolders.has(relativePath)) {
190
+ walk(join(folder, entry.name), relativePath);
191
+ }
192
+ continue;
193
+ }
194
+ if (!entry.name.endsWith(".md") || excludedNotes.has(entry.name) || excludedNotes.has(relativePath)) {
195
+ continue;
196
+ }
197
+ const captions = listRenderedButtonCaptions(readFileSync(join(folder, entry.name), "utf-8"));
198
+ if (captions.length > 0) {
199
+ notes.push({ buttonCount: captions.length, captions, name: relativePath });
200
+ }
201
+ }
202
+ }
203
+ walk(demoVaultPath, "");
204
+ return notes.sort((a, b) => a.name.localeCompare(b.name, "en"));
205
+ }
206
+ function registerDemoVaultButtonSuite(options = {}) {
207
+ const rootFolder = options.rootFolder ?? getRootFolder() ?? process.cwd();
208
+ const demoVaultPath = join(rootFolder, "demo-vault");
209
+ const excludedNotes = new Set(options.excludedNotes ?? DEFAULT_EXCLUDED_NOTES);
210
+ const excludedFolders = new Set(options.excludedFolders);
211
+ const expectedNonOkButtons = options.expectedNonOkButtons ?? [];
212
+ const shouldDismissModals = options.shouldDismissModals ?? false;
213
+ const settleTimeoutInMilliseconds = options.settleTimeoutInMilliseconds ?? DEFAULT_SETTLE_TIMEOUT_IN_MILLISECONDS;
214
+ const buttonResultTimeoutInMilliseconds = options.buttonResultTimeoutInMilliseconds ?? DEFAULT_BUTTON_RESULT_TIMEOUT_IN_MILLISECONDS;
215
+ const clickButtonTimeouts = {
216
+ buttonResultTimeoutInMilliseconds,
217
+ settleTimeoutInMilliseconds
218
+ };
219
+ assertClickBudgetsFitTransportCap(clickButtonTimeouts);
220
+ const notes = listNotesWithButtons(demoVaultPath, excludedNotes, excludedFolders);
221
+ describe("demo-vault buttons", () => {
222
+ beforeAll(async () => {
223
+ const isCodeScriptToolkitLoaded = await checkCodeScriptToolkitLoaded(settleTimeoutInMilliseconds);
224
+ expect(isCodeScriptToolkitLoaded, "CodeScript Toolkit did not load, so no button could render").toBe(true);
225
+ });
226
+ it("has at least one note with a code button", () => {
227
+ expect(notes.length).toBeGreaterThan(0);
228
+ });
229
+ for (const note of notes) {
230
+ it(`runs every code button in ${note.name}`, async () => {
231
+ const duplicateCaptions = findDuplicateCaptions(note.captions);
232
+ expect(
233
+ duplicateCaptions,
234
+ `${note.name} declares more than one button captioned ${duplicateCaptions.map((caption) => `"${caption}"`).join(", ")}. This suite addresses a button by its caption, so only the first of them could ever be clicked. Give each button a distinct caption.`
235
+ ).toEqual([]);
236
+ const captions = await openNoteAndListButtonCaptions(note, settleTimeoutInMilliseconds);
237
+ const missingCaptions = note.captions.filter((caption) => !captions.includes(caption));
238
+ expect(
239
+ captions.length,
240
+ `${note.name} declares ${String(note.buttonCount)} button(s) but only ${String(captions.length)} rendered; never seen: ${missingCaptions.map((caption) => `"${caption}"`).join(", ")}`
241
+ ).toBeGreaterThanOrEqual(note.buttonCount);
242
+ const results = [];
243
+ for (const caption of captions) {
244
+ results.push(await clickButton({ buttonCaption: caption, notePath: note.name, shouldDismissModals, timeouts: clickButtonTimeouts }));
245
+ }
246
+ const failures = selectUnexpectedFailures(note.name, results, expectedNonOkButtons);
247
+ expect(failures, formatFailures(note.name, failures)).toEqual([]);
248
+ });
249
+ }
250
+ });
251
+ }
252
+ async function checkCodeScriptToolkitLoaded(timeoutInMilliseconds) {
253
+ return evalInObsidian({
254
+ async callback({ app, codeScriptToolkitPluginId, intervalInMilliseconds, lib: { waitUntil }, timeoutInMilliseconds: timeout }) {
255
+ if (typeof app.plugins.isEnabled === "function" && !app.plugins.isEnabled()) {
256
+ await app.plugins.setEnable(true);
257
+ }
258
+ if (!app.plugins.getPlugin(codeScriptToolkitPluginId)) {
259
+ await app.plugins.enablePlugin(codeScriptToolkitPluginId);
260
+ }
261
+ try {
262
+ await waitUntil({
263
+ intervalInMilliseconds,
264
+ message: "CodeScript Toolkit never loaded",
265
+ predicate: () => app.plugins.getPlugin(codeScriptToolkitPluginId) !== null,
266
+ timeoutInMilliseconds: timeout
267
+ });
268
+ } catch {
269
+ return false;
270
+ }
271
+ return true;
272
+ },
273
+ input: {
274
+ codeScriptToolkitPluginId: CODE_SCRIPT_TOOLKIT_PLUGIN_ID,
275
+ intervalInMilliseconds: POLL_INTERVAL_IN_MILLISECONDS,
276
+ timeoutInMilliseconds
277
+ },
278
+ vaultPath: getTemporaryVault().path
279
+ });
280
+ }
281
+ async function clickButton(params) {
282
+ return evalInObsidian({
283
+ async callback({
284
+ app,
285
+ buttonResultTimeoutInMilliseconds,
286
+ caption,
287
+ intervalInMilliseconds,
288
+ lib: { pressKey, waitUntil },
289
+ notePath: notePathToOpen,
290
+ obsidianModule,
291
+ outputExcerptLength,
292
+ settleTimeoutInMilliseconds,
293
+ shouldDismissModals: shouldDismiss
294
+ }) {
295
+ function view() {
296
+ return app.workspace.getActiveViewOfType(obsidianModule.MarkdownView);
297
+ }
298
+ function previewEl() {
299
+ return view()?.containerEl.querySelector(":scope .markdown-preview-view") ?? null;
300
+ }
301
+ function buttons() {
302
+ return [...view()?.containerEl.querySelectorAll(":scope .block-language-code-button button.mod-cta") ?? []];
303
+ }
304
+ function findButton() {
305
+ return buttons().find((candidate) => candidate.textContent === caption);
306
+ }
307
+ const SCROLL_BOTTOM_TOLERANCE_IN_PIXELS = 4;
308
+ const SCROLL_STEP_RATIO = 0.8;
309
+ function advanceScroll() {
310
+ const scroller = previewEl();
311
+ if (!scroller) {
312
+ return;
313
+ }
314
+ const isAtBottom = scroller.scrollTop + scroller.clientHeight >= scroller.scrollHeight - SCROLL_BOTTOM_TOLERANCE_IN_PIXELS;
315
+ scroller.scrollTop = isAtBottom ? 0 : scroller.scrollTop + Math.floor(scroller.clientHeight * SCROLL_STEP_RATIO);
316
+ }
317
+ async function dismissModals() {
318
+ if (!shouldDismiss) {
319
+ return;
320
+ }
321
+ for (const closeButton of activeDocument.body.querySelectorAll(":scope .modal-container :is(.modal-close-button, .modal-header-button)")) {
322
+ closeButton.click();
323
+ }
324
+ if (activeDocument.querySelector(".modal-container, .prompt")) {
325
+ await pressKey({ key: "Escape" });
326
+ }
327
+ }
328
+ await app.workspace.openLinkText(notePathToOpen.replace(/\.md$/, ""), "", false);
329
+ await app.workspace.getLeaf(false).setViewState({ state: { file: notePathToOpen, mode: "preview" }, type: "markdown" });
330
+ let button;
331
+ try {
332
+ await waitUntil({
333
+ intervalInMilliseconds,
334
+ message: `code button "${caption}" never rendered`,
335
+ predicate: () => {
336
+ advanceScroll();
337
+ button = findButton();
338
+ return button !== void 0;
339
+ },
340
+ timeoutInMilliseconds: settleTimeoutInMilliseconds
341
+ });
342
+ } catch {
343
+ return { caption, output: "", status: "timeout" };
344
+ }
345
+ if (!button) {
346
+ return { caption, output: "", status: "timeout" };
347
+ }
348
+ const block = button.closest(".block-language-code-button") ?? button.parentElement;
349
+ button.scrollIntoView();
350
+ button.click();
351
+ let status;
352
+ try {
353
+ await waitUntil({
354
+ intervalInMilliseconds,
355
+ message: `button "${caption}" never reported a result`,
356
+ predicate: async () => {
357
+ await dismissModals();
358
+ return /Executed (?:successfully|with error)/.test(block?.textContent ?? "");
359
+ },
360
+ timeoutInMilliseconds: buttonResultTimeoutInMilliseconds
361
+ });
362
+ const text = block?.textContent ?? "";
363
+ if (text.includes("Executed with error")) {
364
+ status = "error";
365
+ } else if (text.includes("Executed successfully")) {
366
+ status = "ok";
367
+ } else {
368
+ status = "unknown";
369
+ }
370
+ } catch {
371
+ status = "timeout";
372
+ }
373
+ await dismissModals();
374
+ return { caption, output: (block?.textContent ?? "").slice(0, outputExcerptLength), status };
375
+ },
376
+ input: {
377
+ buttonResultTimeoutInMilliseconds: params.timeouts.buttonResultTimeoutInMilliseconds,
378
+ caption: params.buttonCaption,
379
+ intervalInMilliseconds: POLL_INTERVAL_IN_MILLISECONDS,
380
+ notePath: params.notePath,
381
+ outputExcerptLength: OUTPUT_EXCERPT_LENGTH,
382
+ settleTimeoutInMilliseconds: params.timeouts.settleTimeoutInMilliseconds,
383
+ shouldDismissModals: params.shouldDismissModals
384
+ },
385
+ vaultPath: getTemporaryVault().path
386
+ });
387
+ }
388
+ async function openNoteAndListButtonCaptions(note, settleTimeoutInMilliseconds) {
389
+ return evalInObsidian({
390
+ async callback({ app, expectedButtonCount, intervalInMilliseconds, lib: { waitUntil }, notePath, obsidianModule, timeoutInMilliseconds }) {
391
+ function view() {
392
+ return app.workspace.getActiveViewOfType(obsidianModule.MarkdownView);
393
+ }
394
+ function previewEl() {
395
+ return view()?.containerEl.querySelector(":scope .markdown-preview-view") ?? null;
396
+ }
397
+ const seenCaptions = /* @__PURE__ */ new Set();
398
+ function captions() {
399
+ for (const button of view()?.containerEl.querySelectorAll(":scope .block-language-code-button button.mod-cta") ?? []) {
400
+ if (button.textContent !== "") {
401
+ seenCaptions.add(button.textContent);
402
+ }
403
+ }
404
+ return [...seenCaptions];
405
+ }
406
+ const SCROLL_BOTTOM_TOLERANCE_IN_PIXELS = 4;
407
+ const SCROLL_STEP_RATIO = 0.8;
408
+ function advanceScroll() {
409
+ const scroller = previewEl();
410
+ if (!scroller) {
411
+ return;
412
+ }
413
+ const isAtBottom = scroller.scrollTop + scroller.clientHeight >= scroller.scrollHeight - SCROLL_BOTTOM_TOLERANCE_IN_PIXELS;
414
+ scroller.scrollTop = isAtBottom ? 0 : scroller.scrollTop + Math.floor(scroller.clientHeight * SCROLL_STEP_RATIO);
415
+ }
416
+ await app.workspace.openLinkText(notePath.replace(/\.md$/, ""), "", false);
417
+ await app.workspace.getLeaf(false).setViewState({ state: { file: notePath, mode: "preview" }, type: "markdown" });
418
+ try {
419
+ await waitUntil({
420
+ intervalInMilliseconds,
421
+ message: `"${notePath}" never mounted all ${String(expectedButtonCount)} of its buttons`,
422
+ predicate: () => {
423
+ advanceScroll();
424
+ return captions().length >= expectedButtonCount;
425
+ },
426
+ timeoutInMilliseconds
427
+ });
428
+ } catch {
429
+ }
430
+ return captions();
431
+ },
432
+ input: {
433
+ expectedButtonCount: note.buttonCount,
434
+ intervalInMilliseconds: POLL_INTERVAL_IN_MILLISECONDS,
435
+ notePath: note.name,
436
+ timeoutInMilliseconds: settleTimeoutInMilliseconds
437
+ },
438
+ vaultPath: getTemporaryVault().path
439
+ });
440
+ }
441
+ export {
442
+ CODE_SCRIPT_TOOLKIT_PLUGIN_ID,
443
+ assertClickBudgetsFitTransportCap,
444
+ countRenderedButtons,
445
+ findDuplicateCaptions,
446
+ formatFailures,
447
+ listNotesWithButtons,
448
+ listRenderedButtonCaptions,
449
+ registerDemoVaultButtonSuite,
450
+ selectUnexpectedFailures
451
+ };
452
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2RlbW8tdmF1bHQtYnV0dG9ucy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIEEgdml0ZXN0IHN1aXRlIHRoYXQgb3BlbnMgZXZlcnkgbm90ZSBvZiBhIHBsdWdpbidzIGluLXJlcG8gYGRlbW8tdmF1bHQvYCwgY2xpY2tzIGVhY2ggYGNvZGUtYnV0dG9uYFxuICogaW4gaXQgYWdhaW5zdCBhIHJlYWwgT2JzaWRpYW4sIGFuZCBmYWlscyBvbiBhbnkgYnV0dG9uIHRoYXQgZXJyb3JzIG9yIG5ldmVyIHJlcG9ydHMgYSByZXN1bHQuXG4gKlxuICogQSBkZW1vIHZhdWx0J3MgYnV0dG9ucyBhcmUgdGhlIG9uZSBwYXJ0IG9mIGl0IG5vIG90aGVyIGdhdGUgY2FuIGNoZWNrLiBgbGludDptZGAgcmVhZHMgdGhlIG1hcmtkb3duLFxuICogdGhlIGNvdmVyYWdlIHN1aXRlICh7QGxpbmsgLi9kZW1vLXZhdWx0LWNvdmVyYWdlLnRzIHwgYHJlZ2lzdGVyRGVtb1ZhdWx0Q292ZXJhZ2VTdWl0ZWB9KSBjaGVja3MgdGhlXG4gKiBhdXRob3JpbmcgY29udmVudGlvbnMsIGFuZCBuZWl0aGVyIGV4ZWN1dGVzIGFueXRoaW5nIFx1MjAxNCBhIGJ1dHRvbiB3aG9zZSBgcmVxdWlyZSgnL2RlbW9TZXR1cC50cycpYCBwYXRoXG4gKiBpcyB3cm9uZywgb3IgdGhhdCBjYWxscyBhbiBBUEkgdGhhdCBoYXMgc2luY2UgY2hhbmdlZCBzaGFwZSwgZmFpbHMgYXQgY2xpY2sgdGltZSBhbmQgbm93aGVyZSBlbHNlLlxuICpcbiAqIFRoZSBjb21wYW5pb24gaGFsZiBcdTIwMTQgc2VlZGluZyB0aGUgdGVtcCB2YXVsdCB3aXRoIHRoZSBkZW1vLXZhdWx0IHRyZWUsIGl0cyBgLm9ic2lkaWFuYCBjb25maWcsIGFuZCB0aGVcbiAqIGBDb2RlU2NyaXB0IFRvb2xraXRgIGJpbmFyeSB0aGF0IHR1cm5zIGBgYGAgYGBgY29kZS1idXR0b24gYGBgYCBmZW5jZXMgaW50byBidXR0b25zIFx1MjAxNCBpc1xuICogYGJ1aWxkRGVtb1ZhdWx0UG9wdWxhdGVgIGluIGBvYnNpZGlhbi1pbnRlZ3JhdGlvbi10ZXN0aW5nYDsgaGFuZCBpdHMgcmVzdWx0IHRvIHRoZSBwcm9qZWN0J3NcbiAqIGBnbG9iYWxTZXR1cGAgYW5kIG5hbWUgYENvZGVTY3JpcHQgVG9vbGtpdGAgaW4gYGVuYWJsZUNvbW11bml0eVBsdWdpbnNgLlxuICovXG5cbmltcG9ydCB7IGdldFJvb3RGb2xkZXIgfSBmcm9tICdAbW5hb3Vtb3YvdHlwZXNjcmlwdC1kZXYtdG9vbGtpdC9yb290JztcbmltcG9ydCB7XG4gIHJlYWRkaXJTeW5jLFxuICByZWFkRmlsZVN5bmNcbn0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5pbXBvcnQge1xuICBERUZBVUxUX0VWQUxfQ0FQX0lOX01JTExJU0VDT05EUyxcbiAgZXZhbEluT2JzaWRpYW5cbn0gZnJvbSAnb2JzaWRpYW4taW50ZWdyYXRpb24tdGVzdGluZyc7XG5pbXBvcnQgeyBnZXRUZW1wb3JhcnlWYXVsdCB9IGZyb20gJ29ic2lkaWFuLWludGVncmF0aW9uLXRlc3Rpbmcvdml0ZXN0LWdsb2JhbC1zZXR1cC1wbHVnaW4nO1xuaW1wb3J0IHtcbiAgYmVmb3JlQWxsLFxuICBkZXNjcmliZSxcbiAgZXhwZWN0LFxuICBpdFxufSBmcm9tICd2aXRlc3QnO1xuXG4vKipcbiAqIGBDb2RlU2NyaXB0IFRvb2xraXRgJ3MgbWFuaWZlc3QgaWQuIEl0IGlzIHN0aWxsIHRoZSBwbHVnaW4ncyBvcmlnaW5hbCBgZml4LXJlcXVpcmUtbW9kdWxlc2AgaWQsIHdoaWNoXG4gKiBubyBsb25nZXIgbWF0Y2hlcyBpdHMgbmFtZSBcdTIwMTQgdGhlIGlkIGlzIHB1Ymxpc2hlZCwgc28gaXQgY2Fubm90IGJlIGNoYW5nZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBDT0RFX1NDUklQVF9UT09MS0lUX1BMVUdJTl9JRCA9ICdmaXgtcmVxdWlyZS1tb2R1bGVzJztcblxuLyoqXG4gKiBUaGUgd2FpdGluZyBidWRnZXRzIGEgc2luZ2xlIGJ1dHRvbiBjbGljayBpcyBhbGxvd2VkLlxuICpcbiAqIEJvdGggYXJlIHNwZW50IGluc2lkZSBPTkUgdHJhbnNwb3J0IGNhbGwsIHNvIGl0IGlzIHRoZWlyIFNVTSB0aGF0XG4gKiB7QGxpbmsgYXNzZXJ0Q2xpY2tCdWRnZXRzRml0VHJhbnNwb3J0Q2FwfSBib3VuZHMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2xpY2tCdXR0b25UaW1lb3V0cyB7XG4gIC8qKlxuICAgKiBIb3cgbG9uZyB0byB3YWl0IGZvciB0aGUgY2xpY2tlZCBidXR0b24gdG8gcmVwb3J0IGEgcmVzdWx0LlxuICAgKi9cbiAgcmVhZG9ubHkgYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEhvdyBsb25nIHRvIHdhaXQgZm9yIHRoZSBidXR0b24gaXRzZWxmIHRvIG1vdW50LlxuICAgKi9cbiAgcmVhZG9ubHkgc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG59XG5cbi8qKlxuICogVGhlIG91dGNvbWUgb2YgY2xpY2tpbmcgb25lIGJ1dHRvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZW1vVmF1bHRCdXR0b25SZXN1bHQge1xuICAvKipcbiAgICogVGhlIGJ1dHRvbidzIGNhcHRpb24sIGFzIHJlbmRlcmVkLlxuICAgKi9cbiAgcmVhZG9ubHkgY2FwdGlvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVzdWx0IGxpbmUgYENvZGVTY3JpcHQgVG9vbGtpdGAgcHJpbnRlZCB1bmRlciB0aGUgYnV0dG9uLCB0cnVuY2F0ZWQuXG4gICAqL1xuICByZWFkb25seSBvdXRwdXQ6IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgYnV0dG9uIHJlcG9ydGVkIHN1Y2Nlc3MsIHJlcG9ydGVkIGFuIGVycm9yLCBvciBuZXZlciByZXBvcnRlZCBhdCBhbGwuXG4gICAqL1xuICByZWFkb25seSBzdGF0dXM6ICdlcnJvcicgfCAnb2snIHwgJ3RpbWVvdXQnIHwgJ3Vua25vd24nO1xufVxuXG4vKipcbiAqIE9uZSBkZW1vLXZhdWx0IG5vdGUgYW5kIGhvdyBtYW55IGJ1dHRvbnMgaXRzIHNvdXJjZSBkZWNsYXJlcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZW1vVmF1bHROb3RlIHtcbiAgLyoqXG4gICAqIEhvdyBtYW55IGJ1dHRvbnMgdGhlIG5vdGUncyBzb3VyY2UgcmVuZGVycywgYXMgY291bnRlZCBieSB7QGxpbmsgY291bnRSZW5kZXJlZEJ1dHRvbnN9LlxuICAgKi9cbiAgcmVhZG9ubHkgYnV0dG9uQ291bnQ6IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIGNhcHRpb25zIG9mIHRob3NlIGJ1dHRvbnMsIGluIHNvdXJjZSBvcmRlciwgYXMgcmVhZCBieSB7QGxpbmsgbGlzdFJlbmRlcmVkQnV0dG9uQ2FwdGlvbnN9LlxuICAgKi9cbiAgcmVhZG9ubHkgY2FwdGlvbnM6IHJlYWRvbmx5IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgbm90ZSdzIGZpbGUgbmFtZSwgcmVsYXRpdmUgdG8gdGhlIGRlbW8gdmF1bHQgcm9vdC5cbiAgICovXG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbn1cblxuLyoqXG4gKiBBIGJ1dHRvbiB0aGF0IGlzIEVYUEVDVEVEIG5vdCB0byByZXBvcnQgc3VjY2Vzcywgc28gdGhlIHN1aXRlIGRvZXMgbm90IGZhaWwgb24gaXQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRXhwZWN0ZWROb25Pa0J1dHRvbiB7XG4gIC8qKlxuICAgKiBBIHN1YnN0cmluZyBvZiB0aGUgYnV0dG9uJ3MgcmVuZGVyZWQgY2FwdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGNhcHRpb25JbmNsdWRlczogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbm90ZSBob2xkaW5nIHRoZSBidXR0b24sIHJlbGF0aXZlIHRvIHRoZSBkZW1vIHZhdWx0IHJvb3QuXG4gICAqL1xuICByZWFkb25seSBub3RlOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBzdGF0dXMgdGhlIGJ1dHRvbiBpcyBleHBlY3RlZCB0byBlbmQgaW4uIEFueSBvdGhlciBzdGF0dXMgc3RpbGwgZmFpbHMsIHNvIGFuIGVycm9yIGRlbW8gdGhhdFxuICAgKiBzdGFydHMgdGltaW5nIG91dCBpbnN0ZWFkIGlzIHJlcG9ydGVkIHJhdGhlciB0aGFuIHdhdmVkIHRocm91Z2guXG4gICAqL1xuICByZWFkb25seSBzdGF0dXM6IEV4Y2x1ZGU8RGVtb1ZhdWx0QnV0dG9uUmVzdWx0WydzdGF0dXMnXSwgJ29rJz47XG59XG5cbi8qKlxuICogVGhlIG9wdGlvbnMgZm9yIHtAbGluayByZWdpc3RlckRlbW9WYXVsdEJ1dHRvblN1aXRlfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWdpc3RlckRlbW9WYXVsdEJ1dHRvblN1aXRlT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBIb3cgbG9uZywgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBhIGNsaWNrZWQgYnV0dG9uIHRvIHJlcG9ydCBhIHJlc3VsdC5cbiAgICpcbiAgICogQm91bmRlZCBieSB0aGUgc2FtZSBzdW0gYXMge0BsaW5rIFJlZ2lzdGVyRGVtb1ZhdWx0QnV0dG9uU3VpdGVPcHRpb25zLnNldHRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kc30sXG4gICAqIGFuZCByZWZ1c2VkIGJ5IHRoZSBzYW1lIHRocm93IGF0IHJlZ2lzdHJhdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgYDEwMDAwYFxuICAgKi9cbiAgcmVhZG9ubHkgYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBGb2xkZXJzIHRvIHNraXAgd2hvbGUsIG1hdGNoZWQgYWdhaW5zdCBib3RoIHRoZSBmb2xkZXIgbmFtZSBhbmQgaXRzIHBhdGggcmVsYXRpdmUgdG8gdGhlIGRlbW8gdmF1bHRcbiAgICogcm9vdCBcdTIwMTQgZm9yIGEgZ3JvdXAgd2hvc2Ugbm90ZXMgY2Fubm90IHJ1biB1bmF0dGVuZGVkLCBzdWNoIGFzIG9uZXMgdGhhdCBmaXJzdCBpbnN0YWxsIGEgdGhpcmQtcGFydHlcbiAgICogcGx1Z2luIGZyb20gdGhlIGNvbW11bml0eSBzdG9yZS5cbiAgICpcbiAgICogQGRlZmF1bHQgYFtdYFxuICAgKi9cbiAgcmVhZG9ubHkgZXhjbHVkZWRGb2xkZXJzPzogcmVhZG9ubHkgc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIE5vdGUgZmlsZSBuYW1lcyAocmVsYXRpdmUgdG8gdGhlIGRlbW8gdmF1bHQgcm9vdCkgdG8gc2tpcC5cbiAgICpcbiAgICogQGRlZmF1bHQgYFsnUkVBRE1FLm1kJ11gXG4gICAqL1xuICByZWFkb25seSBleGNsdWRlZE5vdGVzPzogcmVhZG9ubHkgc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEJ1dHRvbnMgdGhhdCBsZWdpdGltYXRlbHkgZG8gbm90IHJlcG9ydCBzdWNjZXNzOiBhbiBlcnJvciBkZW1vLCBvciBhIGJ1dHRvbiB0aGF0IHR1cm5zIHN5c3RlbVxuICAgKiBtZXNzYWdlcyBvZmYgYW5kIHNvIG5ldmVyIHByaW50cyB0aGUgcmVzdWx0IGxpbmUgdGhlIHN1aXRlIGNsYXNzaWZpZXMuXG4gICAqXG4gICAqIEBkZWZhdWx0IGBbXWBcbiAgICovXG4gIHJlYWRvbmx5IGV4cGVjdGVkTm9uT2tCdXR0b25zPzogcmVhZG9ubHkgRXhwZWN0ZWROb25Pa0J1dHRvbltdO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVwb3NpdG9yeSByb290IGhvbGRpbmcgYGRlbW8tdmF1bHQvYC5cbiAgICpcbiAgICogQGRlZmF1bHQgdGhlIHJlc29sdmVkIHJlcG8gcm9vdCwgZmFsbGluZyBiYWNrIHRvIGBwcm9jZXNzLmN3ZCgpYC5cbiAgICovXG4gIHJlYWRvbmx5IHJvb3RGb2xkZXI/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEhvdyBsb25nLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGEgbm90ZSdzIHByZXZpZXcgYW5kIGl0cyBidXR0b25zIHRvIG1vdW50LlxuICAgKlxuICAgKiBUb2dldGhlciB3aXRoIGBidXR0b25SZXN1bHRUaW1lb3V0SW5NaWxsaXNlY29uZHNgIHRoaXMgbXVzdCBzdGF5IHVuZGVyIHRoZSB0cmFuc3BvcnQncyB+MzAgcyBzY3JpcHRcbiAgICogdGltZW91dDogb25lIGJ1dHRvbiBjbGljayBzcGVuZHMgYm90aCBpbnNpZGUgYSBTSU5HTEUgZXZhbHVhdGlvbiwgc28gYSBzdW0gYXQgb3Igb3ZlciB0aGUgY2FwIGNhbm5vdFxuICAgKiBiZSBob25vdXJlZCBhbmQgdHVybnMgYSByZWFsIHRpbWVvdXQgaW50byBhIGJhcmUgYHNjcmlwdCB0aW1lb3V0YCBuYW1pbmcgb25seSB0aGUgdHJhbnNwb3J0LlxuICAgKiB7QGxpbmsgcmVnaXN0ZXJEZW1vVmF1bHRCdXR0b25TdWl0ZX0gdGhyb3dzIG9uIHN1Y2ggYSBwYWlyIHJhdGhlciB0aGFuIHJlZ2lzdGVyaW5nIGl0LlxuICAgKlxuICAgKiBAZGVmYXVsdCBgMTIwMDBgXG4gICAqL1xuICByZWFkb25seSBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHM/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZGlzbWlzcyBhbnkgb3BlbiBtb2RhbCB3aGlsZSB3YWl0aW5nIGZvciBhIGNsaWNrZWQgYnV0dG9uJ3MgcmVzdWx0LCBhbmQgYWdhaW4gb25jZSBpdCBpc1xuICAgKiBjbGFzc2lmaWVkLlxuICAgKlxuICAgKiBBIGJ1dHRvbiB0aGF0IGBhd2FpdGBzIGFuIGBhbGVydGAgLyBgY29uZmlybWAgLyBgcHJvbXB0YCBjYW5ub3QgcmVwb3J0IGEgcmVzdWx0IHVudGlsIHNvbWVib2R5IGNsb3Nlc1xuICAgKiB0aGUgZGlhbG9nLCBzbyB3aXRob3V0IHRoaXMgaXQgZW5kcyBhcyBgdGltZW91dGAgXHUyMDE0IGFuZCB0aGUgZGlhbG9nIGl0IGxlZnQgb3BlbiB0aGVuIHNpdHMgb3ZlciBldmVyeVxuICAgKiBsYXRlciBidXR0b24gaW4gdGhlIHJ1bi4gT2ZmIGJ5IGRlZmF1bHQsIHNvIG5vIHN1aXRlIGNoYW5nZXMgYmVoYXZpb3IgdW5hc2tlZC5cbiAgICpcbiAgICogQGRlZmF1bHQgYGZhbHNlYFxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkRGlzbWlzc01vZGFscz86IGJvb2xlYW47XG59XG5cbi8qXG4gKiBUaGVzZSB0d28gYXJlIHNwZW50IElOU0lERSBPTkUgYGV2YWxJbk9ic2lkaWFuYCBjbG9zdXJlIGJ5IGBjbGlja0J1dHRvbmAsIHdoaWNoIHdhaXRzIGZvciB0aGUgYnV0dG9uIHRvXG4gKiBtb3VudCBhbmQgdGhlbiBmb3IgaXRzIHJlc3VsdCwgc28gaXQgaXMgdGhlaXIgU1VNIHRoYXQgaGFzIHRvIHN0YXkgdW5kZXIgdGhlIHRyYW5zcG9ydCdzIH4zMCBzIHNjcmlwdFxuICogdGltZW91dCBcdTIwMTQgbm90IGVpdGhlciBvbmUgYWxvbmUuIFRoZSBmb3JtZXIgMjAgMDAwICsgMTUgMDAwIGFza2VkIGZvciAzNSBzLCB3aGljaCB0aGUgdHJhbnNwb3J0IGNhbiBuZXZlclxuICogZ3JhbnQ6IGEgc2xvdyBidXR0b24gZGlkIG5vdCByZXBvcnQgXCJuZXZlciByZXBvcnRlZCBhIHJlc3VsdFwiLCBpdCBkaWVkIGFzIGEgYmFyZSBgc2NyaXB0IHRpbWVvdXRgIG5hbWluZ1xuICogb25seSB0aGUgdHJhbnNwb3J0LiBgbm8tb3Zlci1jYXAtd2FpdC1pbi1ldmFsLWluLW9ic2lkaWFuYCBjYW5ub3QgY2F0Y2ggdGhpcyBvbmUsIGJlY2F1c2UgdGhlIGJ1ZGdldHNcbiAqIHJlYWNoIHRoZSBjbG9zdXJlIGZyb20gYSBjYWxsZXIgdHdvIGxldmVscyB1cCByYXRoZXIgdGhhbiBiZWluZyB3cml0dGVuIGF0IHRoZSB3YWl0IFx1MjAxNCB3aGljaCBpcyB3aHlcbiAqIGBhc3NlcnRDbGlja0J1ZGdldHNGaXRUcmFuc3BvcnRDYXBgIGJlbG93IGVuZm9yY2VzIGF0IHJ1bnRpbWUgd2hhdCB0aGUgcnVsZSBjYW5ub3Qgc2VlLiBPdmVycmlkaW5nXG4gKiBlaXRoZXIgZGVmYXVsdCB2aWEgYFJlZ2lzdGVyRGVtb1ZhdWx0QnV0dG9uU3VpdGVPcHRpb25zYCBpcyBzdWJqZWN0IHRvIHRoZSBzYW1lIHN1bS5cbiAqL1xuY29uc3QgREVGQVVMVF9CVVRUT05fUkVTVUxUX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gMTBfMDAwO1xuY29uc3QgREVGQVVMVF9TRVRUTEVfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAxMl8wMDA7XG5cbmludGVyZmFjZSBDbGlja0J1dHRvblBhcmFtcyB7XG4gIC8qKlxuICAgKiBUaGUgYnV0dG9uJ3MgcmVuZGVyZWQgY2FwdGlvbiwgd2hpY2ggaXMgaG93IGl0IGlzIGFkZHJlc3NlZC5cbiAgICovXG4gIHJlYWRvbmx5IGJ1dHRvbkNhcHRpb246IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5vdGUgaG9sZGluZyB0aGUgYnV0dG9uLlxuICAgKi9cbiAgcmVhZG9ubHkgbm90ZVBhdGg6IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0byBkaXNtaXNzIHRoZSBtb2RhbHMgdGhlIGJ1dHRvbiBvcGVucy5cbiAgICovXG4gIHJlYWRvbmx5IHNob3VsZERpc21pc3NNb2RhbHM6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSByZW5kZXIgYW5kIHJlc3VsdCBidWRnZXRzLlxuICAgKi9cbiAgcmVhZG9ubHkgdGltZW91dHM6IENsaWNrQnV0dG9uVGltZW91dHM7XG59XG5cbmNvbnN0IFBPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTID0gMTAwO1xuY29uc3QgT1VUUFVUX0VYQ0VSUFRfTEVOR1RIID0gNDAwO1xuXG4vLyBgUkVBRE1FLm1kYCBpcyB0aGUgcmVwby1mYWNpbmcgcGFnZSBHaXRIdWIgcmVuZGVycywgbm90IGEgd2Fsa3Rocm91Z2guIGAwMCBTdGFydC5tZGAgaXMgZGVsaWJlcmF0ZWx5XG4vLyBOT1QgZXhjbHVkZWQ6IHRoZSBsYW5kaW5nIG5vdGVzIGNhcnJ5IGJ1dHRvbnMgb2YgdGhlaXIgb3duLlxuY29uc3QgREVGQVVMVF9FWENMVURFRF9OT1RFUyA9IFsnUkVBRE1FLm1kJ107XG5cbi8vIEEgZmVuY2UgbGluZTogaXRzIG1hcmtlciBydW4gKHRocmVlIG9yIG1vcmUgYmFja3RpY2tzIG9yIHRpbGRlcykgYW5kIHdoYXRldmVyIGZvbGxvd3MgaXQuXG5jb25zdCBGRU5DRV9SRUdfRVhQID0gL14oPzxpbmRlbnQ+XFxzKikoPzxtYXJrZXI+YHszLH18fnszLH0pKD88aW5mbz4uKikkLztcbmNvbnN0IENPREVfQlVUVE9OX0ZFTkNFX0lORk8gPSAnY29kZS1idXR0b24nO1xuY29uc3QgRlJPTlRfTUFUVEVSX0RFTElNSVRFUiA9ICctLS0nO1xuY29uc3QgUkFXX01PREVfQ09ORklHX1JFR19FWFAgPSAvXmlzUmF3Olxccyp0cnVlXFxzKiQvbTtcbmNvbnN0IENBUFRJT05fQ09ORklHX1JFR19FWFAgPSAvXmNhcHRpb246KD88dmFsdWU+LiopJC9tO1xuY29uc3QgUExBSU5fU0NBTEFSX0NPTU1FTlRfUkVHX0VYUCA9IC9cXHMrIy4qJC87XG5jb25zdCBTSU5HTEVfUVVPVEVEX1NDQUxBUl9SRUdfRVhQID0gL14nKD88Y29udGVudD4uKiknJC87XG5jb25zdCBET1VCTEVfUVVPVEVEX1NDQUxBUl9SRUdfRVhQID0gL15cIig/PGNvbnRlbnQ+LiopXCIkLztcbi8vIGBDb2RlU2NyaXB0IFRvb2xraXRgJ3Mgb3duIGRlZmF1bHQsIHdoaWNoIGEgZmVuY2UgbmFtaW5nIG5vIGNhcHRpb24gcmVuZGVycy5cbmNvbnN0IERFRkFVTFRfQ09ERV9CVVRUT05fQ0FQVElPTiA9ICcobm8gY2FwdGlvbiknO1xuXG4vLyBUaGUgcmVuZGVyZWQtYnV0dG9uIHNlbGVjdG9yIGlzIGA6c2NvcGUgLmJsb2NrLWxhbmd1YWdlLWNvZGUtYnV0dG9uIGJ1dHRvbi5tb2QtY3RhYC4gSXQgaXMgd3JpdHRlblxuLy8gb3V0IGF0IGVhY2ggdXNlIHNpdGUgcmF0aGVyIHRoYW4gaGVsZCBpbiBhIGNvbnN0YW50IGhlcmU6IGV2ZXJ5IGNsb3N1cmUgYmVsb3cgaXMgc2VyaWFsaXplZCB3aXRoXG4vLyBgdG9TdHJpbmcoKWAgYW5kIGV2YWx1YXRlZCBpbnNpZGUgT2JzaWRpYW4sIHdoZXJlIG5vdGhpbmcgZnJvbSB0aGlzIG1vZHVsZSdzIHNjb3BlIGV4aXN0cy5cblxuLyoqXG4gKiBSZWZ1c2VzIGEgc2V0dGxlL3Jlc3VsdCBidWRnZXQgcGFpciB0aGF0IGEgc2luZ2xlIHRyYW5zcG9ydCBjYWxsIGNvdWxkIG5ldmVyIGhvbm91ci5cbiAqXG4gKiBgY2xpY2tCdXR0b25gIHdhaXRzIGZvciB0aGUgYnV0dG9uIHRvIG1vdW50IGFuZCB0aGVuIGZvciBpdHMgcmVzdWx0IElOU0lERSBPTkUgYGV2YWxJbk9ic2lkaWFuYFxuICogY2xvc3VyZSwgc28gdGhlIHRyYW5zcG9ydCdzIHNjcmlwdCB0aW1lb3V0IGJvdW5kcyB0aGVpciBzdW0gcmF0aGVyIHRoYW4gZWl0aGVyIG9uZSBhbG9uZSBcdTIwMTQgYW5kXG4gKiBgUmVnaXN0ZXJEZW1vVmF1bHRCdXR0b25TdWl0ZU9wdGlvbnNgIGxldHMgYSBjb25zdW1lciByYWlzZSBlYWNoIGluZGVwZW5kZW50bHksIHdpdGggbm90aGluZyBzdW1taW5nXG4gKiB0aGVtLiBSYWlzaW5nIGBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHNgIHRvIDIwIDAwMCBmb3Igb25lIHNsb3cgbm90ZSBpcyBhbiBvcmRpbmFyeSB0aGluZyB0byBkbyBhbmRcbiAqIHNpbGVudGx5IHB1dHMgdGhlIHBhaXIgYXQgdGhlIGNhcC5cbiAqXG4gKiBUaHJvd2luZyBoZXJlLCBhdCBzdWl0ZSByZWdpc3RyYXRpb24sIGlzIHRoZSB3aG9sZSB2YWx1ZTogdGhlIGZhaWx1cmUgaXQgcmVwbGFjZXMgaXMgYVxuICogYFdlYkRyaXZlckVycm9yOiBzY3JpcHQgdGltZW91dGAgcmFpc2VkIG1pZC1ydW4gYWdhaW5zdCB3aGljaGV2ZXIgYnV0dG9uIGhhcHBlbmVkIHRvIGJlIHNsb3dlc3QsXG4gKiBuYW1pbmcgdGhlIHRyYW5zcG9ydCBhbmQgbmVpdGhlciBidWRnZXQuXG4gKlxuICogQHBhcmFtIHRpbWVvdXRzIC0gVGhlIHtAbGluayBDbGlja0J1dHRvblRpbWVvdXRzfSB0byBib3VuZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFzc2VydENsaWNrQnVkZ2V0c0ZpdFRyYW5zcG9ydENhcCh0aW1lb3V0czogQ2xpY2tCdXR0b25UaW1lb3V0cyk6IHZvaWQge1xuICBjb25zdCB0b3RhbEluTWlsbGlzZWNvbmRzID0gdGltZW91dHMuc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzICsgdGltZW91dHMuYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzO1xuXG4gIC8qXG4gICAqIFRoZSBjb21wYXJpc29uIGlzIGA8YCByYXRoZXIgdGhhbiBgPD1gIGJlY2F1c2UgYSBzdW0gdGhhdCBtZXJlbHkgUkVBQ0hFUyB0aGUgY2FwIGNhbiBhbHJlYWR5IG5ldmVyXG4gICAqIGJlIGhvbm91cmVkOiBgbm8tb3Zlci1jYXAtd2FpdC1pbi1ldmFsLWluLW9ic2lkaWFuYCByZXBvcnRzIGF0IHRoZSBjYXAgYXMgd2VsbCBhcyBvdmVyIGl0LCBhbmQgYVxuICAgKiBjbG9zdXJlIGhhbmRlZCBleGFjdGx5IHRoZSB0cmFuc3BvcnQncyBidWRnZXQgaGFzIG5vdGhpbmcgbGVmdCBmb3IgdGhlIGRpc3BhdGNoIGl0c2VsZi5cbiAgICovXG4gIGlmICh0b3RhbEluTWlsbGlzZWNvbmRzIDwgREVGQVVMVF9FVkFMX0NBUF9JTl9NSUxMSVNFQ09ORFMpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgYE9uZSBkZW1vLXZhdWx0IGJ1dHRvbiBjbGljayBzcGVuZHMgc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzICgke1N0cmluZyh0aW1lb3V0cy5zZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHMpfSBtcykgYW5kIGBcbiAgICAgICsgYGJ1dHRvblJlc3VsdFRpbWVvdXRJbk1pbGxpc2Vjb25kcyAoJHtTdHJpbmcodGltZW91dHMuYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzKX0gbXMpIGluc2lkZSBhIHNpbmdsZSB0cmFuc3BvcnQgY2FsbCwgYFxuICAgICAgKyBgc28gdGhlaXIgc3VtIG9mICR7U3RyaW5nKHRvdGFsSW5NaWxsaXNlY29uZHMpfSBtcyBpcyBhdCBvciBvdmVyIHRoZSB0cmFuc3BvcnQncyBgXG4gICAgICArIGAke1N0cmluZyhERUZBVUxUX0VWQUxfQ0FQX0lOX01JTExJU0VDT05EUyl9IG1zIHNjcmlwdCB0aW1lb3V0IGFuZCBjYW4gbmV2ZXIgYmUgaG9ub3VyZWQuIGBcbiAgICAgICsgJ0xvd2VyIGVpdGhlciBidWRnZXQgaW4gUmVnaXN0ZXJEZW1vVmF1bHRCdXR0b25TdWl0ZU9wdGlvbnMuJ1xuICApO1xufVxuXG4vKipcbiAqIENvdW50cyB0aGUgYnV0dG9ucyBhIG5vdGUncyBzb3VyY2Ugd2lsbCBhY3R1YWxseSByZW5kZXIuXG4gKlxuICogVGhyZWUga2luZHMgb2YgYCBgYGBjb2RlLWJ1dHRvbiBgIGZlbmNlIHJlbmRlciBubyBjbGlja2FibGUgYnV0dG9uLCBhbmQgYSB2YXVsdCB0aGF0IERPQ1VNRU5UUyBjb2RlXG4gKiBidXR0b25zIGlzIGZ1bGwgb2YgdGhlIGZpcnN0IHR3bzpcbiAqXG4gKiAtIEEgZmVuY2UgbmVzdGVkIGluc2lkZSBhIGxvbmdlciBvciBkaWZmZXJlbnQgZmVuY2UgKGEgYGBgYCBgYGBgbWFya2Rvd24gYGBgYCBvciBgfn5+YCBibG9jaykgaXMgYVxuICogICBtYXJrZG93biBTQU1QTEUgc2hvd24gdG8gdGhlIHJlYWRlcjsgdGhlIHJlbmRlcmVyIG5ldmVyIHNlZXMgaXQgYXMgYSBibG9jay5cbiAqIC0gQW4gYGlzUmF3OiB0cnVlYCBmZW5jZSByZW5kZXJzIGl0cyBvdXRwdXQgZGlyZWN0bHkgYW5kIG5vIGJ1dHRvbiBlbGVtZW50IGF0IGFsbC5cbiAqIC0gQSBmZW5jZSB3aG9zZSBpbmZvIHN0cmluZyBjYXJyaWVzIGFueXRoaW5nIGFmdGVyIGBjb2RlLWJ1dHRvbmAgdXNlcyB0aGUgbGVnYWN5IGFyZ3VtZW50IHN5bnRheCwgd2hpY2hcbiAqICAgcmVuZGVycyBhbiBlcnJvciBiYW5uZXIgYXNraW5nIHRvIHVwZGF0ZSB0aGUgY29uZmlnIHJhdGhlciB0aGFuIHRoZSBidXR0b24uXG4gKlxuICogQ291bnRpbmcgYW55IG9mIHRoZW0gbWFrZXMgdGhlIHN1aXRlJ3Mgc2hvcnRmYWxsIGFzc2VydGlvbiB1bnNhdGlzZmlhYmxlIFx1MjAxNCBpdCBkZW1hbmRzIG1vcmUgYnV0dG9uc1xuICogdGhhbiB0aGUgbm90ZSBjYW4gZXZlciByZW5kZXIgXHUyMDE0IGFuZCBhbiBhc3NlcnRpb24gdGhhdCBjYW5ub3QgcGFzcyBnYXRlcyBub3RoaW5nLlxuICpcbiAqIFRoZSBzY2FuIGZvbGxvd3MgQ29tbW9uTWFyaydzIGZlbmNlIHJ1bGVzOiBhIGZlbmNlIGNsb3NlcyBvbmx5IG9uIGEgcnVuIG9mIHRoZSBTQU1FIGNoYXJhY3RlciBhdCBsZWFzdFxuICogYXMgbG9uZyBhcyB0aGUgb3BlbmVyLCB3aXRoIG5vIGluZm8gc3RyaW5nLCBhbmQgb25lIGxlZnQgb3BlbiBydW5zIHRvIHRoZSBlbmQgb2YgdGhlIGRvY3VtZW50LCB3aGVyZSBpdFxuICogc3RpbGwgcmVuZGVycy5cbiAqXG4gKiBAcGFyYW0gc291cmNlIC0gVGhlIG5vdGUncyBtYXJrZG93bi5cbiAqIEByZXR1cm5zIEhvdyBtYW55IGJ1dHRvbnMgaXQgcmVuZGVycy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvdW50UmVuZGVyZWRCdXR0b25zKHNvdXJjZTogc3RyaW5nKTogbnVtYmVyIHtcbiAgcmV0dXJuIGxpc3RSZW5kZXJlZEJ1dHRvbkNhcHRpb25zKHNvdXJjZSkubGVuZ3RoO1xufVxuXG4vKipcbiAqIEZpbmRzIHRoZSBjYXB0aW9ucyBkZWNsYXJlZCBieSBtb3JlIHRoYW4gb25lIGJ1dHRvbi5cbiAqXG4gKiBUaGUgc3VpdGUgYWRkcmVzc2VzIGEgYnV0dG9uIGJ5IGl0cyBjYXB0aW9uIFx1MjAxNCBpdCBjb2xsZWN0cyB0aGUgY2FwdGlvbnMgdGhhdCBtb3VudGVkIGFuZCBjbGlja3MgdGhlXG4gKiBidXR0b24gY2FycnlpbmcgZWFjaCBvbmUgXHUyMDE0IHNvIHR3byBidXR0b25zIHNoYXJpbmcgYSBjYXB0aW9uIGNvbGxhcHNlIGludG8gb25lOiB0aGUgc2Vjb25kIGlzIG5ldmVyXG4gKiBjbGlja2VkLCBhbmQgdGhlIG5vdGUgcmVhZHMgYXMgZGVjbGFyaW5nIGEgYnV0dG9uIHRoYXQgbmV2ZXIgcmVuZGVyZWQuXG4gKlxuICogQHBhcmFtIGNhcHRpb25zIC0gQSBub3RlJ3MgYnV0dG9uIGNhcHRpb25zLlxuICogQHJldHVybnMgRWFjaCBjYXB0aW9uIG9jY3VycmluZyBtb3JlIHRoYW4gb25jZSwgbGlzdGVkIG9uY2UsIGluIG9yZGVyIG9mIGZpcnN0IHJlcGVhdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmREdXBsaWNhdGVDYXB0aW9ucyhjYXB0aW9uczogcmVhZG9ubHkgc3RyaW5nW10pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IHNlZW5DYXB0aW9ucyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBkdXBsaWNhdGVDYXB0aW9ucyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBmb3IgKGNvbnN0IGNhcHRpb24gb2YgY2FwdGlvbnMpIHtcbiAgICBpZiAoc2VlbkNhcHRpb25zLmhhcyhjYXB0aW9uKSkge1xuICAgICAgZHVwbGljYXRlQ2FwdGlvbnMuYWRkKGNhcHRpb24pO1xuICAgIH1cbiAgICBzZWVuQ2FwdGlvbnMuYWRkKGNhcHRpb24pO1xuICB9XG4gIHJldHVybiBbLi4uZHVwbGljYXRlQ2FwdGlvbnNdO1xufVxuXG4vKipcbiAqIEJ1aWxkcyB0aGUgYXNzZXJ0aW9uIG1lc3NhZ2UgZm9yIGEgbm90ZSdzIGZhaWxpbmcgYnV0dG9ucy5cbiAqXG4gKiBUaGUgY2FwdHVyZWQgb3V0cHV0IGlzIGluY2x1ZGVkIGJlY2F1c2UgYSBidXR0b24ncyBmYWlsdXJlIGlzIGEgcnVudGltZSBvbmUgXHUyMDE0IHRoZSBzdGFja1xuICogYENvZGVTY3JpcHQgVG9vbGtpdGAgcHJpbnRzIHVuZGVyIGl0IGlzIHRoZSBvbmx5IGRpYWdub3NpcyB0aGVyZSBpcy5cbiAqXG4gKiBAcGFyYW0gbm90ZU5hbWUgLSBUaGUgbm90ZSB0aGUgYnV0dG9ucyBiZWxvbmcgdG8uXG4gKiBAcGFyYW0gZmFpbHVyZXMgLSBUaGUgZmFpbGluZyBidXR0b25zLlxuICogQHJldHVybnMgVGhlIG1lc3NhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRGYWlsdXJlcyhub3RlTmFtZTogc3RyaW5nLCBmYWlsdXJlczogcmVhZG9ubHkgRGVtb1ZhdWx0QnV0dG9uUmVzdWx0W10pOiBzdHJpbmcge1xuICBpZiAoZmFpbHVyZXMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuICcnO1xuICB9XG5cbiAgY29uc3QgZGV0YWlscyA9IGZhaWx1cmVzXG4gICAgLm1hcCgoZmFpbHVyZSkgPT4gYCAgLSBcIiR7ZmFpbHVyZS5jYXB0aW9ufVwiIFske2ZhaWx1cmUuc3RhdHVzfV06ICR7ZmFpbHVyZS5vdXRwdXQucmVwbGFjZUFsbCgvXFxzKy9nLCAnICcpLnRyaW0oKX1gKVxuICAgIC5qb2luKCdcXG4nKTtcbiAgcmV0dXJuIGAke1N0cmluZyhmYWlsdXJlcy5sZW5ndGgpfSBidXR0b24ocykgaW4gJHtub3RlTmFtZX0gZGlkIG5vdCBydW4gY2xlYW5seTpcXG4ke2RldGFpbHN9YDtcbn1cblxuLyoqXG4gKiBMaXN0cyB0aGUgY2FwdGlvbnMgb2YgdGhlIGJ1dHRvbnMgYSBub3RlJ3Mgc291cmNlIHdpbGwgYWN0dWFsbHkgcmVuZGVyLCBpbiBzb3VyY2Ugb3JkZXIuXG4gKlxuICogV2hpY2ggZmVuY2VzIHJlbmRlciBhIGJ1dHRvbiBpcyBkZWNpZGVkIGV4YWN0bHkgYXMge0BsaW5rIGNvdW50UmVuZGVyZWRCdXR0b25zfSBkZXNjcmliZXMuIEEgY2FwdGlvbiBpc1xuICogcmVhZCBmcm9tIHRoZSBmZW5jZSdzIG93biBjb25maWcgYmxvY2s7IGEgZmVuY2UgbmFtaW5nIG5vbmUgdGFrZXMgYENvZGVTY3JpcHQgVG9vbGtpdGAncyBkZWZhdWx0LFxuICogYChubyBjYXB0aW9uKWAsIHdoaWNoIGlzIHdoYXQgaXRzIGJ1dHRvbiB0aGVuIHNob3dzLlxuICpcbiAqIEBwYXJhbSBzb3VyY2UgLSBUaGUgbm90ZSdzIG1hcmtkb3duLlxuICogQHJldHVybnMgVGhlIGNhcHRpb25zLCBvbmUgcGVyIHJlbmRlcmVkIGJ1dHRvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3RSZW5kZXJlZEJ1dHRvbkNhcHRpb25zKHNvdXJjZTogc3RyaW5nKTogc3RyaW5nW10ge1xuICBjb25zdCBjYXB0aW9uczogc3RyaW5nW10gPSBbXTtcbiAgbGV0IG9wZW5NYXJrZXIgPSAnJztcbiAgbGV0IGlzQ29kZUJ1dHRvbkZlbmNlID0gZmFsc2U7XG4gIGxldCBmZW5jZUJvZHk6IHN0cmluZ1tdID0gW107XG4gIGxldCBmZW5jZUluZGVudExlbmd0aCA9IDA7XG5cbiAgZnVuY3Rpb24gY2xvc2VGZW5jZSgpOiB2b2lkIHtcbiAgICBpZiAoaXNDb2RlQnV0dG9uRmVuY2UgJiYgIWlzUmF3RmVuY2UoZmVuY2VCb2R5KSkge1xuICAgICAgY2FwdGlvbnMucHVzaChyZWFkQ2FwdGlvbihmZW5jZUJvZHkpKTtcbiAgICB9XG4gICAgb3Blbk1hcmtlciA9ICcnO1xuICB9XG5cbiAgZm9yIChjb25zdCBsaW5lIG9mIHNvdXJjZS5zcGxpdCgvXFxyP1xcbi8pKSB7XG4gICAgY29uc3QgbWF0Y2ggPSBGRU5DRV9SRUdfRVhQLmV4ZWMobGluZSk7XG4gICAgY29uc3QgaW5kZW50ID0gbWF0Y2g/Lmdyb3Vwcz8uWydpbmRlbnQnXSA/PyAnJztcbiAgICBjb25zdCBtYXJrZXIgPSBtYXRjaD8uZ3JvdXBzPy5bJ21hcmtlciddID8/ICcnO1xuICAgIGNvbnN0IGluZm8gPSAobWF0Y2g/Lmdyb3Vwcz8uWydpbmZvJ10gPz8gJycpLnRyaW0oKTtcblxuICAgIGlmIChvcGVuTWFya2VyID09PSAnJykge1xuICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgIG9wZW5NYXJrZXIgPSBtYXJrZXI7XG4gICAgICAgIGlzQ29kZUJ1dHRvbkZlbmNlID0gaW5mbyA9PT0gQ09ERV9CVVRUT05fRkVOQ0VfSU5GTztcbiAgICAgICAgZmVuY2VCb2R5ID0gW107XG4gICAgICAgIGZlbmNlSW5kZW50TGVuZ3RoID0gaW5kZW50Lmxlbmd0aDtcbiAgICAgIH1cbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIC8vIEFueXRoaW5nIGVsc2Ugd2hpbGUgYSBmZW5jZSBpcyBvcGVuIGlzIGl0cyBjb250ZW50IFx1MjAxNCB3aGljaCBpcyBleGFjdGx5IGhvdyBhIGBgYGBtYXJrZG93biBzYW1wbGVcbiAgICAvLyBob2xkcyBhIGBgYGNvZGUtYnV0dG9uLlxuICAgIGlmIChtYXJrZXIuc3RhcnRzV2l0aChvcGVuTWFya2VyLmNoYXJBdCgwKSkgJiYgbWFya2VyLmxlbmd0aCA+PSBvcGVuTWFya2VyLmxlbmd0aCAmJiBpbmZvID09PSAnJykge1xuICAgICAgY2xvc2VGZW5jZSgpO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgLy8gQ29tbW9uTWFyayBzdHJpcHMgdXAgdG8gdGhlIG9wZW5pbmcgZmVuY2UncyBpbmRlbnRhdGlvbiBmcm9tIGVhY2ggY29udGVudCBsaW5lLCBzbyBhIGZlbmNlIG5lc3RlZCBpblxuICAgIC8vIGEgbGlzdCBpdGVtIGNhcnJpZXMgaXRzIGBjYXB0aW9uOmAgLyBgaXNSYXc6YCBrZXlzIGF0IGNvbHVtbiAwIGxpa2UgYW55IG90aGVyLlxuICAgIGZlbmNlQm9keS5wdXNoKGxpbmUuc2xpY2UoTWF0aC5taW4oZmVuY2VJbmRlbnRMZW5ndGgsIGxpbmUubGVuZ3RoIC0gbGluZS50cmltU3RhcnQoKS5sZW5ndGgpKSk7XG4gIH1cblxuICBpZiAob3Blbk1hcmtlciAhPT0gJycpIHtcbiAgICBjbG9zZUZlbmNlKCk7XG4gIH1cblxuICByZXR1cm4gY2FwdGlvbnM7XG59XG5cbi8qKlxuICogUGlja3MgdGhlIGJ1dHRvbnMgdGhhdCBmYWlsZWQgYW5kIHdlcmUgbm90IGV4cGVjdGVkIHRvLlxuICpcbiAqIEBwYXJhbSBub3RlTmFtZSAtIFRoZSBub3RlIHRoZSByZXN1bHRzIGJlbG9uZyB0bywgcmVsYXRpdmUgdG8gdGhlIGRlbW8gdmF1bHQgcm9vdC5cbiAqIEBwYXJhbSByZXN1bHRzIC0gRXZlcnkgYnV0dG9uJ3MgcmVzdWx0IGluIHRoYXQgbm90ZS5cbiAqIEBwYXJhbSBleHBlY3RlZE5vbk9rQnV0dG9ucyAtIFRoZSBidXR0b25zIGFsbG93ZWQgdG8gZW5kIGluIGEgZ2l2ZW4gbm9uLWBva2Agc3RhdHVzLlxuICogQHJldHVybnMgVGhlIHJlc3VsdHMgdGhhdCBhcmUgbm90IGBva2AgYW5kIG1hdGNoIG5vIHtAbGluayBFeHBlY3RlZE5vbk9rQnV0dG9ufS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlbGVjdFVuZXhwZWN0ZWRGYWlsdXJlcyhcbiAgbm90ZU5hbWU6IHN0cmluZyxcbiAgcmVzdWx0czogcmVhZG9ubHkgRGVtb1ZhdWx0QnV0dG9uUmVzdWx0W10sXG4gIGV4cGVjdGVkTm9uT2tCdXR0b25zOiByZWFkb25seSBFeHBlY3RlZE5vbk9rQnV0dG9uW11cbik6IERlbW9WYXVsdEJ1dHRvblJlc3VsdFtdIHtcbiAgcmV0dXJuIHJlc3VsdHMuZmlsdGVyKChyZXN1bHQpID0+XG4gICAgcmVzdWx0LnN0YXR1cyAhPT0gJ29rJ1xuICAgICYmIGV4cGVjdGVkTm9uT2tCdXR0b25zLmV2ZXJ5KChleHBlY3RlZCkgPT5cbiAgICAgICEoZXhwZWN0ZWQubm90ZSA9PT0gbm90ZU5hbWVcbiAgICAgICAgJiYgZXhwZWN0ZWQuc3RhdHVzID09PSByZXN1bHQuc3RhdHVzXG4gICAgICAgICYmIHJlc3VsdC5jYXB0aW9uLmluY2x1ZGVzKGV4cGVjdGVkLmNhcHRpb25JbmNsdWRlcykpXG4gICAgKVxuICApO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgYSBgY29kZS1idXR0b25gIGZlbmNlJ3Mgb3duIFlBTUwgY29uZmlnIGFza3MgZm9yIHJhdyBtb2RlLlxuICpcbiAqIFJlYWQgZnJvbSB0aGUgbGVhZGluZyBgLS0tYCBibG9jayByYXRoZXIgdGhhbiBmcm9tIHRoZSB3aG9sZSBib2R5LCBzbyBhbiBgaXNSYXc6IHRydWVgIHdyaXR0ZW4gaW5zaWRlXG4gKiBhIGJ1dHRvbidzIENPREUgXHUyMDE0IGEgYnV0dG9uIHRoYXQgZGVtb25zdHJhdGVzIHRoZSBrZXkgXHUyMDE0IGlzIG5vdCBtaXN0YWtlbiBmb3IgdGhlIGJ1dHRvbidzIG93biBjb25maWcuXG4gKlxuICogQHBhcmFtIGZlbmNlQm9keSAtIFRoZSBmZW5jZSdzIGxpbmVzLCB3aXRob3V0IHRoZSBmZW5jZSBtYXJrZXJzLlxuICogQHJldHVybnMgV2hldGhlciB0aGUgZmVuY2UgcmVuZGVycyBubyBidXR0b24uXG4gKi9cbmZ1bmN0aW9uIGlzUmF3RmVuY2UoZmVuY2VCb2R5OiByZWFkb25seSBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICBjb25zdCBjb25maWcgPSByZWFkQ29uZmlnQmxvY2soZmVuY2VCb2R5KTtcbiAgcmV0dXJuIGNvbmZpZyAhPT0gbnVsbCAmJiBSQVdfTU9ERV9DT05GSUdfUkVHX0VYUC50ZXN0KGNvbmZpZyk7XG59XG5cbi8qKlxuICogUmVhZHMgdGhlIGNhcHRpb24gYSBgY29kZS1idXR0b25gIGZlbmNlJ3Mgb3duIGNvbmZpZyBibG9jayBnaXZlcyBpdHMgYnV0dG9uLlxuICpcbiAqIEEgZGVsaWJlcmF0ZWx5IHNtYWxsIHJlYWRpbmcgb2YgWUFNTCBcdTIwMTQgYSBwbGFpbiwgc2luZ2xlLXF1b3RlZCBvciBkb3VibGUtcXVvdGVkIHNjYWxhciBvbiB0aGUgYGNhcHRpb246YFxuICogbGluZSBcdTIwMTQgc2luY2UgdGhlIHZhbHVlIG9ubHkgZXZlciBuYW1lcyBhIGJ1dHRvbi4gQSB2YWx1ZSBpdCBjYW5ub3QgcmVhZCBleGFjdGx5LCBzdWNoIGFzIGEgYmxvY2tcbiAqIHNjYWxhciwgaXMgcmV0dXJuZWQgYXMgd3JpdHRlbjogdGhhdCBjYW4gbWFrZSBvbmUgY2FwdGlvbiByZWFkIHdyb25nLCBidXQgaXQgY2Fubm90IG1ha2UgdHdvXG4gKiBkaWZmZXJlbnQgb25lcyBjb21wYXJlIGVxdWFsLlxuICpcbiAqIEBwYXJhbSBmZW5jZUJvZHkgLSBUaGUgZmVuY2UncyBsaW5lcywgd2l0aG91dCB0aGUgZmVuY2UgbWFya2Vycy5cbiAqIEByZXR1cm5zIFRoZSBjYXB0aW9uLlxuICovXG5mdW5jdGlvbiByZWFkQ2FwdGlvbihmZW5jZUJvZHk6IHJlYWRvbmx5IHN0cmluZ1tdKTogc3RyaW5nIHtcbiAgY29uc3QgY29uZmlnID0gcmVhZENvbmZpZ0Jsb2NrKGZlbmNlQm9keSk7XG4gIGNvbnN0IHJhd1ZhbHVlID0gY29uZmlnID09PSBudWxsID8gdW5kZWZpbmVkIDogQ0FQVElPTl9DT05GSUdfUkVHX0VYUC5leGVjKGNvbmZpZyk/Lmdyb3Vwcz8uWyd2YWx1ZSddO1xuICBpZiAocmF3VmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBERUZBVUxUX0NPREVfQlVUVE9OX0NBUFRJT047XG4gIH1cblxuICBjb25zdCB2YWx1ZSA9IHJhd1ZhbHVlLnRyaW0oKTtcbiAgY29uc3Qgc2luZ2xlUXVvdGVkQ29udGVudCA9IFNJTkdMRV9RVU9URURfU0NBTEFSX1JFR19FWFAuZXhlYyh2YWx1ZSk/Lmdyb3Vwcz8uWydjb250ZW50J107XG4gIGlmIChzaW5nbGVRdW90ZWRDb250ZW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gc2luZ2xlUXVvdGVkQ29udGVudC5yZXBsYWNlQWxsKCdcXCdcXCcnLCAnXFwnJyk7XG4gIH1cbiAgY29uc3QgZG91YmxlUXVvdGVkQ29udGVudCA9IERPVUJMRV9RVU9URURfU0NBTEFSX1JFR19FWFAuZXhlYyh2YWx1ZSk/Lmdyb3Vwcz8uWydjb250ZW50J107XG4gIGlmIChkb3VibGVRdW90ZWRDb250ZW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UodmFsdWUpIGFzIHN0cmluZztcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBkb3VibGVRdW90ZWRDb250ZW50O1xuICAgIH1cbiAgfVxuICByZXR1cm4gdmFsdWUucmVwbGFjZShQTEFJTl9TQ0FMQVJfQ09NTUVOVF9SRUdfRVhQLCAnJyk7XG59XG5cbi8qKlxuICogUmVhZHMgYSBgY29kZS1idXR0b25gIGZlbmNlJ3MgbGVhZGluZyBgLS0tYCBjb25maWcgYmxvY2suXG4gKlxuICogT25seSB0aGUgbGVhZGluZyBibG9jayBjb3VudHMsIHNvIGEgYC0tLWAgYmxvY2sgd3JpdHRlbiBpbnNpZGUgYSBidXR0b24ncyBDT0RFIGlzIG5vdCBtaXN0YWtlbiBmb3IgdGhlXG4gKiBidXR0b24ncyBvd24gY29uZmlnLlxuICpcbiAqIEBwYXJhbSBmZW5jZUJvZHkgLSBUaGUgZmVuY2UncyBsaW5lcywgd2l0aG91dCB0aGUgZmVuY2UgbWFya2Vycy5cbiAqIEByZXR1cm5zIFRoZSBibG9jaydzIGNvbnRlbnQsIG9yIGBudWxsYCB3aGVuIHRoZSBmZW5jZSBvcGVucyB3aXRoIG5vIHRlcm1pbmF0ZWQgYmxvY2suXG4gKi9cbmZ1bmN0aW9uIHJlYWRDb25maWdCbG9jayhmZW5jZUJvZHk6IHJlYWRvbmx5IHN0cmluZ1tdKTogbnVsbCB8IHN0cmluZyB7XG4gIGlmIChmZW5jZUJvZHlbMF0/LnRyaW0oKSAhPT0gRlJPTlRfTUFUVEVSX0RFTElNSVRFUikge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgZW5kSW5kZXggPSBmZW5jZUJvZHkuZmluZEluZGV4KChsaW5lLCBpbmRleCkgPT4gaW5kZXggPiAwICYmIGxpbmUudHJpbSgpID09PSBGUk9OVF9NQVRURVJfREVMSU1JVEVSKTtcbiAgcmV0dXJuIGVuZEluZGV4ID09PSAtMSA/IG51bGwgOiBmZW5jZUJvZHkuc2xpY2UoMSwgZW5kSW5kZXgpLmpvaW4oJ1xcbicpO1xufVxuXG4vKipcbiAqIEZvbGRlcnMgdGhhdCBuZXZlciBob2xkIGEgd2Fsa3Rocm91Z2guIGBNYXRlcmlhbHMvYCBob2xkcyB0aGUgZml4dHVyZXMgdGhlIHdhbGt0aHJvdWdocyBhY3Qgb247XG4gKiBgX2Fzc2V0cy9gIGhvbGRzIHRoZSBkZW1vIHNjcmlwdHM7IGAub2JzaWRpYW4vYCBpcyB2YXVsdCBjb25maWcuIEEgZm9sZGVyIHN0YXJ0aW5nIHdpdGggYC5gIG9yIGBfYFxuICogaXMgc2tpcHBlZCBvbiB0aGUgc2FtZSByZWFzb25pbmcsIHdpdGhvdXQgaGF2aW5nIHRvIGJlIGxpc3RlZC5cbiAqL1xuY29uc3QgTk9OX1dBTEtUSFJPVUdIX0ZPTERFUlMgPSBuZXcgU2V0KFsnTWF0ZXJpYWxzJ10pO1xuXG4vKipcbiAqIExpc3RzIHRoZSBkZW1vIHZhdWx0J3Mgbm90ZXMgdGhhdCBkZWNsYXJlIGF0IGxlYXN0IG9uZSBgY29kZS1idXR0b25gLCB3YWxraW5nIGdyb3VwIGZvbGRlcnMgdG9vLlxuICpcbiAqIEEgdmF1bHQgYmlnIGVub3VnaCB0byBuZWVkIGdyb3VwaW5nIHB1dHMgaXRzIHdhbGt0aHJvdWdocyBpbiBudW1iZXJlZCBmb2xkZXJzIFx1MjAxNCBhbmQgYSByb290LW9ubHkgd2Fsa1xuICogZmluZHMgTk9ORSBvZiB0aGVtLCB3aGljaCBpcyB3b3JzZSB0aGFuIGl0IHNvdW5kczogYSB2YXVsdCB3aG9zZSBub3RlcyBhcmUgYWxsIGdyb3VwZWQgcmVwb3J0cyB6ZXJvXG4gKiBub3RlcywgYW5kIG9uZSB0aGF0IGlzIHBhcnRseSBncm91cGVkIHNpbGVudGx5IGdhdGVzIG9ubHkgdGhlIHVuZ3JvdXBlZCBwYXJ0LiBGaXh0dXJlIGFuZCBhc3NldFxuICogZm9sZGVycyBhcmUgc3RpbGwgc2tpcHBlZCwgc28gd2hhdCBpcyB3YWxrZWQgaXMgd2Fsa3Rocm91Z2hzIGFuZCBub3RoaW5nIGVsc2UuXG4gKlxuICogQHBhcmFtIGRlbW9WYXVsdFBhdGggLSBUaGUgZGVtbyB2YXVsdCByb290LlxuICogQHBhcmFtIGV4Y2x1ZGVkTm90ZXMgLSBOb3RlIG5hbWVzIHRvIHNraXAsIG1hdGNoZWQgYWdhaW5zdCBib3RoIHRoZSBmaWxlIG5hbWUgYW5kIHRoZSBwYXRoIHJlbGF0aXZlXG4gKiB0byB0aGUgdmF1bHQgcm9vdC5cbiAqIEBwYXJhbSBleGNsdWRlZEZvbGRlcnMgLSBGb2xkZXJzIHRvIHNraXAgd2hvbGUsIG1hdGNoZWQgdGhlIHNhbWUgd2F5LlxuICogQHJldHVybnMgVGhlIG5vdGVzLCBzb3J0ZWQgYnkgcGF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3ROb3Rlc1dpdGhCdXR0b25zKFxuICBkZW1vVmF1bHRQYXRoOiBzdHJpbmcsXG4gIGV4Y2x1ZGVkTm90ZXM6IFJlYWRvbmx5U2V0PHN0cmluZz4sXG4gIGV4Y2x1ZGVkRm9sZGVyczogUmVhZG9ubHlTZXQ8c3RyaW5nPiA9IG5ldyBTZXQoKVxuKTogRGVtb1ZhdWx0Tm90ZVtdIHtcbiAgY29uc3Qgbm90ZXM6IERlbW9WYXVsdE5vdGVbXSA9IFtdO1xuXG4gIGZ1bmN0aW9uIHdhbGsoZm9sZGVyOiBzdHJpbmcsIHJlbGF0aXZlRm9sZGVyOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIHJlYWRkaXJTeW5jKGZvbGRlciwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pKSB7XG4gICAgICBjb25zdCByZWxhdGl2ZVBhdGggPSByZWxhdGl2ZUZvbGRlciA9PT0gJycgPyBlbnRyeS5uYW1lIDogYCR7cmVsYXRpdmVGb2xkZXJ9LyR7ZW50cnkubmFtZX1gO1xuXG4gICAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgIWVudHJ5Lm5hbWUuc3RhcnRzV2l0aCgnLicpICYmICFlbnRyeS5uYW1lLnN0YXJ0c1dpdGgoJ18nKSAmJiAhTk9OX1dBTEtUSFJPVUdIX0ZPTERFUlMuaGFzKGVudHJ5Lm5hbWUpXG4gICAgICAgICAgJiYgIWV4Y2x1ZGVkRm9sZGVycy5oYXMoZW50cnkubmFtZSkgJiYgIWV4Y2x1ZGVkRm9sZGVycy5oYXMocmVsYXRpdmVQYXRoKVxuICAgICAgICApIHtcbiAgICAgICAgICB3YWxrKGpvaW4oZm9sZGVyLCBlbnRyeS5uYW1lKSwgcmVsYXRpdmVQYXRoKTtcbiAgICAgICAgfVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFlbnRyeS5uYW1lLmVuZHNXaXRoKCcubWQnKSB8fCBleGNsdWRlZE5vdGVzLmhhcyhlbnRyeS5uYW1lKSB8fCBleGNsdWRlZE5vdGVzLmhhcyhyZWxhdGl2ZVBhdGgpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBjYXB0aW9ucyA9IGxpc3RSZW5kZXJlZEJ1dHRvbkNhcHRpb25zKHJlYWRGaWxlU3luYyhqb2luKGZvbGRlciwgZW50cnkubmFtZSksICd1dGYtOCcpKTtcbiAgICAgIGlmIChjYXB0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICAgIG5vdGVzLnB1c2goeyBidXR0b25Db3VudDogY2FwdGlvbnMubGVuZ3RoLCBjYXB0aW9ucywgbmFtZTogcmVsYXRpdmVQYXRoIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHdhbGsoZGVtb1ZhdWx0UGF0aCwgJycpO1xuICByZXR1cm4gbm90ZXMuc29ydCgoYSwgYikgPT4gYS5uYW1lLmxvY2FsZUNvbXBhcmUoYi5uYW1lLCAnZW4nKSk7XG59XG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBFdmVyeSBhc3NlcnRpb24gYmVsb3cgcnVucyBhZ2FpbnN0IGEgcmVhbCBPYnNpZGlhbiBvdmVyIENEUCwgZHJpdmVuIGJ5IGNsb3N1cmVzIHRoaXMgcHJvY2VzcyBzZXJpYWxpemVzIGFuZCBhbm90aGVyIGV4ZWN1dGVzLiBUaGUgdGVzdGFibGUgcGFydHMgYXJlIGxpc3ROb3Rlc1dpdGhCdXR0b25zIGFuZCBmb3JtYXRGYWlsdXJlcywgd2hpY2ggaGF2ZSB0aGVpciBvd24gdW5pdCB0ZXN0cy4gKi9cbi8qKlxuICogUmVnaXN0ZXJzIGEgdml0ZXN0IHN1aXRlIHRoYXQgY2xpY2tzIGV2ZXJ5IGBjb2RlLWJ1dHRvbmAgaW4gdGhlIHJlcG8ncyBkZW1vIHZhdWx0LlxuICpcbiAqIE9uZSBgaXRgIHBlciBub3RlLCBhbmQgb25lIGBldmFsSW5PYnNpZGlhbmAgcGVyIGJ1dHRvbjogYSBzaW5nbGUgY2xvc3VyZSBydW5zIGFzIG9uZSBDRFBcbiAqIGBSdW50aW1lLmV2YWx1YXRlYCwgd2hpY2ggdGhlIGhhcm5lc3MgY2FwcyBhdCAzMCBzLCBzbyBhIG5vdGUgd2l0aCBhIGRvemVuIGJ1dHRvbnMgd291bGQgb3RoZXJ3aXNlXG4gKiB0aW1lIG91dCBhcyBhIHdob2xlIHJhdGhlciB0aGFuIHJlcG9ydGluZyB3aGljaCBidXR0b24gZmFpbGVkLlxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIHtAbGluayBSZWdpc3RlckRlbW9WYXVsdEJ1dHRvblN1aXRlT3B0aW9uc30uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlckRlbW9WYXVsdEJ1dHRvblN1aXRlKG9wdGlvbnM6IFJlZ2lzdGVyRGVtb1ZhdWx0QnV0dG9uU3VpdGVPcHRpb25zID0ge30pOiB2b2lkIHtcbiAgY29uc3Qgcm9vdEZvbGRlciA9IG9wdGlvbnMucm9vdEZvbGRlciA/PyBnZXRSb290Rm9sZGVyKCkgPz8gcHJvY2Vzcy5jd2QoKTtcbiAgY29uc3QgZGVtb1ZhdWx0UGF0aCA9IGpvaW4ocm9vdEZvbGRlciwgJ2RlbW8tdmF1bHQnKTtcbiAgY29uc3QgZXhjbHVkZWROb3RlcyA9IG5ldyBTZXQob3B0aW9ucy5leGNsdWRlZE5vdGVzID8/IERFRkFVTFRfRVhDTFVERURfTk9URVMpO1xuICBjb25zdCBleGNsdWRlZEZvbGRlcnMgPSBuZXcgU2V0KG9wdGlvbnMuZXhjbHVkZWRGb2xkZXJzKTtcbiAgY29uc3QgZXhwZWN0ZWROb25Pa0J1dHRvbnMgPSBvcHRpb25zLmV4cGVjdGVkTm9uT2tCdXR0b25zID8/IFtdO1xuICBjb25zdCBzaG91bGREaXNtaXNzTW9kYWxzID0gb3B0aW9ucy5zaG91bGREaXNtaXNzTW9kYWxzID8/IGZhbHNlO1xuICBjb25zdCBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHMgPSBvcHRpb25zLnNldHRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kcyA/PyBERUZBVUxUX1NFVFRMRV9USU1FT1VUX0lOX01JTExJU0VDT05EUztcbiAgY29uc3QgYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzID0gb3B0aW9ucy5idXR0b25SZXN1bHRUaW1lb3V0SW5NaWxsaXNlY29uZHMgPz8gREVGQVVMVF9CVVRUT05fUkVTVUxUX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTO1xuXG4gIC8vIFJlc29sdmVkIE9OQ0UgYW5kIGhhbmRlZCB0byBib3RoIHRoZSBib3VuZCBhbmQgdGhlIGNsaWNrLCBzbyB0aGUgcGFpciB0aGF0IGlzIGFzc2VydGVkIGFuZCB0aGUgcGFpclxuICAvLyB0aGF0IGlzIHNwZW50IGNhbm5vdCBkcmlmdCBhcGFydC5cbiAgY29uc3QgY2xpY2tCdXR0b25UaW1lb3V0czogQ2xpY2tCdXR0b25UaW1lb3V0cyA9IHtcbiAgICBidXR0b25SZXN1bHRUaW1lb3V0SW5NaWxsaXNlY29uZHMsXG4gICAgc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzXG4gIH07XG4gIGFzc2VydENsaWNrQnVkZ2V0c0ZpdFRyYW5zcG9ydENhcChjbGlja0J1dHRvblRpbWVvdXRzKTtcblxuICBjb25zdCBub3RlcyA9IGxpc3ROb3Rlc1dpdGhCdXR0b25zKGRlbW9WYXVsdFBhdGgsIGV4Y2x1ZGVkTm90ZXMsIGV4Y2x1ZGVkRm9sZGVycyk7XG5cbiAgZGVzY3JpYmUoJ2RlbW8tdmF1bHQgYnV0dG9ucycsICgpID0+IHtcbiAgICBiZWZvcmVBbGwoYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgaXNDb2RlU2NyaXB0VG9vbGtpdExvYWRlZCA9IGF3YWl0IGNoZWNrQ29kZVNjcmlwdFRvb2xraXRMb2FkZWQoc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzKTtcbiAgICAgIC8vIFdpdGhvdXQgaXQgZXZlcnkgYGNvZGUtYnV0dG9uYCBmZW5jZSBzdGF5cyBhIHBsYWluIGNvZGUgYmxvY2ssIHNvIGV2ZXJ5IG5vdGUgYmVsb3cgd291bGQgcmVwb3J0XG4gICAgICAvLyB6ZXJvIGJ1dHRvbnMgYW5kIHBhc3MgdmFjdW91c2x5LiBGYWlsIGhlcmUgaW5zdGVhZCwgb25jZSwgd2l0aCB0aGUgcmVhc29uLlxuICAgICAgZXhwZWN0KGlzQ29kZVNjcmlwdFRvb2xraXRMb2FkZWQsICdDb2RlU2NyaXB0IFRvb2xraXQgZGlkIG5vdCBsb2FkLCBzbyBubyBidXR0b24gY291bGQgcmVuZGVyJykudG9CZSh0cnVlKTtcbiAgICB9KTtcblxuICAgIC8vIEEgZGVtbyB2YXVsdCBoYXMgdG8gZGVtb25zdHJhdGUgZXZlcnkgaGVhZGxpbmUgZmVhdHVyZSwgc28gYSB2YXVsdCB3aG9zZSBub3RlcyBkZWNsYXJlIG5vIGJ1dHRvbnNcbiAgICAvLyBpcyBhIHJlYWwgZmFpbHVyZSBvZiBpdHMgaW50ZXJhY3RpdmUgaGFsZiwgbm90IGEgcmVhc29uIHRvIHJlZ2lzdGVyIG5vdGhpbmcgYW5kIHJlcG9ydCBncmVlbi5cbiAgICBpdCgnaGFzIGF0IGxlYXN0IG9uZSBub3RlIHdpdGggYSBjb2RlIGJ1dHRvbicsICgpID0+IHtcbiAgICAgIGV4cGVjdChub3Rlcy5sZW5ndGgpLnRvQmVHcmVhdGVyVGhhbigwKTtcbiAgICB9KTtcblxuICAgIGZvciAoY29uc3Qgbm90ZSBvZiBub3Rlcykge1xuICAgICAgaXQoYHJ1bnMgZXZlcnkgY29kZSBidXR0b24gaW4gJHtub3RlLm5hbWV9YCwgYXN5bmMgKCkgPT4ge1xuICAgICAgICAvLyBDaGVja2VkIGZyb20gdGhlIHNvdXJjZSwgYmVmb3JlIGFueXRoaW5nIGlzIG9wZW5lZDogYnV0dG9ucyBhcmUgYWRkcmVzc2VkIGJ5IGNhcHRpb24sIHNvIGFcbiAgICAgICAgLy8gc2hhcmVkIG9uZSB3b3VsZCBvdGhlcndpc2Ugc3VyZmFjZSBiZWxvdyBhcyBhIGJ1dHRvbiB0aGF0IFwibmV2ZXIgcmVuZGVyZWRcIi5cbiAgICAgICAgY29uc3QgZHVwbGljYXRlQ2FwdGlvbnMgPSBmaW5kRHVwbGljYXRlQ2FwdGlvbnMobm90ZS5jYXB0aW9ucyk7XG4gICAgICAgIGV4cGVjdChcbiAgICAgICAgICBkdXBsaWNhdGVDYXB0aW9ucyxcbiAgICAgICAgICBgJHtub3RlLm5hbWV9IGRlY2xhcmVzIG1vcmUgdGhhbiBvbmUgYnV0dG9uIGNhcHRpb25lZCAke2R1cGxpY2F0ZUNhcHRpb25zLm1hcCgoY2FwdGlvbikgPT4gYFwiJHtjYXB0aW9ufVwiYCkuam9pbignLCAnKX0uIGBcbiAgICAgICAgICAgICsgJ1RoaXMgc3VpdGUgYWRkcmVzc2VzIGEgYnV0dG9uIGJ5IGl0cyBjYXB0aW9uLCBzbyBvbmx5IHRoZSBmaXJzdCBvZiB0aGVtIGNvdWxkIGV2ZXIgYmUgY2xpY2tlZC4gR2l2ZSBlYWNoIGJ1dHRvbiBhIGRpc3RpbmN0IGNhcHRpb24uJ1xuICAgICAgICApLnRvRXF1YWwoW10pO1xuXG4gICAgICAgIGNvbnN0IGNhcHRpb25zID0gYXdhaXQgb3Blbk5vdGVBbmRMaXN0QnV0dG9uQ2FwdGlvbnMobm90ZSwgc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzKTtcbiAgICAgICAgLy8gUmVhZGluZyB2aWV3IG1vdW50cyBhIG5vdGUncyBsZWFkaW5nIHNlY3Rpb25zIG1vcmUgdGhhbiBvbmNlIHdoaWxlIGl0IHNldHRsZXMsIHNvIHRoZSBET00gY2FuXG4gICAgICAgIC8vIGhvbGQgc2V2ZXJhbCBlbGVtZW50cyBwZXIgZmVuY2UuIFRoZSBjYXB0aW9ucyBhcmUgZGVkdXBsaWNhdGVkLCBhbmQgdGhlIGFzc2VydGlvbiBpcyB0aGF0IGF0XG4gICAgICAgIC8vIGxlYXN0IGFzIG1hbnkgRElTVElOQ1QgYnV0dG9ucyByZW5kZXJlZCBhcyB0aGUgc291cmNlIGRlY2xhcmVzIFx1MjAxNCBhIGZlbmNlIHRoYXQgc2lsZW50bHkgc3RheWVkXG4gICAgICAgIC8vIEEgcGxhaW4gY29kZSBibG9jayBpcyB0aGUgZmFpbHVyZSB0aGlzIGNhdGNoZXMuXG4gICAgICAgIGNvbnN0IG1pc3NpbmdDYXB0aW9ucyA9IG5vdGUuY2FwdGlvbnMuZmlsdGVyKChjYXB0aW9uKSA9PiAhY2FwdGlvbnMuaW5jbHVkZXMoY2FwdGlvbikpO1xuICAgICAgICBleHBlY3QoXG4gICAgICAgICAgY2FwdGlvbnMubGVuZ3RoLFxuICAgICAgICAgIGAke25vdGUubmFtZX0gZGVjbGFyZXMgJHtTdHJpbmcobm90ZS5idXR0b25Db3VudCl9IGJ1dHRvbihzKSBidXQgb25seSAke1N0cmluZyhjYXB0aW9ucy5sZW5ndGgpfSByZW5kZXJlZDsgYFxuICAgICAgICAgICAgKyBgbmV2ZXIgc2VlbjogJHttaXNzaW5nQ2FwdGlvbnMubWFwKChjYXB0aW9uKSA9PiBgXCIke2NhcHRpb259XCJgKS5qb2luKCcsICcpfWBcbiAgICAgICAgKVxuICAgICAgICAgIC50b0JlR3JlYXRlclRoYW5PckVxdWFsKG5vdGUuYnV0dG9uQ291bnQpO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdHM6IERlbW9WYXVsdEJ1dHRvblJlc3VsdFtdID0gW107XG4gICAgICAgIGZvciAoY29uc3QgY2FwdGlvbiBvZiBjYXB0aW9ucykge1xuICAgICAgICAgIHJlc3VsdHMucHVzaChhd2FpdCBjbGlja0J1dHRvbih7IGJ1dHRvbkNhcHRpb246IGNhcHRpb24sIG5vdGVQYXRoOiBub3RlLm5hbWUsIHNob3VsZERpc21pc3NNb2RhbHMsIHRpbWVvdXRzOiBjbGlja0J1dHRvblRpbWVvdXRzIH0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGZhaWx1cmVzID0gc2VsZWN0VW5leHBlY3RlZEZhaWx1cmVzKG5vdGUubmFtZSwgcmVzdWx0cywgZXhwZWN0ZWROb25Pa0J1dHRvbnMpO1xuXG4gICAgICAgIGV4cGVjdChmYWlsdXJlcywgZm9ybWF0RmFpbHVyZXMobm90ZS5uYW1lLCBmYWlsdXJlcykpLnRvRXF1YWwoW10pO1xuICAgICAgfSk7XG4gICAgfVxuICB9KTtcbn1cblxuLyogdjggaWdub3JlIHN0b3AgKi9cblxuLyogdjggaWdub3JlIHN0YXJ0IC0tIERyaXZlcyBhIHJlYWwgT2JzaWRpYW4gb3ZlciBDRFA6IHRoZSBjbG9zdXJlIGlzIHNlcmlhbGl6ZWQgaGVyZSBhbmQgZXhlY3V0ZWQgaW4gYW5vdGhlciBwcm9jZXNzLCBzbyBpdCBjYW5ub3QgYmUgZXhlcmNpc2VkIGJ5IGEgdW5pdCB0ZXN0LiAqL1xuLyoqXG4gKiBUdXJucyByZXN0cmljdGVkIG1vZGUgb2ZmIGFuZCBlbmFibGVzIGBDb2RlU2NyaXB0IFRvb2xraXRgLCB3aG9zZSBiaW5hcnkgdGhlIGdsb2JhbCBzZXR1cCBzZWVkZWQuXG4gKlxuICogQHBhcmFtIHRpbWVvdXRJbk1pbGxpc2Vjb25kcyAtIEhvdyBsb25nIHRvIHdhaXQgZm9yIGl0IHRvIGxvYWQuXG4gKiBAcmV0dXJucyBXaGV0aGVyIGBDb2RlU2NyaXB0IFRvb2xraXRgIGlzIGxvYWRlZC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY2hlY2tDb2RlU2NyaXB0VG9vbGtpdExvYWRlZCh0aW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICByZXR1cm4gZXZhbEluT2JzaWRpYW4oe1xuICAgIGFzeW5jIGNhbGxiYWNrKHsgYXBwLCBjb2RlU2NyaXB0VG9vbGtpdFBsdWdpbklkLCBpbnRlcnZhbEluTWlsbGlzZWNvbmRzLCBsaWI6IHsgd2FpdFVudGlsIH0sIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogdGltZW91dCB9KTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICBpZiAodHlwZW9mIGFwcC5wbHVnaW5zLmlzRW5hYmxlZCA9PT0gJ2Z1bmN0aW9uJyAmJiAhYXBwLnBsdWdpbnMuaXNFbmFibGVkKCkpIHtcbiAgICAgICAgYXdhaXQgYXBwLnBsdWdpbnMuc2V0RW5hYmxlKHRydWUpO1xuICAgICAgfVxuICAgICAgaWYgKCFhcHAucGx1Z2lucy5nZXRQbHVnaW4oY29kZVNjcmlwdFRvb2xraXRQbHVnaW5JZCkpIHtcbiAgICAgICAgYXdhaXQgYXBwLnBsdWdpbnMuZW5hYmxlUGx1Z2luKGNvZGVTY3JpcHRUb29sa2l0UGx1Z2luSWQpO1xuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgd2FpdFVudGlsKHtcbiAgICAgICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzLFxuICAgICAgICAgIG1lc3NhZ2U6ICdDb2RlU2NyaXB0IFRvb2xraXQgbmV2ZXIgbG9hZGVkJyxcbiAgICAgICAgICBwcmVkaWNhdGU6ICgpOiBib29sZWFuID0+IGFwcC5wbHVnaW5zLmdldFBsdWdpbihjb2RlU2NyaXB0VG9vbGtpdFBsdWdpbklkKSAhPT0gbnVsbCxcbiAgICAgICAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IHRpbWVvdXRcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSxcbiAgICBpbnB1dDoge1xuICAgICAgY29kZVNjcmlwdFRvb2xraXRQbHVnaW5JZDogQ09ERV9TQ1JJUFRfVE9PTEtJVF9QTFVHSU5fSUQsXG4gICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzOiBQT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyxcbiAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kc1xuICAgIH0sXG4gICAgdmF1bHRQYXRoOiBnZXRUZW1wb3JhcnlWYXVsdCgpLnBhdGhcbiAgfSk7XG59XG5cbi8qIHY4IGlnbm9yZSBzdG9wICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBEcml2ZXMgYSByZWFsIE9ic2lkaWFuIG92ZXIgQ0RQOiB0aGUgY2xvc3VyZSBpcyBzZXJpYWxpemVkIGhlcmUgYW5kIGV4ZWN1dGVkIGluIGFub3RoZXIgcHJvY2Vzcywgc28gaXQgY2Fubm90IGJlIGV4ZXJjaXNlZCBieSBhIHVuaXQgdGVzdC4gKi9cbi8qKlxuICogQ2xpY2tzIG9uZSBidXR0b24gYW5kIHJlYWRzIHRoZSByZXN1bHQgbGluZSBgQ29kZVNjcmlwdCBUb29sa2l0YCB3cml0ZXMgdW5kZXIgaXQuXG4gKlxuICogQSBidXR0b24gdGhhdCByZS1yZW5kZXJzIGl0cyBvd24gbm90ZSAoYSBzZXR0aW5ncyBjaGFuZ2UsIGEgcmVsb2FkKSBkZXRhY2hlcyB0aGUgYmxvY2sgaXQgbGl2ZXMgaW4sXG4gKiBzbyB0aGUgYmxvY2sgZWxlbWVudCBpcyBjYXB0dXJlZCBCRUZPUkUgdGhlIGNsaWNrIGFuZCByZWFkIGFmdGVyd2FyZHMgXHUyMDE0IGBDb2RlU2NyaXB0IFRvb2xraXRgIHdyaXRlcyB0aGVcbiAqIHJlc3VsdCBpbnRvIHRoYXQgc2FtZSBlbGVtZW50IGV2ZW4gb25jZSBpdCBpcyBkZXRhY2hlZC5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHtAbGluayBDbGlja0J1dHRvblBhcmFtc30uXG4gKiBAcmV0dXJucyBUaGUge0BsaW5rIERlbW9WYXVsdEJ1dHRvblJlc3VsdH0uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGNsaWNrQnV0dG9uKHBhcmFtczogQ2xpY2tCdXR0b25QYXJhbXMpOiBQcm9taXNlPERlbW9WYXVsdEJ1dHRvblJlc3VsdD4ge1xuICByZXR1cm4gZXZhbEluT2JzaWRpYW4oe1xuICAgIGFzeW5jIGNhbGxiYWNrKHtcbiAgICAgIGFwcCxcbiAgICAgIGJ1dHRvblJlc3VsdFRpbWVvdXRJbk1pbGxpc2Vjb25kcyxcbiAgICAgIGNhcHRpb24sXG4gICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzLFxuICAgICAgbGliOiB7IHByZXNzS2V5LCB3YWl0VW50aWwgfSxcbiAgICAgIG5vdGVQYXRoOiBub3RlUGF0aFRvT3BlbixcbiAgICAgIG9ic2lkaWFuTW9kdWxlLFxuICAgICAgb3V0cHV0RXhjZXJwdExlbmd0aCxcbiAgICAgIHNldHRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kcyxcbiAgICAgIHNob3VsZERpc21pc3NNb2RhbHM6IHNob3VsZERpc21pc3NcbiAgICB9KTogUHJvbWlzZTxEZW1vVmF1bHRCdXR0b25SZXN1bHQ+IHtcbiAgICAgIGZ1bmN0aW9uIHZpZXcoKTogSW5zdGFuY2VUeXBlPHR5cGVvZiBvYnNpZGlhbk1vZHVsZS5NYXJrZG93blZpZXc+IHwgbnVsbCB7XG4gICAgICAgIHJldHVybiBhcHAud29ya3NwYWNlLmdldEFjdGl2ZVZpZXdPZlR5cGUob2JzaWRpYW5Nb2R1bGUuTWFya2Rvd25WaWV3KTtcbiAgICAgIH1cbiAgICAgIGZ1bmN0aW9uIHByZXZpZXdFbCgpOiBIVE1MRWxlbWVudCB8IG51bGwge1xuICAgICAgICByZXR1cm4gdmlldygpPy5jb250YWluZXJFbC5xdWVyeVNlbGVjdG9yPEhUTUxFbGVtZW50PignOnNjb3BlIC5tYXJrZG93bi1wcmV2aWV3LXZpZXcnKSA/PyBudWxsO1xuICAgICAgfVxuICAgICAgZnVuY3Rpb24gYnV0dG9ucygpOiBIVE1MQnV0dG9uRWxlbWVudFtdIHtcbiAgICAgICAgcmV0dXJuIFsuLi52aWV3KCk/LmNvbnRhaW5lckVsLnF1ZXJ5U2VsZWN0b3JBbGw8SFRNTEJ1dHRvbkVsZW1lbnQ+KCc6c2NvcGUgLmJsb2NrLWxhbmd1YWdlLWNvZGUtYnV0dG9uIGJ1dHRvbi5tb2QtY3RhJykgPz8gW11dO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBmaW5kQnV0dG9uKCk6IEhUTUxCdXR0b25FbGVtZW50IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIGJ1dHRvbnMoKS5maW5kKChjYW5kaWRhdGUpID0+IGNhbmRpZGF0ZS50ZXh0Q29udGVudCA9PT0gY2FwdGlvbik7XG4gICAgICB9XG5cbiAgICAgIC8vIFJlYWRpbmcgdmlldyBtb3VudHMgbGF6aWx5IGFuZCB1bm1vdW50cyBzZWN0aW9ucyBmYXIgb2ZmLXNjcmVlbiwgc28gTk8gc2luZ2xlIHNjcm9sbCBwb3NpdGlvblxuICAgICAgLy8gaG9sZHMgYSB3aG9sZSBub3RlJ3MgYnV0dG9ucy4gQWR2YW5jZSBhIHZpZXdwb3J0IGF0IGEgdGltZSBhbmQgd3JhcCBiYWNrIHRvIHRoZSB0b3AsIHJlbW91bnRpbmdcbiAgICAgIC8vIGV2ZXJ5IHNlY3Rpb24gaW4gdHVybiB1bnRpbCB0aGUgb25lIGJlaW5nIGxvb2tlZCBmb3IgYXBwZWFycy4gUGlubmluZyB0byB0aGUgQk9UVE9NIGluc3RlYWQgXHUyMDE0XG4gICAgICAvLyB3aGF0IHRoaXMgZGlkIHVudGlsIDk0LjQuMSBcdTIwMTQgb25seSBldmVyIG1vdW50cyB0aGUgbm90ZSdzIHRhaWwsIHNvIGEgYnV0dG9uIGFueXdoZXJlIGJ1dCBhdCB0aGVcbiAgICAgIC8vIGVuZCBvZiBpdHMgbm90ZSB3YXMgcmVwb3J0ZWQgYXMgbmV2ZXIgcmVuZGVyZWQgKGBzdGF0dXM6ICd0aW1lb3V0J2AsIGVtcHR5IG91dHB1dCkgaG93ZXZlclxuICAgICAgLy8gaGVhbHRoeSBpdCB3YXMuXG4gICAgICBjb25zdCBTQ1JPTExfQk9UVE9NX1RPTEVSQU5DRV9JTl9QSVhFTFMgPSA0O1xuICAgICAgY29uc3QgU0NST0xMX1NURVBfUkFUSU8gPSAwLjg7XG4gICAgICBmdW5jdGlvbiBhZHZhbmNlU2Nyb2xsKCk6IHZvaWQge1xuICAgICAgICBjb25zdCBzY3JvbGxlciA9IHByZXZpZXdFbCgpO1xuICAgICAgICBpZiAoIXNjcm9sbGVyKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGlzQXRCb3R0b20gPSBzY3JvbGxlci5zY3JvbGxUb3AgKyBzY3JvbGxlci5jbGllbnRIZWlnaHQgPj0gc2Nyb2xsZXIuc2Nyb2xsSGVpZ2h0IC0gU0NST0xMX0JPVFRPTV9UT0xFUkFOQ0VfSU5fUElYRUxTO1xuICAgICAgICBzY3JvbGxlci5zY3JvbGxUb3AgPSBpc0F0Qm90dG9tID8gMCA6IHNjcm9sbGVyLnNjcm9sbFRvcCArIE1hdGguZmxvb3Ioc2Nyb2xsZXIuY2xpZW50SGVpZ2h0ICogU0NST0xMX1NURVBfUkFUSU8pO1xuICAgICAgfVxuXG4gICAgICAvLyBCb3RoIHRoZSBwcmUtMS4xMyBhbmQgdGhlIDEuMTMgbmFtZSBvZiBhIG1vZGFsJ3MgWDogdGhlIG9sZCBvbmUgYWxvbmUgbWF0Y2hlcyBub3RoaW5nIG9uIGEgY3VycmVudFxuICAgICAgLy8gT2JzaWRpYW4sIGFuZCBjbGlja2luZyBub3RoaW5nIGlzIGEgc2lsZW50IG5vLW9wIHJhdGhlciB0aGFuIGFuIGVycm9yLlxuICAgICAgYXN5bmMgZnVuY3Rpb24gZGlzbWlzc01vZGFscygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCFzaG91bGREaXNtaXNzKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3QgY2xvc2VCdXR0b24gb2YgYWN0aXZlRG9jdW1lbnQuYm9keS5xdWVyeVNlbGVjdG9yQWxsPEhUTUxFbGVtZW50PignOnNjb3BlIC5tb2RhbC1jb250YWluZXIgOmlzKC5tb2RhbC1jbG9zZS1idXR0b24sIC5tb2RhbC1oZWFkZXItYnV0dG9uKScpKSB7XG4gICAgICAgICAgY2xvc2VCdXR0b24uY2xpY2soKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBIHRydXN0ZWQgRXNjYXBlIFx1MjAxNCB3aGF0IGEgdXNlciBwcmVzc2VzIFx1MjAxNCBidXQgb25seSB3aGlsZSBzb21ldGhpbmcgaXMgc3RpbGwgb3BlbjogdGhpcyBydW5zIG9uXG4gICAgICAgIC8vIGV2ZXJ5IHBvbGwsIGFuZCBhbiB1bmNvbmRpdGlvbmFsIGtleSBwcmVzcyB3b3VsZCBsYW5kIGluIHdoYXRldmVyIHRoZSBuZXh0IGJ1dHRvbiBpcyBkb2luZy5cbiAgICAgICAgaWYgKGFjdGl2ZURvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5tb2RhbC1jb250YWluZXIsIC5wcm9tcHQnKSkge1xuICAgICAgICAgIGF3YWl0IHByZXNzS2V5KHsga2V5OiAnRXNjYXBlJyB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBSZS1vcGVuIHRoZSBub3RlIGJlZm9yZSBldmVyeSBjbGljayBpbnN0ZWFkIG9mIGFzc3VtaW5nIHRoZSBwcmV2aW91cyBidXR0b24gbGVmdCB0aGUgd29ya3NwYWNlXG4gICAgICAvLyB3aGVyZSBpdCB3YXMgZm91bmQuIEV2ZXJ5IGhlbHBlciBhYm92ZSByZWFkcyB0aGUgQUNUSVZFIHZpZXcsIGFuZCBvcGVuaW5nIGEgbm90ZSBpcyBvbmUgb2YgdGhlXG4gICAgICAvLyBtb3N0IG9yZGluYXJ5IHRoaW5ncyBhIGRlbW8gYnV0dG9uIGRvZXMgXHUyMDE0IHNvIHRoZSBmaXJzdCBzdWNoIGJ1dHRvbiB3b3VsZCBvdGhlcndpc2Ugc2VuZCBlYWNoXG4gICAgICAvLyBsYXRlciBidXR0b24gaW4gaXRzIG5vdGUgdG8gYHN0YXR1czogJ3RpbWVvdXQnYCB3aXRoIGFuIGVtcHR5IG91dHB1dCwgd2hpY2ggaXMgdGhlIHNoYXBlIG9mIGFcbiAgICAgIC8vIGJ1dHRvbiB0aGF0IG5ldmVyIHJlbmRlcmVkIHJhdGhlciB0aGFuIG9uZSB0aGF0IHdhcyBsb29rZWQgZm9yIGluIHRoZSB3cm9uZyB2aWV3LlxuICAgICAgYXdhaXQgYXBwLndvcmtzcGFjZS5vcGVuTGlua1RleHQobm90ZVBhdGhUb09wZW4ucmVwbGFjZSgvXFwubWQkLywgJycpLCAnJywgZmFsc2UpO1xuICAgICAgYXdhaXQgYXBwLndvcmtzcGFjZS5nZXRMZWFmKGZhbHNlKS5zZXRWaWV3U3RhdGUoeyBzdGF0ZTogeyBmaWxlOiBub3RlUGF0aFRvT3BlbiwgbW9kZTogJ3ByZXZpZXcnIH0sIHR5cGU6ICdtYXJrZG93bicgfSk7XG5cbiAgICAgIC8vIEhlbGQgZnJvbSB0aGUgcHJlZGljYXRlIHJhdGhlciB0aGFuIHJlLXF1ZXJpZWQgYWZ0ZXIgaXQ6IHRoZSB3YWxrIGFib3ZlIGtlZXBzIG1vdmluZyB0aGVcbiAgICAgIC8vIHZpZXdwb3J0LCBzbyBhIGJ1dHRvbiBmb3VuZCBvbiBvbmUgcG9sbCBjYW4gYmUgdW5tb3VudGVkIGFnYWluIGJ5IHRoZSBuZXh0LlxuICAgICAgbGV0IGJ1dHRvbjogSFRNTEJ1dHRvbkVsZW1lbnQgfCB1bmRlZmluZWQ7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB3YWl0VW50aWwoe1xuICAgICAgICAgIGludGVydmFsSW5NaWxsaXNlY29uZHMsXG4gICAgICAgICAgbWVzc2FnZTogYGNvZGUgYnV0dG9uIFwiJHtjYXB0aW9ufVwiIG5ldmVyIHJlbmRlcmVkYCxcbiAgICAgICAgICBwcmVkaWNhdGU6ICgpOiBib29sZWFuID0+IHtcbiAgICAgICAgICAgIGFkdmFuY2VTY3JvbGwoKTtcbiAgICAgICAgICAgIGJ1dHRvbiA9IGZpbmRCdXR0b24oKTtcbiAgICAgICAgICAgIHJldHVybiBidXR0b24gIT09IHVuZGVmaW5lZDtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzXG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHJldHVybiB7IGNhcHRpb24sIG91dHB1dDogJycsIHN0YXR1czogJ3RpbWVvdXQnIH07XG4gICAgICB9XG5cbiAgICAgIGlmICghYnV0dG9uKSB7XG4gICAgICAgIHJldHVybiB7IGNhcHRpb24sIG91dHB1dDogJycsIHN0YXR1czogJ3RpbWVvdXQnIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGJsb2NrID0gYnV0dG9uLmNsb3Nlc3Q8SFRNTEVsZW1lbnQ+KCcuYmxvY2stbGFuZ3VhZ2UtY29kZS1idXR0b24nKSA/PyBidXR0b24ucGFyZW50RWxlbWVudDtcbiAgICAgIGJ1dHRvbi5zY3JvbGxJbnRvVmlldygpO1xuICAgICAgYnV0dG9uLmNsaWNrKCk7XG5cbiAgICAgIGxldCBzdGF0dXM6IERlbW9WYXVsdEJ1dHRvblJlc3VsdFsnc3RhdHVzJ107XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB3YWl0VW50aWwoe1xuICAgICAgICAgIGludGVydmFsSW5NaWxsaXNlY29uZHMsXG4gICAgICAgICAgbWVzc2FnZTogYGJ1dHRvbiBcIiR7Y2FwdGlvbn1cIiBuZXZlciByZXBvcnRlZCBhIHJlc3VsdGAsXG4gICAgICAgICAgcHJlZGljYXRlOiBhc3luYyAoKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gICAgICAgICAgICAvLyBBIGJ1dHRvbiB0aGF0IGF3YWl0cyBhbiBhbGVydCAvIGNvbmZpcm0gLyBwcm9tcHQgcmVwb3J0cyBub3RoaW5nIHVudGlsIHRoZSBkaWFsb2cgY2xvc2VzLlxuICAgICAgICAgICAgYXdhaXQgZGlzbWlzc01vZGFscygpO1xuICAgICAgICAgICAgcmV0dXJuIC9FeGVjdXRlZCAoPzpzdWNjZXNzZnVsbHl8d2l0aCBlcnJvcikvLnRlc3QoYmxvY2s/LnRleHRDb250ZW50ID8/ICcnKTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCB0ZXh0ID0gYmxvY2s/LnRleHRDb250ZW50ID8/ICcnO1xuICAgICAgICBpZiAodGV4dC5pbmNsdWRlcygnRXhlY3V0ZWQgd2l0aCBlcnJvcicpKSB7XG4gICAgICAgICAgc3RhdHVzID0gJ2Vycm9yJztcbiAgICAgICAgfSBlbHNlIGlmICh0ZXh0LmluY2x1ZGVzKCdFeGVjdXRlZCBzdWNjZXNzZnVsbHknKSkge1xuICAgICAgICAgIHN0YXR1cyA9ICdvayc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc3RhdHVzID0gJ3Vua25vd24nO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgc3RhdHVzID0gJ3RpbWVvdXQnO1xuICAgICAgfVxuXG4gICAgICAvLyBXaGF0ZXZlciB0aGlzIGJ1dHRvbiBsZWZ0IG9wZW4gd291bGQgb3RoZXJ3aXNlIHNpdCBvdmVyIHRoZSBuZXh0IG9uZS5cbiAgICAgIGF3YWl0IGRpc21pc3NNb2RhbHMoKTtcblxuICAgICAgcmV0dXJuIHsgY2FwdGlvbiwgb3V0cHV0OiAoYmxvY2s/LnRleHRDb250ZW50ID8/ICcnKS5zbGljZSgwLCBvdXRwdXRFeGNlcnB0TGVuZ3RoKSwgc3RhdHVzIH07XG4gICAgfSxcbiAgICBpbnB1dDoge1xuICAgICAgYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzOiBwYXJhbXMudGltZW91dHMuYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzLFxuICAgICAgY2FwdGlvbjogcGFyYW1zLmJ1dHRvbkNhcHRpb24sXG4gICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzOiBQT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyxcbiAgICAgIG5vdGVQYXRoOiBwYXJhbXMubm90ZVBhdGgsXG4gICAgICBvdXRwdXRFeGNlcnB0TGVuZ3RoOiBPVVRQVVRfRVhDRVJQVF9MRU5HVEgsXG4gICAgICBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHM6IHBhcmFtcy50aW1lb3V0cy5zZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHMsXG4gICAgICBzaG91bGREaXNtaXNzTW9kYWxzOiBwYXJhbXMuc2hvdWxkRGlzbWlzc01vZGFsc1xuICAgIH0sXG4gICAgdmF1bHRQYXRoOiBnZXRUZW1wb3JhcnlWYXVsdCgpLnBhdGhcbiAgfSk7XG59XG5cbi8qKlxuICogT3BlbnMgYSBub3RlIGluIHJlYWRpbmcgdmlldyBhbmQgbGlzdHMgdGhlIGNhcHRpb25zIG9mIHRoZSBidXR0b25zIHRoYXQgbW91bnRlZCwgZGVkdXBsaWNhdGVkIGFuZCBpblxuICogZG9jdW1lbnQgb3JkZXIuXG4gKlxuICogVHdvIHF1aXJrcyBvZiByZWFkaW5nIHZpZXcgc2hhcGUgdGhpcy4gSXQgcmVuZGVycyBsYXppbHkgYW5kIHVubW91bnRzIHNlY3Rpb25zIGZhciBvZmYtc2NyZWVuLCBzbyBub1xuICogc2luZ2xlIHNjcm9sbCBwb3NpdGlvbiBob2xkcyBhIHdob2xlIG5vdGUncyBidXR0b25zIFx1MjAxNCB0aGUgcHJldmlldyBpcyB3YWxrZWQgdG9wIHRvIGJvdHRvbSBhbmQgYmFja1xuICogd2hpbGUgd2FpdGluZywgYW5kIHRoZSBjYXB0aW9ucyBzZWVuIGFsb25nIHRoZSB3YXkgYXJlIEFDQ1VNVUxBVEVEIHJhdGhlciB0aGFuIHJlYWQgb25jZSBhdCB0aGUgZW5kLlxuICogQW5kIHdoaWxlIGl0IHNldHRsZXMgaXQgY2FuIGhvbGQgU0VWRVJBTCBlbGVtZW50cyBwZXIgZmVuY2UgXHUyMDE0IHRoZSBzYW1lIGJ1dHRvbiB3YXMgb2JzZXJ2ZWQgcmVuZGVyZWRcbiAqIHR3aWNlIFx1MjAxNCBzbyB0aGUgY2FwdGlvbnMgYXJlIGRlZHVwbGljYXRlZDsgY2xpY2tpbmcgYnkgY2FwdGlvbiB0aGVuIGFkZHJlc3NlcyBlYWNoIGJ1dHRvbiBvbmNlIGhvd2V2ZXJcbiAqIG1hbnkgY29waWVzIG9mIGl0IHRoZSBET00gaXMgaG9sZGluZy5cbiAqXG4gKiBAcGFyYW0gbm90ZSAtIFRoZSBub3RlIHRvIG9wZW4uXG4gKiBAcGFyYW0gc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzIC0gSG93IGxvbmcgdG8gd2FpdCBmb3IgdGhlIGJ1dHRvbnMgdG8gbW91bnQuXG4gKiBAcmV0dXJucyBUaGUgZGlzdGluY3QgYnV0dG9uIGNhcHRpb25zLlxuICovXG5hc3luYyBmdW5jdGlvbiBvcGVuTm90ZUFuZExpc3RCdXR0b25DYXB0aW9ucyhub3RlOiBEZW1vVmF1bHROb3RlLCBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcik6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgcmV0dXJuIGV2YWxJbk9ic2lkaWFuKHtcbiAgICBhc3luYyBjYWxsYmFjayh7IGFwcCwgZXhwZWN0ZWRCdXR0b25Db3VudCwgaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcywgbGliOiB7IHdhaXRVbnRpbCB9LCBub3RlUGF0aCwgb2JzaWRpYW5Nb2R1bGUsIHRpbWVvdXRJbk1pbGxpc2Vjb25kcyB9KTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgICAgZnVuY3Rpb24gdmlldygpOiBJbnN0YW5jZVR5cGU8dHlwZW9mIG9ic2lkaWFuTW9kdWxlLk1hcmtkb3duVmlldz4gfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIGFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlVmlld09mVHlwZShvYnNpZGlhbk1vZHVsZS5NYXJrZG93blZpZXcpO1xuICAgICAgfVxuICAgICAgZnVuY3Rpb24gcHJldmlld0VsKCk6IEhUTUxFbGVtZW50IHwgbnVsbCB7XG4gICAgICAgIHJldHVybiB2aWV3KCk/LmNvbnRhaW5lckVsLnF1ZXJ5U2VsZWN0b3I8SFRNTEVsZW1lbnQ+KCc6c2NvcGUgLm1hcmtkb3duLXByZXZpZXctdmlldycpID8/IG51bGw7XG4gICAgICB9XG4gICAgICAvLyBBY2N1bXVsYXRlZCBhY3Jvc3MgdGhlIHdhbGsgYmVsb3csIG5ldmVyIHJlYWQgZnJvbSBvbmUgc25hcHNob3Q6IHdpdGggdGhlIHZpZXdwb3J0IG1vdmluZywgYW55XG4gICAgICAvLyBzaW5nbGUgcmVhZGluZyBob2xkcyBvbmx5IHRoZSBzZWN0aW9ucyBjdXJyZW50bHkgbW91bnRlZC5cbiAgICAgIGNvbnN0IHNlZW5DYXB0aW9ucyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgZnVuY3Rpb24gY2FwdGlvbnMoKTogc3RyaW5nW10ge1xuICAgICAgICBmb3IgKGNvbnN0IGJ1dHRvbiBvZiB2aWV3KCk/LmNvbnRhaW5lckVsLnF1ZXJ5U2VsZWN0b3JBbGw8SFRNTEJ1dHRvbkVsZW1lbnQ+KCc6c2NvcGUgLmJsb2NrLWxhbmd1YWdlLWNvZGUtYnV0dG9uIGJ1dHRvbi5tb2QtY3RhJykgPz8gW10pIHtcbiAgICAgICAgICBpZiAoYnV0dG9uLnRleHRDb250ZW50ICE9PSAnJykge1xuICAgICAgICAgICAgc2VlbkNhcHRpb25zLmFkZChidXR0b24udGV4dENvbnRlbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gWy4uLnNlZW5DYXB0aW9uc107XG4gICAgICB9XG5cbiAgICAgIC8vIFNhbWUgd2FsayBhcyBgY2xpY2tCdXR0b25gLCBhbmQgZm9yIHRoZSBzYW1lIHJlYXNvbjogYSBub3RlIHdob3NlIGJ1dHRvbnMgYXJlIGluIHRoZSBNSURETEVcbiAgICAgIC8vIG5ldmVyIG1vdW50cyB0aGVtIGlmIHRoZSBwcmV2aWV3IGlzIHBpbm5lZCB0byB0aGUgYm90dG9tLlxuICAgICAgY29uc3QgU0NST0xMX0JPVFRPTV9UT0xFUkFOQ0VfSU5fUElYRUxTID0gNDtcbiAgICAgIGNvbnN0IFNDUk9MTF9TVEVQX1JBVElPID0gMC44O1xuICAgICAgZnVuY3Rpb24gYWR2YW5jZVNjcm9sbCgpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgc2Nyb2xsZXIgPSBwcmV2aWV3RWwoKTtcbiAgICAgICAgaWYgKCFzY3JvbGxlcikge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBpc0F0Qm90dG9tID0gc2Nyb2xsZXIuc2Nyb2xsVG9wICsgc2Nyb2xsZXIuY2xpZW50SGVpZ2h0ID49IHNjcm9sbGVyLnNjcm9sbEhlaWdodCAtIFNDUk9MTF9CT1RUT01fVE9MRVJBTkNFX0lOX1BJWEVMUztcbiAgICAgICAgc2Nyb2xsZXIuc2Nyb2xsVG9wID0gaXNBdEJvdHRvbSA/IDAgOiBzY3JvbGxlci5zY3JvbGxUb3AgKyBNYXRoLmZsb29yKHNjcm9sbGVyLmNsaWVudEhlaWdodCAqIFNDUk9MTF9TVEVQX1JBVElPKTtcbiAgICAgIH1cblxuICAgICAgYXdhaXQgYXBwLndvcmtzcGFjZS5vcGVuTGlua1RleHQobm90ZVBhdGgucmVwbGFjZSgvXFwubWQkLywgJycpLCAnJywgZmFsc2UpO1xuICAgICAgYXdhaXQgYXBwLndvcmtzcGFjZS5nZXRMZWFmKGZhbHNlKS5zZXRWaWV3U3RhdGUoeyBzdGF0ZTogeyBmaWxlOiBub3RlUGF0aCwgbW9kZTogJ3ByZXZpZXcnIH0sIHR5cGU6ICdtYXJrZG93bicgfSk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHdhaXRVbnRpbCh7XG4gICAgICAgICAgaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcyxcbiAgICAgICAgICBtZXNzYWdlOiBgXCIke25vdGVQYXRofVwiIG5ldmVyIG1vdW50ZWQgYWxsICR7U3RyaW5nKGV4cGVjdGVkQnV0dG9uQ291bnQpfSBvZiBpdHMgYnV0dG9uc2AsXG4gICAgICAgICAgcHJlZGljYXRlOiAoKTogYm9vbGVhbiA9PiB7XG4gICAgICAgICAgICBhZHZhbmNlU2Nyb2xsKCk7XG4gICAgICAgICAgICByZXR1cm4gY2FwdGlvbnMoKS5sZW5ndGggPj0gZXhwZWN0ZWRCdXR0b25Db3VudDtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kc1xuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBUaGUgY2FwdGlvbnMgYXJlIHJldHVybmVkIGVpdGhlciB3YXk7IHRoZSBjYWxsZXIgYXNzZXJ0cyBvbiB0aGVtIGFuZCByZXBvcnRzIHRoZSBzaG9ydGZhbGwuXG4gICAgICB9XG5cbiAgICAgIHJldHVybiBjYXB0aW9ucygpO1xuICAgIH0sXG4gICAgaW5wdXQ6IHtcbiAgICAgIGV4cGVjdGVkQnV0dG9uQ291bnQ6IG5vdGUuYnV0dG9uQ291bnQsXG4gICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzOiBQT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyxcbiAgICAgIG5vdGVQYXRoOiBub3RlLm5hbWUsXG4gICAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IHNldHRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kc1xuICAgIH0sXG4gICAgdmF1bHRQYXRoOiBnZXRUZW1wb3JhcnlWYXVsdCgpLnBhdGhcbiAgfSk7XG59XG5cbi8qIHY4IGln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