@decaf-ts/for-nest 0.11.1 → 0.11.2-refactor.2

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 (370) hide show
  1. package/README.md +1 -1
  2. package/dist/for-nest.cjs +2654 -2
  3. package/dist/for-nest.js +2756 -2
  4. package/lib/cjs/auth/AuthInterceptor.cjs +90 -0
  5. package/lib/cjs/auth/DecafAuthHandler.cjs +37 -0
  6. package/lib/cjs/auth/DecafAuthModule.cjs +56 -0
  7. package/lib/cjs/auth/constants.cjs +10 -0
  8. package/lib/cjs/auth/decorators.cjs +28 -0
  9. package/lib/cjs/auth/index.cjs +23 -0
  10. package/lib/cjs/bin/cli.cjs +2 -2
  11. package/lib/cjs/cli-module.cjs +64 -7
  12. package/lib/cjs/constants.cjs +5 -6
  13. package/lib/cjs/controllers.cjs +13 -109
  14. package/lib/cjs/core-module.cjs +8 -8
  15. package/lib/cjs/decaf-model/DecafModelModule.cjs +23 -4
  16. package/lib/cjs/decaf-model/FromModelController.cjs +751 -789
  17. package/lib/cjs/decaf-model/decorators/ApiOperationFromModel.cjs +53 -16
  18. package/lib/cjs/decaf-model/decorators/ApiParamsFromModel.cjs +2 -2
  19. package/lib/cjs/decaf-model/decorators/DecafBody.cjs +2 -2
  20. package/lib/cjs/decaf-model/decorators/DecafParams.cjs +2 -2
  21. package/lib/cjs/decaf-model/decorators/controller-config.cjs +29 -0
  22. package/lib/cjs/decaf-model/decorators/decorators.cjs +5 -45
  23. package/lib/cjs/decaf-model/decorators/expose.cjs +13 -0
  24. package/lib/cjs/decaf-model/decorators/index.cjs +3 -2
  25. package/lib/cjs/decaf-model/decorators/types.cjs +2 -2
  26. package/lib/cjs/decaf-model/decorators/utils.cjs +2 -2
  27. package/lib/cjs/decaf-model/index.cjs +28 -19
  28. package/lib/cjs/decaf-model/types.cjs +2 -2
  29. package/lib/cjs/decaf-model/utils.cjs +2 -2
  30. package/lib/cjs/decoration.cjs +2 -2
  31. package/lib/cjs/decorators.cjs +85 -0
  32. package/lib/cjs/events-module/DecafStreamModule.cjs +2 -2
  33. package/lib/cjs/events-module/EventsController.cjs +2 -2
  34. package/lib/cjs/events-module/constant.cjs +2 -2
  35. package/lib/cjs/events-module/index.cjs +2 -2
  36. package/lib/cjs/events-module/utils.cjs +2 -2
  37. package/lib/cjs/factory/NestBootstraper.cjs +2 -2
  38. package/lib/cjs/factory/errors/cors.cjs +2 -2
  39. package/lib/cjs/factory/errors/index.cjs +2 -2
  40. package/lib/cjs/factory/errors/throttling.cjs +2 -2
  41. package/lib/cjs/factory/exceptions/DecafErrorFilter.cjs +2 -2
  42. package/lib/cjs/factory/exceptions/decorators.cjs +2 -2
  43. package/lib/cjs/factory/exceptions/index.cjs +2 -2
  44. package/lib/cjs/factory/index.cjs +2 -2
  45. package/lib/cjs/factory/openapi/DtoBuilder.cjs +37 -6
  46. package/lib/cjs/factory/openapi/SwaggerBuilder.cjs +2 -2
  47. package/lib/cjs/factory/openapi/SwaggerCustomUI.cjs +2 -2
  48. package/lib/cjs/factory/openapi/constants.cjs +2 -2
  49. package/lib/cjs/factory/openapi/index.cjs +2 -2
  50. package/lib/cjs/index.cjs +8 -7
  51. package/lib/cjs/interceptors/DecafRequestHandlerInterceptor.cjs +25 -21
  52. package/lib/cjs/interceptors/index.cjs +3 -4
  53. package/lib/cjs/module.cjs +5 -2
  54. package/lib/cjs/overrides/Adapter.cjs +2 -2
  55. package/lib/cjs/overrides/ModelBuilderExtensions.cjs +2 -2
  56. package/lib/cjs/overrides/constants.cjs +2 -2
  57. package/lib/cjs/overrides/decoration.cjs +2 -2
  58. package/lib/cjs/overrides/helpers.cjs +2 -2
  59. package/lib/cjs/overrides/index.cjs +3 -2
  60. package/lib/cjs/overrides/logging.cjs +5 -0
  61. package/lib/cjs/overrides/overrides.cjs +2 -2
  62. package/lib/cjs/request/DecafAuthHandler.cjs +5 -39
  63. package/lib/cjs/request/DecafHandlerExecutor.cjs +2 -2
  64. package/lib/cjs/request/DecafRequestContext.cjs +11 -20
  65. package/lib/cjs/request/DecafResponseInterceptor.cjs +3 -3
  66. package/lib/cjs/request/index.cjs +2 -2
  67. package/lib/cjs/swagger-types.cjs +2 -2
  68. package/lib/cjs/types.cjs +2 -2
  69. package/lib/cjs/utils.cjs +2 -2
  70. package/lib/cjs/webhooks/DecafWebhookModule.cjs +11 -12
  71. package/lib/cjs/webhooks/controllers.cjs +10 -10
  72. package/lib/cjs/webhooks/index.cjs +2 -15
  73. package/lib/cjs/webhooks/types.cjs +2 -2
  74. package/lib/esm/auth/AuthInterceptor.js +81 -0
  75. package/lib/esm/auth/DecafAuthHandler.js +31 -0
  76. package/lib/esm/auth/DecafAuthModule.js +48 -0
  77. package/lib/esm/auth/constants.js +6 -0
  78. package/lib/esm/auth/decorators.js +22 -0
  79. package/lib/esm/auth/index.js +6 -0
  80. package/lib/esm/bin/cli.js +1 -1
  81. package/lib/esm/cli-module.js +63 -6
  82. package/lib/esm/constants.js +3 -4
  83. package/lib/esm/controllers.js +13 -109
  84. package/lib/esm/core-module.js +7 -7
  85. package/lib/esm/decaf-model/DecafModelModule.js +22 -3
  86. package/lib/esm/decaf-model/FromModelController.js +753 -791
  87. package/lib/esm/decaf-model/decorators/ApiOperationFromModel.js +53 -15
  88. package/lib/esm/decaf-model/decorators/ApiParamsFromModel.js +1 -1
  89. package/lib/esm/decaf-model/decorators/DecafBody.js +1 -1
  90. package/lib/esm/decaf-model/decorators/DecafParams.js +1 -1
  91. package/lib/esm/decaf-model/decorators/controller-config.js +25 -0
  92. package/lib/esm/decaf-model/decorators/decorators.js +2 -43
  93. package/lib/esm/decaf-model/decorators/expose.js +9 -0
  94. package/lib/esm/decaf-model/decorators/index.js +2 -1
  95. package/lib/esm/decaf-model/decorators/types.js +1 -1
  96. package/lib/esm/decaf-model/decorators/utils.js +1 -1
  97. package/lib/esm/decaf-model/index.js +11 -4
  98. package/lib/esm/decaf-model/types.js +1 -1
  99. package/lib/esm/decaf-model/utils.js +1 -1
  100. package/lib/esm/decoration.js +1 -1
  101. package/lib/esm/decorators.js +79 -0
  102. package/lib/esm/events-module/DecafStreamModule.js +1 -1
  103. package/lib/esm/events-module/EventsController.js +1 -1
  104. package/lib/esm/events-module/constant.js +1 -1
  105. package/lib/esm/events-module/index.js +1 -1
  106. package/lib/esm/events-module/utils.js +1 -1
  107. package/lib/esm/factory/NestBootstraper.js +1 -1
  108. package/lib/esm/factory/errors/cors.js +1 -1
  109. package/lib/esm/factory/errors/index.js +1 -1
  110. package/lib/esm/factory/errors/throttling.js +1 -1
  111. package/lib/esm/factory/exceptions/DecafErrorFilter.js +1 -1
  112. package/lib/esm/factory/exceptions/decorators.js +1 -1
  113. package/lib/esm/factory/exceptions/index.js +1 -1
  114. package/lib/esm/factory/index.js +1 -1
  115. package/lib/esm/factory/openapi/DtoBuilder.js +36 -5
  116. package/lib/esm/factory/openapi/SwaggerBuilder.js +1 -1
  117. package/lib/esm/factory/openapi/SwaggerCustomUI.js +1 -1
  118. package/lib/esm/factory/openapi/constants.js +1 -1
  119. package/lib/esm/factory/openapi/index.js +1 -1
  120. package/lib/esm/index.js +7 -6
  121. package/lib/esm/interceptors/DecafRequestHandlerInterceptor.js +25 -21
  122. package/lib/esm/interceptors/index.js +2 -3
  123. package/lib/esm/module.js +4 -1
  124. package/lib/esm/overrides/Adapter.js +1 -1
  125. package/lib/esm/overrides/ModelBuilderExtensions.js +1 -1
  126. package/lib/esm/overrides/constants.js +1 -1
  127. package/lib/esm/overrides/decoration.js +1 -1
  128. package/lib/esm/overrides/helpers.js +1 -1
  129. package/lib/esm/overrides/index.js +2 -1
  130. package/lib/esm/overrides/logging.js +2 -0
  131. package/lib/esm/overrides/overrides.js +1 -1
  132. package/lib/esm/request/DecafAuthHandler.js +2 -36
  133. package/lib/esm/request/DecafHandlerExecutor.js +1 -1
  134. package/lib/esm/request/DecafRequestContext.js +10 -19
  135. package/lib/esm/request/DecafResponseInterceptor.js +2 -2
  136. package/lib/esm/request/index.js +1 -1
  137. package/lib/esm/swagger-types.js +1 -1
  138. package/lib/esm/types.js +1 -1
  139. package/lib/esm/utils.js +1 -1
  140. package/lib/esm/webhooks/DecafWebhookModule.js +5 -6
  141. package/lib/esm/webhooks/controllers.js +2 -2
  142. package/lib/esm/webhooks/index.js +1 -2
  143. package/lib/esm/webhooks/types.js +1 -1
  144. package/lib/types/{interceptors → auth}/AuthInterceptor.d.cts +4 -1
  145. package/lib/types/{interceptors → auth}/AuthInterceptor.d.mts +4 -1
  146. package/lib/types/auth/DecafAuthHandler.d.cts +22 -0
  147. package/lib/types/auth/DecafAuthHandler.d.mts +22 -0
  148. package/lib/types/auth/DecafAuthModule.d.cts +9 -0
  149. package/lib/types/auth/DecafAuthModule.d.mts +9 -0
  150. package/lib/types/auth/constants.d.cts +5 -0
  151. package/lib/types/auth/constants.d.mts +5 -0
  152. package/lib/types/auth/decorators.d.cts +4 -0
  153. package/lib/types/auth/decorators.d.mts +4 -0
  154. package/lib/types/auth/index.d.cts +6 -0
  155. package/lib/types/auth/index.d.mts +6 -0
  156. package/lib/types/cli-module.d.cts +1 -4
  157. package/lib/types/cli-module.d.mts +1 -4
  158. package/lib/types/constants.d.cts +2 -3
  159. package/lib/types/constants.d.mts +2 -3
  160. package/lib/types/controllers.d.cts +7 -12
  161. package/lib/types/controllers.d.mts +7 -12
  162. package/lib/types/decaf-model/DecafModelModule.d.cts +1 -0
  163. package/lib/types/decaf-model/DecafModelModule.d.mts +1 -0
  164. package/lib/types/decaf-model/FromModelController.d.cts +40 -52
  165. package/lib/types/decaf-model/FromModelController.d.mts +40 -52
  166. package/lib/types/decaf-model/decorators/ApiOperationFromModel.d.cts +0 -2
  167. package/lib/types/decaf-model/decorators/ApiOperationFromModel.d.mts +0 -2
  168. package/lib/types/decaf-model/decorators/controller-config.d.cts +18 -0
  169. package/lib/types/decaf-model/decorators/controller-config.d.mts +18 -0
  170. package/lib/types/decaf-model/decorators/decorators.d.cts +1 -29
  171. package/lib/types/decaf-model/decorators/decorators.d.mts +1 -29
  172. package/lib/types/decaf-model/decorators/expose.d.cts +1 -0
  173. package/lib/types/decaf-model/decorators/expose.d.mts +1 -0
  174. package/lib/types/decaf-model/decorators/index.d.cts +1 -0
  175. package/lib/types/decaf-model/decorators/index.d.mts +1 -0
  176. package/lib/types/decaf-model/decorators/types.d.cts +8 -21
  177. package/lib/types/decaf-model/decorators/types.d.mts +8 -21
  178. package/lib/types/decaf-model/index.d.cts +11 -3
  179. package/lib/types/decaf-model/index.d.mts +11 -3
  180. package/lib/types/decaf-model/utils.d.cts +2 -1
  181. package/lib/types/decaf-model/utils.d.mts +2 -1
  182. package/lib/types/decorators.d.cts +34 -0
  183. package/lib/types/decorators.d.mts +34 -0
  184. package/lib/types/factory/openapi/DtoBuilder.d.cts +7 -3
  185. package/lib/types/factory/openapi/DtoBuilder.d.mts +7 -3
  186. package/lib/types/index.d.cts +5 -5
  187. package/lib/types/index.d.mts +5 -5
  188. package/lib/types/interceptors/DecafRequestHandlerInterceptor.d.cts +1 -2
  189. package/lib/types/interceptors/DecafRequestHandlerInterceptor.d.mts +1 -2
  190. package/lib/types/interceptors/index.d.cts +1 -2
  191. package/lib/types/interceptors/index.d.mts +1 -2
  192. package/lib/types/overrides/Adapter.d.cts +1 -1
  193. package/lib/types/overrides/Adapter.d.mts +1 -1
  194. package/lib/types/overrides/index.d.cts +1 -0
  195. package/lib/types/overrides/index.d.mts +1 -0
  196. package/lib/types/overrides/logging.d.cts +1 -0
  197. package/lib/types/overrides/logging.d.mts +1 -0
  198. package/lib/types/request/DecafAuthHandler.d.cts +1 -10
  199. package/lib/types/request/DecafAuthHandler.d.mts +1 -10
  200. package/lib/types/request/DecafRequestContext.d.cts +4 -5
  201. package/lib/types/request/DecafRequestContext.d.mts +4 -5
  202. package/lib/types/types.d.cts +12 -24
  203. package/lib/types/types.d.mts +12 -24
  204. package/lib/types/webhooks/controllers.d.cts +1 -1
  205. package/lib/types/webhooks/controllers.d.mts +1 -1
  206. package/lib/types/webhooks/index.d.cts +0 -1
  207. package/lib/types/webhooks/index.d.mts +0 -1
  208. package/package.json +5 -13
  209. package/dist/for-nest.cjs.map +0 -1
  210. package/dist/for-nest.js.map +0 -1
  211. package/lib/cjs/bin/cli.cjs.map +0 -1
  212. package/lib/cjs/cli-module.cjs.map +0 -1
  213. package/lib/cjs/constants.cjs.map +0 -1
  214. package/lib/cjs/controllers.cjs.map +0 -1
  215. package/lib/cjs/core-module.cjs.map +0 -1
  216. package/lib/cjs/decaf-model/DecafModelModule.cjs.map +0 -1
  217. package/lib/cjs/decaf-model/FromModelController.cjs.map +0 -1
  218. package/lib/cjs/decaf-model/decorators/ApiOperationFromModel.cjs.map +0 -1
  219. package/lib/cjs/decaf-model/decorators/ApiParamsFromModel.cjs.map +0 -1
  220. package/lib/cjs/decaf-model/decorators/DecafBody.cjs.map +0 -1
  221. package/lib/cjs/decaf-model/decorators/DecafParams.cjs.map +0 -1
  222. package/lib/cjs/decaf-model/decorators/decorators.cjs.map +0 -1
  223. package/lib/cjs/decaf-model/decorators/index.cjs.map +0 -1
  224. package/lib/cjs/decaf-model/decorators/types.cjs.map +0 -1
  225. package/lib/cjs/decaf-model/decorators/utils.cjs.map +0 -1
  226. package/lib/cjs/decaf-model/index.cjs.map +0 -1
  227. package/lib/cjs/decaf-model/types.cjs.map +0 -1
  228. package/lib/cjs/decaf-model/utils.cjs.map +0 -1
  229. package/lib/cjs/decoration.cjs.map +0 -1
  230. package/lib/cjs/events-module/DecafStreamModule.cjs.map +0 -1
  231. package/lib/cjs/events-module/EventsController.cjs.map +0 -1
  232. package/lib/cjs/events-module/constant.cjs.map +0 -1
  233. package/lib/cjs/events-module/index.cjs.map +0 -1
  234. package/lib/cjs/events-module/utils.cjs.map +0 -1
  235. package/lib/cjs/factory/NestBootstraper.cjs.map +0 -1
  236. package/lib/cjs/factory/errors/cors.cjs.map +0 -1
  237. package/lib/cjs/factory/errors/index.cjs.map +0 -1
  238. package/lib/cjs/factory/errors/throttling.cjs.map +0 -1
  239. package/lib/cjs/factory/exceptions/DecafErrorFilter.cjs.map +0 -1
  240. package/lib/cjs/factory/exceptions/decorators.cjs.map +0 -1
  241. package/lib/cjs/factory/exceptions/index.cjs.map +0 -1
  242. package/lib/cjs/factory/index.cjs.map +0 -1
  243. package/lib/cjs/factory/openapi/DtoBuilder.cjs.map +0 -1
  244. package/lib/cjs/factory/openapi/SwaggerBuilder.cjs.map +0 -1
  245. package/lib/cjs/factory/openapi/SwaggerCustomUI.cjs.map +0 -1
  246. package/lib/cjs/factory/openapi/constants.cjs.map +0 -1
  247. package/lib/cjs/factory/openapi/index.cjs.map +0 -1
  248. package/lib/cjs/index.cjs.map +0 -1
  249. package/lib/cjs/interceptors/AuthInterceptor.cjs +0 -52
  250. package/lib/cjs/interceptors/AuthInterceptor.cjs.map +0 -1
  251. package/lib/cjs/interceptors/DecafRequestHandlerInterceptor.cjs.map +0 -1
  252. package/lib/cjs/interceptors/context.cjs +0 -18
  253. package/lib/cjs/interceptors/context.cjs.map +0 -1
  254. package/lib/cjs/interceptors/index.cjs.map +0 -1
  255. package/lib/cjs/migrations/index.cjs +0 -35
  256. package/lib/cjs/migrations/index.cjs.map +0 -1
  257. package/lib/cjs/migrations/migration-module.cjs +0 -60
  258. package/lib/cjs/migrations/migration-module.cjs.map +0 -1
  259. package/lib/cjs/migrations/migration-options.cjs +0 -4
  260. package/lib/cjs/migrations/migration-options.cjs.map +0 -1
  261. package/lib/cjs/module.cjs.map +0 -1
  262. package/lib/cjs/overrides/Adapter.cjs.map +0 -1
  263. package/lib/cjs/overrides/ModelBuilderExtensions.cjs.map +0 -1
  264. package/lib/cjs/overrides/constants.cjs.map +0 -1
  265. package/lib/cjs/overrides/decoration.cjs.map +0 -1
  266. package/lib/cjs/overrides/helpers.cjs.map +0 -1
  267. package/lib/cjs/overrides/index.cjs.map +0 -1
  268. package/lib/cjs/overrides/overrides.cjs.map +0 -1
  269. package/lib/cjs/ram/RamRequestTransformer.cjs +0 -26
  270. package/lib/cjs/ram/RamRequestTransformer.cjs.map +0 -1
  271. package/lib/cjs/ram/index.cjs +0 -19
  272. package/lib/cjs/ram/index.cjs.map +0 -1
  273. package/lib/cjs/request/DecafAuthHandler.cjs.map +0 -1
  274. package/lib/cjs/request/DecafHandlerExecutor.cjs.map +0 -1
  275. package/lib/cjs/request/DecafRequestContext.cjs.map +0 -1
  276. package/lib/cjs/request/DecafResponseInterceptor.cjs.map +0 -1
  277. package/lib/cjs/request/index.cjs.map +0 -1
  278. package/lib/cjs/swagger-types.cjs.map +0 -1
  279. package/lib/cjs/types.cjs.map +0 -1
  280. package/lib/cjs/utils.cjs.map +0 -1
  281. package/lib/cjs/webhooks/DecafWebhookModule.cjs.map +0 -1
  282. package/lib/cjs/webhooks/controllers.cjs.map +0 -1
  283. package/lib/cjs/webhooks/index.cjs.map +0 -1
  284. package/lib/cjs/webhooks/types.cjs.map +0 -1
  285. package/lib/esm/bin/cli.js.map +0 -1
  286. package/lib/esm/cli-module.js.map +0 -1
  287. package/lib/esm/constants.js.map +0 -1
  288. package/lib/esm/controllers.js.map +0 -1
  289. package/lib/esm/core-module.js.map +0 -1
  290. package/lib/esm/decaf-model/DecafModelModule.js.map +0 -1
  291. package/lib/esm/decaf-model/FromModelController.js.map +0 -1
  292. package/lib/esm/decaf-model/decorators/ApiOperationFromModel.js.map +0 -1
  293. package/lib/esm/decaf-model/decorators/ApiParamsFromModel.js.map +0 -1
  294. package/lib/esm/decaf-model/decorators/DecafBody.js.map +0 -1
  295. package/lib/esm/decaf-model/decorators/DecafParams.js.map +0 -1
  296. package/lib/esm/decaf-model/decorators/decorators.js.map +0 -1
  297. package/lib/esm/decaf-model/decorators/index.js.map +0 -1
  298. package/lib/esm/decaf-model/decorators/types.js.map +0 -1
  299. package/lib/esm/decaf-model/decorators/utils.js.map +0 -1
  300. package/lib/esm/decaf-model/index.js.map +0 -1
  301. package/lib/esm/decaf-model/types.js.map +0 -1
  302. package/lib/esm/decaf-model/utils.js.map +0 -1
  303. package/lib/esm/decoration.js.map +0 -1
  304. package/lib/esm/events-module/DecafStreamModule.js.map +0 -1
  305. package/lib/esm/events-module/EventsController.js.map +0 -1
  306. package/lib/esm/events-module/constant.js.map +0 -1
  307. package/lib/esm/events-module/index.js.map +0 -1
  308. package/lib/esm/events-module/utils.js.map +0 -1
  309. package/lib/esm/factory/NestBootstraper.js.map +0 -1
  310. package/lib/esm/factory/errors/cors.js.map +0 -1
  311. package/lib/esm/factory/errors/index.js.map +0 -1
  312. package/lib/esm/factory/errors/throttling.js.map +0 -1
  313. package/lib/esm/factory/exceptions/DecafErrorFilter.js.map +0 -1
  314. package/lib/esm/factory/exceptions/decorators.js.map +0 -1
  315. package/lib/esm/factory/exceptions/index.js.map +0 -1
  316. package/lib/esm/factory/index.js.map +0 -1
  317. package/lib/esm/factory/openapi/DtoBuilder.js.map +0 -1
  318. package/lib/esm/factory/openapi/SwaggerBuilder.js.map +0 -1
  319. package/lib/esm/factory/openapi/SwaggerCustomUI.js.map +0 -1
  320. package/lib/esm/factory/openapi/constants.js.map +0 -1
  321. package/lib/esm/factory/openapi/index.js.map +0 -1
  322. package/lib/esm/index.js.map +0 -1
  323. package/lib/esm/interceptors/AuthInterceptor.js +0 -43
  324. package/lib/esm/interceptors/AuthInterceptor.js.map +0 -1
  325. package/lib/esm/interceptors/DecafRequestHandlerInterceptor.js.map +0 -1
  326. package/lib/esm/interceptors/context.js +0 -12
  327. package/lib/esm/interceptors/context.js.map +0 -1
  328. package/lib/esm/interceptors/index.js.map +0 -1
  329. package/lib/esm/migrations/index.js +0 -18
  330. package/lib/esm/migrations/index.js.map +0 -1
  331. package/lib/esm/migrations/migration-module.js +0 -52
  332. package/lib/esm/migrations/migration-module.js.map +0 -1
  333. package/lib/esm/migrations/migration-options.js +0 -7
  334. package/lib/esm/migrations/migration-options.js.map +0 -1
  335. package/lib/esm/module.js.map +0 -1
  336. package/lib/esm/overrides/Adapter.js.map +0 -1
  337. package/lib/esm/overrides/ModelBuilderExtensions.js.map +0 -1
  338. package/lib/esm/overrides/constants.js.map +0 -1
  339. package/lib/esm/overrides/decoration.js.map +0 -1
  340. package/lib/esm/overrides/helpers.js.map +0 -1
  341. package/lib/esm/overrides/index.js.map +0 -1
  342. package/lib/esm/overrides/overrides.js.map +0 -1
  343. package/lib/esm/ram/RamRequestTransformer.js +0 -21
  344. package/lib/esm/ram/RamRequestTransformer.js.map +0 -1
  345. package/lib/esm/ram/index.js +0 -2
  346. package/lib/esm/ram/index.js.map +0 -1
  347. package/lib/esm/request/DecafAuthHandler.js.map +0 -1
  348. package/lib/esm/request/DecafHandlerExecutor.js.map +0 -1
  349. package/lib/esm/request/DecafRequestContext.js.map +0 -1
  350. package/lib/esm/request/DecafResponseInterceptor.js.map +0 -1
  351. package/lib/esm/request/index.js.map +0 -1
  352. package/lib/esm/swagger-types.js.map +0 -1
  353. package/lib/esm/types.js.map +0 -1
  354. package/lib/esm/utils.js.map +0 -1
  355. package/lib/esm/webhooks/DecafWebhookModule.js.map +0 -1
  356. package/lib/esm/webhooks/controllers.js.map +0 -1
  357. package/lib/esm/webhooks/index.js.map +0 -1
  358. package/lib/esm/webhooks/types.js.map +0 -1
  359. package/lib/types/interceptors/context.d.cts +0 -6
  360. package/lib/types/interceptors/context.d.mts +0 -6
  361. package/lib/types/migrations/index.d.cts +0 -17
  362. package/lib/types/migrations/index.d.mts +0 -17
  363. package/lib/types/migrations/migration-module.d.cts +0 -15
  364. package/lib/types/migrations/migration-module.d.mts +0 -15
  365. package/lib/types/migrations/migration-options.d.cts +0 -11
  366. package/lib/types/migrations/migration-options.d.mts +0 -11
  367. package/lib/types/ram/RamRequestTransformer.d.cts +0 -5
  368. package/lib/types/ram/RamRequestTransformer.d.mts +0 -5
  369. package/lib/types/ram/index.d.cts +0 -1
  370. package/lib/types/ram/index.d.mts +0 -1
@@ -7,73 +7,24 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- var __param = (this && this.__param) || function (paramIndex, decorator) {
11
- return function (target, key) { decorator(target, key, paramIndex); }
12
- };
13
- import { Controller, Param, Query, Response } from "@nestjs/common";
14
- import { ApiBadRequestResponse, ApiBody, ApiCreatedResponse, ApiExtraModels, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiParam, ApiQuery, ApiTags, ApiUnprocessableEntityResponse, getSchemaPath, } from "@nestjs/swagger";
10
+ var DynamicModelController_1;
11
+ import { Controller, Param, Query, Response, SetMetadata } from "@nestjs/common";
12
+ import { ApiBadRequestResponse, ApiBody, ApiCreatedResponse, ApiExtraModels, ApiNoContentResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiParam, ApiQuery, ApiTags, ApiUnprocessableEntityResponse, getSchemaPath, } from "@nestjs/swagger";
15
13
  import { ModelService, OrderDirection, PersistenceKeys, PreparedStatementKeys, Repository, Service, } from "@decaf-ts/core";
16
14
  import { Model } from "@decaf-ts/decorator-validation";
17
15
  import { Logging, toKebabCase } from "@decaf-ts/logging";
18
16
  import { BulkCrudOperationKeys, DBKeys, OperationKeys, ValidationError, } from "@decaf-ts/db-decorators";
19
17
  import { Metadata } from "@decaf-ts/decoration";
20
18
  import { ApiOperationFromModel, ApiParamsFromModel, DecafBody, DecafParams, DecafQuery, } from "./decorators/index.js";
19
+ import { HttpVerbToDecorator } from "./decorators/utils.js";
21
20
  import { DecafRequestContext } from "./../request/index.js";
22
- import { DECAF_ROUTE } from "./../constants.js";
23
- import { applyApiDecorators, createRouteHandler, defineRouteMethod, getApiDecorators, resolvePersistenceMethod, } from "./utils.js";
24
- import { Auth } from "./decorators/decorators.js";
21
+ import { DECAF_CONTROLLER_CONFIG, DECAF_ROUTE } from "./../constants.js";
22
+ import { SKIP_MODEL_ROLES_KEY } from "./../auth/constants.js";
23
+ import { Auth, Public, RequireRoles } from "./../auth/decorators.js";
25
24
  import { DecafModelController } from "./../controllers.js";
26
25
  import { DtoFor } from "./../factory/openapi/DtoBuilder.js";
27
26
  import "./../overrides/index.js";
28
- /**
29
- * @description
30
- * Factory and utilities for generating dynamic NestJS controllers from Decaf {@link Model} definitions.
31
- *
32
- * @summary
33
- * The `FromModelController` class provides the infrastructure necessary to automatically generate
34
- * strongly-typed CRUD controllers based on a given {@link ModelConstructor}. It inspects metadata from
35
- * the model, derives route paths, parameters, and generates a dynamic controller class at runtime with
36
- * full support for querying, creation, update, and deletion of model entities through a {@link Repo}.
37
- *
38
- * @template T The {@link Model} type associated with the generated controller.
39
- *
40
- * @param ModelClazz The model class to generate the controller from.
41
- *
42
- * @class FromModelController
43
- *
44
- * @example
45
- * ```ts
46
- * // Given a Decaf Model:
47
- * class User extends Model<User> {
48
- * id!: string;
49
- * name!: string;
50
- * }
51
- *
52
- * // Register controller:
53
- * const UserController = FromModelController.create(User);
54
- *
55
- * // NestJS will expose:
56
- * // POST /user
57
- * // GET /user/:id
58
- * // GET /user/query/:method
59
- * // PUT /user/:id
60
- * // DELETE /user/:id
61
- * ```
62
- *
63
- * @mermaid
64
- * sequenceDiagram
65
- * participant Client
66
- * participant Controller
67
- * participant Repo
68
- * participant DB
69
- *
70
- * Client->>Controller: HTTP Request
71
- * Controller->>Repo: Resolve repository for Model
72
- * Repo->>DB: Execute DB operation
73
- * DB-->>Repo: DB Result
74
- * Repo-->>Controller: Model Instance(s)
75
- * Controller-->>Client: JSON Response
76
- */
27
+ import { ModelControllerFactory, } from "@decaf-ts/for-http/server";
77
28
  export class FromModelController {
78
29
  static { this.log = Logging.for(FromModelController.name); }
79
30
  static getPersistence(ModelClazz) {
@@ -83,20 +34,17 @@ export class FromModelController {
83
34
  catch (e) {
84
35
  try {
85
36
  return ModelService.getService(ModelClazz);
86
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
87
37
  }
88
- catch (e) {
38
+ catch (e2) {
89
39
  return Repository.forModel(ModelClazz);
90
40
  }
91
41
  }
92
42
  }
93
43
  static createQueryRoutesFromRepository(persistence, prefix = PersistenceKeys.QUERY) {
94
- const log = FromModelController.log.for(FromModelController.createQueryRoutesFromRepository);
95
44
  const repo = persistence instanceof ModelService ? persistence.repo : persistence;
96
45
  const ModelConstr = repo.class;
97
46
  const queryMethods = Metadata.get(repo.constructor, Metadata.key(PersistenceKeys.QUERY)) ?? {};
98
47
  const routeMethods = Metadata.get(persistence.constructor, Metadata.key(DECAF_ROUTE)) ?? {};
99
- // create base class
100
48
  class QueryController extends DecafModelController {
101
49
  get class() {
102
50
  throw new Error("Method not implemented.");
@@ -106,733 +54,700 @@ export class FromModelController {
106
54
  }
107
55
  }
108
56
  for (const [methodName, params] of Object.entries(routeMethods)) {
109
- // regex to trim slashes from start and end
110
57
  const routePath = [params.path.replace(/^\/+|\/+$/g, "")]
111
58
  .filter((segment) => segment && segment.trim())
112
59
  .join("/");
113
- // const handler = params.handler.value;
114
- const handler = createRouteHandler(methodName);
115
- if (!handler) {
116
- const message = `Invalid or missing handler for model ${ModelConstr.name} on decorated method ${methodName}`;
117
- log.error(message);
118
- throw new Error(message);
119
- }
120
- const descriptor = defineRouteMethod(QueryController, methodName, handler);
121
- if (descriptor) {
122
- const decorators = getApiDecorators(methodName, routePath, params.httpMethod);
123
- applyApiDecorators(QueryController, methodName, descriptor, decorators);
124
- }
60
+ const handler = FromModelController.createComplexQueryHandler(methodName);
61
+ FromModelController.defineMethod(QueryController, methodName, handler);
62
+ const httpDecorator = HttpVerbToDecorator(params.httpMethod)(routePath || undefined);
63
+ const decorators = FromModelController.getQueryDecorators(methodName, routePath, params.httpMethod);
64
+ FromModelController.applyDecorators(QueryController, methodName, [httpDecorator, ...decorators]);
125
65
  }
126
66
  for (const [methodName, objValues] of Object.entries(queryMethods)) {
127
67
  const fields = objValues.fields ?? [];
128
68
  const routePath = [prefix, methodName, ...fields.map((f) => `:${f}`)]
129
69
  .filter((segment) => segment && segment.trim())
130
70
  .join("/");
131
- const handler = createRouteHandler(methodName);
132
- const descriptor = defineRouteMethod(QueryController, methodName, handler);
133
- if (descriptor) {
134
- const decorators = getApiDecorators(methodName, routePath, "GET", true);
135
- applyApiDecorators(QueryController, methodName, descriptor, decorators);
136
- }
71
+ const handler = FromModelController.createComplexQueryHandler(methodName);
72
+ FromModelController.defineMethod(QueryController, methodName, handler);
73
+ const httpDecorator = HttpVerbToDecorator("GET")(routePath || undefined);
74
+ const decorators = FromModelController.getQueryDecorators(methodName, routePath, "GET", true);
75
+ FromModelController.applyDecorators(QueryController, methodName, [httpDecorator, ...decorators]);
137
76
  }
138
77
  return QueryController;
139
78
  }
140
- static create(ModelConstr) {
79
+ static create(ModelConstr, moduleConfigOverrides, globalDefaults) {
141
80
  const log = FromModelController.log.for(FromModelController.create);
142
81
  const tableName = Model.tableName(ModelConstr);
143
82
  const routePath = toKebabCase(tableName);
144
83
  const modelClazzName = ModelConstr.name;
145
84
  const persistence = FromModelController.getPersistence(ModelConstr);
146
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
147
- const { description, getPK, apiProperties, path } = FromModelController.getRouteParametersFromModel(ModelConstr);
148
- log.debug(`Creating controller for model: ${modelClazzName}`);
149
- const BaseController = FromModelController.createQueryRoutesFromRepository(persistence // instanceof ModelService ? persistence.repo : persistence
150
- );
151
- let DynamicModelController = class DynamicModelController extends BaseController {
85
+ // When persistence is a ModelService, the @query/@route metadata lives on
86
+ // the underlying repository class (custom repo), not on ModelService itself.
87
+ // Pass the repo to the factory so addComplexQueries() can discover them.
88
+ const factoryPersistence = persistence instanceof ModelService ? persistence.repo : persistence;
89
+ const decoratorConfig = Metadata.get(ModelConstr, Metadata.key(DECAF_CONTROLLER_CONFIG));
90
+ const moduleOverride = moduleConfigOverrides?.[ModelConstr.name];
91
+ const mergedConfig = {
92
+ ...(globalDefaults || {}),
93
+ ...(decoratorConfig || {}),
94
+ ...(moduleOverride || {}),
95
+ };
96
+ const FactoryController = ModelControllerFactory.create(ModelConstr, factoryPersistence, mergedConfig);
97
+ const factoryRoutes = FactoryController.__routes__;
98
+ const { getPK, apiProperties, path: pkPath } = FromModelController.getRouteParametersFromModel(ModelConstr);
99
+ log.debug(`Creating controller for model: ${modelClazzName} with ${factoryRoutes?.length ?? 0} factory routes`);
100
+ const authConfig = mergedConfig.auth;
101
+ function applyClassAuth(target) {
102
+ if (authConfig?.public) {
103
+ Public()(target);
104
+ }
105
+ else if (authConfig?.roles?.length) {
106
+ RequireRoles(...authConfig.roles)(target);
107
+ }
108
+ else {
109
+ Auth(ModelConstr)(target);
110
+ }
111
+ if (authConfig?.skipModelRoles) {
112
+ SetMetadata(SKIP_MODEL_ROLES_KEY, true)(target);
113
+ }
114
+ }
115
+ let DynamicModelController = DynamicModelController_1 = class DynamicModelController extends DecafModelController {
152
116
  static get class() {
153
117
  return ModelConstr;
154
118
  }
155
119
  get class() {
156
120
  return ModelConstr;
157
- // return DynamicModelController.class;
158
121
  }
159
122
  constructor(clientContext) {
160
- super(clientContext);
123
+ super(clientContext, DynamicModelController_1.name);
161
124
  this.pk = Model.pk(ModelConstr);
162
125
  log.info(`Registering dynamic controller for model: ${this.class.name} route: /${routePath}`);
163
126
  }
164
- //
165
- // @ApiOperationFromModel(ModelClazz, "GET", "query/:condition/:orderBy")
166
- // @ApiOperation({ summary: `Retrieve ${modelClazzName} records by query.` })
167
- // @ApiParam({ name: "method", description: "Query method to be called" })
168
- // @ApiOkResponse({
169
- // description: `${modelClazzName} retrieved successfully.`,
170
- // })
171
- // @ApiNotFoundResponse({
172
- // description: `No ${modelClazzName} records matches the query.`,
173
- // })
174
- // async query(
175
- // @Param("condition") condition: Condition<any>,
176
- // @Param("orderBy") orderBy: string,
177
- // @QueryDetails() details: DirectionLimitOffset,
178
- // ) {
179
- // const {direction, limit, offset} = details;
180
- // return this.persistence.query(condition, orderBy as keyof Model, direction, limit, offset);
181
- // }
182
- async listBy(key, details) {
183
- const { ctx } = (await this.logCtx([], PreparedStatementKeys.LIST_BY, true)).for(this.listBy);
184
- return this.persistence(ctx).listBy(key, details.direction, ctx);
185
- }
186
- async paginateBy(key, details) {
187
- const { ctx } = (await this.logCtx([], PreparedStatementKeys.PAGE_BY, true)).for(this.paginateBy);
188
- return this.persistence(ctx).paginateBy(key, details.direction, details, ctx);
189
- }
190
- async find(value, details) {
191
- const { ctx } = (await this.logCtx([], PreparedStatementKeys.FIND, true)).for(this.find);
192
- const direction = (details.direction ??
193
- OrderDirection.ASC);
194
- return resolvePersistenceMethod(this.persistence(ctx), this.find.name, value, direction, ctx);
195
- }
196
- async page(value, details) {
197
- const { ctx } = (await this.logCtx([], PreparedStatementKeys.PAGE, true)).for(this.page);
198
- const { direction = OrderDirection.ASC, limit, offset, bookmark, } = details;
199
- const ref = {
200
- offset: offset ?? 1,
201
- limit: limit ?? 10,
202
- bookmark,
203
- };
204
- return resolvePersistenceMethod(this.persistence(ctx), this.page.name, value, direction, ref, ctx);
205
- }
206
- async findOneBy(key, value) {
207
- const { ctx } = (await this.logCtx([], PreparedStatementKeys.FIND_ONE_BY, true)).for(this.findOneBy);
208
- return this.persistence(ctx).findOneBy(key, value, ctx);
209
- }
210
- async findBy(key, value, details) {
211
- const { ctx } = (await this.logCtx([], PreparedStatementKeys.FIND_BY, true)).for(this.findBy);
212
- return this.persistence(ctx)
213
- .for(ctx.toOverrides())
214
- .findBy(key, value, ctx);
215
- }
216
- async statement(name, args, details) {
217
- const { ctx } = (await this.logCtx([], PersistenceKeys.STATEMENT, true)).for(this.statement);
218
- const { direction, offset, limit, bookmark } = details;
219
- args = args.map((a) => (typeof a === "string" ? parseInt(a) : a) || a);
220
- const pathDirection = args.length > 1 ? args[1] : undefined;
221
- const resolvedDirection = (direction ?? pathDirection);
222
- if (resolvedDirection && args.length > 1)
223
- args[1] = resolvedDirection;
224
- switch (name) {
225
- case PreparedStatementKeys.FIND:
226
- case PreparedStatementKeys.FIND_BY:
227
- break;
228
- case PreparedStatementKeys.LIST_BY:
229
- args.push(direction);
230
- break;
231
- case PreparedStatementKeys.PAGE:
232
- case PreparedStatementKeys.PAGE_BY:
233
- args = [
234
- args[0],
235
- resolvedDirection,
236
- {
237
- limit: limit,
238
- offset: offset,
239
- bookmark: bookmark,
240
- },
241
- ];
242
- break;
243
- case PreparedStatementKeys.FIND_ONE_BY:
244
- break;
245
- case PreparedStatementKeys.COUNT_OF:
246
- case PreparedStatementKeys.MAX_OF:
247
- case PreparedStatementKeys.MIN_OF:
248
- case PreparedStatementKeys.AVG_OF:
249
- case PreparedStatementKeys.SUM_OF:
250
- case PreparedStatementKeys.DISTINCT_OF:
251
- case PreparedStatementKeys.GROUP_OF:
252
- // Aggregation methods - args[0] is the field name (if provided)
253
- break;
254
- }
255
- return this.persistence(ctx).statement(name, ...args, ctx);
256
- }
257
- //
258
- // @ApiOperationFromModel(ModelConstr, "GET", "countOf")
259
- // @ApiOperation({ summary: `Count all ${modelClazzName} records.` })
260
- // @ApiOkResponse({
261
- // description: `Count of ${modelClazzName} records.`,
262
- // type: Number,
263
- // })
264
- // async countOf() {
265
- // const { ctx } = (
266
- // await this.logCtx([], PreparedStatementKeys.COUNT_OF, true)
267
- // ).for(this.countOf);
268
- // return this.persistence(ctx).statement(
269
- // PreparedStatementKeys.COUNT_OF,
270
- // ctx
271
- // );
272
- // }
273
- //
274
- // @ApiOperationFromModel(ModelConstr, "GET", "countOf/:field")
275
- // @ApiOperation({ summary: `Count ${modelClazzName} records by field.` })
276
- // @ApiParam({ name: "field", description: "The field to count" })
277
- // @ApiOkResponse({
278
- // description: `Count of ${modelClazzName} records.`,
279
- // type: Number,
280
- // })
281
- // async countOfField(@Param("field") field: string) {
282
- // const { ctx } = (
283
- // await this.logCtx([], PreparedStatementKeys.COUNT_OF, true)
284
- // ).for(this.countOfField);
285
- // return this.persistence(ctx).statement(
286
- // PreparedStatementKeys.COUNT_OF,
287
- // field,
288
- // ctx
289
- // );
290
- // }
291
- //
292
- // @ApiOperationFromModel(ModelConstr, "GET", "maxOf/:field")
293
- // @ApiOperation({
294
- // summary: `Find maximum value of a field in ${modelClazzName}.`,
295
- // })
296
- // @ApiParam({ name: "field", description: "The field to find max of" })
297
- // @ApiOkResponse({
298
- // description: `Maximum value of the field in ${modelClazzName}.`,
299
- // })
300
- // async maxOf(@Param("field") field: string) {
301
- // const { ctx } = (
302
- // await this.logCtx([], PreparedStatementKeys.MAX_OF, true)
303
- // ).for(this.maxOf);
304
- // return this.persistence(ctx).statement(
305
- // PreparedStatementKeys.MAX_OF,
306
- // field,
307
- // ctx
308
- // );
309
- // }
310
- //
311
- // @ApiOperationFromModel(ModelConstr, "GET", "minOf/:field")
312
- // @ApiOperation({
313
- // summary: `Find minimum value of a field in ${modelClazzName}.`,
314
- // })
315
- // @ApiParam({ name: "field", description: "The field to find min of" })
316
- // @ApiOkResponse({
317
- // description: `Minimum value of the field in ${modelClazzName}.`,
318
- // })
319
- // async minOf(@Param("field") field: string) {
320
- // const { ctx } = (
321
- // await this.logCtx([], PreparedStatementKeys.MIN_OF, true)
322
- // ).for(this.minOf);
323
- // return this.persistence(ctx).statement(
324
- // PreparedStatementKeys.MIN_OF,
325
- // field,
326
- // ctx
327
- // );
328
- // }
329
- //
330
- // @ApiOperationFromModel(ModelConstr, "GET", "avgOf/:field")
331
- // @ApiOperation({
332
- // summary: `Calculate average of a field in ${modelClazzName}.`,
333
- // })
334
- // @ApiParam({
335
- // name: "field",
336
- // description: "The field to calculate average of",
337
- // })
338
- // @ApiOkResponse({
339
- // description: `Average value of the field in ${modelClazzName}.`,
340
- // type: Number,
341
- // })
342
- // async avgOf(@Param("field") field: string) {
343
- // const { ctx } = (
344
- // await this.logCtx([], PreparedStatementKeys.AVG_OF, true)
345
- // ).for(this.avgOf);
346
- // return this.persistence(ctx).statement(
347
- // PreparedStatementKeys.AVG_OF,
348
- // field,
349
- // ctx
350
- // );
351
- // }
352
- //
353
- // @ApiOperationFromModel(ModelConstr, "GET", "sumOf/:field")
354
- // @ApiOperation({
355
- // summary: `Calculate sum of a field in ${modelClazzName}.`,
356
- // })
357
- // @ApiParam({ name: "field", description: "The field to calculate sum of" })
358
- // @ApiOkResponse({
359
- // description: `Sum of the field in ${modelClazzName}.`,
360
- // type: Number,
361
- // })
362
- // async sumOf(@Param("field") field: string) {
363
- // const { ctx } = (
364
- // await this.logCtx([], PreparedStatementKeys.SUM_OF, true)
365
- // ).for(this.sumOf);
366
- // return this.persistence(ctx).statement(
367
- // PreparedStatementKeys.SUM_OF,
368
- // field,
369
- // ctx
370
- // );
371
- // }
372
- //
373
- // @ApiOperationFromModel(ModelConstr, "GET", "distinctOf/:field")
374
- // @ApiOperation({
375
- // summary: `Find distinct values of a field in ${modelClazzName}.`,
376
- // })
377
- // @ApiParam({
378
- // name: "field",
379
- // description: "The field to find distinct values of",
380
- // })
381
- // @ApiOkResponse({
382
- // description: `Distinct values of the field in ${modelClazzName}.`,
383
- // type: [String],
384
- // })
385
- // async distinctOf(@Param("field") field: string) {
386
- // const { ctx } = (
387
- // await this.logCtx([], PreparedStatementKeys.DISTINCT_OF, true)
388
- // ).for(this.distinctOf);
389
- // return this.persistence(ctx).statement(
390
- // PreparedStatementKeys.DISTINCT_OF,
391
- // field,
392
- // ctx
393
- // );
394
- // }
395
- //
396
- // @ApiOperationFromModel(ModelConstr, "GET", "groupOf/:field")
397
- // @ApiOperation({
398
- // summary: `Group ${modelClazzName} records by a field.`,
399
- // })
400
- // @ApiParam({ name: "field", description: "The field to group by" })
401
- // @ApiOkResponse({
402
- // description: `${modelClazzName} records grouped by the field.`,
403
- // })
404
- // async groupOf(@Param("field") field: string) {
405
- // const { ctx } = (
406
- // await this.logCtx([], PreparedStatementKeys.GROUP_OF, true)
407
- // ).for(this.groupOf);
408
- // return this.persistence(ctx).statement(
409
- // PreparedStatementKeys.GROUP_OF,
410
- // field,
411
- // ctx
412
- // );
413
- // }
414
- async createAll(data, resp) {
415
- const { ctx, log } = (await this.logCtx([], BulkCrudOperationKeys.CREATE_ALL, true)).for(this.createAll);
416
- log.verbose(`creating new ${modelClazzName}`);
417
- let created;
418
- try {
419
- created = await this.persistence(ctx).createAll(data.map((d) => new ModelConstr(d)), ctx);
420
- }
421
- catch (e) {
422
- log.error(`Failed to create new ${modelClazzName}`, e);
423
- throw e;
127
+ };
128
+ DynamicModelController = DynamicModelController_1 = __decorate([
129
+ Controller(routePath),
130
+ ApiTags(modelClazzName),
131
+ ApiExtraModels(ModelConstr),
132
+ __metadata("design:paramtypes", [DecafRequestContext])
133
+ ], DynamicModelController);
134
+ applyClassAuth(DynamicModelController);
135
+ if (factoryRoutes) {
136
+ const sortedRoutes = [...factoryRoutes].sort((a, b) => {
137
+ const aSegments = a.path.split("/").filter(Boolean);
138
+ const bSegments = b.path.split("/").filter(Boolean);
139
+ const aParamCount = aSegments.filter((s) => s.startsWith(":")).length;
140
+ const bParamCount = bSegments.filter((s) => s.startsWith(":")).length;
141
+ const aLiteralCount = aSegments.length - aParamCount;
142
+ const bLiteralCount = bSegments.length - bParamCount;
143
+ if (aLiteralCount !== bLiteralCount)
144
+ return bLiteralCount - aLiteralCount;
145
+ if (aParamCount !== bParamCount)
146
+ return aParamCount - bParamCount;
147
+ return 0;
148
+ });
149
+ for (const route of sortedRoutes) {
150
+ const registration = FromModelController.matchRoute(route, pkPath, apiProperties, getPK, ModelConstr, modelClazzName, factoryPersistence);
151
+ if (!registration)
152
+ continue;
153
+ const { methodName, handler, decorators, paramDecorators } = registration;
154
+ const descriptor = FromModelController.defineMethod(DynamicModelController, methodName, handler);
155
+ if (descriptor) {
156
+ const httpDecorator = HttpVerbToDecorator(route.method)(route.path.replace(/^\/+|\/+$/g, "") || undefined);
157
+ FromModelController.applyDecorators(DynamicModelController, methodName, [httpDecorator, ...decorators], paramDecorators);
424
158
  }
425
- log.info(`created new ${modelClazzName} with id ${created[this.pk]}`);
159
+ }
160
+ }
161
+ return DynamicModelController;
162
+ }
163
+ static getRouteParametersFromModel(ModelClazz) {
164
+ const pk = Model.pk(ModelClazz);
165
+ const composed = Metadata.get(ModelClazz, Metadata.key(DBKeys.COMPOSED, pk));
166
+ const composedKeys = composed?.args ?? [];
167
+ const uniqueKeys = Array.isArray(composedKeys) && composedKeys.length > 0
168
+ ? Array.from(new Set([...composedKeys]))
169
+ : Array.from(new Set([pk]));
170
+ const description = Metadata.description(ModelClazz) ?? "";
171
+ const path = `:${uniqueKeys.join("/:")}`;
172
+ const apiProperties = uniqueKeys.map((key) => {
173
+ return {
174
+ name: key,
175
+ description: Metadata.description(ModelClazz, key),
176
+ required: true,
177
+ type: String,
178
+ };
179
+ });
180
+ return {
181
+ path,
182
+ description,
183
+ apiProperties,
184
+ getPK: (...params) => composed?.separator ? params.join(composed.separator) : params.join(""),
185
+ };
186
+ }
187
+ static defineMethod(target, methodName, handler) {
188
+ Object.defineProperty(target.prototype || target, methodName, {
189
+ value: handler,
190
+ writable: false,
191
+ configurable: true,
192
+ enumerable: false,
193
+ });
194
+ return Object.getOwnPropertyDescriptor(target.prototype || target, methodName);
195
+ }
196
+ static applyDecorators(target, methodName, methodDecorators, paramDecorators = []) {
197
+ const proto = target?.prototype ?? target;
198
+ const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
199
+ methodDecorators.forEach((d) => d(proto, methodName, descriptor));
200
+ paramDecorators.forEach(({ decorator, index }) => decorator(proto, methodName, index));
201
+ }
202
+ static matchRoute(route, pkPath, apiProperties, getPK, ModelConstr, modelClazzName, persistence) {
203
+ const { method, path } = route;
204
+ const normalizedPath = path.replace(/^\/+|\/+$/g, "");
205
+ if (method === "POST" && normalizedPath === "") {
206
+ return FromModelController.createRegistration("create", FromModelController.createCreateHandler(ModelConstr, modelClazzName), FromModelController.createCreateDecorators(ModelConstr, modelClazzName), [{ decorator: DecafBody(), index: 0 }, { decorator: Response({ passthrough: true }), index: 1 }]);
207
+ }
208
+ if (method === "POST" && normalizedPath === "bulk") {
209
+ return FromModelController.createRegistration("createAll", FromModelController.createBulkCreateHandler(ModelConstr, modelClazzName), FromModelController.bulkCreateDecorators(ModelConstr, modelClazzName), [{ decorator: DecafBody(), index: 0 }, { decorator: Response({ passthrough: true }), index: 1 }]);
210
+ }
211
+ if (method === "GET" && normalizedPath === "bulk") {
212
+ return FromModelController.createRegistration("readAll", FromModelController.createBulkReadHandler(modelClazzName), FromModelController.bulkReadDecorators(ModelConstr, modelClazzName), [{ decorator: Query("ids"), index: 0 }]);
213
+ }
214
+ if (method === "PUT" && normalizedPath === "bulk") {
215
+ return FromModelController.createRegistration("updateAll", FromModelController.createBulkUpdateHandler(modelClazzName), FromModelController.bulkUpdateDecorators(ModelConstr, modelClazzName, apiProperties), [{ decorator: DecafBody(), index: 0 }, { decorator: Response({ passthrough: true }), index: 1 }]);
216
+ }
217
+ if (method === "DELETE" && normalizedPath === "bulk") {
218
+ return FromModelController.createRegistration("deleteAll", FromModelController.createBulkDeleteHandler(modelClazzName), FromModelController.bulkDeleteDecorators(ModelConstr, modelClazzName, apiProperties), [{ decorator: Query("ids"), index: 0 }, { decorator: Response({ passthrough: true }), index: 1 }]);
219
+ }
220
+ if (method === "GET" && normalizedPath === pkPath) {
221
+ return FromModelController.createRegistration("read", FromModelController.createReadHandler(getPK, modelClazzName), FromModelController.readDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), [{ decorator: DecafParams(apiProperties), index: 0 }]);
222
+ }
223
+ if (method === "PUT" && normalizedPath === pkPath) {
224
+ return FromModelController.createRegistration("update", FromModelController.createUpdateHandler(getPK, ModelConstr, modelClazzName), FromModelController.updateDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), [
225
+ { decorator: DecafParams(apiProperties), index: 0 },
226
+ { decorator: DecafBody(), index: 1 },
227
+ { decorator: Response({ passthrough: true }), index: 2 },
228
+ ]);
229
+ }
230
+ if (method === "DELETE" && normalizedPath === pkPath) {
231
+ return FromModelController.createRegistration("delete", FromModelController.createDeleteHandler(getPK, modelClazzName), FromModelController.deleteDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), [
232
+ { decorator: DecafParams(apiProperties), index: 0 },
233
+ { decorator: Response({ passthrough: true }), index: 1 },
234
+ ]);
235
+ }
236
+ // Composed PK fallback routes (filterEmpty) — path differs from pkPath
237
+ const fallbackSegments = normalizedPath.split("/").filter(Boolean);
238
+ const isAllParams = fallbackSegments.length > 0 && fallbackSegments.every((s) => s.startsWith(":"));
239
+ if (isAllParams && normalizedPath !== pkPath) {
240
+ const fallbackApiProps = fallbackSegments.map((s) => s.slice(1)).map((name) => ({
241
+ name,
242
+ description: `${name} parameter`,
243
+ required: true,
244
+ type: String,
245
+ }));
246
+ const suffix = fallbackSegments.map((s) => s.slice(1)).join("And");
247
+ if (method === "GET") {
248
+ return FromModelController.createRegistration(`readBy${suffix}`, FromModelController.createReadHandler(getPK, modelClazzName), FromModelController.readDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), [{ decorator: DecafParams(fallbackApiProps), index: 0 }]);
249
+ }
250
+ if (method === "PUT") {
251
+ return FromModelController.createRegistration(`updateBy${suffix}`, FromModelController.createUpdateHandler(getPK, ModelConstr, modelClazzName), FromModelController.updateDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), [
252
+ { decorator: DecafParams(fallbackApiProps), index: 0 },
253
+ { decorator: DecafBody(), index: 1 },
254
+ { decorator: Response({ passthrough: true }), index: 2 },
255
+ ]);
256
+ }
257
+ if (method === "DELETE") {
258
+ return FromModelController.createRegistration(`deleteBy${suffix}`, FromModelController.createDeleteHandler(getPK, modelClazzName), FromModelController.deleteDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), [
259
+ { decorator: DecafParams(fallbackApiProps), index: 0 },
260
+ { decorator: Response({ passthrough: true }), index: 1 },
261
+ ]);
262
+ }
263
+ }
264
+ if (method === "GET" && normalizedPath === "statement/:method/*args") {
265
+ return FromModelController.createRegistration("statement", FromModelController.createStatementHandler(modelClazzName), FromModelController.statementDecorators(ModelConstr, modelClazzName), [
266
+ { decorator: Param("method"), index: 0 },
267
+ { decorator: Param("args"), index: 1 },
268
+ { decorator: DecafQuery(), index: 2 },
269
+ ]);
270
+ }
271
+ const statementRoutes = {
272
+ "listBy/:key": PreparedStatementKeys.LIST_BY,
273
+ "paginateBy/:key/:page": PreparedStatementKeys.PAGE_BY,
274
+ "find/:value": PreparedStatementKeys.FIND,
275
+ "page/:value": PreparedStatementKeys.PAGE,
276
+ "findOneBy/:key/:value": PreparedStatementKeys.FIND_ONE_BY,
277
+ "findBy/:key/:value": PreparedStatementKeys.FIND_BY,
278
+ "countOf/:field": PreparedStatementKeys.COUNT_OF,
279
+ "maxOf/:field": PreparedStatementKeys.MAX_OF,
280
+ "minOf/:field": PreparedStatementKeys.MIN_OF,
281
+ "avgOf/:field": PreparedStatementKeys.AVG_OF,
282
+ "sumOf/:field": PreparedStatementKeys.SUM_OF,
283
+ "distinctOf/:field": PreparedStatementKeys.DISTINCT_OF,
284
+ "groupOf/:field": PreparedStatementKeys.GROUP_OF,
285
+ };
286
+ const statementKey = statementRoutes[normalizedPath];
287
+ if (statementKey && method === "GET") {
288
+ return FromModelController.createRegistration(FromModelController.statementMethodName(normalizedPath), FromModelController.createStatementShortcutHandler(statementKey, modelClazzName), FromModelController.statementShortcutDecorators(ModelConstr, modelClazzName, normalizedPath, statementKey), FromModelController.statementShortcutParams(normalizedPath));
289
+ }
290
+ if (method === "GET" && normalizedPath.startsWith("query/")) {
291
+ const queryMethod = normalizedPath.replace(/^query\//, "").split("/")[0];
292
+ return FromModelController.createRegistration(queryMethod, FromModelController.createComplexQueryHandler(queryMethod), FromModelController.getQueryDecorators(queryMethod, normalizedPath, "GET", true), FromModelController.complexQueryParams(normalizedPath));
293
+ }
294
+ // Fallback for custom @route() paths (e.g. "metadata/for-product/:productCode")
295
+ const pathSegments = normalizedPath.split("/").filter(Boolean);
296
+ const knownPrefixes = new Set([
297
+ "listBy", "findBy", "findByPaginate", "findOneBy", "paginateBy",
298
+ "find", "page", "countOf", "maxOf", "minOf", "avgOf", "sumOf",
299
+ "distinctOf", "groupOf", "statement", "bulk", "query",
300
+ ]);
301
+ if (pathSegments.length > 0 &&
302
+ !normalizedPath.startsWith("query/") &&
303
+ !knownPrefixes.has(pathSegments[0])) {
304
+ // Look up the actual method name from @route metadata by matching the path.
305
+ // The @route decorator stores { path, httpMethod, handler } keyed by method name
306
+ // on the repository constructor.
307
+ const routeMetadata = Metadata.get(persistence?.constructor, Metadata.key(DECAF_ROUTE)) ?? {};
308
+ const matchedEntry = Object.entries(routeMetadata).find(([, info]) => info &&
309
+ typeof info === "object" &&
310
+ info.path?.replace(/^\/+|\/+$/g, "") === normalizedPath);
311
+ const actualMethodName = matchedEntry?.[0] || pathSegments[0];
312
+ const paramSegments = pathSegments.filter((s) => s.startsWith(":"));
313
+ const apiPathParams = paramSegments.map((s) => s.slice(1)).map((name) => ({
314
+ name,
315
+ description: `${name} parameter for the query`,
316
+ required: true,
317
+ type: String,
318
+ }));
319
+ return FromModelController.createRegistration(actualMethodName, FromModelController.createCustomRouteHandler(actualMethodName), [
320
+ ...apiPathParams.map((p) => ApiParam(p)),
321
+ ApiOperation({ summary: `Retrieve records using "${actualMethodName}".` }),
322
+ ApiOkResponse({ description: "Result successfully retrieved." }),
323
+ ApiNoContentResponse({ description: "No content returned by the method." }),
324
+ ], FromModelController.complexQueryParams(normalizedPath));
325
+ }
326
+ return undefined;
327
+ }
328
+ static createRegistration(methodName, handler, decorators, paramDecorators) {
329
+ return { methodName, handler, decorators, paramDecorators };
330
+ }
331
+ static statementMethodName(path) {
332
+ const firstSegment = path.split("/")[0];
333
+ return firstSegment;
334
+ }
335
+ static statementShortcutParams(path) {
336
+ const segments = path.split("/").filter((s) => s.startsWith(":"));
337
+ const params = [];
338
+ segments.forEach((seg, i) => {
339
+ const name = seg.replace(":", "");
340
+ params.push({ decorator: Param(name), index: i });
341
+ });
342
+ if (path.startsWith("listBy/") ||
343
+ path.startsWith("paginateBy/") ||
344
+ path.startsWith("find/") ||
345
+ path.startsWith("page/")) {
346
+ params.push({ decorator: DecafQuery(), index: segments.length });
347
+ }
348
+ return params;
349
+ }
350
+ static complexQueryParams(path) {
351
+ const segments = path.split("/").filter((s) => s.startsWith(":"));
352
+ const params = [];
353
+ segments.forEach((seg, i) => {
354
+ const name = seg.replace(":", "");
355
+ params.push({ decorator: Param(name), index: i });
356
+ });
357
+ if (path.startsWith("query/")) {
358
+ params.push({ decorator: DecafQuery(), index: segments.length });
359
+ }
360
+ return params;
361
+ }
362
+ static createCreateHandler(ModelConstr, modelClazzName) {
363
+ return async function create(data, resp) {
364
+ const { ctx, log } = (await this.logCtx([], OperationKeys.CREATE, true)).for(create);
365
+ log.verbose(`creating new ${modelClazzName}`);
366
+ let created;
367
+ try {
368
+ created = await this.persistence(ctx).create(data, ctx);
369
+ }
370
+ catch (e) {
371
+ log.error(`Failed to create new ${modelClazzName}`, e);
372
+ throw e;
373
+ }
374
+ log.info(`created new ${modelClazzName} with id ${created[this.pk]}`);
375
+ if (resp)
426
376
  ctx.toResponse(resp);
427
- return created;
377
+ return created;
378
+ };
379
+ }
380
+ static createBulkCreateHandler(ModelConstr, modelClazzName) {
381
+ return async function createAll(data, resp) {
382
+ const { ctx, log } = (await this.logCtx([], BulkCrudOperationKeys.CREATE_ALL, true)).for(createAll);
383
+ log.verbose(`creating new ${modelClazzName}`);
384
+ let created;
385
+ try {
386
+ created = await this.persistence(ctx).createAll(data.map((d) => new ModelConstr(d)), ctx);
428
387
  }
429
- async create(data, resp) {
430
- const { ctx, log } = (await this.logCtx([], OperationKeys.CREATE, true)).for(this.create);
431
- log.verbose(`creating new ${modelClazzName}`);
432
- let created;
433
- try {
434
- const persistence = this.persistence(ctx);
435
- created = await persistence.create(data, ctx);
436
- }
437
- catch (e) {
438
- log.error(`Failed to create new ${modelClazzName}`, e);
439
- throw e;
440
- }
441
- log.info(`created new ${modelClazzName} with id ${created[this.pk]}`);
388
+ catch (e) {
389
+ log.error(`Failed to create new ${modelClazzName}`, e);
390
+ throw e;
391
+ }
392
+ log.info(`created new ${modelClazzName} with id ${created[this.pk]}`);
393
+ if (resp)
442
394
  ctx.toResponse(resp);
443
- return created;
444
- }
445
- async readAll(ids) {
446
- const { ctx, log } = (await this.logCtx([], BulkCrudOperationKeys.READ_ALL, true)).for(this.readAll);
447
- const normalizedIds = Array.isArray(ids) ? ids : [ids];
448
- let read;
449
- try {
450
- log.debug(`reading ${normalizedIds} ${modelClazzName}: ${normalizedIds}`);
451
- const persistence = this.persistence(ctx);
452
- read = await persistence.readAll(normalizedIds, ctx);
395
+ return created;
396
+ };
397
+ }
398
+ static createBulkReadHandler(modelClazzName) {
399
+ return async function readAll(ids) {
400
+ const { ctx, log } = (await this.logCtx([], BulkCrudOperationKeys.READ_ALL, true)).for(readAll);
401
+ const normalizedIds = Array.isArray(ids) ? ids : [ids];
402
+ let read;
403
+ try {
404
+ log.debug(`reading ${normalizedIds} ${modelClazzName}`);
405
+ read = await this.persistence(ctx).readAll(normalizedIds, ctx);
406
+ }
407
+ catch (e) {
408
+ log.error(`Failed to read ${modelClazzName}`, e);
409
+ throw e;
410
+ }
411
+ log.info(`read ${read.length} ${modelClazzName}`);
412
+ return read;
413
+ };
414
+ }
415
+ static createBulkUpdateHandler(modelClazzName) {
416
+ return async function updateAll(body, resp) {
417
+ const { ctx, log } = (await this.logCtx([], BulkCrudOperationKeys.UPDATE_ALL, true)).for(updateAll);
418
+ let updated;
419
+ try {
420
+ log.info(`updating ${body.length} ${modelClazzName}`);
421
+ updated = await this.persistence(ctx).updateAll(body, ctx);
422
+ }
423
+ catch (e) {
424
+ log.error(e);
425
+ throw e;
426
+ }
427
+ if (resp)
428
+ ctx.toResponse(resp);
429
+ return updated;
430
+ };
431
+ }
432
+ static createBulkDeleteHandler(modelClazzName) {
433
+ return async function deleteAll(ids, resp) {
434
+ const { ctx, log } = (await this.logCtx([], BulkCrudOperationKeys.DELETE_ALL, true)).for(deleteAll);
435
+ const normalizedIds = Array.isArray(ids) ? ids : [ids];
436
+ let read;
437
+ try {
438
+ log.debug(`deleting ${normalizedIds.length} ${modelClazzName}`);
439
+ read = await this.persistence(ctx).deleteAll(normalizedIds, ctx);
440
+ }
441
+ catch (e) {
442
+ log.error(`Failed to delete ${modelClazzName}`, e);
443
+ throw e;
444
+ }
445
+ log.info(`deleted ${read.length} ${modelClazzName}`);
446
+ if (resp)
447
+ ctx.toResponse(resp);
448
+ return read;
449
+ };
450
+ }
451
+ static createReadHandler(getPK, modelClazzName) {
452
+ return async function read(routeParams) {
453
+ const { ctx, log } = (await this.logCtx([], OperationKeys.READ, true)).for(read);
454
+ const id = getPK(...routeParams.valuesInOrder);
455
+ if (typeof id === "undefined")
456
+ throw new ValidationError(`No ${this.pk} provided`);
457
+ let readResult;
458
+ try {
459
+ log.debug(`reading ${modelClazzName} with ${this.pk} ${id}`);
460
+ readResult = await this.persistence(ctx).read(id, ctx);
461
+ }
462
+ catch (e) {
463
+ log.error(`Failed to read ${modelClazzName} with id ${id}`, e);
464
+ throw e;
465
+ }
466
+ log.info(`read ${modelClazzName} with id ${readResult[this.pk]}`);
467
+ return readResult;
468
+ };
469
+ }
470
+ static createUpdateHandler(getPK, ModelConstr, modelClazzName) {
471
+ return async function update(routeParams, body, resp) {
472
+ const { ctx, log } = (await this.logCtx([], OperationKeys.UPDATE, true)).for(update);
473
+ const id = getPK(...routeParams.valuesInOrder);
474
+ if (typeof id === "undefined")
475
+ throw new ValidationError(`No ${this.pk} provided`);
476
+ let updated;
477
+ try {
478
+ log.info(`updating ${modelClazzName} with ${this.pk} ${id}`);
479
+ const payload = JSON.parse(JSON.stringify(body));
480
+ updated = await this.persistence(ctx).update(new ModelConstr({ ...payload, [this.pk]: id }), ctx);
481
+ }
482
+ catch (e) {
483
+ log.error(e);
484
+ throw e;
485
+ }
486
+ if (resp)
487
+ ctx.toResponse(resp);
488
+ return updated;
489
+ };
490
+ }
491
+ static createDeleteHandler(getPK, modelClazzName) {
492
+ return async function remove(routeParams, resp) {
493
+ const { ctx, log } = (await this.logCtx([], OperationKeys.DELETE, true)).for(remove);
494
+ const id = getPK(...routeParams.valuesInOrder);
495
+ if (typeof id === "undefined")
496
+ throw new ValidationError(`No ${this.pk} provided`);
497
+ let del;
498
+ try {
499
+ log.debug(`deleting ${modelClazzName} with ${this.pk} ${id}`);
500
+ del = await this.persistence(ctx).delete(id, ctx);
501
+ }
502
+ catch (e) {
503
+ log.error(`Failed to delete ${modelClazzName} with id ${id}`, e);
504
+ throw e;
505
+ }
506
+ log.info(`deleted ${modelClazzName} with id ${id}`);
507
+ if (resp)
508
+ ctx.toResponse(resp);
509
+ return del;
510
+ };
511
+ }
512
+ static createStatementHandler(modelClazzName) {
513
+ return async function statement(name, args, details) {
514
+ const { ctx } = (await this.logCtx([], PersistenceKeys.STATEMENT, true)).for(statement);
515
+ const { direction, offset, limit, bookmark } = details;
516
+ args = args.map((a) => (typeof a === "string" ? parseInt(a) : a) || a);
517
+ const pathDirection = args.length > 1 ? args[1] : undefined;
518
+ const resolvedDirection = (direction ?? pathDirection);
519
+ if (resolvedDirection && args.length > 1)
520
+ args[1] = resolvedDirection;
521
+ switch (name) {
522
+ case PreparedStatementKeys.FIND:
523
+ case PreparedStatementKeys.FIND_BY:
524
+ break;
525
+ case PreparedStatementKeys.LIST_BY:
526
+ args.push(direction);
527
+ break;
528
+ case PreparedStatementKeys.PAGE:
529
+ case PreparedStatementKeys.PAGE_BY:
530
+ args = [
531
+ args[0],
532
+ resolvedDirection,
533
+ { limit, offset, bookmark },
534
+ ];
535
+ break;
536
+ case PreparedStatementKeys.FIND_ONE_BY:
537
+ break;
538
+ case PreparedStatementKeys.COUNT_OF:
539
+ case PreparedStatementKeys.MAX_OF:
540
+ case PreparedStatementKeys.MIN_OF:
541
+ case PreparedStatementKeys.AVG_OF:
542
+ case PreparedStatementKeys.SUM_OF:
543
+ case PreparedStatementKeys.DISTINCT_OF:
544
+ case PreparedStatementKeys.GROUP_OF:
545
+ break;
546
+ }
547
+ return this.persistence(ctx).statement(name, ...args, ctx);
548
+ };
549
+ }
550
+ static createStatementShortcutHandler(statementKey, modelClazzName) {
551
+ return async function statementShortcut(...args) {
552
+ const { ctx } = (await this.logCtx([], statementKey, true)).for(statementShortcut);
553
+ switch (statementKey) {
554
+ case PreparedStatementKeys.LIST_BY: {
555
+ const [key, details] = args;
556
+ return this.persistence(ctx).listBy(key, details?.direction, ctx);
453
557
  }
454
- catch (e) {
455
- log.error(`Failed to ${modelClazzName} with id ${normalizedIds}`, e);
456
- throw e;
558
+ case PreparedStatementKeys.PAGE_BY: {
559
+ const [key, page, details] = args;
560
+ return this.persistence(ctx).paginateBy(key, details?.direction, {
561
+ limit: details?.limit,
562
+ offset: details?.offset,
563
+ page,
564
+ }, ctx);
457
565
  }
458
- log.info(`read ${read.length} ${modelClazzName}`);
459
- return read;
460
- }
461
- async read(routeParams) {
462
- const { ctx, log } = (await this.logCtx([], OperationKeys.READ, true)).for(this.read);
463
- const id = getPK(...routeParams.valuesInOrder);
464
- if (typeof id === "undefined")
465
- throw new ValidationError(`No ${this.pk} provided`);
466
- let read;
467
- try {
468
- log.debug(`reading ${modelClazzName} with ${this.pk} ${id}`);
566
+ case PreparedStatementKeys.FIND: {
567
+ const [value, details] = args;
568
+ const direction = details?.direction ?? OrderDirection.ASC;
469
569
  const persistence = this.persistence(ctx);
470
- read = await persistence.read(id, ctx);
471
- }
472
- catch (e) {
473
- log.error(`Failed to read ${modelClazzName} with id ${id}`, e);
474
- throw e;
475
- }
476
- log.info(`read ${modelClazzName} with id ${read[this.pk]}`);
477
- return read;
478
- }
479
- async updateAll(body, resp) {
480
- const { ctx, log } = (await this.logCtx([], BulkCrudOperationKeys.UPDATE_ALL, true)).for(this.updateAll);
481
- let updated;
482
- try {
483
- log.info(`updating ${body.length} ${modelClazzName}`);
484
- updated = await this.persistence(ctx).updateAll(body, ctx);
485
- }
486
- catch (e) {
487
- log.error(e);
488
- throw e;
570
+ if (typeof persistence.find === "function")
571
+ return persistence.find(value, direction, ctx);
572
+ return persistence.statement(PreparedStatementKeys.FIND, value, direction, ctx);
489
573
  }
490
- ctx.toResponse(resp);
491
- return updated;
492
- }
493
- async update(routeParams, body, resp) {
494
- const { ctx, log } = (await this.logCtx([], OperationKeys.UPDATE, true)).for(this.update);
495
- const id = getPK(...routeParams.valuesInOrder);
496
- if (typeof id === "undefined")
497
- throw new ValidationError(`No ${this.pk} provided`);
498
- let updated;
499
- try {
500
- log.info(`updating ${modelClazzName} with ${this.pk} ${id}`);
501
- const payload = JSON.parse(JSON.stringify(body));
574
+ case PreparedStatementKeys.PAGE: {
575
+ const [value, details] = args;
576
+ const ref = {
577
+ offset: details?.offset ?? 1,
578
+ limit: details?.limit ?? 10,
579
+ bookmark: details?.bookmark,
580
+ };
502
581
  const persistence = this.persistence(ctx);
503
- updated = await persistence.update(new ModelConstr({
504
- ...payload,
505
- [this.pk]: id,
506
- }), ctx);
507
- }
508
- catch (e) {
509
- log.error(e);
510
- throw e;
582
+ const direction = details?.direction ?? OrderDirection.ASC;
583
+ if (typeof persistence.page === "function")
584
+ return persistence.page(value, direction, ref, ctx);
585
+ return persistence.statement(PreparedStatementKeys.PAGE, value, direction, ref, ctx);
511
586
  }
512
- ctx.toResponse(resp);
513
- return updated;
514
- }
515
- async deleteAll(ids, resp) {
516
- const { ctx, log } = (await this.logCtx([], BulkCrudOperationKeys.DELETE_ALL, true)).for(this.deleteAll);
517
- const normalizedIds = Array.isArray(ids) ? ids : [ids];
518
- let read;
519
- try {
520
- log.debug(`deleting ${normalizedIds.length} ${modelClazzName}: ${normalizedIds}`);
521
- read = await this.persistence(ctx).deleteAll(normalizedIds, ctx);
587
+ case PreparedStatementKeys.FIND_ONE_BY: {
588
+ const [key, value] = args;
589
+ return this.persistence(ctx).findOneBy(key, value, ctx);
522
590
  }
523
- catch (e) {
524
- log.error(`Failed to delete ${modelClazzName} with id ${normalizedIds}`, e);
525
- throw e;
591
+ case PreparedStatementKeys.FIND_BY: {
592
+ const [key, value] = args;
593
+ return this.persistence(ctx)
594
+ .for(ctx.toOverrides())
595
+ .findBy(key, value, ctx);
526
596
  }
527
- log.info(`deleted ${read.length} ${modelClazzName}`);
528
- ctx.toResponse(resp);
529
- return read;
530
- }
531
- async delete(routeParams, resp) {
532
- const { ctx, log } = (await this.logCtx([], OperationKeys.DELETE, true)).for(this.delete);
533
- const id = getPK(...routeParams.valuesInOrder);
534
- if (typeof id === "undefined")
535
- throw new ValidationError(`No ${this.pk} provided`);
536
- let del;
537
- try {
538
- log.debug(`deleting ${modelClazzName} with ${this.pk} ${id}`);
539
- del = await this.persistence(ctx).delete(id, ctx);
597
+ default:
598
+ if (statementKey === PreparedStatementKeys.COUNT_OF ||
599
+ statementKey === PreparedStatementKeys.MAX_OF ||
600
+ statementKey === PreparedStatementKeys.MIN_OF ||
601
+ statementKey === PreparedStatementKeys.AVG_OF ||
602
+ statementKey === PreparedStatementKeys.SUM_OF ||
603
+ statementKey === PreparedStatementKeys.DISTINCT_OF ||
604
+ statementKey === PreparedStatementKeys.GROUP_OF) {
605
+ const [field] = args;
606
+ return this.persistence(ctx).statement(statementKey, field, ctx);
607
+ }
608
+ throw new Error(`Unknown statement: ${statementKey}`);
609
+ }
610
+ };
611
+ }
612
+ static createComplexQueryHandler(methodName) {
613
+ return async function complexQuery(...args) {
614
+ const log = this.log?.for?.(complexQuery);
615
+ try {
616
+ if (log)
617
+ log.debug(`Invoking custom query "${methodName}"`);
618
+ const { ctx } = (await this.logCtx([], methodName, true)).for(complexQuery);
619
+ const persistence = this.persistence(ctx);
620
+ const spreadArgs = FromModelController.extractQueryArgs(args);
621
+ if (typeof persistence[methodName] === "function") {
622
+ return persistence[methodName](...spreadArgs, ctx);
540
623
  }
541
- catch (e) {
542
- log.error(`Failed to delete ${modelClazzName} with id ${id}`, e);
543
- throw e;
624
+ if (typeof persistence.statement === "function") {
625
+ return persistence.statement(methodName, ...spreadArgs, ctx);
544
626
  }
545
- log.info(`deleted ${modelClazzName} with id ${id}`);
546
- ctx.toResponse(resp);
547
- return del;
627
+ throw new Error(`Persistence method "${methodName}" not found on ${persistence?.constructor?.name}`);
628
+ }
629
+ catch (e) {
630
+ if (log)
631
+ log.error(`Custom query "${methodName}" failed`, e);
632
+ throw e;
548
633
  }
549
634
  };
550
- __decorate([
551
- ApiOperationFromModel(ModelConstr, "GET", "listBy/:key"),
552
- ApiOperation({ summary: `Retrieve ${modelClazzName} records by query.` }),
553
- ApiParam({ name: "key", description: "the model key to sort by" }),
554
- ApiQuery({ name: "direction", required: true, enum: OrderDirection }),
555
- ApiOkResponse({
556
- description: `${modelClazzName} listed successfully.`,
557
- }),
558
- __param(0, Param("key")),
559
- __param(1, DecafQuery()),
560
- __metadata("design:type", Function),
561
- __metadata("design:paramtypes", [String, Object]),
562
- __metadata("design:returntype", Promise)
563
- ], DynamicModelController.prototype, "listBy", null);
564
- __decorate([
565
- ApiOperationFromModel(ModelConstr, "GET", "paginateBy/:key/:page"),
566
- ApiOperation({ summary: `Retrieve ${modelClazzName} records by query.` }),
567
- ApiParam({ name: "key", description: "the model key to sort by" }),
568
- ApiParam({
569
- name: "page",
570
- description: "the page to retrieve or the bookmark",
571
- }),
572
- ApiQuery({
573
- name: "direction",
574
- required: true,
575
- enum: OrderDirection,
576
- description: "the sort order",
577
- }),
578
- ApiQuery({ name: "limit", required: true, description: "the page size" }),
579
- ApiQuery({ name: "offset", description: "the bookmark when necessary" }),
580
- ApiOkResponse({
581
- description: `${modelClazzName} listed paginated.`,
582
- }),
583
- __param(0, Param("key")),
584
- __param(1, DecafQuery()),
585
- __metadata("design:type", Function),
586
- __metadata("design:paramtypes", [String, Object]),
587
- __metadata("design:returntype", Promise)
588
- ], DynamicModelController.prototype, "paginateBy", null);
589
- __decorate([
590
- ApiOperationFromModel(ModelConstr, "GET", "find/:value"),
591
- ApiOperation({
592
- summary: `Find ${modelClazzName} records using the default query attributes.`,
593
- }),
594
- ApiParam({
595
- name: "value",
596
- description: "The string to match against the default query attributes",
597
- }),
598
- ApiQuery({
599
- name: "direction",
600
- required: false,
601
- enum: OrderDirection,
602
- description: "the sort order for the matching results",
603
- }),
604
- ApiOkResponse({
605
- description: `${modelClazzName} records matching the provided prefix.`,
606
- }),
607
- __param(0, Param("value")),
608
- __param(1, DecafQuery()),
609
- __metadata("design:type", Function),
610
- __metadata("design:paramtypes", [String, Object]),
611
- __metadata("design:returntype", Promise)
612
- ], DynamicModelController.prototype, "find", null);
613
- __decorate([
614
- ApiOperationFromModel(ModelConstr, "GET", "page/:value"),
615
- ApiOperation({
616
- summary: `Page ${modelClazzName} records using the default query attributes.`,
617
- }),
618
- ApiParam({
619
- name: "value",
620
- description: "The string to match against the default query attributes",
621
- }),
622
- ApiQuery({
623
- name: "direction",
624
- required: false,
625
- enum: OrderDirection,
626
- description: "the sort order for the paged results",
627
- }),
628
- ApiQuery({
629
- name: "limit",
630
- required: false,
631
- description: "page size",
632
- }),
633
- ApiQuery({
634
- name: "offset",
635
- required: false,
636
- description: "page number",
637
- }),
638
- ApiQuery({
639
- name: "bookmark",
640
- required: false,
641
- description: "bookmark for cursor pagination",
642
- }),
643
- ApiOkResponse({
644
- description: `${modelClazzName} records paged by the provided prefix.`,
645
- }),
646
- __param(0, Param("value")),
647
- __param(1, DecafQuery()),
648
- __metadata("design:type", Function),
649
- __metadata("design:paramtypes", [String, Object]),
650
- __metadata("design:returntype", Promise)
651
- ], DynamicModelController.prototype, "page", null);
652
- __decorate([
653
- ApiOperationFromModel(ModelConstr, "GET", "findOneBy/:key"),
654
- ApiOperation({ summary: `Retrieve ${modelClazzName} records by query.` }),
655
- ApiParam({ name: "key", description: "the model key to sort by" }),
656
- ApiOkResponse({
657
- description: `${modelClazzName} listed found.`,
658
- }),
659
- ApiNotFoundResponse({
660
- description: `No ${modelClazzName} record matches the provided identifier.`,
661
- }),
662
- __param(0, Param("key")),
663
- __param(1, Param("value")),
664
- __metadata("design:type", Function),
665
- __metadata("design:paramtypes", [String, Object]),
666
- __metadata("design:returntype", Promise)
667
- ], DynamicModelController.prototype, "findOneBy", null);
668
- __decorate([
669
- ApiOperationFromModel(ModelConstr, "GET", "findBy/:key/:value"),
670
- ApiOperation({ summary: `Retrieve ${modelClazzName} records by query.` }),
671
- ApiParam({ name: "key", description: "the model key to compare" }),
672
- ApiParam({ name: "value", description: "the value to match" }),
673
- ApiQuery({
674
- name: "direction",
675
- required: true,
676
- enum: OrderDirection,
677
- description: "the sort order when applicable",
678
- }),
679
- ApiOkResponse({
680
- description: `${modelClazzName} listed found.`,
681
- }),
682
- ApiNotFoundResponse({
683
- description: `No ${modelClazzName} record matches the provided identifier.`,
684
- }),
685
- __param(0, Param("key")),
686
- __param(1, Param("value")),
687
- __param(2, DecafQuery()),
688
- __metadata("design:type", Function),
689
- __metadata("design:paramtypes", [String, Object, Object]),
690
- __metadata("design:returntype", Promise)
691
- ], DynamicModelController.prototype, "findBy", null);
692
- __decorate([
693
- ApiOperationFromModel(ModelConstr, "GET", "statement/:method/*args"),
694
- ApiOperation({
695
- summary: `Executes a prepared statement on ${modelClazzName}.`,
696
- }),
697
- ApiParam({
698
- name: "method",
699
- description: "the prepared statement to execute",
700
- }),
701
- ApiParam({
702
- name: "args",
703
- description: "concatenated list of arguments the prepared statement can accept",
704
- }),
705
- ApiQuery({
706
- name: "direction",
707
- required: true,
708
- enum: OrderDirection,
709
- description: "the sort order when applicable",
710
- }),
711
- ApiQuery({
712
- name: "limit",
713
- required: true,
714
- description: "limit or page size when applicable",
715
- }),
716
- ApiQuery({
717
- name: "offset",
718
- required: true,
719
- description: "offset or bookmark when applicable",
720
- }),
721
- ApiOkResponse({
722
- description: `${modelClazzName} listed found.`,
723
- }),
724
- ApiNotFoundResponse({
725
- description: `No ${modelClazzName} record matches the provided identifier.`,
726
- }),
727
- __param(0, Param("method")),
728
- __param(1, Param("args")),
729
- __param(2, DecafQuery()),
730
- __metadata("design:type", Function),
731
- __metadata("design:paramtypes", [String, Array, Object]),
732
- __metadata("design:returntype", Promise)
733
- ], DynamicModelController.prototype, "statement", null);
734
- __decorate([
735
- ApiOperationFromModel(ModelConstr, "POST", "bulk"),
635
+ }
636
+ static createCustomRouteHandler(methodName) {
637
+ return async function customRoute(...args) {
638
+ const log = this.log?.for?.(customRoute);
639
+ const { ctx } = (await this.logCtx([], methodName, true)).for(customRoute);
640
+ const persistence = this.persistence(ctx);
641
+ const spreadArgs = FromModelController.extractQueryArgs(args);
642
+ // Try the persistence directly (works when it's a custom Repository)
643
+ if (typeof persistence[methodName] === "function") {
644
+ return persistence[methodName](...spreadArgs, ctx);
645
+ }
646
+ // When persistence is a ModelService, the method lives on the underlying repo
647
+ if (persistence?.repo && typeof persistence.repo[methodName] === "function") {
648
+ return persistence.repo[methodName](...spreadArgs, ctx);
649
+ }
650
+ // Fall back to statement gateway
651
+ if (typeof persistence.statement === "function") {
652
+ return persistence.statement(methodName, ...spreadArgs, ctx);
653
+ }
654
+ throw new Error(`Method "${methodName}" not found on ${persistence?.constructor?.name} or its repo`);
655
+ };
656
+ }
657
+ static extractQueryArgs(args) {
658
+ if (args.length === 0)
659
+ return args;
660
+ const last = args[args.length - 1];
661
+ if (last &&
662
+ typeof last === "object" &&
663
+ !Array.isArray(last)) {
664
+ const queryObj = args.pop();
665
+ const hasDirection = queryObj.direction !== undefined;
666
+ const hasLimit = queryObj.limit !== undefined;
667
+ const hasOffset = queryObj.offset !== undefined;
668
+ if (!hasDirection && !hasLimit && !hasOffset)
669
+ return args;
670
+ const extras = [];
671
+ if (hasDirection)
672
+ extras.push(queryObj.direction);
673
+ else if (hasLimit || hasOffset)
674
+ extras.push(undefined);
675
+ if (hasLimit)
676
+ extras.push(queryObj.limit);
677
+ if (hasOffset)
678
+ extras.push(queryObj.offset);
679
+ return [...args, ...extras];
680
+ }
681
+ return args;
682
+ }
683
+ static createCreateDecorators(ModelConstr, modelClazzName) {
684
+ return [
685
+ ApiOperationFromModel(ModelConstr, "POST"),
736
686
  ApiOperation({ summary: `Create a new ${modelClazzName}.` }),
737
687
  ApiBody({
738
688
  description: `Payload for ${modelClazzName}`,
739
- schema: {
740
- type: "array",
741
- items: {
742
- $ref: getSchemaPath(ModelConstr),
743
- // $ref: getSchemaPath(DtoFor(OperationKeys.CREATE, ModelConstr)),
744
- },
745
- },
689
+ type: DtoFor(OperationKeys.CREATE, ModelConstr),
746
690
  }),
747
691
  ApiCreatedResponse({
748
692
  description: `${modelClazzName} created successfully.`,
749
- schema: {
750
- type: "array",
751
- items: {
752
- $ref: getSchemaPath(ModelConstr),
753
- },
754
- },
693
+ schema: { $ref: getSchemaPath(ModelConstr) },
755
694
  }),
756
695
  ApiBadRequestResponse({ description: "Payload validation failed." }),
757
696
  ApiUnprocessableEntityResponse({
758
697
  description: "Repository rejected the provided payload.",
759
698
  }),
760
- __param(0, DecafBody()),
761
- __param(1, Response({ passthrough: true })),
762
- __metadata("design:type", Function),
763
- __metadata("design:paramtypes", [Array, Object]),
764
- __metadata("design:returntype", Promise)
765
- ], DynamicModelController.prototype, "createAll", null);
766
- __decorate([
767
- ApiOperationFromModel(ModelConstr, "POST"),
699
+ ];
700
+ }
701
+ static bulkCreateDecorators(ModelConstr, modelClazzName) {
702
+ return [
703
+ ApiOperationFromModel(ModelConstr, "POST", "bulk"),
768
704
  ApiOperation({ summary: `Create a new ${modelClazzName}.` }),
769
705
  ApiBody({
770
706
  description: `Payload for ${modelClazzName}`,
771
- type: DtoFor(OperationKeys.CREATE, ModelConstr),
707
+ schema: {
708
+ type: "array",
709
+ items: { $ref: getSchemaPath(ModelConstr) },
710
+ },
772
711
  }),
773
712
  ApiCreatedResponse({
774
713
  description: `${modelClazzName} created successfully.`,
775
714
  schema: {
776
- $ref: getSchemaPath(ModelConstr),
715
+ type: "array",
716
+ items: { $ref: getSchemaPath(ModelConstr) },
777
717
  },
778
718
  }),
779
719
  ApiBadRequestResponse({ description: "Payload validation failed." }),
780
720
  ApiUnprocessableEntityResponse({
781
721
  description: "Repository rejected the provided payload.",
782
722
  }),
783
- __param(0, DecafBody()),
784
- __param(1, Response({ passthrough: true })),
785
- __metadata("design:type", Function),
786
- __metadata("design:paramtypes", [Object, Object]),
787
- __metadata("design:returntype", Promise)
788
- ], DynamicModelController.prototype, "create", null);
789
- __decorate([
723
+ ];
724
+ }
725
+ static bulkReadDecorators(ModelConstr, modelClazzName) {
726
+ return [
790
727
  ApiOperationFromModel(ModelConstr, "GET", "bulk"),
791
- ApiOperation({ summary: `Retrieve a ${modelClazzName} record by id.` }),
728
+ ApiOperation({ summary: `Retrieve ${modelClazzName} records by ids.` }),
792
729
  ApiQuery({ name: "ids", required: true, type: "array" }),
793
730
  ApiOkResponse({
794
731
  description: `${modelClazzName} retrieved successfully.`,
795
732
  schema: {
796
733
  type: "array",
797
- items: {
798
- $ref: getSchemaPath(ModelConstr),
799
- },
734
+ items: { $ref: getSchemaPath(ModelConstr) },
800
735
  },
801
736
  }),
802
737
  ApiNotFoundResponse({
803
738
  description: `No ${modelClazzName} record matches the provided identifier.`,
804
739
  }),
805
- __param(0, Query("ids")),
806
- __metadata("design:type", Function),
807
- __metadata("design:paramtypes", [Array]),
808
- __metadata("design:returntype", Promise)
809
- ], DynamicModelController.prototype, "readAll", null);
810
- __decorate([
811
- ApiOperationFromModel(ModelConstr, "GET", path),
812
- ApiParamsFromModel(apiProperties),
813
- ApiOperation({ summary: `Retrieve a ${modelClazzName} record by id.` }),
814
- ApiOkResponse({
815
- description: `${modelClazzName} retrieved successfully.`,
816
- schema: {
817
- $ref: getSchemaPath(ModelConstr),
818
- },
819
- }),
820
- ApiNotFoundResponse({
821
- description: `No ${modelClazzName} record matches the provided identifier.`,
822
- }),
823
- __param(0, DecafParams(apiProperties)),
824
- __metadata("design:type", Function),
825
- __metadata("design:paramtypes", [Object]),
826
- __metadata("design:returntype", Promise)
827
- ], DynamicModelController.prototype, "read", null);
828
- __decorate([
829
- ApiOperationFromModel(ModelConstr, "PUT", `bulk`),
740
+ ];
741
+ }
742
+ static bulkUpdateDecorators(ModelConstr, modelClazzName, apiProperties) {
743
+ return [
744
+ ApiOperationFromModel(ModelConstr, "PUT", "bulk"),
830
745
  ApiParamsFromModel(apiProperties),
831
746
  ApiOperation({
832
- summary: `Replace an existing ${modelClazzName} record with a new payload.`,
747
+ summary: `Replace existing ${modelClazzName} records with new payloads.`,
833
748
  }),
834
749
  ApiBody({
835
- description: `Payload for replace a existing record of ${modelClazzName}`,
750
+ description: `Payload for replacing existing records of ${modelClazzName}`,
836
751
  schema: {
837
752
  type: "array",
838
753
  $ref: getSchemaPath(DtoFor(OperationKeys.UPDATE, ModelConstr)),
@@ -842,123 +757,170 @@ export class FromModelController {
842
757
  description: `${modelClazzName} updated successfully.`,
843
758
  schema: {
844
759
  type: "array",
845
- items: {
846
- $ref: getSchemaPath(ModelConstr),
847
- },
760
+ items: { $ref: getSchemaPath(ModelConstr) },
848
761
  },
849
762
  }),
850
763
  ApiNotFoundResponse({
851
764
  description: `No ${modelClazzName} record matches the provided identifier.`,
852
765
  }),
853
766
  ApiBadRequestResponse({ description: "Payload validation failed." }),
854
- __param(0, DecafBody()),
855
- __param(1, Response({ passthrough: true })),
856
- __metadata("design:type", Function),
857
- __metadata("design:paramtypes", [Array, Object]),
858
- __metadata("design:returntype", Promise)
859
- ], DynamicModelController.prototype, "updateAll", null);
860
- __decorate([
861
- ApiOperationFromModel(ModelConstr, "PUT", path),
767
+ ];
768
+ }
769
+ static bulkDeleteDecorators(ModelConstr, modelClazzName, apiProperties) {
770
+ return [
771
+ ApiOperationFromModel(ModelConstr, "DELETE", "bulk"),
772
+ ApiParamsFromModel(apiProperties),
773
+ ApiOperation({ summary: `Delete ${modelClazzName} records by ids.` }),
774
+ ApiQuery({ name: "ids", required: true, type: "array" }),
775
+ ApiOkResponse({
776
+ description: `${modelClazzName} deleted successfully.`,
777
+ schema: {
778
+ type: "array",
779
+ items: { $ref: getSchemaPath(ModelConstr) },
780
+ },
781
+ }),
782
+ ApiNotFoundResponse({
783
+ description: `No ${modelClazzName} record matches the provided identifier.`,
784
+ }),
785
+ ];
786
+ }
787
+ static readDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
788
+ return [
789
+ ApiOperationFromModel(ModelConstr, "GET", pkPath),
790
+ ApiParamsFromModel(apiProperties),
791
+ ApiOperation({ summary: `Retrieve a ${modelClazzName} record by id.` }),
792
+ ApiOkResponse({
793
+ description: `${modelClazzName} retrieved successfully.`,
794
+ schema: { $ref: getSchemaPath(ModelConstr) },
795
+ }),
796
+ ApiNotFoundResponse({
797
+ description: `No ${modelClazzName} record matches the provided identifier.`,
798
+ }),
799
+ ];
800
+ }
801
+ static updateDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
802
+ return [
803
+ ApiOperationFromModel(ModelConstr, "PUT", pkPath),
862
804
  ApiParamsFromModel(apiProperties),
863
805
  ApiOperation({
864
806
  summary: `Replace an existing ${modelClazzName} record with a new payload.`,
865
807
  }),
866
808
  ApiBody({
867
- description: `Payload for replace a existing record of ${modelClazzName}`,
809
+ description: `Payload for replacing an existing record of ${modelClazzName}`,
868
810
  type: DtoFor(OperationKeys.UPDATE, ModelConstr),
869
811
  }),
870
812
  ApiOkResponse({
871
813
  description: `${modelClazzName} updated successfully.`,
872
- schema: {
873
- $ref: getSchemaPath(ModelConstr),
874
- },
814
+ schema: { $ref: getSchemaPath(ModelConstr) },
875
815
  }),
876
816
  ApiNotFoundResponse({
877
817
  description: `No ${modelClazzName} record matches the provided identifier.`,
878
818
  }),
879
819
  ApiBadRequestResponse({ description: "Payload validation failed." }),
880
- __param(0, DecafParams(apiProperties)),
881
- __param(1, DecafBody()),
882
- __param(2, Response({ passthrough: true })),
883
- __metadata("design:type", Function),
884
- __metadata("design:paramtypes", [Object, Object, Object]),
885
- __metadata("design:returntype", Promise)
886
- ], DynamicModelController.prototype, "update", null);
887
- __decorate([
888
- ApiOperationFromModel(ModelConstr, "DELETE", "bulk"),
820
+ ];
821
+ }
822
+ static deleteDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
823
+ return [
824
+ ApiOperationFromModel(ModelConstr, "DELETE", pkPath),
889
825
  ApiParamsFromModel(apiProperties),
890
- ApiOperation({ summary: `Retrieve a ${modelClazzName} record by id.` }),
891
- ApiQuery({ name: "ids", required: true, type: "array" }),
826
+ ApiOperation({ summary: `Delete a ${modelClazzName} record by id.` }),
892
827
  ApiOkResponse({
893
828
  description: `${modelClazzName} deleted successfully.`,
894
- schema: {
895
- type: "array",
896
- items: {
897
- $ref: getSchemaPath(ModelConstr),
898
- },
899
- },
829
+ schema: { $ref: getSchemaPath(ModelConstr) },
900
830
  }),
901
831
  ApiNotFoundResponse({
902
832
  description: `No ${modelClazzName} record matches the provided identifier.`,
903
833
  }),
904
- __param(0, Query("ids")),
905
- __param(1, Response({ passthrough: true })),
906
- __metadata("design:type", Function),
907
- __metadata("design:paramtypes", [Array, Object]),
908
- __metadata("design:returntype", Promise)
909
- ], DynamicModelController.prototype, "deleteAll", null);
910
- __decorate([
911
- ApiOperationFromModel(ModelConstr, "DELETE", path),
912
- ApiParamsFromModel(apiProperties),
913
- ApiOperation({ summary: `Delete a ${modelClazzName} record by id.` }),
914
- ApiOkResponse({
915
- description: `${modelClazzName} deleted successfully.`,
916
- schema: {
917
- $ref: getSchemaPath(ModelConstr),
918
- },
834
+ ];
835
+ }
836
+ static statementDecorators(ModelConstr, modelClazzName) {
837
+ return [
838
+ ApiOperationFromModel(ModelConstr, "GET", "statement/:method/*args"),
839
+ ApiOperation({
840
+ summary: `Executes a prepared statement on ${modelClazzName}.`,
841
+ }),
842
+ ApiParam({ name: "method", description: "the prepared statement to execute" }),
843
+ ApiParam({
844
+ name: "args",
845
+ description: "concatenated list of arguments the prepared statement can accept",
846
+ }),
847
+ ApiQuery({
848
+ name: "direction",
849
+ required: true,
850
+ enum: OrderDirection,
851
+ description: "the sort order when applicable",
919
852
  }),
853
+ ApiQuery({ name: "limit", required: true, description: "limit or page size when applicable" }),
854
+ ApiQuery({ name: "offset", required: true, description: "offset or bookmark when applicable" }),
855
+ ApiOkResponse({ description: `${modelClazzName} listed found.` }),
920
856
  ApiNotFoundResponse({
921
857
  description: `No ${modelClazzName} record matches the provided identifier.`,
922
858
  }),
923
- __param(0, DecafParams(apiProperties)),
924
- __param(1, Response({ passthrough: true })),
925
- __metadata("design:type", Function),
926
- __metadata("design:paramtypes", [Object, Object]),
927
- __metadata("design:returntype", Promise)
928
- ], DynamicModelController.prototype, "delete", null);
929
- DynamicModelController = __decorate([
930
- Controller(routePath),
931
- ApiTags(modelClazzName),
932
- ApiExtraModels(ModelConstr),
933
- Auth(ModelConstr),
934
- __metadata("design:paramtypes", [DecafRequestContext])
935
- ], DynamicModelController);
936
- return DynamicModelController;
859
+ ];
937
860
  }
938
- static getRouteParametersFromModel(ModelClazz) {
939
- const pk = Model.pk(ModelClazz);
940
- const composed = Metadata.get(ModelClazz, Metadata.key(DBKeys.COMPOSED, pk));
941
- const composedKeys = composed?.args ?? [];
942
- // remove duplicates while preserving order
943
- const uniqueKeys = Array.isArray(composedKeys) && composedKeys.length > 0
944
- ? Array.from(new Set([...composedKeys]))
945
- : Array.from(new Set([pk]));
946
- const description = Metadata.description(ModelClazz);
947
- const path = `:${uniqueKeys.join("/:")}`;
948
- const apiProperties = uniqueKeys.map((key) => {
949
- return {
950
- name: key,
951
- description: Metadata.description(ModelClazz, key),
952
- required: true,
953
- type: String,
954
- };
861
+ static statementShortcutDecorators(ModelConstr, modelClazzName, path, statementKey) {
862
+ const base = [
863
+ ApiOperationFromModel(ModelConstr, "GET", path),
864
+ ApiOperation({ summary: `Retrieve ${modelClazzName} records.` }),
865
+ ApiOkResponse({ description: `${modelClazzName} retrieved successfully.` }),
866
+ ];
867
+ const segments = path.split("/").filter((s) => s.startsWith(":"));
868
+ segments.forEach((seg) => {
869
+ const name = seg.replace(":", "");
870
+ base.push(ApiParam({ name, description: `The ${name} parameter` }));
955
871
  });
956
- return {
957
- path,
958
- description,
959
- apiProperties,
960
- getPK: (...params) => composed?.separator ? params.join(composed.separator) : params.join(""),
961
- };
872
+ if (path.startsWith("listBy/") ||
873
+ path.startsWith("paginateBy/") ||
874
+ path.startsWith("find/") ||
875
+ path.startsWith("page/")) {
876
+ base.push(ApiQuery({
877
+ name: "direction",
878
+ required: true,
879
+ enum: OrderDirection,
880
+ description: "the sort order",
881
+ }));
882
+ }
883
+ if (path.startsWith("paginateBy/") || path.startsWith("page/")) {
884
+ base.push(ApiQuery({ name: "limit", required: false, description: "page size" }), ApiQuery({ name: "offset", required: false, description: "page number" }), ApiQuery({ name: "bookmark", required: false, description: "bookmark for cursor pagination" }));
885
+ }
886
+ if (path.startsWith("findOneBy/") || path.startsWith("findBy/")) {
887
+ base.push(ApiNotFoundResponse({
888
+ description: `No ${modelClazzName} record matches the provided identifier.`,
889
+ }));
890
+ }
891
+ if (statementKey === PreparedStatementKeys.COUNT_OF ||
892
+ statementKey === PreparedStatementKeys.AVG_OF ||
893
+ statementKey === PreparedStatementKeys.SUM_OF) {
894
+ base.push(ApiOkResponse({ description: `Result for ${modelClazzName}.`, type: Number }));
895
+ }
896
+ if (statementKey === PreparedStatementKeys.DISTINCT_OF) {
897
+ base.push(ApiOkResponse({ description: `Distinct values for ${modelClazzName}.`, type: [String] }));
898
+ }
899
+ return base;
900
+ }
901
+ static getQueryDecorators(methodName, routePath, httpVerb, includeQueryParams = false) {
902
+ const extractPathParams = (p) => p.split("/").filter((s) => s.startsWith(":")).map((s) => s.slice(1));
903
+ const apiPathParams = extractPathParams(routePath).map((name) => ({
904
+ name,
905
+ description: `${name} parameter for the query`,
906
+ required: true,
907
+ type: String,
908
+ }));
909
+ const decorators = [
910
+ ...apiPathParams.map((p) => ApiParam(p)),
911
+ ApiOperation({ summary: `Retrieve records using "${methodName}".` }),
912
+ ApiOkResponse({ description: "Result successfully retrieved." }),
913
+ ApiNoContentResponse({ description: "No content returned by the method." }),
914
+ ];
915
+ if (httpVerb === "GET" && includeQueryParams) {
916
+ decorators.push(ApiQuery({
917
+ name: "direction",
918
+ required: false,
919
+ enum: OrderDirection,
920
+ description: "the sort order when applicable",
921
+ }), ApiQuery({ name: "limit", required: false, description: "limit or page size" }), ApiQuery({ name: "offset", required: false, description: "offset or bookmark" }));
922
+ }
923
+ return decorators;
962
924
  }
963
925
  }
964
- //# sourceMappingURL=FromModelController.js.map
926
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRnJvbU1vZGVsQ29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kZWNhZi1tb2RlbC9Gcm9tTW9kZWxDb250cm9sbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2pGLE9BQU8sRUFDTCxxQkFBcUIsRUFDckIsT0FBTyxFQUNQLGtCQUFrQixFQUNsQixjQUFjLEVBQ2Qsb0JBQW9CLEVBQ3BCLG1CQUFtQixFQUNuQixhQUFhLEVBQ2IsWUFBWSxFQUNaLFFBQVEsRUFDUixRQUFRLEVBQ1IsT0FBTyxFQUNQLDhCQUE4QixFQUM5QixhQUFhLEdBQ2QsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QixPQUFPLEVBRUwsWUFBWSxFQUNaLGNBQWMsRUFDZCxlQUFlLEVBQ2YscUJBQXFCLEVBRXJCLFVBQVUsRUFDVixPQUFPLEdBQ1IsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsS0FBSyxFQUFvQixNQUFNLGdDQUFnQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDekQsT0FBTyxFQUNMLHFCQUFxQixFQUNyQixNQUFNLEVBQ04sYUFBYSxFQUNiLGVBQWUsR0FDaEIsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQWUsUUFBUSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDN0QsT0FBTyxFQUNMLHFCQUFxQixFQUNyQixrQkFBa0IsRUFFbEIsU0FBUyxFQUNULFdBQVcsRUFDWCxVQUFVLEdBQ1gsOEJBQXFCO0FBQ3RCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSw4QkFBMkI7QUFFekQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLDhCQUFtQjtBQUNqRCxPQUFPLEVBQUUsdUJBQXVC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RSxRQUFRLENBQUMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLG9CQUFvQixFQUFFLENBQUMsQ0FDakYsQ0FBQztRQUNKLENBQUM7UUFFRCxPQUFPLFVBQVUsQ0FBQztJQUNwQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29udHJvbGxlciwgUGFyYW0sIFF1ZXJ5LCBSZXNwb25zZSwgU2V0TWV0YWRhdGEgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7XG4gIEFwaUJhZFJlcXVlc3RSZXNwb25zZSxcbiAgQXBpQm9keSxcbiAgQXBpQ3JlYXRlZFJlc3BvbnNlLFxuICBBcGlFeHRyYU1vZGVscyxcbiAgQXBpTm9Db250ZW50UmVzcG9uc2UsXG4gIEFwaU5vdEZvdW5kUmVzcG9uc2UsXG4gIEFwaU9rUmVzcG9uc2UsXG4gIEFwaU9wZXJhdGlvbixcbiAgQXBpUGFyYW0sXG4gIEFwaVF1ZXJ5LFxuICBBcGlUYWdzLFxuICBBcGlVbnByb2Nlc3NhYmxlRW50aXR5UmVzcG9uc2UsXG4gIGdldFNjaGVtYVBhdGgsXG59IGZyb20gXCJAbmVzdGpzL3N3YWdnZXJcIjtcbmltcG9ydCB7XG4gIHR5cGUgRGlyZWN0aW9uTGltaXRPZmZzZXQsXG4gIE1vZGVsU2VydmljZSxcbiAgT3JkZXJEaXJlY3Rpb24sXG4gIFBlcnNpc3RlbmNlS2V5cyxcbiAgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLFxuICB0eXBlIFJlcG8sXG4gIFJlcG9zaXRvcnksXG4gIFNlcnZpY2UsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgTW9kZWwsIE1vZGVsQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBMb2dnaW5nLCB0b0tlYmFiQ2FzZSB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHtcbiAgQnVsa0NydWRPcGVyYXRpb25LZXlzLFxuICBEQktleXMsXG4gIE9wZXJhdGlvbktleXMsXG4gIFZhbGlkYXRpb25FcnJvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7XG4gIEFwaU9wZXJhdGlvbkZyb21Nb2RlbCxcbiAgQXBpUGFyYW1zRnJvbU1vZGVsLFxuICB0eXBlIERlY2FmQXBpUHJvcGVydHksXG4gIERlY2FmQm9keSxcbiAgRGVjYWZQYXJhbXMsXG4gIERlY2FmUXVlcnksXG59IGZyb20gXCIuL2RlY29yYXRvcnNcIjtcbmltcG9ydCB7IEh0dHBWZXJiVG9EZWNvcmF0b3IgfSBmcm9tIFwiLi9kZWNvcmF0b3JzL3V0aWxzXCI7XG5pbXBvcnQgdHlwZSB7IEh0dHBWZXJicyB9IGZyb20gXCIuL2RlY29yYXRvcnMvdHlwZXNcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdFwiO1xuaW1wb3J0IHsgREVDQUZfQ09OVFJPTExFUl9DT05GSUcsIERFQ0FGX1JPVVRFIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgU0tJUF9NT0RFTF9ST0xFU19LRVkgfSBmcm9tIFwiLi4vYXV0aC9jb25zdGFudHNcIjtcbmltcG9ydCB7IEF1dGgsIFB1YmxpYywgUmVxdWlyZVJvbGVzIH0gZnJvbSBcIi4uL2F1dGgvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29udHJvbGxlckNvbnN0cnVjdG9yIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IERlY2FmTW9kZWxDb250cm9sbGVyIH0gZnJvbSBcIi4uL2NvbnRyb2xsZXJzXCI7XG5pbXBvcnQgeyBEdG9Gb3IgfSBmcm9tIFwiLi4vZmFjdG9yeS9vcGVuYXBpL0R0b0J1aWxkZXJcIjtcbmltcG9ydCBcIi4uL292ZXJyaWRlc1wiO1xuaW1wb3J0IHtcbiAgTW9kZWxDb250cm9sbGVyRmFjdG9yeSxcbiAgdHlwZSBNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnLFxuICB0eXBlIEF1dGhDb25maWcsXG4gIHR5cGUgU2VydmVyUm91dGUsXG59IGZyb20gXCJAZGVjYWYtdHMvZm9yLWh0dHAvc2VydmVyXCI7XG5cbmV4cG9ydCBjbGFzcyBGcm9tTW9kZWxDb250cm9sbGVyIHtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgbG9nID0gTG9nZ2luZy5mb3IoRnJvbU1vZGVsQ29udHJvbGxlci5uYW1lKTtcblxuICBzdGF0aWMgZ2V0UGVyc2lzdGVuY2U8VCBleHRlbmRzIE1vZGVsPGJvb2xlYW4+PihcbiAgICBNb2RlbENsYXp6OiBNb2RlbENvbnN0cnVjdG9yPFQ+XG4gICk6IFJlcG88VD4gfCBNb2RlbFNlcnZpY2U8VD4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gU2VydmljZS5nZXQ8TW9kZWxTZXJ2aWNlPFQ+PihNb2RlbENsYXp6KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gTW9kZWxTZXJ2aWNlLmdldFNlcnZpY2UoTW9kZWxDbGF6eikgYXMgTW9kZWxTZXJ2aWNlPFQ+O1xuICAgICAgfSBjYXRjaCAoZTI6IHVua25vd24pIHtcbiAgICAgICAgcmV0dXJuIFJlcG9zaXRvcnkuZm9yTW9kZWwoTW9kZWxDbGF6eikgYXMgUmVwbzxUPjtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBzdGF0aWMgY3JlYXRlUXVlcnlSb3V0ZXNGcm9tUmVwb3NpdG9yeTxUIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4+KFxuICAgIHBlcnNpc3RlbmNlOiBSZXBvPFQ+IHwgTW9kZWxTZXJ2aWNlPFQ+LFxuICAgIHByZWZpeDogc3RyaW5nID0gUGVyc2lzdGVuY2VLZXlzLlFVRVJZXG4gICk6IENvbnRyb2xsZXJDb25zdHJ1Y3RvcjxUPiB7XG4gICAgY29uc3QgcmVwbzogUmVwbzxUPiA9XG4gICAgICBwZXJzaXN0ZW5jZSBpbnN0YW5jZW9mIE1vZGVsU2VydmljZSA/IHBlcnNpc3RlbmNlLnJlcG8gOiBwZXJzaXN0ZW5jZTtcbiAgICBjb25zdCBNb2RlbENvbnN0cjogQ29uc3RydWN0b3IgPSByZXBvLmNsYXNzO1xuICAgIGNvbnN0IHF1ZXJ5TWV0aG9kczogUmVjb3JkPHN0cmluZywgeyBmaWVsZHM/OiBzdHJpbmdbXSB8IHVuZGVmaW5lZCB9PiA9XG4gICAgICBNZXRhZGF0YS5nZXQoXG4gICAgICAgIHJlcG8uY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IsXG4gICAgICAgIE1ldGFkYXRhLmtleShQZXJzaXN0ZW5jZUtleXMuUVVFUlkpXG4gICAgICApID8/IHt9O1xuXG4gICAgY29uc3Qgcm91dGVNZXRob2RzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID1cbiAgICAgIE1ldGFkYXRhLmdldChcbiAgICAgICAgcGVyc2lzdGVuY2UuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IsXG4gICAgICAgIE1ldGFkYXRhLmtleShERUNBRl9ST1VURSlcbiAgICAgICkgPz8ge307XG5cbiAgICBjbGFzcyBRdWVyeUNvbnRyb2xsZXIgZXh0ZW5kcyBEZWNhZk1vZGVsQ29udHJvbGxlcjxUPiB7XG4gICAgICBvdmVycmlkZSBnZXQgY2xhc3MoKTogTW9kZWxDb25zdHJ1Y3RvcjxUPiB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk1ldGhvZCBub3QgaW1wbGVtZW50ZWQuXCIpO1xuICAgICAgfVxuICAgICAgY29uc3RydWN0b3IoY2xpZW50Q29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCwgbmFtZTogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKGNsaWVudENvbnRleHQsIG5hbWUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAoY29uc3QgW21ldGhvZE5hbWUsIHBhcmFtc10gb2YgT2JqZWN0LmVudHJpZXMocm91dGVNZXRob2RzKSkge1xuICAgICAgY29uc3Qgcm91dGVQYXRoID0gW3BhcmFtcy5wYXRoLnJlcGxhY2UoL15cXC8rfFxcLyskL2csIFwiXCIpXVxuICAgICAgICAuZmlsdGVyKChzZWdtZW50OiBzdHJpbmcpID0+IHNlZ21lbnQgJiYgc2VnbWVudC50cmltKCkpXG4gICAgICAgIC5qb2luKFwiL1wiKTtcblxuICAgICAgY29uc3QgaGFuZGxlciA9IEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlQ29tcGxleFF1ZXJ5SGFuZGxlcihcbiAgICAgICAgbWV0aG9kTmFtZVxuICAgICAgKSBhcyBhbnk7XG4gICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmRlZmluZU1ldGhvZChcbiAgICAgICAgUXVlcnlDb250cm9sbGVyLFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICBoYW5kbGVyXG4gICAgICApO1xuXG4gICAgICBjb25zdCBodHRwRGVjb3JhdG9yID0gSHR0cFZlcmJUb0RlY29yYXRvcihwYXJhbXMuaHR0cE1ldGhvZCBhcyBIdHRwVmVyYnMpKHJvdXRlUGF0aCB8fCB1bmRlZmluZWQpO1xuICAgICAgY29uc3QgZGVjb3JhdG9ycyA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UXVlcnlEZWNvcmF0b3JzKFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICByb3V0ZVBhdGgsXG4gICAgICAgIHBhcmFtcy5odHRwTWV0aG9kXG4gICAgICApO1xuICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5hcHBseURlY29yYXRvcnMoXG4gICAgICAgIFF1ZXJ5Q29udHJvbGxlcixcbiAgICAgICAgbWV0aG9kTmFtZSxcbiAgICAgICAgW2h0dHBEZWNvcmF0b3IsIC4uLmRlY29yYXRvcnNdXG4gICAgICApO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgW21ldGhvZE5hbWUsIG9ialZhbHVlc10gb2YgT2JqZWN0LmVudHJpZXMocXVlcnlNZXRob2RzKSkge1xuICAgICAgY29uc3QgZmllbGRzID0gb2JqVmFsdWVzLmZpZWxkcyA/PyBbXTtcbiAgICAgIGNvbnN0IHJvdXRlUGF0aCA9IFtwcmVmaXgsIG1ldGhvZE5hbWUsIC4uLmZpZWxkcy5tYXAoKGYpID0+IGA6JHtmfWApXVxuICAgICAgICAuZmlsdGVyKChzZWdtZW50KSA9PiBzZWdtZW50ICYmIHNlZ21lbnQudHJpbSgpKVxuICAgICAgICAuam9pbihcIi9cIik7XG5cbiAgICAgIGNvbnN0IGhhbmRsZXIgPSBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUNvbXBsZXhRdWVyeUhhbmRsZXIoXG4gICAgICAgIG1ldGhvZE5hbWVcbiAgICAgICkgYXMgYW55O1xuICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5kZWZpbmVNZXRob2QoXG4gICAgICAgIFF1ZXJ5Q29udHJvbGxlcixcbiAgICAgICAgbWV0aG9kTmFtZSxcbiAgICAgICAgaGFuZGxlclxuICAgICAgKTtcblxuICAgICAgY29uc3QgaHR0cERlY29yYXRvciA9IEh0dHBWZXJiVG9EZWNvcmF0b3IoXCJHRVRcIiBhcyBIdHRwVmVyYnMpKHJvdXRlUGF0aCB8fCB1bmRlZmluZWQpO1xuICAgICAgY29uc3QgZGVjb3JhdG9ycyA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UXVlcnlEZWNvcmF0b3JzKFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICByb3V0ZVBhdGgsXG4gICAgICAgIFwiR0VUXCIsXG4gICAgICAgIHRydWVcbiAgICAgICk7XG4gICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmFwcGx5RGVjb3JhdG9ycyhcbiAgICAgICAgUXVlcnlDb250cm9sbGVyLFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICBbaHR0cERlY29yYXRvciwgLi4uZGVjb3JhdG9yc11cbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIFF1ZXJ5Q29udHJvbGxlcjtcbiAgfVxuXG4gIHN0YXRpYyBjcmVhdGU8VCBleHRlbmRzIE1vZGVsPGFueT4+KFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPFQ+LFxuICAgIG1vZHVsZUNvbmZpZ092ZXJyaWRlcz86IFJlY29yZDxzdHJpbmcsIE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWc+LFxuICAgIGdsb2JhbERlZmF1bHRzPzogUGFydGlhbDxNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnPlxuICApOiBDb250cm9sbGVyQ29uc3RydWN0b3I8VD4ge1xuICAgIGNvbnN0IGxvZyA9IEZyb21Nb2RlbENvbnRyb2xsZXIubG9nLmZvcihGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZSk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKE1vZGVsQ29uc3RyKTtcbiAgICBjb25zdCByb3V0ZVBhdGggPSB0b0tlYmFiQ2FzZSh0YWJsZU5hbWUpO1xuICAgIGNvbnN0IG1vZGVsQ2xhenpOYW1lID0gTW9kZWxDb25zdHIubmFtZTtcbiAgICBjb25zdCBwZXJzaXN0ZW5jZSA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UGVyc2lzdGVuY2UoTW9kZWxDb25zdHIpO1xuXG4gICAgLy8gV2hlbiBwZXJzaXN0ZW5jZSBpcyBhIE1vZGVsU2VydmljZSwgdGhlIEBxdWVyeS9Acm91dGUgbWV0YWRhdGEgbGl2ZXMgb25cbiAgICAvLyB0aGUgdW5kZXJseWluZyByZXBvc2l0b3J5IGNsYXNzIChjdXN0b20gcmVwbyksIG5vdCBvbiBNb2RlbFNlcnZpY2UgaXRzZWxmLlxuICAgIC8vIFBhc3MgdGhlIHJlcG8gdG8gdGhlIGZhY3Rvcnkgc28gYWRkQ29tcGxleFF1ZXJpZXMoKSBjYW4gZGlzY292ZXIgdGhlbS5cbiAgICBjb25zdCBmYWN0b3J5UGVyc2lzdGVuY2UgPVxuICAgICAgcGVyc2lzdGVuY2UgaW5zdGFuY2VvZiBNb2RlbFNlcnZpY2UgPyBwZXJzaXN0ZW5jZS5yZXBvIDogcGVyc2lzdGVuY2U7XG5cbiAgICBjb25zdCBkZWNvcmF0b3JDb25maWcgPSBNZXRhZGF0YS5nZXQoXG4gICAgICBNb2RlbENvbnN0cixcbiAgICAgIE1ldGFkYXRhLmtleShERUNBRl9DT05UUk9MTEVSX0NPTkZJRylcbiAgICApIGFzIE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWcgfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgbW9kdWxlT3ZlcnJpZGUgPSBtb2R1bGVDb25maWdPdmVycmlkZXM/LltNb2RlbENvbnN0ci5uYW1lXTtcbiAgICBjb25zdCBtZXJnZWRDb25maWc6IE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWcgPSB7XG4gICAgICAuLi4oZ2xvYmFsRGVmYXVsdHMgfHwge30pLFxuICAgICAgLi4uKGRlY29yYXRvckNvbmZpZyB8fCB7fSksXG4gICAgICAuLi4obW9kdWxlT3ZlcnJpZGUgfHwge30pLFxuICAgIH07XG5cbiAgICBjb25zdCBGYWN0b3J5Q29udHJvbGxlciA9IE1vZGVsQ29udHJvbGxlckZhY3RvcnkuY3JlYXRlPFQ+KFxuICAgICAgTW9kZWxDb25zdHIsXG4gICAgICBmYWN0b3J5UGVyc2lzdGVuY2UsXG4gICAgICBtZXJnZWRDb25maWdcbiAgICApO1xuICAgIGNvbnN0IGZhY3RvcnlSb3V0ZXMgPSAoRmFjdG9yeUNvbnRyb2xsZXIgYXMgYW55KS5fX3JvdXRlc19fIGFzXG4gICAgICB8IFNlcnZlclJvdXRlW11cbiAgICAgIHwgdW5kZWZpbmVkO1xuXG4gICAgY29uc3QgeyBnZXRQSywgYXBpUHJvcGVydGllcywgcGF0aDogcGtQYXRoIH0gPVxuICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5nZXRSb3V0ZVBhcmFtZXRlcnNGcm9tTW9kZWwoTW9kZWxDb25zdHIpO1xuXG4gICAgbG9nLmRlYnVnKFxuICAgICAgYENyZWF0aW5nIGNvbnRyb2xsZXIgZm9yIG1vZGVsOiAke21vZGVsQ2xhenpOYW1lfSB3aXRoICR7ZmFjdG9yeVJvdXRlcz8ubGVuZ3RoID8/IDB9IGZhY3Rvcnkgcm91dGVzYFxuICAgICk7XG5cbiAgICBjb25zdCBhdXRoQ29uZmlnOiBBdXRoQ29uZmlnIHwgdW5kZWZpbmVkID0gbWVyZ2VkQ29uZmlnLmF1dGg7XG5cbiAgICBmdW5jdGlvbiBhcHBseUNsYXNzQXV0aCh0YXJnZXQ6IGFueSkge1xuICAgICAgaWYgKGF1dGhDb25maWc/LnB1YmxpYykge1xuICAgICAgICBQdWJsaWMoKSh0YXJnZXQpO1xuICAgICAgfSBlbHNlIGlmIChhdXRoQ29uZmlnPy5yb2xlcz8ubGVuZ3RoKSB7XG4gICAgICAgIFJlcXVpcmVSb2xlcyguLi5hdXRoQ29uZmlnLnJvbGVzKSh0YXJnZXQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgQXV0aChNb2RlbENvbnN0cikodGFyZ2V0KTtcbiAgICAgIH1cbiAgICAgIGlmIChhdXRoQ29uZmlnPy5za2lwTW9kZWxSb2xlcykge1xuICAgICAgICBTZXRNZXRhZGF0YShTS0lQX01PREVMX1JPTEVTX0tFWSwgdHJ1ZSkodGFyZ2V0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBAQ29udHJvbGxlcihyb3V0ZVBhdGgpXG4gICAgQEFwaVRhZ3MobW9kZWxDbGF6ek5hbWUpXG4gICAgQEFwaUV4dHJhTW9kZWxzKE1vZGVsQ29uc3RyKVxuICAgIGNsYXNzIER5bmFtaWNNb2RlbENvbnRyb2xsZXIgZXh0ZW5kcyBEZWNhZk1vZGVsQ29udHJvbGxlcjxUPiB7XG4gICAgICBwcml2YXRlIHJlYWRvbmx5IHBrOiBzdHJpbmcgPSBNb2RlbC5wayhNb2RlbENvbnN0cikgYXMgc3RyaW5nO1xuXG4gICAgICBwcm90ZWN0ZWQgc3RhdGljIGdldCBjbGFzcygpIHtcbiAgICAgICAgcmV0dXJuIE1vZGVsQ29uc3RyO1xuICAgICAgfVxuXG4gICAgICBvdmVycmlkZSBnZXQgY2xhc3MoKTogTW9kZWxDb25zdHJ1Y3RvcjxUPiB7XG4gICAgICAgIHJldHVybiBNb2RlbENvbnN0cjtcbiAgICAgIH1cblxuICAgICAgY29uc3RydWN0b3IoY2xpZW50Q29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCkge1xuICAgICAgICBzdXBlcihjbGllbnRDb250ZXh0LCBEeW5hbWljTW9kZWxDb250cm9sbGVyLm5hbWUpO1xuICAgICAgICBsb2cuaW5mbyhcbiAgICAgICAgICBgUmVnaXN0ZXJpbmcgZHluYW1pYyBjb250cm9sbGVyIGZvciBtb2RlbDogJHt0aGlzLmNsYXNzLm5hbWV9IHJvdXRlOiAvJHtyb3V0ZVBhdGh9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGFwcGx5Q2xhc3NBdXRoKER5bmFtaWNNb2RlbENvbnRyb2xsZXIpO1xuXG4gICAgaWYgKGZhY3RvcnlSb3V0ZXMpIHtcbiAgICAgIGNvbnN0IHNvcnRlZFJvdXRlcyA9IFsuLi5mYWN0b3J5Um91dGVzXS5zb3J0KChhLCBiKSA9PiB7XG4gICAgICAgIGNvbnN0IGFTZWdtZW50cyA9IGEucGF0aC5zcGxpdChcIi9cIikuZmlsdGVyKEJvb2xlYW4pO1xuICAgICAgICBjb25zdCBiU2VnbWVudHMgPSBiLnBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgICAgICAgY29uc3QgYVBhcmFtQ291bnQgPSBhU2VnbWVudHMuZmlsdGVyKChzKSA9PiBzLnN0YXJ0c1dpdGgoXCI6XCIpKS5sZW5ndGg7XG4gICAgICAgIGNvbnN0IGJQYXJhbUNvdW50ID0gYlNlZ21lbnRzLmZpbHRlcigocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSkubGVuZ3RoO1xuICAgICAgICBjb25zdCBhTGl0ZXJhbENvdW50ID0gYVNlZ21lbnRzLmxlbmd0aCAtIGFQYXJhbUNvdW50O1xuICAgICAgICBjb25zdCBiTGl0ZXJhbENvdW50ID0gYlNlZ21lbnRzLmxlbmd0aCAtIGJQYXJhbUNvdW50O1xuICAgICAgICBpZiAoYUxpdGVyYWxDb3VudCAhPT0gYkxpdGVyYWxDb3VudClcbiAgICAgICAgICByZXR1cm4gYkxpdGVyYWxDb3VudCAtIGFMaXRlcmFsQ291bnQ7XG4gICAgICAgIGlmIChhUGFyYW1Db3VudCAhPT0gYlBhcmFtQ291bnQpXG4gICAgICAgICAgcmV0dXJuIGFQYXJhbUNvdW50IC0gYlBhcmFtQ291bnQ7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfSk7XG4gICAgICBmb3IgKGNvbnN0IHJvdXRlIG9mIHNvcnRlZFJvdXRlcykge1xuICAgICAgICBjb25zdCByZWdpc3RyYXRpb24gPSBGcm9tTW9kZWxDb250cm9sbGVyLm1hdGNoUm91dGUoXG4gICAgICAgICAgcm91dGUsXG4gICAgICAgICAgcGtQYXRoLFxuICAgICAgICAgIGFwaVByb3BlcnRpZXMsXG4gICAgICAgICAgZ2V0UEssXG4gICAgICAgICAgTW9kZWxDb25zdHIsXG4gICAgICAgICAgbW9kZWxDbGF6ek5hbWUsXG4gICAgICAgICAgZmFjdG9yeVBlcnNpc3RlbmNlXG4gICAgICAgICk7XG4gICAgICAgIGlmICghcmVnaXN0cmF0aW9uKSBjb250aW51ZTtcblxuICAgICAgICBjb25zdCB7IG1ldGhvZE5hbWUsIGhhbmRsZXIsIGRlY29yYXRvcnMsIHBhcmFtRGVjb3JhdG9ycyB9ID1cbiAgICAgICAgICByZWdpc3RyYXRpb247XG5cbiAgICAgICAgY29uc3QgZGVzY3JpcHRvciA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZGVmaW5lTWV0aG9kKFxuICAgICAgICAgIER5bmFtaWNNb2RlbENvbnRyb2xsZXIsXG4gICAgICAgICAgbWV0aG9kTmFtZSxcbiAgICAgICAgICBoYW5kbGVyXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKGRlc2NyaXB0b3IpIHtcbiAgICAgICAgICBjb25zdCBodHRwRGVjb3JhdG9yID0gSHR0cFZlcmJUb0RlY29yYXRvcihyb3V0ZS5tZXRob2QgYXMgSHR0cFZlcmJzKShcbiAgICAgICAgICAgIHJvdXRlLnBhdGgucmVwbGFjZSgvXlxcLyt8XFwvKyQvZywgXCJcIikgfHwgdW5kZWZpbmVkXG4gICAgICAgICAgKTtcbiAgICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmFwcGx5RGVjb3JhdG9ycyhcbiAgICAgICAgICAgIER5bmFtaWNNb2RlbENvbnRyb2xsZXIsXG4gICAgICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICAgICAgW2h0dHBEZWNvcmF0b3IsIC4uLmRlY29yYXRvcnNdLFxuICAgICAgICAgICAgcGFyYW1EZWNvcmF0b3JzXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBEeW5hbWljTW9kZWxDb250cm9sbGVyIGFzIGFueTtcbiAgfVxuXG4gIHN0YXRpYyBnZXRSb3V0ZVBhcmFtZXRlcnNGcm9tTW9kZWw8VCBleHRlbmRzIE1vZGVsPGFueT4+KFxuICAgIE1vZGVsQ2xheno6IE1vZGVsQ29uc3RydWN0b3I8VD5cbiAgKToge1xuICAgIHBhdGg6IHN0cmluZztcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAgIGFwaVByb3BlcnRpZXM6IERlY2FmQXBpUHJvcGVydHlbXTtcbiAgICBnZXRQSzogKC4uLnBhcmFtczogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nO1xuICB9IHtcbiAgICBjb25zdCBwayA9IE1vZGVsLnBrKE1vZGVsQ2xhenopIGFzIGtleW9mIE1vZGVsPGFueT47XG4gICAgY29uc3QgY29tcG9zZWQgPSBNZXRhZGF0YS5nZXQoXG4gICAgICBNb2RlbENsYXp6LFxuICAgICAgTWV0YWRhdGEua2V5KERCS2V5cy5DT01QT1NFRCwgcGspXG4gICAgKTtcbiAgICBjb25zdCBjb21wb3NlZEtleXMgPSBjb21wb3NlZD8uYXJncyA/PyBbXTtcblxuICAgIGNvbnN0IHVuaXF1ZUtleXMgPVxuICAgICAgQXJyYXkuaXNBcnJheShjb21wb3NlZEtleXMpICYmIGNvbXBvc2VkS2V5cy5sZW5ndGggPiAwXG4gICAgICAgID8gQXJyYXkuZnJvbShuZXcgU2V0KFsuLi5jb21wb3NlZEtleXNdKSlcbiAgICAgICAgOiBBcnJheS5mcm9tKG5ldyBTZXQoW3BrXSkpO1xuXG4gICAgY29uc3QgZGVzY3JpcHRpb24gPSBNZXRhZGF0YS5kZXNjcmlwdGlvbihNb2RlbENsYXp6KSA/PyBcIlwiO1xuICAgIGNvbnN0IHBhdGggPSBgOiR7dW5pcXVlS2V5cy5qb2luKFwiLzpcIil9YDtcbiAgICBjb25zdCBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10gPSB1bmlxdWVLZXlzLm1hcCgoa2V5KSA9PiB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBuYW1lOiBrZXksXG4gICAgICAgIGRlc2NyaXB0aW9uOiBNZXRhZGF0YS5kZXNjcmlwdGlvbihNb2RlbENsYXp6LCBrZXkpLFxuICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICBwYXRoLFxuICAgICAgZGVzY3JpcHRpb24sXG4gICAgICBhcGlQcm9wZXJ0aWVzLFxuICAgICAgZ2V0UEs6ICguLi5wYXJhbXM6IEFycmF5PHN0cmluZyB8IG51bWJlcj4pID0+XG4gICAgICAgIGNvbXBvc2VkPy5zZXBhcmF0b3IgPyBwYXJhbXMuam9pbihjb21wb3NlZC5zZXBhcmF0b3IpIDogcGFyYW1zLmpvaW4oXCJcIiksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGRlZmluZU1ldGhvZChcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gICAgaGFuZGxlcjogKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnlcbiAgKTogUHJvcGVydHlEZXNjcmlwdG9yIHwgdW5kZWZpbmVkIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoXG4gICAgICB0YXJnZXQucHJvdG90eXBlIHx8IHRhcmdldCxcbiAgICAgIG1ldGhvZE5hbWUsXG4gICAgICB7XG4gICAgICAgIHZhbHVlOiBoYW5kbGVyLFxuICAgICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICB9XG4gICAgKTtcblxuICAgIHJldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKFxuICAgICAgdGFyZ2V0LnByb3RvdHlwZSB8fCB0YXJnZXQsXG4gICAgICBtZXRob2ROYW1lXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGFwcGx5RGVjb3JhdG9ycyhcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gICAgbWV0aG9kRGVjb3JhdG9yczogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPixcbiAgICBwYXJhbURlY29yYXRvcnM6IEFycmF5PHsgZGVjb3JhdG9yOiBQYXJhbWV0ZXJEZWNvcmF0b3I7IGluZGV4OiBudW1iZXIgfT4gPSBbXVxuICApIHtcbiAgICBjb25zdCBwcm90byA9IHRhcmdldD8ucHJvdG90eXBlID8/IHRhcmdldDtcbiAgICBjb25zdCBkZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihwcm90bywgbWV0aG9kTmFtZSk7XG4gICAgbWV0aG9kRGVjb3JhdG9ycy5mb3JFYWNoKChkKSA9PiBkKHByb3RvLCBtZXRob2ROYW1lLCBkZXNjcmlwdG9yKSk7XG4gICAgcGFyYW1EZWNvcmF0b3JzLmZvckVhY2goKHsgZGVjb3JhdG9yLCBpbmRleCB9KSA9PlxuICAgICAgZGVjb3JhdG9yKHByb3RvLCBtZXRob2ROYW1lLCBpbmRleClcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgbWF0Y2hSb3V0ZShcbiAgICByb3V0ZTogU2VydmVyUm91dGUsXG4gICAgcGtQYXRoOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdLFxuICAgIGdldFBLOiAoLi4ucDogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nLFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBwZXJzaXN0ZW5jZT86IGFueVxuICApOiB7XG4gICAgbWV0aG9kTmFtZTogc3RyaW5nO1xuICAgIGhhbmRsZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55O1xuICAgIGRlY29yYXRvcnM6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD47XG4gICAgcGFyYW1EZWNvcmF0b3JzOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+O1xuICB9IHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCB7IG1ldGhvZCwgcGF0aCB9ID0gcm91dGU7XG4gICAgY29uc3Qgbm9ybWFsaXplZFBhdGggPSBwYXRoLnJlcGxhY2UoL15cXC8rfFxcLyskL2csIFwiXCIpO1xuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJQT1NUXCIgJiYgbm9ybWFsaXplZFBhdGggPT09IFwiXCIpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJjcmVhdGVcIixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVDcmVhdGVIYW5kbGVyKE1vZGVsQ29uc3RyLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlQ3JlYXRlRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBbeyBkZWNvcmF0b3I6IERlY2FmQm9keSgpIGFzIGFueSwgaW5kZXg6IDAgfSwgeyBkZWNvcmF0b3I6IFJlc3BvbnNlKHsgcGFzc3Rocm91Z2g6IHRydWUgfSkgYXMgYW55LCBpbmRleDogMSB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIlBPU1RcIiAmJiBub3JtYWxpemVkUGF0aCA9PT0gXCJidWxrXCIpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJjcmVhdGVBbGxcIixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVCdWxrQ3JlYXRlSGFuZGxlcihNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmJ1bGtDcmVhdGVEZWNvcmF0b3JzKE1vZGVsQ29uc3RyLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIFt7IGRlY29yYXRvcjogRGVjYWZCb2R5KCkgYXMgYW55LCBpbmRleDogMCB9LCB7IGRlY29yYXRvcjogUmVzcG9uc2UoeyBwYXNzdGhyb3VnaDogdHJ1ZSB9KSBhcyBhbnksIGluZGV4OiAxIH1dXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChtZXRob2QgPT09IFwiR0VUXCIgJiYgbm9ybWFsaXplZFBhdGggPT09IFwiYnVsa1wiKSB7XG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIFwicmVhZEFsbFwiLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUJ1bGtSZWFkSGFuZGxlcihtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuYnVsa1JlYWREZWNvcmF0b3JzKE1vZGVsQ29uc3RyLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIFt7IGRlY29yYXRvcjogUXVlcnkoXCJpZHNcIikgYXMgYW55LCBpbmRleDogMCB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIlBVVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBcImJ1bGtcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBcInVwZGF0ZUFsbFwiLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUJ1bGtVcGRhdGVIYW5kbGVyKG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5idWxrVXBkYXRlRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUsIGFwaVByb3BlcnRpZXMpLFxuICAgICAgICBbeyBkZWNvcmF0b3I6IERlY2FmQm9keSgpIGFzIGFueSwgaW5kZXg6IDAgfSwgeyBkZWNvcmF0b3I6IFJlc3BvbnNlKHsgcGFzc3Rocm91Z2g6IHRydWUgfSkgYXMgYW55LCBpbmRleDogMSB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkRFTEVURVwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBcImJ1bGtcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBcImRlbGV0ZUFsbFwiLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUJ1bGtEZWxldGVIYW5kbGVyKG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5idWxrRGVsZXRlRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUsIGFwaVByb3BlcnRpZXMpLFxuICAgICAgICBbeyBkZWNvcmF0b3I6IFF1ZXJ5KFwiaWRzXCIpIGFzIGFueSwgaW5kZXg6IDAgfSwgeyBkZWNvcmF0b3I6IFJlc3BvbnNlKHsgcGFzc3Rocm91Z2g6IHRydWUgfSkgYXMgYW55LCBpbmRleDogMSB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkdFVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBwa1BhdGgpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJyZWFkXCIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVhZEhhbmRsZXIoZ2V0UEssIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5yZWFkRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUsIGFwaVByb3BlcnRpZXMsIHBrUGF0aCksXG4gICAgICAgIFt7IGRlY29yYXRvcjogRGVjYWZQYXJhbXMoYXBpUHJvcGVydGllcykgYXMgYW55LCBpbmRleDogMCB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIlBVVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBwa1BhdGgpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJ1cGRhdGVcIixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVVcGRhdGVIYW5kbGVyKGdldFBLLCBNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnVwZGF0ZURlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBhcGlQcm9wZXJ0aWVzLCBwa1BhdGgpLFxuICAgICAgICBbXG4gICAgICAgICAgeyBkZWNvcmF0b3I6IERlY2FmUGFyYW1zKGFwaVByb3BlcnRpZXMpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogRGVjYWZCb2R5KCkgYXMgYW55LCBpbmRleDogMSB9LFxuICAgICAgICAgIHsgZGVjb3JhdG9yOiBSZXNwb25zZSh7IHBhc3N0aHJvdWdoOiB0cnVlIH0pIGFzIGFueSwgaW5kZXg6IDIgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkRFTEVURVwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBwa1BhdGgpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJkZWxldGVcIixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVEZWxldGVIYW5kbGVyKGdldFBLLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuZGVsZXRlRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUsIGFwaVByb3BlcnRpZXMsIHBrUGF0aCksXG4gICAgICAgIFtcbiAgICAgICAgICB7IGRlY29yYXRvcjogRGVjYWZQYXJhbXMoYXBpUHJvcGVydGllcykgYXMgYW55LCBpbmRleDogMCB9LFxuICAgICAgICAgIHsgZGVjb3JhdG9yOiBSZXNwb25zZSh7IHBhc3N0aHJvdWdoOiB0cnVlIH0pIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDb21wb3NlZCBQSyBmYWxsYmFjayByb3V0ZXMgKGZpbHRlckVtcHR5KSDigJQgcGF0aCBkaWZmZXJzIGZyb20gcGtQYXRoXG4gICAgY29uc3QgZmFsbGJhY2tTZWdtZW50cyA9IG5vcm1hbGl6ZWRQYXRoLnNwbGl0KFwiL1wiKS5maWx0ZXIoQm9vbGVhbik7XG4gICAgY29uc3QgaXNBbGxQYXJhbXMgPSBmYWxsYmFja1NlZ21lbnRzLmxlbmd0aCA+IDAgJiYgZmFsbGJhY2tTZWdtZW50cy5ldmVyeSgocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSk7XG4gICAgaWYgKGlzQWxsUGFyYW1zICYmIG5vcm1hbGl6ZWRQYXRoICE9PSBwa1BhdGgpIHtcbiAgICAgIGNvbnN0IGZhbGxiYWNrQXBpUHJvcHMgPSBmYWxsYmFja1NlZ21lbnRzLm1hcCgocykgPT4gcy5zbGljZSgxKSkubWFwKChuYW1lKSA9PiAoe1xuICAgICAgICBuYW1lLFxuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bmFtZX0gcGFyYW1ldGVyYCxcbiAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgIHR5cGU6IFN0cmluZyxcbiAgICAgIH0pKTtcbiAgICAgIGNvbnN0IHN1ZmZpeCA9IGZhbGxiYWNrU2VnbWVudHMubWFwKChzKSA9PiBzLnNsaWNlKDEpKS5qb2luKFwiQW5kXCIpO1xuICAgICAgaWYgKG1ldGhvZCA9PT0gXCJHRVRcIikge1xuICAgICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgICAgYHJlYWRCeSR7c3VmZml4fWAsXG4gICAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWFkSGFuZGxlcihnZXRQSywgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIucmVhZERlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBmYWxsYmFja0FwaVByb3BzLCBub3JtYWxpemVkUGF0aCksXG4gICAgICAgICAgW3sgZGVjb3JhdG9yOiBEZWNhZlBhcmFtcyhmYWxsYmFja0FwaVByb3BzKSBhcyBhbnksIGluZGV4OiAwIH1dXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAobWV0aG9kID09PSBcIlBVVFwiKSB7XG4gICAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgICBgdXBkYXRlQnkke3N1ZmZpeH1gLFxuICAgICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlVXBkYXRlSGFuZGxlcihnZXRQSywgTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnVwZGF0ZURlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBmYWxsYmFja0FwaVByb3BzLCBub3JtYWxpemVkUGF0aCksXG4gICAgICAgICAgW1xuICAgICAgICAgICAgeyBkZWNvcmF0b3I6IERlY2FmUGFyYW1zKGZhbGxiYWNrQXBpUHJvcHMpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICAgIHsgZGVjb3JhdG9yOiBEZWNhZkJvZHkoKSBhcyBhbnksIGluZGV4OiAxIH0sXG4gICAgICAgICAgICB7IGRlY29yYXRvcjogUmVzcG9uc2UoeyBwYXNzdGhyb3VnaDogdHJ1ZSB9KSBhcyBhbnksIGluZGV4OiAyIH0sXG4gICAgICAgICAgXVxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKG1ldGhvZCA9PT0gXCJERUxFVEVcIikge1xuICAgICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgICAgYGRlbGV0ZUJ5JHtzdWZmaXh9YCxcbiAgICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZURlbGV0ZUhhbmRsZXIoZ2V0UEssIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmRlbGV0ZURlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBmYWxsYmFja0FwaVByb3BzLCBub3JtYWxpemVkUGF0aCksXG4gICAgICAgICAgW1xuICAgICAgICAgICAgeyBkZWNvcmF0b3I6IERlY2FmUGFyYW1zKGZhbGxiYWNrQXBpUHJvcHMpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICAgIHsgZGVjb3JhdG9yOiBSZXNwb25zZSh7IHBhc3N0aHJvdWdoOiB0cnVlIH0pIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgICBdXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJHRVRcIiAmJiBub3JtYWxpemVkUGF0aCA9PT0gXCJzdGF0ZW1lbnQvOm1ldGhvZC8qYXJnc1wiKSB7XG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIFwic3RhdGVtZW50XCIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlU3RhdGVtZW50SGFuZGxlcihtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuc3RhdGVtZW50RGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBbXG4gICAgICAgICAgeyBkZWNvcmF0b3I6IFBhcmFtKFwibWV0aG9kXCIpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogUGFyYW0oXCJhcmdzXCIpIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogRGVjYWZRdWVyeSgpIGFzIGFueSwgaW5kZXg6IDIgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBzdGF0ZW1lbnRSb3V0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICBcImxpc3RCeS86a2V5XCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5MSVNUX0JZLFxuICAgICAgXCJwYWdpbmF0ZUJ5LzprZXkvOnBhZ2VcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlBBR0VfQlksXG4gICAgICBcImZpbmQvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5ELFxuICAgICAgXCJwYWdlLzp2YWx1ZVwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRSxcbiAgICAgIFwiZmluZE9uZUJ5LzprZXkvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWSxcbiAgICAgIFwiZmluZEJ5LzprZXkvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZLFxuICAgICAgXCJjb3VudE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuQ09VTlRfT0YsXG4gICAgICBcIm1heE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUFYX09GLFxuICAgICAgXCJtaW5PZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLk1JTl9PRixcbiAgICAgIFwiYXZnT2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5BVkdfT0YsXG4gICAgICBcInN1bU9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GLFxuICAgICAgXCJkaXN0aW5jdE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuRElTVElOQ1RfT0YsXG4gICAgICBcImdyb3VwT2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5HUk9VUF9PRixcbiAgICB9O1xuXG4gICAgY29uc3Qgc3RhdGVtZW50S2V5ID0gc3RhdGVtZW50Um91dGVzW25vcm1hbGl6ZWRQYXRoXTtcbiAgICBpZiAoc3RhdGVtZW50S2V5ICYmIG1ldGhvZCA9PT0gXCJHRVRcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnN0YXRlbWVudE1ldGhvZE5hbWUobm9ybWFsaXplZFBhdGgpLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVN0YXRlbWVudFNob3J0Y3V0SGFuZGxlcihzdGF0ZW1lbnRLZXksIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5zdGF0ZW1lbnRTaG9ydGN1dERlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBub3JtYWxpemVkUGF0aCwgc3RhdGVtZW50S2V5KSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5zdGF0ZW1lbnRTaG9ydGN1dFBhcmFtcyhub3JtYWxpemVkUGF0aClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJHRVRcIiAmJiBub3JtYWxpemVkUGF0aC5zdGFydHNXaXRoKFwicXVlcnkvXCIpKSB7XG4gICAgICBjb25zdCBxdWVyeU1ldGhvZCA9IG5vcm1hbGl6ZWRQYXRoLnJlcGxhY2UoL15xdWVyeVxcLy8sIFwiXCIpLnNwbGl0KFwiL1wiKVswXTtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgcXVlcnlNZXRob2QsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlQ29tcGxleFF1ZXJ5SGFuZGxlcihxdWVyeU1ldGhvZCksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UXVlcnlEZWNvcmF0b3JzKHF1ZXJ5TWV0aG9kLCBub3JtYWxpemVkUGF0aCwgXCJHRVRcIiwgdHJ1ZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY29tcGxleFF1ZXJ5UGFyYW1zKG5vcm1hbGl6ZWRQYXRoKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBGYWxsYmFjayBmb3IgY3VzdG9tIEByb3V0ZSgpIHBhdGhzIChlLmcuIFwibWV0YWRhdGEvZm9yLXByb2R1Y3QvOnByb2R1Y3RDb2RlXCIpXG4gICAgY29uc3QgcGF0aFNlZ21lbnRzID0gbm9ybWFsaXplZFBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgICBjb25zdCBrbm93blByZWZpeGVzID0gbmV3IFNldDxzdHJpbmc+KFtcbiAgICAgIFwibGlzdEJ5XCIsIFwiZmluZEJ5XCIsIFwiZmluZEJ5UGFnaW5hdGVcIiwgXCJmaW5kT25lQnlcIiwgXCJwYWdpbmF0ZUJ5XCIsXG4gICAgICBcImZpbmRcIiwgXCJwYWdlXCIsIFwiY291bnRPZlwiLCBcIm1heE9mXCIsIFwibWluT2ZcIiwgXCJhdmdPZlwiLCBcInN1bU9mXCIsXG4gICAgICBcImRpc3RpbmN0T2ZcIiwgXCJncm91cE9mXCIsIFwic3RhdGVtZW50XCIsIFwiYnVsa1wiLCBcInF1ZXJ5XCIsXG4gICAgXSk7XG4gICAgaWYgKFxuICAgICAgcGF0aFNlZ21lbnRzLmxlbmd0aCA+IDAgJiZcbiAgICAgICFub3JtYWxpemVkUGF0aC5zdGFydHNXaXRoKFwicXVlcnkvXCIpICYmXG4gICAgICAha25vd25QcmVmaXhlcy5oYXMocGF0aFNlZ21lbnRzWzBdKVxuICAgICkge1xuICAgICAgLy8gTG9vayB1cCB0aGUgYWN0dWFsIG1ldGhvZCBuYW1lIGZyb20gQHJvdXRlIG1ldGFkYXRhIGJ5IG1hdGNoaW5nIHRoZSBwYXRoLlxuICAgICAgLy8gVGhlIEByb3V0ZSBkZWNvcmF0b3Igc3RvcmVzIHsgcGF0aCwgaHR0cE1ldGhvZCwgaGFuZGxlciB9IGtleWVkIGJ5IG1ldGhvZCBuYW1lXG4gICAgICAvLyBvbiB0aGUgcmVwb3NpdG9yeSBjb25zdHJ1Y3Rvci5cbiAgICAgIGNvbnN0IHJvdXRlTWV0YWRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT4gPVxuICAgICAgICBNZXRhZGF0YS5nZXQoXG4gICAgICAgICAgKHBlcnNpc3RlbmNlIGFzIGFueSk/LmNvbnN0cnVjdG9yLFxuICAgICAgICAgIE1ldGFkYXRhLmtleShERUNBRl9ST1VURSlcbiAgICAgICAgKSA/PyB7fTtcbiAgICAgIGNvbnN0IG1hdGNoZWRFbnRyeSA9IE9iamVjdC5lbnRyaWVzKHJvdXRlTWV0YWRhdGEpLmZpbmQoXG4gICAgICAgIChbLCBpbmZvXSkgPT5cbiAgICAgICAgICBpbmZvICYmXG4gICAgICAgICAgdHlwZW9mIGluZm8gPT09IFwib2JqZWN0XCIgJiZcbiAgICAgICAgICBpbmZvLnBhdGg/LnJlcGxhY2UoL15cXC8rfFxcLyskL2csIFwiXCIpID09PSBub3JtYWxpemVkUGF0aFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGFjdHVhbE1ldGhvZE5hbWUgPSBtYXRjaGVkRW50cnk/LlswXSB8fCBwYXRoU2VnbWVudHNbMF07XG5cbiAgICAgIGNvbnN0IHBhcmFtU2VnbWVudHMgPSBwYXRoU2VnbWVudHMuZmlsdGVyKChzKSA9PiBzLnN0YXJ0c1dpdGgoXCI6XCIpKTtcbiAgICAgIGNvbnN0IGFwaVBhdGhQYXJhbXMgPSBwYXJhbVNlZ21lbnRzLm1hcCgocykgPT4gcy5zbGljZSgxKSkubWFwKChuYW1lKSA9PiAoe1xuICAgICAgICBuYW1lLFxuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bmFtZX0gcGFyYW1ldGVyIGZvciB0aGUgcXVlcnlgLFxuICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgfSkpO1xuXG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIGFjdHVhbE1ldGhvZE5hbWUsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlQ3VzdG9tUm91dGVIYW5kbGVyKGFjdHVhbE1ldGhvZE5hbWUpLFxuICAgICAgICBbXG4gICAgICAgICAgLi4uYXBpUGF0aFBhcmFtcy5tYXAoKHApID0+IEFwaVBhcmFtKHApKSxcbiAgICAgICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgUmV0cmlldmUgcmVjb3JkcyB1c2luZyBcIiR7YWN0dWFsTWV0aG9kTmFtZX1cIi5gIH0pLFxuICAgICAgICAgIEFwaU9rUmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJSZXN1bHQgc3VjY2Vzc2Z1bGx5IHJldHJpZXZlZC5cIiB9KSxcbiAgICAgICAgICBBcGlOb0NvbnRlbnRSZXNwb25zZSh7IGRlc2NyaXB0aW9uOiBcIk5vIGNvbnRlbnQgcmV0dXJuZWQgYnkgdGhlIG1ldGhvZC5cIiB9KSxcbiAgICAgICAgXSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jb21wbGV4UXVlcnlQYXJhbXMobm9ybWFsaXplZFBhdGgpXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgbWV0aG9kTmFtZTogc3RyaW5nLFxuICAgIGhhbmRsZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55LFxuICAgIGRlY29yYXRvcnM6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4sXG4gICAgcGFyYW1EZWNvcmF0b3JzOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+XG4gICkge1xuICAgIHJldHVybiB7IG1ldGhvZE5hbWUsIGhhbmRsZXIsIGRlY29yYXRvcnMsIHBhcmFtRGVjb3JhdG9ycyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgc3RhdGVtZW50TWV0aG9kTmFtZShwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGZpcnN0U2VnbWVudCA9IHBhdGguc3BsaXQoXCIvXCIpWzBdO1xuICAgIHJldHVybiBmaXJzdFNlZ21lbnQ7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBzdGF0ZW1lbnRTaG9ydGN1dFBhcmFtcyhcbiAgICBwYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8eyBkZWNvcmF0b3I6IFBhcmFtZXRlckRlY29yYXRvcjsgaW5kZXg6IG51bWJlciB9PiB7XG4gICAgY29uc3Qgc2VnbWVudHMgPSBwYXRoLnNwbGl0KFwiL1wiKS5maWx0ZXIoKHMpID0+IHMuc3RhcnRzV2l0aChcIjpcIikpO1xuICAgIGNvbnN0IHBhcmFtczogQXJyYXk8eyBkZWNvcmF0b3I6IFBhcmFtZXRlckRlY29yYXRvcjsgaW5kZXg6IG51bWJlciB9PiA9IFtdO1xuICAgIHNlZ21lbnRzLmZvckVhY2goKHNlZywgaSkgPT4ge1xuICAgICAgY29uc3QgbmFtZSA9IHNlZy5yZXBsYWNlKFwiOlwiLCBcIlwiKTtcbiAgICAgIHBhcmFtcy5wdXNoKHsgZGVjb3JhdG9yOiBQYXJhbShuYW1lKSBhcyBhbnksIGluZGV4OiBpIH0pO1xuICAgIH0pO1xuICAgIGlmIChcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcImxpc3RCeS9cIikgfHxcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcInBhZ2luYXRlQnkvXCIpIHx8XG4gICAgICBwYXRoLnN0YXJ0c1dpdGgoXCJmaW5kL1wiKSB8fFxuICAgICAgcGF0aC5zdGFydHNXaXRoKFwicGFnZS9cIilcbiAgICApIHtcbiAgICAgIHBhcmFtcy5wdXNoKHsgZGVjb3JhdG9yOiBEZWNhZlF1ZXJ5KCkgYXMgYW55LCBpbmRleDogc2VnbWVudHMubGVuZ3RoIH0pO1xuICAgIH1cbiAgICByZXR1cm4gcGFyYW1zO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY29tcGxleFF1ZXJ5UGFyYW1zKFxuICAgIHBhdGg6IHN0cmluZ1xuICApOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+IHtcbiAgICBjb25zdCBzZWdtZW50cyA9IHBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcigocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSk7XG4gICAgY29uc3QgcGFyYW1zOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+ID0gW107XG4gICAgc2VnbWVudHMuZm9yRWFjaCgoc2VnLCBpKSA9PiB7XG4gICAgICBjb25zdCBuYW1lID0gc2VnLnJlcGxhY2UoXCI6XCIsIFwiXCIpO1xuICAgICAgcGFyYW1zLnB1c2goeyBkZWNvcmF0b3I6IFBhcmFtKG5hbWUpIGFzIGFueSwgaW5kZXg6IGkgfSk7XG4gICAgfSk7XG4gICAgaWYgKHBhdGguc3RhcnRzV2l0aChcInF1ZXJ5L1wiKSkge1xuICAgICAgcGFyYW1zLnB1c2goeyBkZWNvcmF0b3I6IERlY2FmUXVlcnkoKSBhcyBhbnksIGluZGV4OiBzZWdtZW50cy5sZW5ndGggfSk7XG4gICAgfVxuICAgIHJldHVybiBwYXJhbXM7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVDcmVhdGVIYW5kbGVyKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gY3JlYXRlKFxuICAgICAgdGhpczogYW55LFxuICAgICAgZGF0YTogYW55LFxuICAgICAgcmVzcD86IGFueVxuICAgICk6IFByb21pc2U8TW9kZWw8YW55Pj4ge1xuICAgICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgT3BlcmF0aW9uS2V5cy5DUkVBVEUsIHRydWUpXG4gICAgICApLmZvcihjcmVhdGUpO1xuICAgICAgbG9nLnZlcmJvc2UoYGNyZWF0aW5nIG5ldyAke21vZGVsQ2xhenpOYW1lfWApO1xuICAgICAgbGV0IGNyZWF0ZWQ6IE1vZGVsO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY3JlYXRlZCA9IGF3YWl0IHRoaXMucGVyc2lzdGVuY2UoY3R4KS5jcmVhdGUoZGF0YSwgY3R4KTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gY3JlYXRlIG5ldyAke21vZGVsQ2xhenpOYW1lfWAsIGUgYXMgRXJyb3IpO1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgICAgbG9nLmluZm8oYGNyZWF0ZWQgbmV3ICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggaWQgJHsoY3JlYXRlZCBhcyBhbnkpW3RoaXMucGtdfWApO1xuICAgICAgaWYgKHJlc3ApIGN0eC50b1Jlc3BvbnNlKHJlc3ApO1xuICAgICAgcmV0dXJuIGNyZWF0ZWQ7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZUJ1bGtDcmVhdGVIYW5kbGVyKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gY3JlYXRlQWxsKFxuICAgICAgdGhpczogYW55LFxuICAgICAgZGF0YTogYW55W10sXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxNb2RlbFtdPiB7XG4gICAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSAoXG4gICAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KFtdLCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuQ1JFQVRFX0FMTCwgdHJ1ZSlcbiAgICAgICkuZm9yKGNyZWF0ZUFsbCk7XG4gICAgICBsb2cudmVyYm9zZShgY3JlYXRpbmcgbmV3ICR7bW9kZWxDbGF6ek5hbWV9YCk7XG4gICAgICBsZXQgY3JlYXRlZDogYW55W107XG4gICAgICB0cnkge1xuICAgICAgICBjcmVhdGVkID0gYXdhaXQgdGhpcy5wZXJzaXN0ZW5jZShjdHgpLmNyZWF0ZUFsbChcbiAgICAgICAgICBkYXRhLm1hcCgoZCkgPT4gbmV3IE1vZGVsQ29uc3RyKGQpKSxcbiAgICAgICAgICBjdHhcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gY3JlYXRlIG5ldyAke21vZGVsQ2xhenpOYW1lfWAsIGUgYXMgRXJyb3IpO1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgICAgbG9nLmluZm8oYGNyZWF0ZWQgbmV3ICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggaWQgJHsoY3JlYXRlZCBhcyBhbnkpW3RoaXMucGtdfWApO1xuICAgICAgaWYgKHJlc3ApIGN0eC50b1Jlc3BvbnNlKHJlc3ApO1xuICAgICAgcmV0dXJuIGNyZWF0ZWQ7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZUJ1bGtSZWFkSGFuZGxlcihtb2RlbENsYXp6TmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIHJlYWRBbGwoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICBpZHM6IHN0cmluZ1tdXG4gICAgKTogUHJvbWlzZTxNb2RlbFtdPiB7XG4gICAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSAoXG4gICAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KFtdLCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuUkVBRF9BTEwsIHRydWUpXG4gICAgICApLmZvcihyZWFkQWxsKTtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRJZHMgPSBBcnJheS5pc0FycmF5KGlkcykgPyBpZHMgOiBbaWRzXTtcbiAgICAgIGxldCByZWFkOiBNb2RlbFtdO1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmRlYnVnKGByZWFkaW5nICR7bm9ybWFsaXplZElkc30gJHttb2RlbENsYXp6TmFtZX1gKTtcbiAgICAgICAgcmVhZCA9IGF3YWl0IHRoaXMucGVyc2lzdGVuY2UoY3R4KS5yZWFkQWxsKG5vcm1hbGl6ZWRJZHMgYXMgYW55LCBjdHgpO1xuICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICBsb2cuZXJyb3IoYEZhaWxlZCB0byByZWFkICR7bW9kZWxDbGF6ek5hbWV9YCwgZSBhcyBFcnJvcik7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgICBsb2cuaW5mbyhgcmVhZCAke3JlYWQubGVuZ3RofSAke21vZGVsQ2xhenpOYW1lfWApO1xuICAgICAgcmV0dXJuIHJlYWQ7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZUJ1bGtVcGRhdGVIYW5kbGVyKG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gdXBkYXRlQWxsKFxuICAgICAgdGhpczogYW55LFxuICAgICAgYm9keTogYW55W10sXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxhbnlbXT4ge1xuICAgICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgQnVsa0NydWRPcGVyYXRpb25LZXlzLlVQREFURV9BTEwsIHRydWUpXG4gICAgICApLmZvcih1cGRhdGVBbGwpO1xuICAgICAgbGV0IHVwZGF0ZWQ6IGFueVtdO1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmluZm8oYHVwZGF0aW5nICR7Ym9keS5sZW5ndGh9ICR7bW9kZWxDbGF6ek5hbWV9YCk7XG4gICAgICAgIHVwZGF0ZWQgPSBhd2FpdCB0aGlzLnBlcnNpc3RlbmNlKGN0eCkudXBkYXRlQWxsKGJvZHksIGN0eCk7XG4gICAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICAgIGxvZy5lcnJvcihlIGFzIEVycm9yKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICAgIGlmIChyZXNwKSBjdHgudG9SZXNwb25zZShyZXNwKTtcbiAgICAgIHJldHVybiB1cGRhdGVkO1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVCdWxrRGVsZXRlSGFuZGxlcihtb2RlbENsYXp6TmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIGRlbGV0ZUFsbChcbiAgICAgIHRoaXM6IGFueSxcbiAgICAgIGlkczogc3RyaW5nW10sXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxNb2RlbFtdPiB7XG4gICAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSAoXG4gICAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KFtdLCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuREVMRVRFX0FMTCwgdHJ1ZSlcbiAgICAgICkuZm9yKGRlbGV0ZUFsbCk7XG4gICAgICBjb25zdCBub3JtYWxpemVkSWRzID0gQXJyYXkuaXNBcnJheShpZHMpID8gaWRzIDogW2lkc107XG4gICAgICBsZXQgcmVhZDogTW9kZWxbXTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGxvZy5kZWJ1ZyhgZGVsZXRpbmcgJHtub3JtYWxpemVkSWRzLmxlbmd0aH0gJHttb2RlbENsYXp6TmFtZX1gKTtcbiAgICAgICAgcmVhZCA9IGF3YWl0IHRoaXMucGVyc2lzdGVuY2UoY3R4KS5kZWxldGVBbGwobm9ybWFsaXplZElkcywgY3R4KTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gZGVsZXRlICR7bW9kZWxDbGF6ek5hbWV9YCwgZSBhcyBFcnJvcik7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgICBsb2cuaW5mbyhgZGVsZXRlZCAke3JlYWQubGVuZ3RofSAke21vZGVsQ2xhenpOYW1lfWApO1xuICAgICAgaWYgKHJlc3ApIGN0eC50b1Jlc3BvbnNlKHJlc3ApO1xuICAgICAgcmV0dXJuIHJlYWQ7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZVJlYWRIYW5kbGVyKFxuICAgIGdldFBLOiAoLi4ucDogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nLFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIHJlYWQoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICByb3V0ZVBhcmFtczogYW55XG4gICAgKTogUHJvbWlzZTxNb2RlbD4ge1xuICAgICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgT3BlcmF0aW9uS2V5cy5SRUFELCB0cnVlKVxuICAgICAgKS5mb3IocmVhZCk7XG4gICAgICBjb25zdCBpZCA9IGdldFBLKC4uLnJvdXRlUGFyYW1zLnZhbHVlc0luT3JkZXIpO1xuICAgICAgaWYgKHR5cGVvZiBpZCA9PT0gXCJ1bmRlZmluZWRcIilcbiAgICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihgTm8gJHt0aGlzLnBrfSBwcm92aWRlZGApO1xuICAgICAgbGV0IHJlYWRSZXN1bHQ6IE1vZGVsO1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmRlYnVnKGByZWFkaW5nICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggJHt0aGlzLnBrfSAke2lkfWApO1xuICAgICAgICByZWFkUmVzdWx0ID0gYXdhaXQgdGhpcy5wZXJzaXN0ZW5jZShjdHgpLnJlYWQoaWQsIGN0eCk7XG4gICAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICAgIGxvZy5lcnJvcihgRmFpbGVkIHRvIHJlYWQgJHttb2RlbENsYXp6TmFtZX0gd2l0aCBpZCAke2lkfWAsIGUgYXMgRXJyb3IpO1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgICAgbG9nLmluZm8oYHJlYWQgJHttb2RlbENsYXp6TmFtZX0gd2l0aCBpZCAkeyhyZWFkUmVzdWx0IGFzIGFueSlbdGhpcy5wa119YCk7XG4gICAgICByZXR1cm4gcmVhZFJlc3VsdDtcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlVXBkYXRlSGFuZGxlcihcbiAgICBnZXRQSzogKC4uLnA6IEFycmF5PHN0cmluZyB8IG51bWJlcj4pID0+IHN0cmluZyxcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIHVwZGF0ZShcbiAgICAgIHRoaXM6IGFueSxcbiAgICAgIHJvdXRlUGFyYW1zOiBhbnksXG4gICAgICBib2R5OiBhbnksXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgIGNvbnN0IHsgY3R4LCBsb2cgfSA9IChcbiAgICAgICAgYXdhaXQgdGhpcy5sb2dDdHgoW10sIE9wZXJhdGlvbktleXMuVVBEQVRFLCB0cnVlKVxuICAgICAgKS5mb3IodXBkYXRlKTtcbiAgICAgIGNvbnN0IGlkID0gZ2V0UEsoLi4ucm91dGVQYXJhbXMudmFsdWVzSW5PcmRlcik7XG4gICAgICBpZiAodHlwZW9mIGlkID09PSBcInVuZGVmaW5lZFwiKVxuICAgICAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKGBObyAke3RoaXMucGt9IHByb3ZpZGVkYCk7XG4gICAgICBsZXQgdXBkYXRlZDogYW55O1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmluZm8oYHVwZGF0aW5nICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggJHt0aGlzLnBrfSAke2lkfWApO1xuICAgICAgICBjb25zdCBwYXlsb2FkID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShib2R5KSk7XG4gICAgICAgIHVwZGF0ZWQgPSBhd2FpdCB0aGlzLnBlcnNpc3RlbmNlKGN0eCkudXBkYXRlKFxuICAgICAgICAgIG5ldyBNb2RlbENvbnN0cih7IC4uLnBheWxvYWQsIFt0aGlzLnBrXTogaWQgfSksXG4gICAgICAgICAgY3R4XG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICAgIGxvZy5lcnJvcihlIGFzIEVycm9yKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICAgIGlmIChyZXNwKSBjdHgudG9SZXNwb25zZShyZXNwKTtcbiAgICAgIHJldHVybiB1cGRhdGVkO1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVEZWxldGVIYW5kbGVyKFxuICAgIGdldFBLOiAoLi4ucDogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nLFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIHJlbW92ZShcbiAgICAgIHRoaXM6IGFueSxcbiAgICAgIHJvdXRlUGFyYW1zOiBhbnksXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxNb2RlbD4ge1xuICAgICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgT3BlcmF0aW9uS2V5cy5ERUxFVEUsIHRydWUpXG4gICAgICApLmZvcihyZW1vdmUpO1xuICAgICAgY29uc3QgaWQgPSBnZXRQSyguLi5yb3V0ZVBhcmFtcy52YWx1ZXNJbk9yZGVyKTtcbiAgICAgIGlmICh0eXBlb2YgaWQgPT09IFwidW5kZWZpbmVkXCIpXG4gICAgICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoYE5vICR7dGhpcy5wa30gcHJvdmlkZWRgKTtcbiAgICAgIGxldCBkZWw6IE1vZGVsO1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmRlYnVnKGBkZWxldGluZyAke21vZGVsQ2xhenpOYW1lfSB3aXRoICR7dGhpcy5wa30gJHtpZH1gKTtcbiAgICAgICAgZGVsID0gYXdhaXQgdGhpcy5wZXJzaXN0ZW5jZShjdHgpLmRlbGV0ZShpZCwgY3R4KTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gZGVsZXRlICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggaWQgJHtpZH1gLCBlIGFzIEVycm9yKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICAgIGxvZy5pbmZvKGBkZWxldGVkICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggaWQgJHtpZH1gKTtcbiAgICAgIGlmIChyZXNwKSBjdHgudG9SZXNwb25zZShyZXNwKTtcbiAgICAgIHJldHVybiBkZWw7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZVN0YXRlbWVudEhhbmRsZXIobW9kZWxDbGF6ek5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBhc3luYyBmdW5jdGlvbiBzdGF0ZW1lbnQoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICBuYW1lOiBzdHJpbmcsXG4gICAgICBhcmdzOiAoc3RyaW5nIHwgbnVtYmVyKVtdLFxuICAgICAgZGV0YWlsczogRGlyZWN0aW9uTGltaXRPZmZzZXRcbiAgICApOiBQcm9taXNlPGFueT4ge1xuICAgICAgY29uc3QgeyBjdHggfSA9IChcbiAgICAgICAgYXdhaXQgdGhpcy5sb2dDdHgoW10sIFBlcnNpc3RlbmNlS2V5cy5TVEFURU1FTlQsIHRydWUpXG4gICAgICApLmZvcihzdGF0ZW1lbnQpO1xuICAgICAgY29uc3QgeyBkaXJlY3Rpb24sIG9mZnNldCwgbGltaXQsIGJvb2ttYXJrIH0gPSBkZXRhaWxzO1xuICAgICAgYXJncyA9IGFyZ3MubWFwKFxuICAgICAgICAoYSkgPT4gKHR5cGVvZiBhID09PSBcInN0cmluZ1wiID8gcGFyc2VJbnQoYSBhcyBzdHJpbmcpIDogYSkgfHwgYVxuICAgICAgKSBhcyBhbnlbXTtcbiAgICAgIGNvbnN0IHBhdGhEaXJlY3Rpb24gPSBhcmdzLmxlbmd0aCA+IDEgPyBhcmdzWzFdIDogdW5kZWZpbmVkO1xuICAgICAgY29uc3QgcmVzb2x2ZWREaXJlY3Rpb24gPSAoZGlyZWN0aW9uID8/IHBhdGhEaXJlY3Rpb24pIGFzXG4gICAgICAgIHwgc3RyaW5nXG4gICAgICAgIHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKHJlc29sdmVkRGlyZWN0aW9uICYmIGFyZ3MubGVuZ3RoID4gMSkgYXJnc1sxXSA9IHJlc29sdmVkRGlyZWN0aW9uO1xuICAgICAgc3dpdGNoIChuYW1lKSB7XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkQ6XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkRfQlk6XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkxJU1RfQlk6XG4gICAgICAgICAgYXJncy5wdXNoKGRpcmVjdGlvbiBhcyBzdHJpbmcpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5QQUdFOlxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5QQUdFX0JZOlxuICAgICAgICAgIGFyZ3MgPSBbXG4gICAgICAgICAgICBhcmdzWzBdLFxuICAgICAgICAgICAgcmVzb2x2ZWREaXJlY3Rpb24gYXMgYW55LFxuICAgICAgICAgICAgeyBsaW1pdCwgb2Zmc2V0LCBib29rbWFyayB9LFxuICAgICAgICAgIF07XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkRfT05FX0JZOlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRjpcbiAgICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUFYX09GOlxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5NSU5fT0Y6XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkFWR19PRjpcbiAgICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GOlxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5ESVNUSU5DVF9PRjpcbiAgICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuR1JPVVBfT0Y6XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5wZXJzaXN0ZW5jZShjdHgpLnN0YXRlbWVudChuYW1lLCAuLi5hcmdzLCBjdHgpO1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVTdGF0ZW1lbnRTaG9ydGN1dEhhbmRsZXIoXG4gICAgc3RhdGVtZW50S2V5OiBzdHJpbmcsXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gc3RhdGVtZW50U2hvcnRjdXQoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICAuLi5hcmdzOiBhbnlbXVxuICAgICk6IFByb21pc2U8YW55PiB7XG4gICAgICBjb25zdCB7IGN0eCB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgc3RhdGVtZW50S2V5LCB0cnVlKVxuICAgICAgKS5mb3Ioc3RhdGVtZW50U2hvcnRjdXQpO1xuXG4gICAgICBzd2l0Y2ggKHN0YXRlbWVudEtleSkge1xuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5MSVNUX0JZOiB7XG4gICAgICAgICAgY29uc3QgW2tleSwgZGV0YWlsc10gPSBhcmdzO1xuICAgICAgICAgIHJldHVybiB0aGlzLnBlcnNpc3RlbmNlKGN0eCkubGlzdEJ5KFxuICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgKGRldGFpbHMgYXMgYW55KT8uZGlyZWN0aW9uIGFzIE9yZGVyRGlyZWN0aW9uLFxuICAgICAgICAgICAgY3R4XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5QQUdFX0JZOiB7XG4gICAgICAgICAgY29uc3QgW2tleSwgcGFnZSwgZGV0YWlsc10gPSBhcmdzO1xuICAgICAgICAgIHJldHVybiB0aGlzLnBlcnNpc3RlbmNlKGN0eCkucGFnaW5hdGVCeShcbiAgICAgICAgICAgIGtleSxcbiAgICAgICAgICAgIChkZXRhaWxzIGFzIGFueSk/LmRpcmVjdGlvbiBhcyBPcmRlckRpcmVjdGlvbixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgbGltaXQ6IChkZXRhaWxzIGFzIGFueSk/LmxpbWl0LFxuICAgICAgICAgICAgICBvZmZzZXQ6IChkZXRhaWxzIGFzIGFueSk/Lm9mZnNldCxcbiAgICAgICAgICAgICAgcGFnZSxcbiAgICAgICAgICAgIH0gYXMgYW55LFxuICAgICAgICAgICAgY3R4XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EOiB7XG4gICAgICAgICAgY29uc3QgW3ZhbHVlLCBkZXRhaWxzXSA9IGFyZ3M7XG4gICAgICAgICAgY29uc3QgZGlyZWN0aW9uID1cbiAgICAgICAgICAgIChkZXRhaWxzIGFzIGFueSk/LmRpcmVjdGlvbiA/PyBPcmRlckRpcmVjdGlvbi5BU0M7XG4gICAgICAgICAgY29uc3QgcGVyc2lzdGVuY2UgPSB0aGlzLnBlcnNpc3RlbmNlKGN0eCk7XG4gICAgICAgICAgaWYgKHR5cGVvZiBwZXJzaXN0ZW5jZS5maW5kID09PSBcImZ1bmN0aW9uXCIpXG4gICAgICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2UuZmluZCh2YWx1ZSwgZGlyZWN0aW9uLCBjdHgpO1xuICAgICAgICAgIHJldHVybiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQoUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkQsIHZhbHVlLCBkaXJlY3Rpb24sIGN0eCk7XG4gICAgICAgIH1cbiAgICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRToge1xuICAgICAgICAgIGNvbnN0IFt2YWx1ZSwgZGV0YWlsc10gPSBhcmdzO1xuICAgICAgICAgIGNvbnN0IHJlZiA9IHtcbiAgICAgICAgICAgIG9mZnNldDogKGRldGFpbHMgYXMgYW55KT8ub2Zmc2V0ID8/IDEsXG4gICAgICAgICAgICBsaW1pdDogKGRldGFpbHMgYXMgYW55KT8ubGltaXQgPz8gMTAsXG4gICAgICAgICAgICBib29rbWFyazogKGRldGFpbHMgYXMgYW55KT8uYm9va21hcmssXG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zdCBwZXJzaXN0ZW5jZSA9IHRoaXMucGVyc2lzdGVuY2UoY3R4KTtcbiAgICAgICAgICBjb25zdCBkaXJlY3Rpb24gPSAoZGV0YWlscyBhcyBhbnkpPy5kaXJlY3Rpb24gPz8gT3JkZXJEaXJlY3Rpb24uQVNDO1xuICAgICAgICAgIGlmICh0eXBlb2YgcGVyc2lzdGVuY2UucGFnZSA9PT0gXCJmdW5jdGlvblwiKVxuICAgICAgICAgICAgcmV0dXJuIHBlcnNpc3RlbmNlLnBhZ2UodmFsdWUsIGRpcmVjdGlvbiwgcmVmLCBjdHgpO1xuICAgICAgICAgIHJldHVybiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQoUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlBBR0UsIHZhbHVlLCBkaXJlY3Rpb24sIHJlZiwgY3R4KTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWToge1xuICAgICAgICAgIGNvbnN0IFtrZXksIHZhbHVlXSA9IGFyZ3M7XG4gICAgICAgICAgcmV0dXJuIHRoaXMucGVyc2lzdGVuY2UoY3R4KS5maW5kT25lQnkoa2V5LCB2YWx1ZSwgY3R4KTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZOiB7XG4gICAgICAgICAgY29uc3QgW2tleSwgdmFsdWVdID0gYXJncztcbiAgICAgICAgICByZXR1cm4gdGhpcy5wZXJzaXN0ZW5jZShjdHgpXG4gICAgICAgICAgICAuZm9yKGN0eC50b092ZXJyaWRlcygpKVxuICAgICAgICAgICAgLmZpbmRCeShrZXksIHZhbHVlLCBjdHgpO1xuICAgICAgICB9XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuQ09VTlRfT0YgfHxcbiAgICAgICAgICAgIHN0YXRlbWVudEtleSA9PT0gUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLk1BWF9PRiB8fFxuICAgICAgICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUlOX09GIHx8XG4gICAgICAgICAgICBzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5BVkdfT0YgfHxcbiAgICAgICAgICAgIHN0YXRlbWVudEtleSA9PT0gUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlNVTV9PRiB8fFxuICAgICAgICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuRElTVElOQ1RfT0YgfHxcbiAgICAgICAgICAgIHN0YXRlbWVudEtleSA9PT0gUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkdST1VQX09GXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCBbZmllbGRdID0gYXJncztcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBlcnNpc3RlbmNlKGN0eCkuc3RhdGVtZW50KHN0YXRlbWVudEtleSwgZmllbGQsIGN0eCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBzdGF0ZW1lbnQ6ICR7c3RhdGVtZW50S2V5fWApO1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVDb21wbGV4UXVlcnlIYW5kbGVyKG1ldGhvZE5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBhc3luYyBmdW5jdGlvbiBjb21wbGV4UXVlcnkoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICAuLi5hcmdzOiBhbnlbXVxuICAgICk6IFByb21pc2U8YW55PiB7XG4gICAgICBjb25zdCBsb2c6IGFueSA9IHRoaXMubG9nPy5mb3I/Lihjb21wbGV4UXVlcnkpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKGxvZykgbG9nLmRlYnVnKGBJbnZva2luZyBjdXN0b20gcXVlcnkgXCIke21ldGhvZE5hbWV9XCJgKTtcbiAgICAgICAgY29uc3QgeyBjdHggfSA9IChcbiAgICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgbWV0aG9kTmFtZSwgdHJ1ZSlcbiAgICAgICAgKS5mb3IoY29tcGxleFF1ZXJ5KTtcbiAgICAgICAgY29uc3QgcGVyc2lzdGVuY2UgPSB0aGlzLnBlcnNpc3RlbmNlKGN0eCk7XG4gICAgICAgIGNvbnN0IHNwcmVhZEFyZ3MgPSBGcm9tTW9kZWxDb250cm9sbGVyLmV4dHJhY3RRdWVyeUFyZ3MoYXJncyk7XG4gICAgICAgIGlmICh0eXBlb2YgcGVyc2lzdGVuY2VbbWV0aG9kTmFtZV0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgIHJldHVybiBwZXJzaXN0ZW5jZVttZXRob2ROYW1lXSguLi5zcHJlYWRBcmdzLCBjdHgpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgcGVyc2lzdGVuY2Uuc3RhdGVtZW50ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2Uuc3RhdGVtZW50KG1ldGhvZE5hbWUsIC4uLnNwcmVhZEFyZ3MsIGN0eCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBQZXJzaXN0ZW5jZSBtZXRob2QgXCIke21ldGhvZE5hbWV9XCIgbm90IGZvdW5kIG9uICR7cGVyc2lzdGVuY2U/LmNvbnN0cnVjdG9yPy5uYW1lfWBcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICBpZiAobG9nKSBsb2cuZXJyb3IoYEN1c3RvbSBxdWVyeSBcIiR7bWV0aG9kTmFtZX1cIiBmYWlsZWRgLCBlKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlQ3VzdG9tUm91dGVIYW5kbGVyKG1ldGhvZE5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBhc3luYyBmdW5jdGlvbiBjdXN0b21Sb3V0ZShcbiAgICAgIHRoaXM6IGFueSxcbiAgICAgIC4uLmFyZ3M6IGFueVtdXG4gICAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgIGNvbnN0IGxvZzogYW55ID0gdGhpcy5sb2c/LmZvcj8uKGN1c3RvbVJvdXRlKTtcbiAgICAgIGNvbnN0IHsgY3R4IH0gPSAoXG4gICAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KFtdLCBtZXRob2ROYW1lLCB0cnVlKVxuICAgICAgKS5mb3IoY3VzdG9tUm91dGUpO1xuICAgICAgY29uc3QgcGVyc2lzdGVuY2UgPSB0aGlzLnBlcnNpc3RlbmNlKGN0eCk7XG4gICAgICBjb25zdCBzcHJlYWRBcmdzID0gRnJvbU1vZGVsQ29udHJvbGxlci5leHRyYWN0UXVlcnlBcmdzKGFyZ3MpO1xuXG4gICAgICAvLyBUcnkgdGhlIHBlcnNpc3RlbmNlIGRpcmVjdGx5ICh3b3JrcyB3aGVuIGl0J3MgYSBjdXN0b20gUmVwb3NpdG9yeSlcbiAgICAgIGlmICh0eXBlb2YgcGVyc2lzdGVuY2VbbWV0aG9kTmFtZV0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2VbbWV0aG9kTmFtZV0oLi4uc3ByZWFkQXJncywgY3R4KTtcbiAgICAgIH1cbiAgICAgIC8vIFdoZW4gcGVyc2lzdGVuY2UgaXMgYSBNb2RlbFNlcnZpY2UsIHRoZSBtZXRob2QgbGl2ZXMgb24gdGhlIHVuZGVybHlpbmcgcmVwb1xuICAgICAgaWYgKHBlcnNpc3RlbmNlPy5yZXBvICYmIHR5cGVvZiBwZXJzaXN0ZW5jZS5yZXBvW21ldGhvZE5hbWVdID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuIHBlcnNpc3RlbmNlLnJlcG9bbWV0aG9kTmFtZV0oLi4uc3ByZWFkQXJncywgY3R4KTtcbiAgICAgIH1cbiAgICAgIC8vIEZhbGwgYmFjayB0byBzdGF0ZW1lbnQgZ2F0ZXdheVxuICAgICAgaWYgKHR5cGVvZiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2Uuc3RhdGVtZW50KG1ldGhvZE5hbWUsIC4uLnNwcmVhZEFyZ3MsIGN0eCk7XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBNZXRob2QgXCIke21ldGhvZE5hbWV9XCIgbm90IGZvdW5kIG9uICR7cGVyc2lzdGVuY2U/LmNvbnN0cnVjdG9yPy5uYW1lfSBvciBpdHMgcmVwb2BcbiAgICAgICk7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGV4dHJhY3RRdWVyeUFyZ3MoYXJnczogYW55W10pOiBhbnlbXSB7XG4gICAgaWYgKGFyZ3MubGVuZ3RoID09PSAwKSByZXR1cm4gYXJncztcbiAgICBjb25zdCBsYXN0ID0gYXJnc1thcmdzLmxlbmd0aCAtIDFdO1xuICAgIGlmIChcbiAgICAgIGxhc3QgJiZcbiAgICAgIHR5cGVvZiBsYXN0ID09PSBcIm9iamVjdFwiICYmXG4gICAgICAhQXJyYXkuaXNBcnJheShsYXN0KVxuICAgICkge1xuICAgICAgY29uc3QgcXVlcnlPYmogPSBhcmdzLnBvcCgpO1xuICAgICAgY29uc3QgaGFzRGlyZWN0aW9uID0gcXVlcnlPYmouZGlyZWN0aW9uICE9PSB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBoYXNMaW1pdCA9IHF1ZXJ5T2JqLmxpbWl0ICE9PSB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBoYXNPZmZzZXQgPSBxdWVyeU9iai5vZmZzZXQgIT09IHVuZGVmaW5lZDtcbiAgICAgIGlmICghaGFzRGlyZWN0aW9uICYmICFoYXNMaW1pdCAmJiAhaGFzT2Zmc2V0KSByZXR1cm4gYXJncztcbiAgICAgIGNvbnN0IGV4dHJhczogYW55W10gPSBbXTtcbiAgICAgIGlmIChoYXNEaXJlY3Rpb24pIGV4dHJhcy5wdXNoKHF1ZXJ5T2JqLmRpcmVjdGlvbik7XG4gICAgICBlbHNlIGlmIChoYXNMaW1pdCB8fCBoYXNPZmZzZXQpIGV4dHJhcy5wdXNoKHVuZGVmaW5lZCk7XG4gICAgICBpZiAoaGFzTGltaXQpIGV4dHJhcy5wdXNoKHF1ZXJ5T2JqLmxpbWl0KTtcbiAgICAgIGlmIChoYXNPZmZzZXQpIGV4dHJhcy5wdXNoKHF1ZXJ5T2JqLm9mZnNldCk7XG4gICAgICByZXR1cm4gWy4uLmFyZ3MsIC4uLmV4dHJhc107XG4gICAgfVxuICAgIHJldHVybiBhcmdzO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlQ3JlYXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJQT1NUXCIpLFxuICAgICAgQXBpT3BlcmF0aW9uKHsgc3VtbWFyeTogYENyZWF0ZSBhIG5ldyAke21vZGVsQ2xhenpOYW1lfS5gIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgJHttb2RlbENsYXp6TmFtZX1gLFxuICAgICAgICB0eXBlOiBEdG9Gb3IoT3BlcmF0aW9uS2V5cy5DUkVBVEUsIE1vZGVsQ29uc3RyKSxcbiAgICAgIH0pLFxuICAgICAgQXBpQ3JlYXRlZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSBjcmVhdGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpQmFkUmVxdWVzdFJlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiUGF5bG9hZCB2YWxpZGF0aW9uIGZhaWxlZC5cIiB9KSxcbiAgICAgIEFwaVVucHJvY2Vzc2FibGVFbnRpdHlSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIlJlcG9zaXRvcnkgcmVqZWN0ZWQgdGhlIHByb3ZpZGVkIHBheWxvYWQuXCIsXG4gICAgICB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgYnVsa0NyZWF0ZURlY29yYXRvcnMoXG4gICAgTW9kZWxDb25zdHI6IE1vZGVsQ29uc3RydWN0b3I8YW55PixcbiAgICBtb2RlbENsYXp6TmFtZTogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiUE9TVFwiLCBcImJ1bGtcIiksXG4gICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgQ3JlYXRlIGEgbmV3ICR7bW9kZWxDbGF6ek5hbWV9LmAgfSksXG4gICAgICBBcGlCb2R5KHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBQYXlsb2FkIGZvciAke21vZGVsQ2xhenpOYW1lfWAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlDcmVhdGVkUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlCYWRSZXF1ZXN0UmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJQYXlsb2FkIHZhbGlkYXRpb24gZmFpbGVkLlwiIH0pLFxuICAgICAgQXBpVW5wcm9jZXNzYWJsZUVudGl0eVJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IFwiUmVwb3NpdG9yeSByZWplY3RlZCB0aGUgcHJvdmlkZWQgcGF5bG9hZC5cIixcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrUmVhZERlY29yYXRvcnMoXG4gICAgTW9kZWxDb25zdHI6IE1vZGVsQ29uc3RydWN0b3I8YW55PixcbiAgICBtb2RlbENsYXp6TmFtZTogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiR0VUXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBSZXRyaWV2ZSAke21vZGVsQ2xhenpOYW1lfSByZWNvcmRzIGJ5IGlkcy5gIH0pLFxuICAgICAgQXBpUXVlcnkoeyBuYW1lOiBcImlkc1wiLCByZXF1aXJlZDogdHJ1ZSwgdHlwZTogXCJhcnJheVwiIH0pLFxuICAgICAgQXBpT2tSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHttb2RlbENsYXp6TmFtZX0gcmV0cmlldmVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHtcbiAgICAgICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICAgICAgaXRlbXM6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrVXBkYXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiUFVUXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7XG4gICAgICAgIHN1bW1hcnk6IGBSZXBsYWNlIGV4aXN0aW5nICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZHMgd2l0aCBuZXcgcGF5bG9hZHMuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgcmVwbGFjaW5nIGV4aXN0aW5nIHJlY29yZHMgb2YgJHttb2RlbENsYXp6TmFtZX1gLFxuICAgICAgICBzY2hlbWE6IHtcbiAgICAgICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICAgICAgJHJlZjogZ2V0U2NoZW1hUGF0aChEdG9Gb3IoT3BlcmF0aW9uS2V5cy5VUERBVEUsIE1vZGVsQ29uc3RyKSksXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IHVwZGF0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlOb3RGb3VuZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgfSksXG4gICAgICBBcGlCYWRSZXF1ZXN0UmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJQYXlsb2FkIHZhbGlkYXRpb24gZmFpbGVkLlwiIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrRGVsZXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiREVMRVRFXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBEZWxldGUgJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkcyBieSBpZHMuYCB9KSxcbiAgICAgIEFwaVF1ZXJ5KHsgbmFtZTogXCJpZHNcIiwgcmVxdWlyZWQ6IHRydWUsIHR5cGU6IFwiYXJyYXlcIiB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IGRlbGV0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlOb3RGb3VuZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgfSksXG4gICAgXTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHJlYWREZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10sXG4gICAgcGtQYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJHRVRcIiwgcGtQYXRoKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBSZXRyaWV2ZSBhICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZCBieSBpZC5gIH0pLFxuICAgICAgQXBpT2tSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHttb2RlbENsYXp6TmFtZX0gcmV0cmlldmVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyB1cGRhdGVEZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10sXG4gICAgcGtQYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJQVVRcIiwgcGtQYXRoKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7XG4gICAgICAgIHN1bW1hcnk6IGBSZXBsYWNlIGFuIGV4aXN0aW5nICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZCB3aXRoIGEgbmV3IHBheWxvYWQuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgcmVwbGFjaW5nIGFuIGV4aXN0aW5nIHJlY29yZCBvZiAke21vZGVsQ2xhenpOYW1lfWAsXG4gICAgICAgIHR5cGU6IER0b0ZvcihPcGVyYXRpb25LZXlzLlVQREFURSwgTW9kZWxDb25zdHIpLFxuICAgICAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSB1cGRhdGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQmFkUmVxdWVzdFJlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiUGF5bG9hZCB2YWxpZGF0aW9uIGZhaWxlZC5cIiB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZGVsZXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdLFxuICAgIHBrUGF0aDogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiREVMRVRFXCIsIHBrUGF0aCksXG4gICAgICBBcGlQYXJhbXNGcm9tTW9kZWwoYXBpUHJvcGVydGllcyksXG4gICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgRGVsZXRlIGEgJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIGJ5IGlkLmAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSBkZWxldGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBzdGF0ZW1lbnREZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+IHtcbiAgICByZXR1cm4gW1xuICAgICAgQXBpT3BlcmF0aW9uRnJvbU1vZGVsKE1vZGVsQ29uc3RyLCBcIkdFVFwiLCBcInN0YXRlbWVudC86bWV0aG9kLyphcmdzXCIpLFxuICAgICAgQXBpT3BlcmF0aW9uKHtcbiAgICAgICAgc3VtbWFyeTogYEV4ZWN1dGVzIGEgcHJlcGFyZWQgc3RhdGVtZW50IG9uICR7bW9kZWxDbGF6ek5hbWV9LmAsXG4gICAgICB9KSxcbiAgICAgIEFwaVBhcmFtKHsgbmFtZTogXCJtZXRob2RcIiwgZGVzY3JpcHRpb246IFwidGhlIHByZXBhcmVkIHN0YXRlbWVudCB0byBleGVjdXRlXCIgfSksXG4gICAgICBBcGlQYXJhbSh7XG4gICAgICAgIG5hbWU6IFwiYXJnc1wiLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJjb25jYXRlbmF0ZWQgbGlzdCBvZiBhcmd1bWVudHMgdGhlIHByZXBhcmVkIHN0YXRlbWVudCBjYW4gYWNjZXB0XCIsXG4gICAgICB9KSxcbiAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgbmFtZTogXCJkaXJlY3Rpb25cIixcbiAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgIGVudW06IE9yZGVyRGlyZWN0aW9uLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJ0aGUgc29ydCBvcmRlciB3aGVuIGFwcGxpY2FibGVcIixcbiAgICAgIH0pLFxuICAgICAgQXBpUXVlcnkoeyBuYW1lOiBcImxpbWl0XCIsIHJlcXVpcmVkOiB0cnVlLCBkZXNjcmlwdGlvbjogXCJsaW1pdCBvciBwYWdlIHNpemUgd2hlbiBhcHBsaWNhYmxlXCIgfSksXG4gICAgICBBcGlRdWVyeSh7IG5hbWU6IFwib2Zmc2V0XCIsIHJlcXVpcmVkOiB0cnVlLCBkZXNjcmlwdGlvbjogXCJvZmZzZXQgb3IgYm9va21hcmsgd2hlbiBhcHBsaWNhYmxlXCIgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHsgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSBsaXN0ZWQgZm91bmQuYCB9KSxcbiAgICAgIEFwaU5vdEZvdW5kUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYE5vICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZCBtYXRjaGVzIHRoZSBwcm92aWRlZCBpZGVudGlmaWVyLmAsXG4gICAgICB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgc3RhdGVtZW50U2hvcnRjdXREZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgc3RhdGVtZW50S2V5OiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgY29uc3QgYmFzZTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiA9IFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJHRVRcIiwgcGF0aCksXG4gICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgUmV0cmlldmUgJHttb2RlbENsYXp6TmFtZX0gcmVjb3Jkcy5gIH0pLFxuICAgICAgQXBpT2tSZXNwb25zZSh7IGRlc2NyaXB0aW9uOiBgJHttb2RlbENsYXp6TmFtZX0gcmV0cmlldmVkIHN1Y2Nlc3NmdWxseS5gIH0pLFxuICAgIF07XG5cbiAgICBjb25zdCBzZWdtZW50cyA9IHBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcigocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSk7XG4gICAgc2VnbWVudHMuZm9yRWFjaCgoc2VnKSA9PiB7XG4gICAgICBjb25zdCBuYW1lID0gc2VnLnJlcGxhY2UoXCI6XCIsIFwiXCIpO1xuICAgICAgYmFzZS5wdXNoKEFwaVBhcmFtKHsgbmFtZSwgZGVzY3JpcHRpb246IGBUaGUgJHtuYW1lfSBwYXJhbWV0ZXJgIH0pKTtcbiAgICB9KTtcblxuICAgIGlmIChcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcImxpc3RCeS9cIikgfHxcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcInBhZ2luYXRlQnkvXCIpIHx8XG4gICAgICBwYXRoLnN0YXJ0c1dpdGgoXCJmaW5kL1wiKSB8fFxuICAgICAgcGF0aC5zdGFydHNXaXRoKFwicGFnZS9cIilcbiAgICApIHtcbiAgICAgIGJhc2UucHVzaChcbiAgICAgICAgQXBpUXVlcnkoe1xuICAgICAgICAgIG5hbWU6IFwiZGlyZWN0aW9uXCIsXG4gICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgICAgZW51bTogT3JkZXJEaXJlY3Rpb24sXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwidGhlIHNvcnQgb3JkZXJcIixcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCJwYWdpbmF0ZUJ5L1wiKSB8fCBwYXRoLnN0YXJ0c1dpdGgoXCJwYWdlL1wiKSkge1xuICAgICAgYmFzZS5wdXNoKFxuICAgICAgICBBcGlRdWVyeSh7IG5hbWU6IFwibGltaXRcIiwgcmVxdWlyZWQ6IGZhbHNlLCBkZXNjcmlwdGlvbjogXCJwYWdlIHNpemVcIiB9KSxcbiAgICAgICAgQXBpUXVlcnkoeyBuYW1lOiBcIm9mZnNldFwiLCByZXF1aXJlZDogZmFsc2UsIGRlc2NyaXB0aW9uOiBcInBhZ2UgbnVtYmVyXCIgfSksXG4gICAgICAgIEFwaVF1ZXJ5KHsgbmFtZTogXCJib29rbWFya1wiLCByZXF1aXJlZDogZmFsc2UsIGRlc2NyaXB0aW9uOiBcImJvb2ttYXJrIGZvciBjdXJzb3IgcGFnaW5hdGlvblwiIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCJmaW5kT25lQnkvXCIpIHx8IHBhdGguc3RhcnRzV2l0aChcImZpbmRCeS9cIikpIHtcbiAgICAgIGJhc2UucHVzaChcbiAgICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRiB8fFxuICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuQVZHX09GIHx8XG4gICAgICBzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5TVU1fT0ZcbiAgICApIHtcbiAgICAgIGJhc2UucHVzaChBcGlPa1Jlc3BvbnNlKHsgZGVzY3JpcHRpb246IGBSZXN1bHQgZm9yICR7bW9kZWxDbGF6ek5hbWV9LmAsIHR5cGU6IE51bWJlciB9KSk7XG4gICAgfVxuICAgIGlmIChzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5ESVNUSU5DVF9PRikge1xuICAgICAgYmFzZS5wdXNoKEFwaU9rUmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogYERpc3RpbmN0IHZhbHVlcyBmb3IgJHttb2RlbENsYXp6TmFtZX0uYCwgdHlwZTogW1N0cmluZ10gfSkpO1xuICAgIH1cblxuICAgIHJldHVybiBiYXNlO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0UXVlcnlEZWNvcmF0b3JzKFxuICAgIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgICByb3V0ZVBhdGg6IHN0cmluZyxcbiAgICBodHRwVmVyYjogc3RyaW5nLFxuICAgIGluY2x1ZGVRdWVyeVBhcmFtczogYm9vbGVhbiA9IGZhbHNlXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIGNvbnN0IGV4dHJhY3RQYXRoUGFyYW1zID0gKHA6IHN0cmluZyk6IHN0cmluZ1tdID0+XG4gICAgICBwLnNwbGl0KFwiL1wiKS5maWx0ZXIoKHMpID0+IHMuc3RhcnRzV2l0aChcIjpcIikpLm1hcCgocykgPT4gcy5zbGljZSgxKSk7XG5cbiAgICBjb25zdCBhcGlQYXRoUGFyYW1zID0gZXh0cmFjdFBhdGhQYXJhbXMocm91dGVQYXRoKS5tYXAoKG5hbWUpID0+ICh7XG4gICAgICBuYW1lLFxuICAgICAgZGVzY3JpcHRpb246IGAke25hbWV9IHBhcmFtZXRlciBmb3IgdGhlIHF1ZXJ5YCxcbiAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgICAgdHlwZTogU3RyaW5nLFxuICAgIH0pKTtcblxuICAgIGNvbnN0IGRlY29yYXRvcnM6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4gPSBbXG4gICAgICAuLi5hcGlQYXRoUGFyYW1zLm1hcCgocCkgPT4gQXBpUGFyYW0ocCkpLFxuICAgICAgQXBpT3BlcmF0aW9uKHsgc3VtbWFyeTogYFJldHJpZXZlIHJlY29yZHMgdXNpbmcgXCIke21ldGhvZE5hbWV9XCIuYCB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJSZXN1bHQgc3VjY2Vzc2Z1bGx5IHJldHJpZXZlZC5cIiB9KSxcbiAgICAgIEFwaU5vQ29udGVudFJlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiTm8gY29udGVudCByZXR1cm5lZCBieSB0aGUgbWV0aG9kLlwiIH0pLFxuICAgIF07XG5cbiAgICBpZiAoaHR0cFZlcmIgPT09IFwiR0VUXCIgJiYgaW5jbHVkZVF1ZXJ5UGFyYW1zKSB7XG4gICAgICBkZWNvcmF0b3JzLnB1c2goXG4gICAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgICBuYW1lOiBcImRpcmVjdGlvblwiLFxuICAgICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgICBlbnVtOiBPcmRlckRpcmVjdGlvbixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJ0aGUgc29ydCBvcmRlciB3aGVuIGFwcGxpY2FibGVcIixcbiAgICAgICAgfSksXG4gICAgICAgIEFwaVF1ZXJ5KHsgbmFtZTogXCJsaW1pdFwiLCByZXF1aXJlZDogZmFsc2UsIGRlc2NyaXB0aW9uOiBcImxpbWl0IG9yIHBhZ2Ugc2l6ZVwiIH0pLFxuICAgICAgICBBcGlRdWVyeSh7IG5hbWU6IFwib2Zmc2V0XCIsIHJlcXVpcmVkOiBmYWxzZSwgZGVzY3JpcHRpb246IFwib2Zmc2V0IG9yIGJvb2ttYXJrXCIgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlY29yYXRvcnM7XG4gIH1cbn1cbiJdfQ==