velocious 1.0.431 → 1.0.433

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 (794) hide show
  1. package/build/application.js +229 -0
  2. package/build/authorization/ability.js +329 -0
  3. package/build/authorization/base-resource.js +143 -0
  4. package/build/background-jobs/client.js +50 -0
  5. package/build/background-jobs/cron-expression.js +277 -0
  6. package/build/background-jobs/forked-runner-child.js +86 -0
  7. package/build/background-jobs/job-record.js +13 -0
  8. package/build/background-jobs/job-registry.js +92 -0
  9. package/build/background-jobs/job-runner.js +107 -0
  10. package/build/background-jobs/job.js +77 -0
  11. package/build/background-jobs/json-socket.js +78 -0
  12. package/build/background-jobs/main.js +926 -0
  13. package/build/background-jobs/normalize-error.js +26 -0
  14. package/build/background-jobs/scheduler.js +274 -0
  15. package/build/background-jobs/socket-request.js +68 -0
  16. package/build/background-jobs/status-reporter.js +101 -0
  17. package/build/background-jobs/store.js +994 -0
  18. package/build/background-jobs/types.js +70 -0
  19. package/build/background-jobs/web/authorization.js +89 -0
  20. package/build/background-jobs/web/controller.js +280 -0
  21. package/build/background-jobs/web/index.js +57 -0
  22. package/build/background-jobs/web/path-matcher.js +74 -0
  23. package/build/background-jobs/web/registry.js +49 -0
  24. package/build/background-jobs/worker.js +683 -0
  25. package/build/beacon/client.js +330 -0
  26. package/build/beacon/in-process-broker.js +71 -0
  27. package/build/beacon/in-process-client.js +139 -0
  28. package/build/beacon/server.js +148 -0
  29. package/build/beacon/types.js +55 -0
  30. package/build/cli/base-command.js +67 -0
  31. package/build/cli/browser-cli.js +45 -0
  32. package/build/cli/commands/background-jobs-main.js +7 -0
  33. package/build/cli/commands/background-jobs-runner.js +7 -0
  34. package/build/cli/commands/background-jobs-worker.js +7 -0
  35. package/build/cli/commands/beacon.js +7 -0
  36. package/build/cli/commands/console.js +12 -0
  37. package/build/cli/commands/db/base-command.js +82 -0
  38. package/build/cli/commands/db/create.js +64 -0
  39. package/build/cli/commands/db/drop.js +75 -0
  40. package/build/cli/commands/db/migrate.js +17 -0
  41. package/build/cli/commands/db/reset.js +22 -0
  42. package/build/cli/commands/db/rollback.js +15 -0
  43. package/build/cli/commands/db/schema/dump.js +12 -0
  44. package/build/cli/commands/db/schema/load.js +12 -0
  45. package/build/cli/commands/db/seed.js +12 -0
  46. package/build/cli/commands/db/tenants/check.js +38 -0
  47. package/build/cli/commands/db/tenants/create.js +33 -0
  48. package/build/cli/commands/db/tenants/migrate.js +49 -0
  49. package/build/cli/commands/destroy/migration.js +7 -0
  50. package/build/cli/commands/generate/base-models.js +7 -0
  51. package/build/cli/commands/generate/frontend-models.js +12 -0
  52. package/build/cli/commands/generate/migration.js +7 -0
  53. package/build/cli/commands/generate/model.js +7 -0
  54. package/build/cli/commands/init.js +11 -0
  55. package/build/cli/commands/routes.js +7 -0
  56. package/build/cli/commands/run-script.js +12 -0
  57. package/build/cli/commands/runner.js +12 -0
  58. package/build/cli/commands/server.js +7 -0
  59. package/build/cli/commands/test.js +9 -0
  60. package/build/cli/index.js +152 -0
  61. package/build/cli/tenant-database-command-helper.js +198 -0
  62. package/build/cli/use-browser-cli.js +30 -0
  63. package/build/configuration-resolver.js +65 -0
  64. package/build/configuration-types.js +429 -0
  65. package/build/configuration.js +2590 -0
  66. package/build/controller.js +421 -0
  67. package/build/current-configuration.js +31 -0
  68. package/build/current.js +80 -0
  69. package/build/database/annotations-async-hooks.js +47 -0
  70. package/build/database/annotations.js +40 -0
  71. package/build/database/drivers/base-column.js +182 -0
  72. package/build/database/drivers/base-columns-index.js +81 -0
  73. package/build/database/drivers/base-foreign-key.js +104 -0
  74. package/build/database/drivers/base-table.js +156 -0
  75. package/build/database/drivers/base.js +1609 -0
  76. package/build/database/drivers/mssql/column.js +74 -0
  77. package/build/database/drivers/mssql/columns-index.js +6 -0
  78. package/build/database/drivers/mssql/connect-connection.js +16 -0
  79. package/build/database/drivers/mssql/foreign-key.js +12 -0
  80. package/build/database/drivers/mssql/index.js +590 -0
  81. package/build/database/drivers/mssql/options.js +79 -0
  82. package/build/database/drivers/mssql/query-parser.js +6 -0
  83. package/build/database/drivers/mssql/sql/alter-table.js +4 -0
  84. package/build/database/drivers/mssql/sql/create-database.js +36 -0
  85. package/build/database/drivers/mssql/sql/create-index.js +4 -0
  86. package/build/database/drivers/mssql/sql/create-table.js +4 -0
  87. package/build/database/drivers/mssql/sql/delete.js +19 -0
  88. package/build/database/drivers/mssql/sql/drop-database.js +36 -0
  89. package/build/database/drivers/mssql/sql/drop-table.js +4 -0
  90. package/build/database/drivers/mssql/sql/insert.js +4 -0
  91. package/build/database/drivers/mssql/sql/update.js +31 -0
  92. package/build/database/drivers/mssql/sql/upsert.js +23 -0
  93. package/build/database/drivers/mssql/structure-sql.js +120 -0
  94. package/build/database/drivers/mssql/table.js +145 -0
  95. package/build/database/drivers/mysql/column.js +112 -0
  96. package/build/database/drivers/mysql/columns-index.js +22 -0
  97. package/build/database/drivers/mysql/foreign-key.js +12 -0
  98. package/build/database/drivers/mysql/index.js +473 -0
  99. package/build/database/drivers/mysql/options.js +34 -0
  100. package/build/database/drivers/mysql/query-parser.js +6 -0
  101. package/build/database/drivers/mysql/query.js +37 -0
  102. package/build/database/drivers/mysql/sql/alter-table.js +6 -0
  103. package/build/database/drivers/mysql/sql/create-database.js +39 -0
  104. package/build/database/drivers/mysql/sql/create-index.js +6 -0
  105. package/build/database/drivers/mysql/sql/create-table.js +6 -0
  106. package/build/database/drivers/mysql/sql/delete.js +21 -0
  107. package/build/database/drivers/mysql/sql/drop-database.js +6 -0
  108. package/build/database/drivers/mysql/sql/drop-table.js +6 -0
  109. package/build/database/drivers/mysql/sql/insert.js +6 -0
  110. package/build/database/drivers/mysql/sql/update.js +33 -0
  111. package/build/database/drivers/mysql/sql/upsert.js +13 -0
  112. package/build/database/drivers/mysql/structure-sql.js +93 -0
  113. package/build/database/drivers/mysql/table.js +121 -0
  114. package/build/database/drivers/pgsql/column.js +90 -0
  115. package/build/database/drivers/pgsql/columns-index.js +6 -0
  116. package/build/database/drivers/pgsql/foreign-key.js +12 -0
  117. package/build/database/drivers/pgsql/index.js +441 -0
  118. package/build/database/drivers/pgsql/options.js +32 -0
  119. package/build/database/drivers/pgsql/query-parser.js +6 -0
  120. package/build/database/drivers/pgsql/sql/alter-table.js +6 -0
  121. package/build/database/drivers/pgsql/sql/create-database.js +38 -0
  122. package/build/database/drivers/pgsql/sql/create-index.js +6 -0
  123. package/build/database/drivers/pgsql/sql/create-table.js +6 -0
  124. package/build/database/drivers/pgsql/sql/delete.js +21 -0
  125. package/build/database/drivers/pgsql/sql/drop-database.js +6 -0
  126. package/build/database/drivers/pgsql/sql/drop-table.js +6 -0
  127. package/build/database/drivers/pgsql/sql/insert.js +6 -0
  128. package/build/database/drivers/pgsql/sql/update.js +33 -0
  129. package/build/database/drivers/pgsql/sql/upsert.js +14 -0
  130. package/build/database/drivers/pgsql/structure-sql.js +126 -0
  131. package/build/database/drivers/pgsql/table.js +135 -0
  132. package/build/database/drivers/sqlite/base.js +509 -0
  133. package/build/database/drivers/sqlite/column.js +75 -0
  134. package/build/database/drivers/sqlite/columns-index.js +30 -0
  135. package/build/database/drivers/sqlite/connection-sql-js.js +46 -0
  136. package/build/database/drivers/sqlite/foreign-key.js +24 -0
  137. package/build/database/drivers/sqlite/index.js +394 -0
  138. package/build/database/drivers/sqlite/index.native.js +72 -0
  139. package/build/database/drivers/sqlite/index.web.js +99 -0
  140. package/build/database/drivers/sqlite/options.js +32 -0
  141. package/build/database/drivers/sqlite/query-parser.js +6 -0
  142. package/build/database/drivers/sqlite/query.js +35 -0
  143. package/build/database/drivers/sqlite/query.native.js +35 -0
  144. package/build/database/drivers/sqlite/query.web.js +49 -0
  145. package/build/database/drivers/sqlite/sql/alter-table.js +187 -0
  146. package/build/database/drivers/sqlite/sql/create-index.js +6 -0
  147. package/build/database/drivers/sqlite/sql/create-table.js +6 -0
  148. package/build/database/drivers/sqlite/sql/delete.js +26 -0
  149. package/build/database/drivers/sqlite/sql/drop-table.js +6 -0
  150. package/build/database/drivers/sqlite/sql/insert.js +6 -0
  151. package/build/database/drivers/sqlite/sql/update.js +33 -0
  152. package/build/database/drivers/sqlite/sql/upsert.js +14 -0
  153. package/build/database/drivers/sqlite/structure-sql.js +56 -0
  154. package/build/database/drivers/sqlite/table-rebuilder.js +96 -0
  155. package/build/database/drivers/sqlite/table.js +131 -0
  156. package/build/database/drivers/structure-sql/utils.js +35 -0
  157. package/build/database/handler.js +13 -0
  158. package/build/database/initializer-from-require-context.js +101 -0
  159. package/build/database/migration/index.js +438 -0
  160. package/build/database/migrator/files-finder.js +55 -0
  161. package/build/database/migrator/types.js +31 -0
  162. package/build/database/migrator.js +557 -0
  163. package/build/database/pool/async-tracked-multi-connection.js +1164 -0
  164. package/build/database/pool/base-methods-forward.js +52 -0
  165. package/build/database/pool/base.js +380 -0
  166. package/build/database/pool/single-multi-use.js +118 -0
  167. package/build/database/query/alter-table-base.js +104 -0
  168. package/build/database/query/base.js +49 -0
  169. package/build/database/query/create-database-base.js +42 -0
  170. package/build/database/query/create-index-base.js +117 -0
  171. package/build/database/query/create-table-base.js +205 -0
  172. package/build/database/query/delete-base.js +19 -0
  173. package/build/database/query/drop-database-base.js +38 -0
  174. package/build/database/query/drop-table-base.js +58 -0
  175. package/build/database/query/from-base.js +36 -0
  176. package/build/database/query/from-plain.js +16 -0
  177. package/build/database/query/from-table.js +18 -0
  178. package/build/database/query/index.js +533 -0
  179. package/build/database/query/insert-base.js +172 -0
  180. package/build/database/query/join-base.js +43 -0
  181. package/build/database/query/join-object.js +167 -0
  182. package/build/database/query/join-plain.js +18 -0
  183. package/build/database/query/join-tracker.js +93 -0
  184. package/build/database/query/model-class-query.js +1577 -0
  185. package/build/database/query/order-base.js +33 -0
  186. package/build/database/query/order-column.js +77 -0
  187. package/build/database/query/order-plain.js +28 -0
  188. package/build/database/query/preloader/belongs-to.js +267 -0
  189. package/build/database/query/preloader/ensure-model-class-initialized.js +18 -0
  190. package/build/database/query/preloader/has-many.js +316 -0
  191. package/build/database/query/preloader/has-one.js +123 -0
  192. package/build/database/query/preloader/selection.js +152 -0
  193. package/build/database/query/preloader.js +201 -0
  194. package/build/database/query/query-data.js +305 -0
  195. package/build/database/query/select-base.js +30 -0
  196. package/build/database/query/select-plain.js +18 -0
  197. package/build/database/query/select-table-and-column.js +28 -0
  198. package/build/database/query/update-base.js +41 -0
  199. package/build/database/query/upsert-base.js +103 -0
  200. package/build/database/query/where-base.js +38 -0
  201. package/build/database/query/where-combinator.js +31 -0
  202. package/build/database/query/where-hash.js +77 -0
  203. package/build/database/query/where-model-class-hash.js +505 -0
  204. package/build/database/query/where-not.js +23 -0
  205. package/build/database/query/where-plain.js +20 -0
  206. package/build/database/query/with-count.js +219 -0
  207. package/build/database/query-parser/base-query-parser.js +40 -0
  208. package/build/database/query-parser/from-parser.js +49 -0
  209. package/build/database/query-parser/group-parser.js +55 -0
  210. package/build/database/query-parser/joins-parser.js +37 -0
  211. package/build/database/query-parser/limit-parser.js +77 -0
  212. package/build/database/query-parser/options.js +94 -0
  213. package/build/database/query-parser/order-parser.js +45 -0
  214. package/build/database/query-parser/select-parser.js +67 -0
  215. package/build/database/query-parser/where-parser.js +46 -0
  216. package/build/database/record/acts-as-list.js +374 -0
  217. package/build/database/record/attachments/download.js +49 -0
  218. package/build/database/record/attachments/handle.js +188 -0
  219. package/build/database/record/attachments/normalize-input.js +213 -0
  220. package/build/database/record/attachments/storage-drivers/filesystem.js +114 -0
  221. package/build/database/record/attachments/storage-drivers/native.js +146 -0
  222. package/build/database/record/attachments/storage-drivers/s3.js +245 -0
  223. package/build/database/record/attachments/store.js +591 -0
  224. package/build/database/record/index.js +4119 -0
  225. package/build/database/record/instance-relationships/base.js +289 -0
  226. package/build/database/record/instance-relationships/belongs-to.js +84 -0
  227. package/build/database/record/instance-relationships/has-many.js +284 -0
  228. package/build/database/record/instance-relationships/has-one.js +117 -0
  229. package/build/database/record/record-not-found-error.js +3 -0
  230. package/build/database/record/relationships/base.js +195 -0
  231. package/build/database/record/relationships/belongs-to.js +57 -0
  232. package/build/database/record/relationships/has-many.js +46 -0
  233. package/build/database/record/relationships/has-one.js +46 -0
  234. package/build/database/record/state-machine.js +278 -0
  235. package/build/database/record/user-module.js +43 -0
  236. package/build/database/record/validators/base.js +27 -0
  237. package/build/database/record/validators/format.js +50 -0
  238. package/build/database/record/validators/presence.js +24 -0
  239. package/build/database/record/validators/uniqueness.js +124 -0
  240. package/build/database/table-data/index.js +241 -0
  241. package/build/database/table-data/table-column.js +416 -0
  242. package/build/database/table-data/table-foreign-key.js +69 -0
  243. package/build/database/table-data/table-index.js +46 -0
  244. package/build/database/table-data/table-reference.js +13 -0
  245. package/build/database/use-database.js +48 -0
  246. package/build/environment-handlers/base.js +561 -0
  247. package/build/environment-handlers/browser.js +338 -0
  248. package/build/environment-handlers/node/cli/commands/background-jobs-main.js +21 -0
  249. package/build/environment-handlers/node/cli/commands/background-jobs-runner.js +24 -0
  250. package/build/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -0
  251. package/build/environment-handlers/node/cli/commands/beacon.js +21 -0
  252. package/build/environment-handlers/node/cli/commands/cli-command-context.js +31 -0
  253. package/build/environment-handlers/node/cli/commands/console.js +149 -0
  254. package/build/environment-handlers/node/cli/commands/db/schema/dump.js +43 -0
  255. package/build/environment-handlers/node/cli/commands/db/schema/load.js +69 -0
  256. package/build/environment-handlers/node/cli/commands/db/seed.js +79 -0
  257. package/build/environment-handlers/node/cli/commands/destroy/migration.js +47 -0
  258. package/build/environment-handlers/node/cli/commands/generate/base-models.js +396 -0
  259. package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +872 -0
  260. package/build/environment-handlers/node/cli/commands/generate/migration.js +45 -0
  261. package/build/environment-handlers/node/cli/commands/generate/model.js +45 -0
  262. package/build/environment-handlers/node/cli/commands/init.js +68 -0
  263. package/build/environment-handlers/node/cli/commands/routes.js +63 -0
  264. package/build/environment-handlers/node/cli/commands/run-script.js +85 -0
  265. package/build/environment-handlers/node/cli/commands/runner.js +84 -0
  266. package/build/environment-handlers/node/cli/commands/server.js +151 -0
  267. package/build/environment-handlers/node/cli/commands/test.js +118 -0
  268. package/build/environment-handlers/node.js +887 -0
  269. package/build/error-logger.js +30 -0
  270. package/build/frontend-model-controller.js +3491 -0
  271. package/build/frontend-model-resource/base-resource.js +939 -0
  272. package/build/frontend-models/base.js +4004 -0
  273. package/build/frontend-models/clear-pending-debounced-callback.js +16 -0
  274. package/build/frontend-models/event-hook-models.js +49 -0
  275. package/build/frontend-models/model-registry.js +28 -0
  276. package/build/frontend-models/outgoing-event-buffer.js +51 -0
  277. package/build/frontend-models/preloader.js +169 -0
  278. package/build/frontend-models/query.js +2245 -0
  279. package/build/frontend-models/resource-config-validation.js +56 -0
  280. package/build/frontend-models/resource-definition.js +399 -0
  281. package/build/frontend-models/transport-serialization.js +369 -0
  282. package/build/frontend-models/use-created-event.js +21 -0
  283. package/build/frontend-models/use-destroyed-event.js +148 -0
  284. package/build/frontend-models/use-model-class-event.js +164 -0
  285. package/build/frontend-models/use-updated-event.js +152 -0
  286. package/build/frontend-models/websocket-channel.js +494 -0
  287. package/build/frontend-models/websocket-publishers.js +224 -0
  288. package/build/http-client/header.js +17 -0
  289. package/build/http-client/index.js +139 -0
  290. package/build/http-client/request.js +94 -0
  291. package/build/http-client/response.js +151 -0
  292. package/build/http-client/websocket-client.js +27 -0
  293. package/build/http-server/client/index.js +507 -0
  294. package/build/http-server/client/params-to-object.js +152 -0
  295. package/build/http-server/client/request-buffer/form-data-part.js +139 -0
  296. package/build/http-server/client/request-buffer/header.js +19 -0
  297. package/build/http-server/client/request-buffer/index.js +535 -0
  298. package/build/http-server/client/request-parser.js +195 -0
  299. package/build/http-server/client/request-runner.js +321 -0
  300. package/build/http-server/client/request-timing.js +171 -0
  301. package/build/http-server/client/request.js +114 -0
  302. package/build/http-server/client/response.js +251 -0
  303. package/build/http-server/client/uploaded-file/memory-uploaded-file.js +32 -0
  304. package/build/http-server/client/uploaded-file/temporary-uploaded-file.js +32 -0
  305. package/build/http-server/client/uploaded-file/uploaded-file.js +36 -0
  306. package/build/http-server/client/websocket-request.js +147 -0
  307. package/build/http-server/client/websocket-session.js +1755 -0
  308. package/build/http-server/cookie.js +245 -0
  309. package/build/http-server/development-reloader.js +240 -0
  310. package/build/http-server/index.js +561 -0
  311. package/build/http-server/remote-address.js +77 -0
  312. package/build/http-server/server-client.js +222 -0
  313. package/build/http-server/server-lock.js +178 -0
  314. package/build/http-server/websocket-channel-subscribers.js +110 -0
  315. package/build/http-server/websocket-channel.js +137 -0
  316. package/build/http-server/websocket-connection.js +118 -0
  317. package/build/http-server/websocket-event-log-store.js +433 -0
  318. package/build/http-server/websocket-events-host.js +170 -0
  319. package/build/http-server/websocket-events.js +50 -0
  320. package/build/http-server/worker-handler/channel-subscriber-dispatch.js +28 -0
  321. package/build/http-server/worker-handler/in-process.js +155 -0
  322. package/build/http-server/worker-handler/index.js +370 -0
  323. package/build/http-server/worker-handler/worker-script.js +6 -0
  324. package/build/http-server/worker-handler/worker-thread.js +286 -0
  325. package/build/initializer.js +39 -0
  326. package/build/jobs/mail-delivery.js +22 -0
  327. package/build/logger/base-logger.js +34 -0
  328. package/build/logger/console-logger.js +28 -0
  329. package/build/logger/file-logger.js +36 -0
  330. package/build/logger/outputs/array-output.js +50 -0
  331. package/build/logger/outputs/console-output.js +32 -0
  332. package/build/logger/outputs/file-output.js +55 -0
  333. package/build/logger/outputs/stdout-output.js +64 -0
  334. package/build/logger.js +507 -0
  335. package/build/mailer/backends/smtp.js +197 -0
  336. package/build/mailer/base.js +337 -0
  337. package/build/mailer/delivery.js +70 -0
  338. package/build/mailer/index.js +24 -0
  339. package/build/mailer.js +15 -0
  340. package/build/plugins/sqljs-wasm-route-controller.js +70 -0
  341. package/build/plugins/sqljs-wasm-route.js +71 -0
  342. package/build/record-payload-values.js +83 -0
  343. package/build/routes/app-routes.js +17 -0
  344. package/build/routes/base-route.js +133 -0
  345. package/build/routes/basic-route.js +109 -0
  346. package/build/routes/built-in/debug/controller.js +12 -0
  347. package/build/routes/built-in/errors/controller.js +7 -0
  348. package/build/routes/get-route.js +75 -0
  349. package/build/routes/hooks/frontend-model-command-route-hook.js +100 -0
  350. package/build/routes/index.js +50 -0
  351. package/build/routes/namespace-route.js +51 -0
  352. package/build/routes/plugin-routes.js +141 -0
  353. package/build/routes/post-route.js +74 -0
  354. package/build/routes/resolver.js +535 -0
  355. package/build/routes/resource-route.js +154 -0
  356. package/build/routes/root-route.js +11 -0
  357. package/build/src/application.js +187 -214
  358. package/build/src/authorization/ability.js +250 -297
  359. package/build/src/authorization/base-resource.js +120 -136
  360. package/build/src/background-jobs/client.js +43 -47
  361. package/build/src/background-jobs/cron-expression.js +127 -166
  362. package/build/src/background-jobs/forked-runner-child.js +37 -47
  363. package/build/src/background-jobs/job-record.js +8 -10
  364. package/build/src/background-jobs/job-registry.js +72 -84
  365. package/build/src/background-jobs/job-runner.js +74 -81
  366. package/build/src/background-jobs/job.js +62 -72
  367. package/build/src/background-jobs/json-socket.js +65 -70
  368. package/build/src/background-jobs/main.js +841 -900
  369. package/build/src/background-jobs/normalize-error.js +12 -11
  370. package/build/src/background-jobs/scheduler.js +205 -247
  371. package/build/src/background-jobs/socket-request.js +60 -65
  372. package/build/src/background-jobs/status-reporter.js +86 -96
  373. package/build/src/background-jobs/store.js +862 -980
  374. package/build/src/background-jobs/types.js +2 -3
  375. package/build/src/background-jobs/web/authorization.js +38 -50
  376. package/build/src/background-jobs/web/controller.js +232 -268
  377. package/build/src/background-jobs/web/index.js +36 -40
  378. package/build/src/background-jobs/web/path-matcher.js +45 -48
  379. package/build/src/background-jobs/web/registry.js +9 -14
  380. package/build/src/background-jobs/worker.js +585 -639
  381. package/build/src/beacon/client.js +264 -293
  382. package/build/src/beacon/in-process-broker.js +20 -25
  383. package/build/src/beacon/in-process-client.js +104 -116
  384. package/build/src/beacon/server.js +110 -126
  385. package/build/src/beacon/types.js +2 -8
  386. package/build/src/cli/base-command.js +49 -57
  387. package/build/src/cli/browser-cli.js +37 -42
  388. package/build/src/cli/commands/background-jobs-main.js +5 -5
  389. package/build/src/cli/commands/background-jobs-runner.js +5 -5
  390. package/build/src/cli/commands/background-jobs-worker.js +5 -5
  391. package/build/src/cli/commands/beacon.js +5 -5
  392. package/build/src/cli/commands/console.js +10 -10
  393. package/build/src/cli/commands/db/base-command.js +71 -76
  394. package/build/src/cli/commands/db/create.js +53 -61
  395. package/build/src/cli/commands/db/drop.js +62 -71
  396. package/build/src/cli/commands/db/migrate.js +13 -15
  397. package/build/src/cli/commands/db/reset.js +16 -19
  398. package/build/src/cli/commands/db/rollback.js +12 -13
  399. package/build/src/cli/commands/db/schema/dump.js +9 -9
  400. package/build/src/cli/commands/db/schema/load.js +9 -9
  401. package/build/src/cli/commands/db/seed.js +9 -9
  402. package/build/src/cli/commands/db/tenants/check.js +32 -35
  403. package/build/src/cli/commands/db/tenants/create.js +26 -29
  404. package/build/src/cli/commands/db/tenants/migrate.js +40 -44
  405. package/build/src/cli/commands/destroy/migration.js +5 -5
  406. package/build/src/cli/commands/generate/base-models.js +5 -5
  407. package/build/src/cli/commands/generate/frontend-models.js +9 -9
  408. package/build/src/cli/commands/generate/migration.js +5 -5
  409. package/build/src/cli/commands/generate/model.js +5 -5
  410. package/build/src/cli/commands/init.js +7 -9
  411. package/build/src/cli/commands/routes.js +6 -6
  412. package/build/src/cli/commands/run-script.js +9 -9
  413. package/build/src/cli/commands/runner.js +9 -9
  414. package/build/src/cli/commands/server.js +6 -6
  415. package/build/src/cli/commands/test.js +6 -7
  416. package/build/src/cli/index.js +127 -141
  417. package/build/src/cli/tenant-database-command-helper.js +154 -185
  418. package/build/src/cli/use-browser-cli.js +15 -20
  419. package/build/src/configuration-resolver.js +47 -54
  420. package/build/src/configuration-types.d.ts +5 -3
  421. package/build/src/configuration-types.d.ts.map +1 -1
  422. package/build/src/configuration-types.js +3 -54
  423. package/build/src/configuration.js +2240 -2547
  424. package/build/src/controller.js +363 -407
  425. package/build/src/current-configuration.js +9 -12
  426. package/build/src/current.js +70 -75
  427. package/build/src/database/annotations-async-hooks.js +16 -22
  428. package/build/src/database/annotations.js +12 -18
  429. package/build/src/database/drivers/base-column.js +155 -179
  430. package/build/src/database/drivers/base-columns-index.js +69 -78
  431. package/build/src/database/drivers/base-foreign-key.js +89 -101
  432. package/build/src/database/drivers/base-table.js +124 -149
  433. package/build/src/database/drivers/base.js +1306 -1489
  434. package/build/src/database/drivers/mssql/column.js +39 -50
  435. package/build/src/database/drivers/mssql/columns-index.js +2 -3
  436. package/build/src/database/drivers/mssql/connect-connection.js +11 -9
  437. package/build/src/database/drivers/mssql/foreign-key.js +8 -9
  438. package/build/src/database/drivers/mssql/index.js +507 -587
  439. package/build/src/database/drivers/mssql/options.js +68 -75
  440. package/build/src/database/drivers/mssql/query-parser.js +2 -3
  441. package/build/src/database/drivers/mssql/sql/alter-table.js +2 -2
  442. package/build/src/database/drivers/mssql/sql/create-database.js +24 -31
  443. package/build/src/database/drivers/mssql/sql/create-index.js +2 -2
  444. package/build/src/database/drivers/mssql/sql/create-table.js +2 -2
  445. package/build/src/database/drivers/mssql/sql/delete.js +14 -16
  446. package/build/src/database/drivers/mssql/sql/drop-database.js +24 -31
  447. package/build/src/database/drivers/mssql/sql/drop-table.js +2 -2
  448. package/build/src/database/drivers/mssql/sql/insert.js +2 -2
  449. package/build/src/database/drivers/mssql/sql/update.js +24 -28
  450. package/build/src/database/drivers/mssql/sql/upsert.js +18 -20
  451. package/build/src/database/drivers/mssql/structure-sql.js +102 -114
  452. package/build/src/database/drivers/mssql/table.js +81 -96
  453. package/build/src/database/drivers/mysql/column.js +75 -92
  454. package/build/src/database/drivers/mysql/columns-index.js +16 -19
  455. package/build/src/database/drivers/mysql/foreign-key.js +8 -9
  456. package/build/src/database/drivers/mysql/index.js +396 -457
  457. package/build/src/database/drivers/mysql/options.js +26 -30
  458. package/build/src/database/drivers/mysql/query-parser.js +2 -3
  459. package/build/src/database/drivers/mysql/query.js +26 -29
  460. package/build/src/database/drivers/mysql/sql/alter-table.js +2 -3
  461. package/build/src/database/drivers/mysql/sql/create-database.js +23 -28
  462. package/build/src/database/drivers/mysql/sql/create-index.js +2 -3
  463. package/build/src/database/drivers/mysql/sql/create-table.js +2 -3
  464. package/build/src/database/drivers/mysql/sql/delete.js +14 -17
  465. package/build/src/database/drivers/mysql/sql/drop-database.js +2 -3
  466. package/build/src/database/drivers/mysql/sql/drop-table.js +2 -3
  467. package/build/src/database/drivers/mysql/sql/insert.js +2 -3
  468. package/build/src/database/drivers/mysql/sql/update.js +24 -29
  469. package/build/src/database/drivers/mysql/sql/upsert.js +8 -10
  470. package/build/src/database/drivers/mysql/structure-sql.js +79 -88
  471. package/build/src/database/drivers/mysql/table.js +83 -98
  472. package/build/src/database/drivers/pgsql/column.js +56 -72
  473. package/build/src/database/drivers/pgsql/columns-index.js +2 -3
  474. package/build/src/database/drivers/pgsql/foreign-key.js +8 -9
  475. package/build/src/database/drivers/pgsql/index.js +377 -438
  476. package/build/src/database/drivers/pgsql/options.js +25 -28
  477. package/build/src/database/drivers/pgsql/query-parser.js +2 -3
  478. package/build/src/database/drivers/pgsql/sql/alter-table.js +2 -3
  479. package/build/src/database/drivers/pgsql/sql/create-database.js +19 -23
  480. package/build/src/database/drivers/pgsql/sql/create-index.js +2 -3
  481. package/build/src/database/drivers/pgsql/sql/create-table.js +2 -3
  482. package/build/src/database/drivers/pgsql/sql/delete.js +14 -17
  483. package/build/src/database/drivers/pgsql/sql/drop-database.js +2 -3
  484. package/build/src/database/drivers/pgsql/sql/drop-table.js +2 -3
  485. package/build/src/database/drivers/pgsql/sql/insert.js +2 -3
  486. package/build/src/database/drivers/pgsql/sql/update.js +24 -29
  487. package/build/src/database/drivers/pgsql/sql/upsert.js +9 -11
  488. package/build/src/database/drivers/pgsql/structure-sql.js +108 -120
  489. package/build/src/database/drivers/pgsql/table.js +60 -77
  490. package/build/src/database/drivers/sqlite/base.js +405 -478
  491. package/build/src/database/drivers/sqlite/column.js +54 -69
  492. package/build/src/database/drivers/sqlite/columns-index.js +22 -27
  493. package/build/src/database/drivers/sqlite/connection-sql-js.js +35 -42
  494. package/build/src/database/drivers/sqlite/foreign-key.js +18 -21
  495. package/build/src/database/drivers/sqlite/index.js +330 -373
  496. package/build/src/database/drivers/sqlite/index.native.js +55 -64
  497. package/build/src/database/drivers/sqlite/index.web.js +69 -87
  498. package/build/src/database/drivers/sqlite/options.js +25 -28
  499. package/build/src/database/drivers/sqlite/query-parser.js +2 -3
  500. package/build/src/database/drivers/sqlite/query.js +21 -24
  501. package/build/src/database/drivers/sqlite/query.native.js +20 -25
  502. package/build/src/database/drivers/sqlite/query.web.js +30 -37
  503. package/build/src/database/drivers/sqlite/sql/alter-table.js +159 -179
  504. package/build/src/database/drivers/sqlite/sql/create-index.js +2 -3
  505. package/build/src/database/drivers/sqlite/sql/create-table.js +2 -3
  506. package/build/src/database/drivers/sqlite/sql/delete.js +17 -22
  507. package/build/src/database/drivers/sqlite/sql/drop-table.js +2 -3
  508. package/build/src/database/drivers/sqlite/sql/insert.js +2 -3
  509. package/build/src/database/drivers/sqlite/sql/update.js +24 -29
  510. package/build/src/database/drivers/sqlite/sql/upsert.js +9 -11
  511. package/build/src/database/drivers/sqlite/structure-sql.js +49 -52
  512. package/build/src/database/drivers/sqlite/table-rebuilder.js +62 -75
  513. package/build/src/database/drivers/sqlite/table.js +102 -125
  514. package/build/src/database/drivers/structure-sql/utils.js +14 -17
  515. package/build/src/database/handler.js +9 -10
  516. package/build/src/database/initializer-from-require-context.js +76 -87
  517. package/build/src/database/migration/index.js +332 -395
  518. package/build/src/database/migrator/files-finder.js +40 -50
  519. package/build/src/database/migrator/types.js +2 -30
  520. package/build/src/database/migrator.js +454 -526
  521. package/build/src/database/pool/async-tracked-multi-connection.js +997 -1147
  522. package/build/src/database/pool/base-methods-forward.js +40 -43
  523. package/build/src/database/pool/base.js +298 -343
  524. package/build/src/database/pool/single-multi-use.js +93 -110
  525. package/build/src/database/query/alter-table-base.js +84 -99
  526. package/build/src/database/query/base.js +39 -46
  527. package/build/src/database/query/create-database-base.js +25 -30
  528. package/build/src/database/query/create-index-base.js +75 -94
  529. package/build/src/database/query/create-table-base.js +151 -193
  530. package/build/src/database/query/delete-base.js +14 -16
  531. package/build/src/database/query/drop-database-base.js +23 -28
  532. package/build/src/database/query/drop-table-base.js +42 -53
  533. package/build/src/database/query/from-base.js +30 -33
  534. package/build/src/database/query/from-plain.js +11 -13
  535. package/build/src/database/query/from-table.js +13 -15
  536. package/build/src/database/query/index.js +410 -472
  537. package/build/src/database/query/insert-base.js +143 -164
  538. package/build/src/database/query/join-base.js +35 -40
  539. package/build/src/database/query/join-object.js +128 -153
  540. package/build/src/database/query/join-plain.js +13 -15
  541. package/build/src/database/query/join-tracker.js +76 -90
  542. package/build/src/database/query/model-class-query.js +1134 -1370
  543. package/build/src/database/query/order-base.js +27 -30
  544. package/build/src/database/query/order-column.js +44 -53
  545. package/build/src/database/query/order-plain.js +20 -24
  546. package/build/src/database/query/preloader/belongs-to.js +210 -258
  547. package/build/src/database/query/preloader/ensure-model-class-initialized.js +8 -9
  548. package/build/src/database/query/preloader/has-many.js +240 -301
  549. package/build/src/database/query/preloader/has-one.js +91 -117
  550. package/build/src/database/query/preloader/selection.js +117 -129
  551. package/build/src/database/query/preloader.js +160 -185
  552. package/build/src/database/query/query-data.js +157 -201
  553. package/build/src/database/query/select-base.js +25 -27
  554. package/build/src/database/query/select-plain.js +13 -15
  555. package/build/src/database/query/select-table-and-column.js +21 -25
  556. package/build/src/database/query/update-base.js +35 -38
  557. package/build/src/database/query/upsert-base.js +93 -100
  558. package/build/src/database/query/where-base.js +32 -35
  559. package/build/src/database/query/where-combinator.js +25 -28
  560. package/build/src/database/query/where-hash.js +61 -68
  561. package/build/src/database/query/where-model-class-hash.js +414 -469
  562. package/build/src/database/query/where-not.js +18 -20
  563. package/build/src/database/query/where-plain.js +15 -17
  564. package/build/src/database/query/with-count.js +125 -159
  565. package/build/src/database/query-parser/base-query-parser.js +32 -37
  566. package/build/src/database/query-parser/from-parser.js +36 -45
  567. package/build/src/database/query-parser/group-parser.js +42 -50
  568. package/build/src/database/query-parser/joins-parser.js +28 -33
  569. package/build/src/database/query-parser/limit-parser.js +67 -70
  570. package/build/src/database/query-parser/options.js +75 -82
  571. package/build/src/database/query-parser/order-parser.js +36 -40
  572. package/build/src/database/query-parser/select-parser.js +49 -60
  573. package/build/src/database/query-parser/where-parser.js +36 -41
  574. package/build/src/database/record/acts-as-list.js +235 -273
  575. package/build/src/database/record/attachments/download.js +44 -45
  576. package/build/src/database/record/attachments/handle.js +141 -161
  577. package/build/src/database/record/attachments/normalize-input.js +128 -138
  578. package/build/src/database/record/attachments/storage-drivers/filesystem.js +77 -91
  579. package/build/src/database/record/attachments/storage-drivers/native.js +112 -121
  580. package/build/src/database/record/attachments/storage-drivers/s3.js +177 -208
  581. package/build/src/database/record/attachments/store.js +467 -539
  582. package/build/src/database/record/index.d.ts +109 -25
  583. package/build/src/database/record/index.d.ts.map +1 -1
  584. package/build/src/database/record/index.js +3502 -3898
  585. package/build/src/database/record/instance-relationships/base.js +234 -268
  586. package/build/src/database/record/instance-relationships/belongs-to.js +58 -73
  587. package/build/src/database/record/instance-relationships/has-many.js +225 -264
  588. package/build/src/database/record/instance-relationships/has-one.js +85 -105
  589. package/build/src/database/record/record-not-found-error.js +3 -2
  590. package/build/src/database/record/relationships/base.js +144 -166
  591. package/build/src/database/record/relationships/belongs-to.js +44 -51
  592. package/build/src/database/record/relationships/has-many.js +32 -40
  593. package/build/src/database/record/relationships/has-one.js +32 -40
  594. package/build/src/database/record/state-machine.js +156 -208
  595. package/build/src/database/record/user-module.js +32 -38
  596. package/build/src/database/record/validators/base.js +22 -24
  597. package/build/src/database/record/validators/format.js +36 -46
  598. package/build/src/database/record/validators/presence.js +18 -20
  599. package/build/src/database/record/validators/uniqueness.js +99 -117
  600. package/build/src/database/table-data/index.js +199 -231
  601. package/build/src/database/table-data/table-column.js +338 -382
  602. package/build/src/database/table-data/table-foreign-key.js +57 -66
  603. package/build/src/database/table-data/table-index.js +29 -36
  604. package/build/src/database/table-data/table-reference.js +10 -10
  605. package/build/src/database/use-database.js +32 -40
  606. package/build/src/environment-handlers/base.js +484 -544
  607. package/build/src/environment-handlers/browser.js +241 -294
  608. package/build/src/environment-handlers/node/cli/commands/background-jobs-main.js +16 -19
  609. package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.js +18 -21
  610. package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.js +22 -29
  611. package/build/src/environment-handlers/node/cli/commands/beacon.js +16 -19
  612. package/build/src/environment-handlers/node/cli/commands/cli-command-context.js +14 -15
  613. package/build/src/environment-handlers/node/cli/commands/console.js +99 -120
  614. package/build/src/environment-handlers/node/cli/commands/db/schema/dump.js +34 -39
  615. package/build/src/environment-handlers/node/cli/commands/db/schema/load.js +57 -63
  616. package/build/src/environment-handlers/node/cli/commands/db/seed.js +51 -63
  617. package/build/src/environment-handlers/node/cli/commands/destroy/migration.js +32 -40
  618. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts +4 -2
  619. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
  620. package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +326 -358
  621. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +10 -10
  622. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
  623. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +729 -844
  624. package/build/src/environment-handlers/node/cli/commands/generate/migration.js +34 -38
  625. package/build/src/environment-handlers/node/cli/commands/generate/model.js +34 -38
  626. package/build/src/environment-handlers/node/cli/commands/init.js +56 -61
  627. package/build/src/environment-handlers/node/cli/commands/routes.js +51 -59
  628. package/build/src/environment-handlers/node/cli/commands/run-script.js +54 -68
  629. package/build/src/environment-handlers/node/cli/commands/runner.js +56 -74
  630. package/build/src/environment-handlers/node/cli/commands/server.js +93 -106
  631. package/build/src/environment-handlers/node/cli/commands/test.js +97 -113
  632. package/build/src/environment-handlers/node.js +753 -874
  633. package/build/src/error-logger.js +22 -21
  634. package/build/src/frontend-model-controller.js +2791 -3291
  635. package/build/src/frontend-model-resource/base-resource.d.ts +8 -3
  636. package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
  637. package/build/src/frontend-model-resource/base-resource.js +770 -865
  638. package/build/src/frontend-models/base.js +3136 -3593
  639. package/build/src/frontend-models/clear-pending-debounced-callback.js +7 -8
  640. package/build/src/frontend-models/event-hook-models.js +16 -21
  641. package/build/src/frontend-models/model-registry.js +9 -11
  642. package/build/src/frontend-models/outgoing-event-buffer.js +10 -17
  643. package/build/src/frontend-models/preloader.js +131 -149
  644. package/build/src/frontend-models/query.js +1557 -1855
  645. package/build/src/frontend-models/resource-config-validation.js +27 -37
  646. package/build/src/frontend-models/resource-definition.d.ts +6 -7
  647. package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
  648. package/build/src/frontend-models/resource-definition.js +237 -291
  649. package/build/src/frontend-models/transport-serialization.js +203 -266
  650. package/build/src/frontend-models/use-created-event.js +5 -7
  651. package/build/src/frontend-models/use-destroyed-event.js +80 -93
  652. package/build/src/frontend-models/use-model-class-event.js +79 -91
  653. package/build/src/frontend-models/use-updated-event.js +84 -97
  654. package/build/src/frontend-models/websocket-channel.js +381 -441
  655. package/build/src/frontend-models/websocket-publishers.js +142 -175
  656. package/build/src/http-client/header.js +13 -14
  657. package/build/src/http-client/index.js +116 -132
  658. package/build/src/http-client/request.js +71 -87
  659. package/build/src/http-client/response.js +122 -140
  660. package/build/src/http-client/websocket-client.js +15 -17
  661. package/build/src/http-server/client/index.js +409 -465
  662. package/build/src/http-server/client/params-to-object.js +124 -135
  663. package/build/src/http-server/client/request-buffer/form-data-part.js +111 -132
  664. package/build/src/http-server/client/request-buffer/header.js +15 -16
  665. package/build/src/http-server/client/request-buffer/index.js +446 -506
  666. package/build/src/http-server/client/request-parser.js +163 -186
  667. package/build/src/http-server/client/request-runner.js +226 -259
  668. package/build/src/http-server/client/request-timing.js +132 -151
  669. package/build/src/http-server/client/request.js +96 -108
  670. package/build/src/http-server/client/response.js +213 -235
  671. package/build/src/http-server/client/uploaded-file/memory-uploaded-file.js +25 -29
  672. package/build/src/http-server/client/uploaded-file/temporary-uploaded-file.js +25 -29
  673. package/build/src/http-server/client/uploaded-file/uploaded-file.js +33 -33
  674. package/build/src/http-server/client/websocket-request.js +114 -137
  675. package/build/src/http-server/client/websocket-session.js +1452 -1657
  676. package/build/src/http-server/cookie.js +216 -236
  677. package/build/src/http-server/development-reloader.js +190 -221
  678. package/build/src/http-server/index.js +451 -525
  679. package/build/src/http-server/remote-address.js +38 -50
  680. package/build/src/http-server/server-client.js +181 -208
  681. package/build/src/http-server/server-lock.js +153 -167
  682. package/build/src/http-server/websocket-channel-subscribers.js +81 -93
  683. package/build/src/http-server/websocket-channel.js +104 -117
  684. package/build/src/http-server/websocket-connection.js +96 -104
  685. package/build/src/http-server/websocket-event-log-store.js +350 -404
  686. package/build/src/http-server/websocket-events-host.js +145 -164
  687. package/build/src/http-server/websocket-events.js +47 -47
  688. package/build/src/http-server/worker-handler/channel-subscriber-dispatch.js +13 -14
  689. package/build/src/http-server/worker-handler/in-process.js +123 -141
  690. package/build/src/http-server/worker-handler/index.js +313 -349
  691. package/build/src/http-server/worker-handler/worker-script.js +4 -5
  692. package/build/src/http-server/worker-handler/worker-thread.js +240 -269
  693. package/build/src/initializer.js +31 -36
  694. package/build/src/jobs/mail-delivery.js +13 -15
  695. package/build/src/logger/base-logger.js +24 -26
  696. package/build/src/logger/console-logger.js +21 -23
  697. package/build/src/logger/file-logger.js +29 -31
  698. package/build/src/logger/outputs/array-output.js +37 -42
  699. package/build/src/logger/outputs/console-output.js +20 -24
  700. package/build/src/logger/outputs/file-output.js +43 -48
  701. package/build/src/logger/outputs/stdout-output.js +39 -48
  702. package/build/src/logger.js +338 -394
  703. package/build/src/mailer/backends/smtp.js +134 -163
  704. package/build/src/mailer/base.js +211 -251
  705. package/build/src/mailer/delivery.js +56 -64
  706. package/build/src/mailer/index.js +4 -22
  707. package/build/src/mailer.js +4 -13
  708. package/build/src/plugins/sqljs-wasm-route-controller.js +42 -52
  709. package/build/src/plugins/sqljs-wasm-route.js +28 -38
  710. package/build/src/record-payload-values.js +25 -28
  711. package/build/src/routes/app-routes.js +12 -14
  712. package/build/src/routes/base-route.js +112 -130
  713. package/build/src/routes/basic-route.js +83 -102
  714. package/build/src/routes/built-in/debug/controller.js +10 -10
  715. package/build/src/routes/built-in/errors/controller.js +5 -5
  716. package/build/src/routes/get-route.js +50 -63
  717. package/build/src/routes/hooks/frontend-model-command-route-hook.js +66 -80
  718. package/build/src/routes/index.js +36 -43
  719. package/build/src/routes/namespace-route.js +38 -47
  720. package/build/src/routes/plugin-routes.js +107 -124
  721. package/build/src/routes/post-route.js +51 -62
  722. package/build/src/routes/resolver.js +422 -494
  723. package/build/src/routes/resource-route.js +124 -143
  724. package/build/src/routes/root-route.js +7 -8
  725. package/build/src/testing/base-expect.js +13 -14
  726. package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +329 -405
  727. package/build/src/testing/browser-test-app.js +23 -29
  728. package/build/src/testing/expect-to-change.js +41 -50
  729. package/build/src/testing/expect-utils.js +139 -184
  730. package/build/src/testing/expect.js +638 -731
  731. package/build/src/testing/request-client.js +70 -85
  732. package/build/src/testing/test-files-finder.js +285 -339
  733. package/build/src/testing/test-filter-parser.js +124 -155
  734. package/build/src/testing/test-runner.js +883 -1020
  735. package/build/src/testing/test-suite-splitter.js +114 -142
  736. package/build/src/testing/test.js +216 -256
  737. package/build/src/utils/backtrace-cleaner-node.js +62 -69
  738. package/build/src/utils/backtrace-cleaner.js +188 -216
  739. package/build/src/utils/ensure-error.js +7 -7
  740. package/build/src/utils/event-emitter.js +4 -6
  741. package/build/src/utils/file-exists.js +9 -10
  742. package/build/src/utils/format-value.js +67 -76
  743. package/build/src/utils/model-scope.js +27 -31
  744. package/build/src/utils/nest-callbacks.js +10 -13
  745. package/build/src/utils/plain-object.js +5 -6
  746. package/build/src/utils/ransack.js +448 -563
  747. package/build/src/utils/rest-args-error.js +5 -6
  748. package/build/src/utils/singularize-model-name.js +9 -11
  749. package/build/src/utils/split-sql-statements.js +68 -79
  750. package/build/src/utils/to-import-specifier.js +24 -30
  751. package/build/src/utils/with-tracked-stack-async-hooks.js +60 -74
  752. package/build/src/utils/with-tracked-stack.js +14 -18
  753. package/build/src/velocious-error.js +27 -30
  754. package/build/templates/configuration.js +61 -0
  755. package/build/templates/generate-migration.js +11 -0
  756. package/build/templates/generate-model.js +6 -0
  757. package/build/templates/routes.js +11 -0
  758. package/build/testing/base-expect.js +17 -0
  759. package/build/testing/browser-frontend-model-event-hook-scenarios.js +520 -0
  760. package/build/testing/browser-test-app.js +32 -0
  761. package/build/testing/expect-to-change.js +55 -0
  762. package/build/testing/expect-utils.js +269 -0
  763. package/build/testing/expect.js +763 -0
  764. package/build/testing/request-client.js +90 -0
  765. package/build/testing/test-files-finder.js +364 -0
  766. package/build/testing/test-filter-parser.js +198 -0
  767. package/build/testing/test-runner.js +1168 -0
  768. package/build/testing/test-suite-splitter.js +177 -0
  769. package/build/testing/test.js +370 -0
  770. package/build/utils/backtrace-cleaner-node.js +87 -0
  771. package/build/utils/backtrace-cleaner.js +266 -0
  772. package/build/utils/ensure-error.js +15 -0
  773. package/build/utils/event-emitter.js +8 -0
  774. package/build/utils/file-exists.js +18 -0
  775. package/build/utils/format-value.js +101 -0
  776. package/build/utils/model-scope.js +56 -0
  777. package/build/utils/nest-callbacks.js +22 -0
  778. package/build/utils/plain-object.js +14 -0
  779. package/build/utils/ransack.js +859 -0
  780. package/build/utils/rest-args-error.js +14 -0
  781. package/build/utils/singularize-model-name.js +18 -0
  782. package/build/utils/split-sql-statements.js +88 -0
  783. package/build/utils/to-import-specifier.js +53 -0
  784. package/build/utils/with-tracked-stack-async-hooks.js +103 -0
  785. package/build/utils/with-tracked-stack.js +38 -0
  786. package/build/velocious-error.js +34 -0
  787. package/package.json +3 -3
  788. package/src/configuration-types.js +1 -1
  789. package/src/database/record/index.js +174 -25
  790. package/src/environment-handlers/node/cli/commands/generate/base-models.js +50 -21
  791. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +5 -5
  792. package/src/frontend-model-resource/base-resource.js +6 -2
  793. package/src/frontend-models/resource-definition.js +3 -3
  794. package/src/frontend-models/websocket-publishers.js +6 -6
@@ -1,86 +1,73 @@
1
1
  // @ts-check
2
-
3
- import {incorporate} from "incorporator"
4
- import * as inflection from "inflection"
5
- import {isPlainObject} from "is-plain-object"
6
- import Logger from "../../logger.js"
7
- import Preloader from "./preloader.js"
8
- import {normalizeQueryDataSpec, runQueryData} from "./query-data.js"
9
- import {normalizeWithCount, runWithCount} from "./with-count.js"
10
- import DatabaseQuery from "./index.js"
11
- import JoinObject from "./join-object.js"
12
- import JoinPlain from "./join-plain.js"
13
- import JoinTracker from "./join-tracker.js"
14
- import RecordNotFoundError from "../record/record-not-found-error.js"
15
- import {normalizeRansackGroup, parseRansackSort} from "../../utils/ransack.js"
16
- import {isModelScopeDescriptor} from "../../utils/model-scope.js"
17
- import WhereCombinator from "./where-combinator.js"
18
- import WhereModelClassHash from "./where-model-class-hash.js"
19
- import WhereNot from "./where-not.js"
20
- import JoinsParser from "../query-parser/joins-parser.js"
21
- import WhereParser from "../query-parser/where-parser.js"
22
-
2
+ import { incorporate } from "incorporator";
3
+ import * as inflection from "inflection";
4
+ import { isPlainObject } from "is-plain-object";
5
+ import Logger from "../../logger.js";
6
+ import Preloader from "./preloader.js";
7
+ import { normalizeQueryDataSpec, runQueryData } from "./query-data.js";
8
+ import { normalizeWithCount, runWithCount } from "./with-count.js";
9
+ import DatabaseQuery from "./index.js";
10
+ import JoinObject from "./join-object.js";
11
+ import JoinPlain from "./join-plain.js";
12
+ import JoinTracker from "./join-tracker.js";
13
+ import RecordNotFoundError from "../record/record-not-found-error.js";
14
+ import { normalizeRansackGroup, parseRansackSort } from "../../utils/ransack.js";
15
+ import { isModelScopeDescriptor } from "../../utils/model-scope.js";
16
+ import WhereCombinator from "./where-combinator.js";
17
+ import WhereModelClassHash from "./where-model-class-hash.js";
18
+ import WhereNot from "./where-not.js";
19
+ import JoinsParser from "../query-parser/joins-parser.js";
20
+ import WhereParser from "../query-parser/where-parser.js";
23
21
  /**
24
22
  * Runs unquote sql identifier.
25
23
  * @param {string} value - Potentially quoted SQL identifier.
26
24
  * @returns {string} - Unquoted identifier.
27
25
  */
28
26
  function unquoteSqlIdentifier(value) {
29
- const trimmed = value.trim()
30
-
31
- if (trimmed.length >= 2 && ((trimmed.startsWith("`") && trimmed.endsWith("`")) || (trimmed.startsWith("\"") && trimmed.endsWith("\"")))) {
32
- return trimmed.slice(1, -1)
33
- }
34
-
35
- if (trimmed.length >= 2 && trimmed.startsWith("[") && trimmed.endsWith("]")) {
36
- return trimmed.slice(1, -1)
37
- }
38
-
39
- return trimmed
27
+ const trimmed = value.trim();
28
+ if (trimmed.length >= 2 && ((trimmed.startsWith("`") && trimmed.endsWith("`")) || (trimmed.startsWith("\"") && trimmed.endsWith("\"")))) {
29
+ return trimmed.slice(1, -1);
30
+ }
31
+ if (trimmed.length >= 2 && trimmed.startsWith("[") && trimmed.endsWith("]")) {
32
+ return trimmed.slice(1, -1);
33
+ }
34
+ return trimmed;
40
35
  }
41
-
42
36
  /**
43
37
  * Runs parse from plain table reference.
44
38
  * @param {string} fromPlain - FROM clause source.
45
39
  * @returns {string | null} - Parsed table reference or null when unsupported.
46
40
  */
47
41
  function parseFromPlainTableReference(fromPlain) {
48
- const trimmed = fromPlain.trim()
49
-
50
- if (trimmed.length < 1) return null
51
-
52
- const aliasMatch = trimmed.match(/(?:^|\s)(?:AS\s+)?([`"]?[a-zA-Z_][a-zA-Z0-9_]*[`"]?|\[[a-zA-Z_][a-zA-Z0-9_]*\])\s*$/i)
53
-
54
- if (!aliasMatch || !aliasMatch[1]) return null
55
-
56
- return unquoteSqlIdentifier(aliasMatch[1])
42
+ const trimmed = fromPlain.trim();
43
+ if (trimmed.length < 1)
44
+ return null;
45
+ const aliasMatch = trimmed.match(/(?:^|\s)(?:AS\s+)?([`"]?[a-zA-Z_][a-zA-Z0-9_]*[`"]?|\[[a-zA-Z_][a-zA-Z0-9_]*\])\s*$/i);
46
+ if (!aliasMatch || !aliasMatch[1])
47
+ return null;
48
+ return unquoteSqlIdentifier(aliasMatch[1]);
57
49
  }
58
-
59
50
  /**
60
51
  * Runs normalize scope path.
61
52
  * @param {string | string[]} path - Scope path input.
62
53
  * @returns {string[]} - Normalized path.
63
54
  */
64
55
  function normalizeScopePath(path) {
65
- if (typeof path === "string") {
66
- if (path.length < 1) throw new Error("Scope path strings must be non-empty")
67
-
68
- return [path]
69
- }
70
-
71
- if (!Array.isArray(path)) {
72
- throw new Error(`Invalid scope path type: ${typeof path}`)
73
- }
74
-
75
- for (const entry of path) {
76
- if (typeof entry !== "string" || entry.length < 1) {
77
- throw new Error("Scope path entries must be non-empty strings")
78
- }
79
- }
80
-
81
- return [...path]
56
+ if (typeof path === "string") {
57
+ if (path.length < 1)
58
+ throw new Error("Scope path strings must be non-empty");
59
+ return [path];
60
+ }
61
+ if (!Array.isArray(path)) {
62
+ throw new Error(`Invalid scope path type: ${typeof path}`);
63
+ }
64
+ for (const entry of path) {
65
+ if (typeof entry !== "string" || entry.length < 1) {
66
+ throw new Error("Scope path entries must be non-empty strings");
67
+ }
68
+ }
69
+ return [...path];
82
70
  }
83
-
84
71
  /**
85
72
  * Deep-copies a preload select map (keyed by model name with attribute arrays)
86
73
  * so a cloned query's selections can be mutated without affecting the original.
@@ -88,79 +75,64 @@ function normalizeScopePath(path) {
88
75
  * @returns {Record<string, string[]>} - A copy with independent arrays.
89
76
  */
90
77
  function clonePreloadSelectMap(map) {
91
- /**
92
- * Result.
93
- @type {Record<string, string[]>} */
94
- const result = {}
95
-
96
- for (const [modelName, attributes] of Object.entries(map)) {
97
- result[modelName] = [...attributes]
98
- }
99
-
100
- return result
78
+ /**
79
+ * Result.
80
+ @type {Record<string, string[]>} */
81
+ const result = {};
82
+ for (const [modelName, attributes] of Object.entries(map)) {
83
+ result[modelName] = [...attributes];
84
+ }
85
+ return result;
101
86
  }
102
-
103
87
  /**
104
88
  * Runs normalize preload record.
105
89
  * @param {import("./index.js").NestedPreloadRecord | string | Array<string | import("./index.js").NestedPreloadRecord>} preload - Preload data in shorthand or nested form.
106
90
  * @returns {import("./index.js").NestedPreloadRecord} - Normalized preload record.
107
91
  */
108
92
  function normalizePreloadRecord(preload) {
109
- if (!preload) return {}
110
-
111
- if (typeof preload == "string") {
112
- return {[preload]: true}
113
- }
114
-
115
- if (Array.isArray(preload)) {
93
+ if (!preload)
94
+ return {};
95
+ if (typeof preload == "string") {
96
+ return { [preload]: true };
97
+ }
98
+ if (Array.isArray(preload)) {
99
+ /**
100
+ * Result.
101
+ @type {import("./index.js").NestedPreloadRecord} */
102
+ const result = {};
103
+ for (const entry of preload) {
104
+ if (typeof entry == "string") {
105
+ result[entry] = true;
106
+ continue;
107
+ }
108
+ if (isPlainObject(entry)) {
109
+ incorporate(result, normalizePreloadRecord(entry));
110
+ continue;
111
+ }
112
+ throw new Error(`Invalid preload entry type: ${typeof entry}`);
113
+ }
114
+ return result;
115
+ }
116
+ if (!isPlainObject(preload)) {
117
+ throw new Error(`Invalid preload type: ${typeof preload}`);
118
+ }
116
119
  /**
117
120
  * Result.
118
121
  @type {import("./index.js").NestedPreloadRecord} */
119
- const result = {}
120
-
121
- for (const entry of preload) {
122
- if (typeof entry == "string") {
123
- result[entry] = true
124
- continue
125
- }
126
-
127
- if (isPlainObject(entry)) {
128
- incorporate(result, normalizePreloadRecord(entry))
129
- continue
130
- }
131
-
132
- throw new Error(`Invalid preload entry type: ${typeof entry}`)
133
- }
134
-
135
- return result
136
- }
137
-
138
- if (!isPlainObject(preload)) {
139
- throw new Error(`Invalid preload type: ${typeof preload}`)
140
- }
141
-
142
- /**
143
- * Result.
144
- @type {import("./index.js").NestedPreloadRecord} */
145
- const result = {}
146
-
147
- for (const [key, value] of Object.entries(preload)) {
148
- if (value === true || value === false) {
149
- result[key] = value
150
- continue
151
- }
152
-
153
- if (typeof value == "string" || Array.isArray(value) || isPlainObject(value)) {
154
- result[key] = normalizePreloadRecord(value)
155
- continue
156
- }
157
-
158
- throw new Error(`Invalid preload value for ${key}: ${typeof value}`)
159
- }
160
-
161
- return result
122
+ const result = {};
123
+ for (const [key, value] of Object.entries(preload)) {
124
+ if (value === true || value === false) {
125
+ result[key] = value;
126
+ continue;
127
+ }
128
+ if (typeof value == "string" || Array.isArray(value) || isPlainObject(value)) {
129
+ result[key] = normalizePreloadRecord(value);
130
+ continue;
131
+ }
132
+ throw new Error(`Invalid preload value for ${key}: ${typeof value}`);
133
+ }
134
+ return result;
162
135
  }
163
-
164
136
  /**
165
137
  * Defines this typedef.
166
138
  * @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
@@ -170,972 +142,815 @@ function normalizePreloadRecord(preload) {
170
142
  * @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
171
143
  * @typedef {import("./index.js").QueryArgsType & {modelClass: MC, joinBasePath?: string[], joinTracker?: import("./join-tracker.js").default, forceQualifyBaseTable?: boolean, withCount?: import("./with-count.js").WithCountEntry[], queryData?: import("./query-data.js").QueryDataEntry[]}} ModelClassQueryArgsType
172
144
  */
173
-
174
145
  /**
175
146
  * A generic query over some model type.
176
147
  * @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
177
148
  */
178
149
  export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery {
179
- /**
180
- * Runs constructor.
181
- * @param {ModelClassQueryArgsType<MC>} args - Query constructor arguments.
182
- */
183
- constructor(args) {
184
- const {modelClass} = args
185
-
186
- if (!modelClass) throw new Error(`No modelClass given in ${Object.keys(args).join(", ")}`)
187
-
188
- super(args)
189
- this.logger = new Logger(this)
190
-
191
150
  /**
192
- * Narrows the runtime value to the documented type.
193
- @type {MC} */
194
- this.modelClass = modelClass
195
-
151
+ * Runs constructor.
152
+ * @param {ModelClassQueryArgsType<MC>} args - Query constructor arguments.
153
+ */
154
+ constructor(args) {
155
+ const { modelClass } = args;
156
+ if (!modelClass)
157
+ throw new Error(`No modelClass given in ${Object.keys(args).join(", ")}`);
158
+ super(args);
159
+ this.logger = new Logger(this);
160
+ /**
161
+ * Narrows the runtime value to the documented type.
162
+ @type {MC} */
163
+ this.modelClass = modelClass;
164
+ /**
165
+ * Narrows the runtime value to the documented type.
166
+ @type {string[]} */
167
+ this._joinBasePath = args.joinBasePath || [];
168
+ this._joinTracker = args.joinTracker || new JoinTracker({ modelClass: this.modelClass });
169
+ this._forceQualifyBaseTable = Boolean(args.forceQualifyBaseTable);
170
+ /**
171
+ * Narrows the runtime value to the documented type.
172
+ @type {import("./with-count.js").WithCountEntry[]} */
173
+ this._withCount = args.withCount ? [...args.withCount] : [];
174
+ /**
175
+ * Narrows the runtime value to the documented type.
176
+ @type {import("./query-data.js").QueryDataEntry[]} */
177
+ this._queryData = args.queryData ? [...args.queryData] : [];
178
+ }
196
179
  /**
197
- * Narrows the runtime value to the documented type.
198
- @type {string[]} */
199
- this._joinBasePath = args.joinBasePath || []
200
- this._joinTracker = args.joinTracker || new JoinTracker({modelClass: this.modelClass})
201
- this._forceQualifyBaseTable = Boolean(args.forceQualifyBaseTable)
202
-
180
+ * Runs clone.
181
+ * @returns {this} - The clone.
182
+ */
183
+ clone() {
184
+ const newQuery = /**
185
+ * Narrows the runtime value to the documented type.
186
+ @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (new VelociousDatabaseQueryModelClassQuery({
187
+ driver: this._driverFn,
188
+ froms: [...this._froms],
189
+ handler: this.handler.clone(),
190
+ groups: [...this._groups],
191
+ joins: [...this._joins],
192
+ limit: this._limit,
193
+ modelClass: this.modelClass,
194
+ offset: this._offset,
195
+ orders: [...this._orders],
196
+ page: this._page,
197
+ perPage: this._perPage,
198
+ preload: { ...this._preload },
199
+ preloadSelects: clonePreloadSelectMap(this._preloadSelects),
200
+ preloadSelectsExtra: clonePreloadSelectMap(this._preloadSelectsExtra),
201
+ distinct: this._distinct,
202
+ selects: [...this._selects],
203
+ wheres: [...this._wheres],
204
+ joinBasePath: [...this._joinBasePath],
205
+ joinTracker: this._joinTracker.clone(),
206
+ forceQualifyBaseTable: this._forceQualifyBaseTable,
207
+ withCount: [...this._withCount],
208
+ queryData: [...this._queryData]
209
+ }));
210
+ // @ts-expect-error
211
+ return newQuery;
212
+ }
203
213
  /**
204
- * Narrows the runtime value to the documented type.
205
- @type {import("./with-count.js").WithCountEntry[]} */
206
- this._withCount = args.withCount ? [...args.withCount] : []
207
-
214
+ * Tell the query to attach one or more association counts onto every
215
+ * loaded record. The counts land as regular attributes on each record;
216
+ * read them with `model.readAttribute("<name>Count")`.
217
+ * @param {import("./with-count.js").WithCountSpec} spec - Count spec in shorthand or nested form.
218
+ * @returns {this} - This query, for chaining.
219
+ */
220
+ withCount(spec) {
221
+ for (const entry of normalizeWithCount(spec)) {
222
+ this._withCount.push(entry);
223
+ }
224
+ return this;
225
+ }
208
226
  /**
209
- * Narrows the runtime value to the documented type.
210
- @type {import("./query-data.js").QueryDataEntry[]} */
211
- this._queryData = args.queryData ? [...args.queryData] : []
212
- }
213
-
214
- /**
215
- * Runs clone.
216
- * @returns {this} - The clone.
217
- */
218
- clone() {
219
- const newQuery = /**
220
- * Narrows the runtime value to the documented type.
221
- @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (new VelociousDatabaseQueryModelClassQuery({
222
- driver: this._driverFn,
223
- froms: [...this._froms],
224
- handler: this.handler.clone(),
225
- groups: [...this._groups],
226
- joins: [...this._joins],
227
- limit: this._limit,
228
- modelClass: this.modelClass,
229
- offset: this._offset,
230
- orders: [...this._orders],
231
- page: this._page,
232
- perPage: this._perPage,
233
- preload: {...this._preload},
234
- preloadSelects: clonePreloadSelectMap(this._preloadSelects),
235
- preloadSelectsExtra: clonePreloadSelectMap(this._preloadSelectsExtra),
236
- distinct: this._distinct,
237
- selects: [...this._selects],
238
- wheres: [...this._wheres],
239
- joinBasePath: [...this._joinBasePath],
240
- joinTracker: this._joinTracker.clone(),
241
- forceQualifyBaseTable: this._forceQualifyBaseTable,
242
- withCount: [...this._withCount],
243
- queryData: [...this._queryData]
244
- }))
245
-
246
- // @ts-expect-error
247
- return newQuery
248
- }
249
-
250
- /**
251
- * Tell the query to attach one or more association counts onto every
252
- * loaded record. The counts land as regular attributes on each record;
253
- * read them with `model.readAttribute("<name>Count")`.
254
- * @param {import("./with-count.js").WithCountSpec} spec - Count spec in shorthand or nested form.
255
- * @returns {this} - This query, for chaining.
256
- */
257
- withCount(spec) {
258
- for (const entry of normalizeWithCount(spec)) {
259
- this._withCount.push(entry)
260
- }
261
-
262
- return this
263
- }
264
-
265
- /**
266
- * Attach one or more consumer-defined, per-row computed values onto
267
- * every loaded root record. Leaf strings in the spec are names of
268
- * functions previously registered via `Model.queryData(name, fn)`.
269
- * Nested object keys are relationship names traced from the root to
270
- * the model that declares the fn. Every resulting SELECT alias is
271
- * attached to the **root** record (not to the intermediate joined
272
- * rows); read values with `record.queryData(aliasName)`.
273
- *
274
- * See also `src/database/query/query-data.js`.
275
- * @param {import("./query-data.js").QueryDataSpec} spec - Spec in shorthand or nested form.
276
- * @returns {this} - This query, for chaining.
277
- */
278
- queryData(spec) {
279
- for (const entry of normalizeQueryDataSpec(spec)) {
280
- this._queryData.push(entry)
281
- }
282
-
283
- return this
284
- }
285
-
286
- /**
287
- * Return the table reference (alias or table name) registered for the
288
- * given relationship chain, relative to the query's current join base
289
- * path. Convenience wrapper around `getTableReferenceForJoin` for use
290
- * inside `queryData` callbacks where the writer's intent reads more
291
- * naturally as "give me the table name for 'tasks'".
292
- * @param {...string} path - Relationship path segments.
293
- * @returns {string} - Unquoted table reference.
294
- */
295
- tableNameFor(...path) {
296
- return this.getTableReferenceForJoin(...path)
297
- }
298
-
299
- /**
300
- * Runs count.
301
- * @returns {Promise<number>} - Resolves with the count.
302
- */
303
- async count() {
304
- if (this._limit !== null || this._offset !== null) {
305
- return await this.paginatedCount()
306
- }
307
-
308
- // Generate count SQL
309
- const primaryKey = `${this.driver.quoteTable(this.getModelClass().tableName())}.${this.driver.quoteColumn(this.getModelClass().primaryKey())}`
310
- const distinctPrefix = this._distinct ? "DISTINCT " : ""
311
- let sql = `COUNT(${distinctPrefix}${primaryKey})`
312
-
313
- if (this.driver.getType() == "pgsql") sql += "::int"
314
-
315
- sql += " AS count"
316
-
317
-
318
- // Clone query and execute count
319
- const countQuery = this.clone()
320
-
321
- countQuery._distinct = false
322
- countQuery._selects = []
323
- countQuery.select(sql)
324
-
325
- const results = /**
326
- * Narrows the runtime value to the documented type.
327
- @type {{count: number}[]} */ (await countQuery._executeQuery({
328
- logName: countQuery.queryLogName("Count")
329
- }))
330
-
331
- // The query isn't grouped and a single result has been given
332
- if (results.length == 1) {
333
- return results[0].count
334
- }
335
-
336
- // The query may be grouped and a lot of different counts a given
337
- let countResult = 0
338
-
339
- for (const result of results) {
340
- if (!("count" in result)) {
341
- throw new Error("Invalid count result")
342
- }
343
-
344
- countResult += result.count
345
- }
346
-
347
- return countResult
348
- }
349
-
350
- /**
351
- * Runs paginated count.
352
- * @returns {Promise<number>} - Resolves with the count after pagination is applied.
353
- */
354
- async paginatedCount() {
355
- const countQuery = this.clone()
356
- const countSql = this.driver.getType() == "pgsql" ? "COUNT(*)::int" : "COUNT(*)"
357
- const sql = [
358
- `SELECT ${countSql} AS ${this.driver.quoteColumn("count")}`,
359
- `FROM (${countQuery.toSql()}) AS ${this.driver.quoteTable("paginated_count_rows")}`
360
- ].join(" ")
361
- const results = /**
362
- * Narrows the runtime value to the documented type.
363
- @type {{count: number}[]} */ (await this.driver.query(
364
- sql,
365
- {logName: this.queryLogName("Count")}
366
- ))
367
-
368
- if (results.length != 1 || !("count" in results[0])) {
369
- throw new Error("Invalid count result")
370
- }
371
-
372
- return results[0].count
373
- }
374
-
375
- /**
376
- * Runs select.
377
- * @param {import("./index.js").SelectArgumentType} select - Select.
378
- * @returns {this} - The select.
379
- */
380
- select(select) {
381
- if (Array.isArray(select)) {
382
- for (const selectEntry of select) {
383
- this.select(selectEntry)
384
- }
385
-
386
- return this
387
- }
388
-
389
- if (typeof select === "string") {
390
- const trimmedSelect = select.trim()
391
-
392
- if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmedSelect)) {
393
- const modelClass = this.getModelClass()
394
- const attributeMap = modelClass.getAttributeNameToColumnNameMap()
395
- const columnName = attributeMap[trimmedSelect] || trimmedSelect
396
- const tableReference = this.rootTableReference()
397
- const qualifiedColumn = `${this.driver.quoteTable(tableReference)}.${this.driver.quoteColumn(columnName)}`
398
-
399
- return super.select(qualifiedColumn)
400
- }
401
- }
402
-
403
- // Object form keyed by target model name, e.g. `.select({Account: ["id"]})`.
404
- // These limit the attributes loaded for preloaded relationship targets
405
- // rather than the root query's SELECT clause.
406
- if (isPlainObject(select)) {
407
- this._mergePreloadSelect(this._preloadSelects, select)
408
-
409
- return this
410
- }
411
-
412
- return super.select(select)
413
- }
414
-
415
- /**
416
- * Loads the default columns plus the given extra selects for preloaded
417
- * relationship targets, keyed by target model name, e.g.
418
- * `.selectsExtra({Account: ["(SELECT count(*) FROM projects) AS projects_count"]})`.
419
- * Unlike `select({...})`, which narrows to only the listed columns, this keeps
420
- * the default `SELECT *` columns and adds the extras on top.
421
- * @param {Record<string, string | string[]>} select - Extra selects keyed by target model name.
422
- * @returns {this} - This query, for chaining.
423
- */
424
- selectsExtra(select) {
425
- this._mergePreloadSelect(this._preloadSelectsExtra, select)
426
-
427
- return this
428
- }
429
-
430
- /**
431
- * Merges an object-form preload select (keyed by target model name) into the
432
- * given target map, de-duplicating attribute/expression entries.
433
- * @param {Record<string, string[]>} target - Map to merge into.
434
- * @param {Record<string, string | string[]>} select - Object-form select.
435
- * @returns {void} - No return value.
436
- */
437
- _mergePreloadSelect(target, select) {
438
- for (const [modelName, attributes] of Object.entries(select)) {
439
- const normalizedAttributes = Array.isArray(attributes) ? attributes : [attributes]
440
-
441
- if (!target[modelName]) target[modelName] = []
442
-
443
- for (const attribute of normalizedAttributes) {
444
- if (!target[modelName].includes(attribute)) target[modelName].push(attribute)
445
- }
446
- }
447
- }
448
-
449
- /**
450
- * Runs root table reference.
451
- * @returns {string} - Root table reference for query select qualification.
452
- */
453
- rootTableReference() {
454
- const froms = this.getFroms()
455
- const lastFrom = froms[froms.length - 1]
456
-
457
- if (lastFrom && typeof /**
458
- * Narrows the runtime value to the documented type.
459
- @type {?} */ (lastFrom).tableName === "string") {
460
- return /** Narrows the runtime value to the documented type. @type {?} */ (lastFrom).tableName
461
- }
462
-
463
- if (lastFrom && typeof /**
464
- * Narrows the runtime value to the documented type.
465
- @type {?} */ (lastFrom).plain === "string") {
466
- const parsedReference = parseFromPlainTableReference(/**
467
- * Narrows the runtime value to the documented type.
468
- @type {?} */ (lastFrom).plain)
469
-
470
- if (parsedReference) return parsedReference
471
- }
472
-
473
- return this.getTableReferenceForJoin()
474
- }
475
-
476
- /**
477
- * Runs get model class.
478
- * @returns {MC} - The model class.
479
- */
480
- getModelClass() {
481
- if (!this.modelClass) throw new Error("modelClass not set")
482
-
483
- return this.modelClass
484
- }
485
-
486
- /**
487
- * Runs get join base path.
488
- * @returns {string[]} - The join base path.
489
- */
490
- getJoinBasePath() {
491
- return this._joinBasePath
492
- }
493
-
494
- /**
495
- * Runs get join tracker.
496
- * @returns {import("./join-tracker.js").default} - The join tracker.
497
- */
498
- getJoinTracker() {
499
- return this._joinTracker
500
- }
501
-
502
- /**
503
- * Runs get force qualify base table.
504
- * @returns {boolean} - Whether to qualify base table.
505
- */
506
- getForceQualifyBaseTable() {
507
- return this._forceQualifyBaseTable
508
- }
509
-
510
- /**
511
- * Runs set join base path.
512
- * @param {string[]} joinBasePath - Join base path.
513
- * @returns {this} - The query with updated base path.
514
- */
515
- setJoinBasePath(joinBasePath) {
516
- this._joinBasePath = joinBasePath
517
- return this
518
- }
519
-
520
- /**
521
- * Runs with join path.
522
- * @param {string[]} joinBasePath - Join base path.
523
- * @returns {VelociousDatabaseQueryModelClassQuery<MC>} - The scoped query.
524
- */
525
- withJoinPath(joinBasePath) {
526
- const scopedQuery = /**
527
- * Narrows the runtime value to the documented type.
528
- @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
529
-
530
- scopedQuery._joinBasePath = joinBasePath
531
- scopedQuery._joinTracker = this._joinTracker
532
-
533
- return scopedQuery
534
- }
535
-
536
- /**
537
- * Runs resolve table name for join path.
538
- * @param {string[]} path - Join path.
539
- * @returns {string} - Table name for path.
540
- */
541
- _resolveTableNameForJoinPath(path) {
542
- return this._resolveModelClassForJoinPath(path).tableName()
543
- }
544
-
545
- /**
546
- * Runs resolve model class for join path.
547
- * @param {string[]} path - Join path.
548
- * @returns {typeof import("../record/index.js").default} - Target model class.
549
- */
550
- _resolveModelClassForJoinPath(path) {
551
- let modelClass = this._joinTracker.getRootModelClass()
552
-
553
- for (const relationshipName of path) {
554
- const relationship = modelClass.getRelationshipByName(relationshipName)
555
- const targetModelClass = relationship.getTargetModelClass()
556
-
557
- if (!targetModelClass) {
558
- throw new Error(`No target model class for ${modelClass.name}#${relationshipName}`)
559
- }
560
-
561
- modelClass = targetModelClass
562
- }
563
-
564
- return modelClass
565
- }
566
-
567
- /**
568
- * Runs register join path.
569
- * @param {string[]} path - Join path.
570
- * @returns {{tableName: string, alias: string | undefined}} - The entry.
571
- */
572
- _registerJoinPath(path) {
573
- const tableName = this._resolveTableNameForJoinPath(path)
574
-
575
- return this._joinTracker.registerPath(path, tableName)
576
- }
577
-
578
- /**
579
- * Runs get join table reference.
580
- * @param {string[]} path - Join path.
581
- * @returns {string} - Unquoted table reference (alias or table name).
582
- */
583
- getJoinTableReference(path) {
584
- const entry = this._joinTracker.getEntry(path) || this._registerJoinPath(path)
585
-
586
- return entry.alias || entry.tableName
587
- }
588
-
589
- /**
590
- * Runs get table reference for join.
591
- * @param {...string} path - Join path segments.
592
- * @returns {string} - Unquoted table reference (alias or table name).
593
- */
594
- getTableReferenceForJoin(...path) {
595
- const fullPath = this._joinBasePath.concat(path)
596
-
597
- return this.getJoinTableReference(fullPath)
598
- }
599
-
600
- /**
601
- * Runs get table for join.
602
- * @param {...string} path - Join path segments.
603
- * @returns {string} - Quoted table name for join path.
604
- */
605
- getTableForJoin(...path) {
606
- return this.driver.quoteTable(this.getTableReferenceForJoin(...path))
607
- }
608
-
609
- /**
610
- * Runs scope.
611
- * @param {import("../../utils/model-scope.js").ModelScopeDescriptor | string | string[]} pathOrScopeDescriptor - Scope descriptor or join path.
612
- * @param {import("../../utils/model-scope.js").ModelScopeDescriptor} [maybeScopeDescriptor] - Scope descriptor when path is given.
613
- * @returns {this} - Scoped query.
614
- */
615
- scope(pathOrScopeDescriptor, maybeScopeDescriptor) {
616
- if (isModelScopeDescriptor(pathOrScopeDescriptor) && !maybeScopeDescriptor) {
617
- return this._applyRootScope(pathOrScopeDescriptor)
618
- }
619
-
620
- if (!maybeScopeDescriptor) {
621
- throw new Error("scope(path, descriptor) requires a scope descriptor")
622
- }
623
-
624
- return this._applyJoinPathScope({
625
- joinPath: normalizeScopePath(/**
626
- * Narrows the runtime value to the documented type.
627
- @type {string | string[]} */ (pathOrScopeDescriptor)),
628
- scopeDescriptor: maybeScopeDescriptor
629
- })
630
- }
631
-
632
- /**
633
- * Runs apply root scope.
634
- * @param {import("../../utils/model-scope.js").ModelScopeDescriptor} scopeDescriptor - Scope descriptor.
635
- * @returns {this} - Scoped query.
636
- */
637
- _applyRootScope(scopeDescriptor) {
638
- if (!isModelScopeDescriptor(scopeDescriptor)) {
639
- throw new Error("scope() expects a descriptor returned by defineScope(...).scope(...)")
640
- }
641
-
642
- if (scopeDescriptor.modelClass !== this.getModelClass()) {
643
- throw new Error(`Cannot apply ${scopeDescriptor.modelClass.name} scope to ${this.getModelClass().name} query`)
644
- }
645
-
646
- const scopedQuery = /**
227
+ * Attach one or more consumer-defined, per-row computed values onto
228
+ * every loaded root record. Leaf strings in the spec are names of
229
+ * functions previously registered via `Model.queryData(name, fn)`.
230
+ * Nested object keys are relationship names traced from the root to
231
+ * the model that declares the fn. Every resulting SELECT alias is
232
+ * attached to the **root** record (not to the intermediate joined
233
+ * rows); read values with `record.queryData(aliasName)`.
234
+ *
235
+ * See also `src/database/query/query-data.js`.
236
+ * @param {import("./query-data.js").QueryDataSpec} spec - Spec in shorthand or nested form.
237
+ * @returns {this} - This query, for chaining.
238
+ */
239
+ queryData(spec) {
240
+ for (const entry of normalizeQueryDataSpec(spec)) {
241
+ this._queryData.push(entry);
242
+ }
243
+ return this;
244
+ }
245
+ /**
246
+ * Return the table reference (alias or table name) registered for the
247
+ * given relationship chain, relative to the query's current join base
248
+ * path. Convenience wrapper around `getTableReferenceForJoin` for use
249
+ * inside `queryData` callbacks where the writer's intent reads more
250
+ * naturally as "give me the table name for 'tasks'".
251
+ * @param {...string} path - Relationship path segments.
252
+ * @returns {string} - Unquoted table reference.
253
+ */
254
+ tableNameFor(...path) {
255
+ return this.getTableReferenceForJoin(...path);
256
+ }
257
+ /**
258
+ * Runs count.
259
+ * @returns {Promise<number>} - Resolves with the count.
260
+ */
261
+ async count() {
262
+ if (this._limit !== null || this._offset !== null) {
263
+ return await this.paginatedCount();
264
+ }
265
+ // Generate count SQL
266
+ const primaryKey = `${this.driver.quoteTable(this.getModelClass().tableName())}.${this.driver.quoteColumn(this.getModelClass().primaryKey())}`;
267
+ const distinctPrefix = this._distinct ? "DISTINCT " : "";
268
+ let sql = `COUNT(${distinctPrefix}${primaryKey})`;
269
+ if (this.driver.getType() == "pgsql")
270
+ sql += "::int";
271
+ sql += " AS count";
272
+ // Clone query and execute count
273
+ const countQuery = this.clone();
274
+ countQuery._distinct = false;
275
+ countQuery._selects = [];
276
+ countQuery.select(sql);
277
+ const results = /**
647
278
  * Narrows the runtime value to the documented type.
648
- @type {this | void} */ (scopeDescriptor.callback({
649
- driver: this.driver,
650
- modelClass: this.getModelClass(),
651
- query: this,
652
- table: this.rootTableReference()
653
- }, ...scopeDescriptor.scopeArgs))
654
-
655
- return scopedQuery || this
656
- }
657
-
658
- /**
659
- * Runs apply join path scope.
660
- * @param {object} args - Join-path scope options.
661
- * @param {string[]} args.joinPath - Join path relative to the current query.
662
- * @param {import("../../utils/model-scope.js").ModelScopeDescriptor} args.scopeDescriptor - Scope descriptor.
663
- * @returns {this} - Scoped query.
664
- */
665
- _applyJoinPathScope({joinPath, scopeDescriptor}) {
666
- if (!isModelScopeDescriptor(scopeDescriptor)) {
667
- throw new Error("scope() expects a descriptor returned by defineScope(...).scope(...)")
668
- }
669
-
670
- const fullJoinPath = this.getJoinBasePath().concat(joinPath)
671
- const targetModelClass = this._resolveModelClassForJoinPath(fullJoinPath)
672
-
673
- if (scopeDescriptor.modelClass !== targetModelClass) {
674
- throw new Error(`Cannot apply ${scopeDescriptor.modelClass.name} scope to join path ${fullJoinPath.join(".")} (${targetModelClass.name})`)
675
- }
676
-
677
- const scopedQuery = this.buildJoinScopeQuery(targetModelClass, fullJoinPath)
678
- const originalJoinCount = scopedQuery._joins.length
679
- const originalWhereCount = scopedQuery._wheres.length
680
- const appliedQuery = /**
681
- * Narrows the runtime value to the documented type.
682
- @type {typeof scopedQuery | void} */ (scopeDescriptor.callback({
683
- driver: scopedQuery.driver,
684
- modelClass: targetModelClass,
685
- path: [...fullJoinPath],
686
- query: scopedQuery,
687
- table: scopedQuery.getTableReferenceForJoin()
688
- }, ...scopeDescriptor.scopeArgs)) || scopedQuery
689
-
690
- if (appliedQuery.getFroms().length !== scopedQuery.getFroms().length ||
691
- appliedQuery.getGroups().length !== scopedQuery.getGroups().length ||
692
- appliedQuery.getSelects().length !== scopedQuery.getSelects().length ||
693
- appliedQuery._orders.length !== scopedQuery._orders.length ||
694
- appliedQuery._limit !== scopedQuery._limit ||
695
- appliedQuery._offset !== scopedQuery._offset ||
696
- appliedQuery._page !== scopedQuery._page ||
697
- appliedQuery._perPage !== scopedQuery._perPage ||
698
- appliedQuery._distinct !== scopedQuery._distinct ||
699
- Object.keys(appliedQuery._preload).length !== Object.keys(scopedQuery._preload).length) {
700
- throw new Error("Joined-path scopes may only add where(...) and joins(...) clauses")
701
- }
702
-
703
- if (appliedQuery._joins.length > originalJoinCount) {
704
- for (const join of appliedQuery._joins.slice(originalJoinCount)) {
705
- if (join instanceof JoinObject) {
706
- this._joins.push(new JoinObject(join.object, fullJoinPath))
707
- } else if (join instanceof JoinPlain) {
708
- this._joins.push(join)
709
- } else {
710
- this._joins.push(join)
279
+ @type {{count: number}[]} */ (await countQuery._executeQuery({
280
+ logName: countQuery.queryLogName("Count")
281
+ }));
282
+ // The query isn't grouped and a single result has been given
283
+ if (results.length == 1) {
284
+ return results[0].count;
711
285
  }
712
- }
713
- }
714
-
715
- if (appliedQuery._wheres.length > originalWhereCount) {
716
- this._wheres.push(...appliedQuery._wheres.slice(originalWhereCount))
717
- }
718
-
719
- return this
720
- }
721
-
722
- /**
723
- * Runs build join scope query.
724
- * @param {typeof import("../record/index.js").default} targetModelClass - Target model class.
725
- * @param {string[]} joinPath - Join path.
726
- * @returns {VelociousDatabaseQueryModelClassQuery<MC>} - The scoped join query.
727
- */
728
- buildJoinScopeQuery(targetModelClass, joinPath) {
729
- const scopedQuery = /**
286
+ // The query may be grouped and a lot of different counts a given
287
+ let countResult = 0;
288
+ for (const result of results) {
289
+ if (!("count" in result)) {
290
+ throw new Error("Invalid count result");
291
+ }
292
+ countResult += result.count;
293
+ }
294
+ return countResult;
295
+ }
296
+ /**
297
+ * Runs paginated count.
298
+ * @returns {Promise<number>} - Resolves with the count after pagination is applied.
299
+ */
300
+ async paginatedCount() {
301
+ const countQuery = this.clone();
302
+ const countSql = this.driver.getType() == "pgsql" ? "COUNT(*)::int" : "COUNT(*)";
303
+ const sql = [
304
+ `SELECT ${countSql} AS ${this.driver.quoteColumn("count")}`,
305
+ `FROM (${countQuery.toSql()}) AS ${this.driver.quoteTable("paginated_count_rows")}`
306
+ ].join(" ");
307
+ const results = /**
730
308
  * Narrows the runtime value to the documented type.
731
- @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (targetModelClass._newQuery())
732
-
733
- scopedQuery._joinTracker = this._joinTracker
734
- scopedQuery._joinBasePath = joinPath
735
- scopedQuery._forceQualifyBaseTable = true
736
-
737
- return scopedQuery
738
- }
739
-
740
- /**
741
- * Runs destroy all.
742
- * @returns {Promise<void>} - Resolves when complete.
743
- */
744
- async destroyAll() {
745
- const records = await this.toArray()
746
-
747
- for (const record of records) {
748
- await record.destroy()
749
- }
750
- }
751
-
752
- /**
753
- * Executes a bulk UPDATE on all rows matching the query's WHERE
754
- * clause. Bypasses model lifecycle callbacks — use this for
755
- * efficient batch updates where per-row hooks aren't needed.
756
- * @param {Record<string, ?>} data - camelCase attribute names → values.
757
- * @returns {Promise<void>} - Resolves when the update completes.
758
- */
759
- async updateAll(data) {
760
- const driver = this.driver
761
- const tableName = this.getModelClass().tableName()
762
- const entries = Object.entries(data)
763
-
764
- if (entries.length === 0) return
765
-
766
- const setCols = entries.map(([key, value]) => {
767
- const columnName = inflection.underscore(key)
768
- const quoted = value === null ? "NULL" : driver.quote(value)
769
-
770
- return `${driver.quoteColumn(columnName)} = ${quoted}`
771
- }).join(", ")
772
-
773
- const joinsSql = new JoinsParser({pretty: false, query: this}).toSql()
774
- const whereSql = new WhereParser({pretty: false, query: this}).toSql()
775
- let sql
776
-
777
- if (joinsSql.length > 0) {
778
- // Use a subquery for cross-driver compatibility (SQLite
779
- // doesn't support UPDATE ... JOIN).
780
- const pk = driver.quoteColumn(this.getModelClass().primaryKey())
781
- const qt = driver.quoteTable(tableName)
782
-
783
- sql = `UPDATE ${qt} SET ${setCols} WHERE ${pk} IN (SELECT ${qt}.${pk} FROM ${qt}${joinsSql}${whereSql})`
784
- } else {
785
- sql = `UPDATE ${driver.quoteTable(tableName)} SET ${setCols}${whereSql}`
786
- }
787
-
788
- await driver.query(sql, {logName: this.queryLogName("Update All")})
789
- }
790
-
791
- /**
792
- * Runs find.
793
- * @param {number|string} recordId - Record id.
794
- * @returns {Promise<InstanceType<MC>>} - Resolves with the find.
795
- */
796
- async find(recordId) {
309
+ @type {{count: number}[]} */ (await this.driver.query(sql, { logName: this.queryLogName("Count") }));
310
+ if (results.length != 1 || !("count" in results[0])) {
311
+ throw new Error("Invalid count result");
312
+ }
313
+ return results[0].count;
314
+ }
797
315
  /**
798
- * Conditions.
799
- @type {{[key: string]: number | string}} */
800
- const conditions = {}
801
-
802
- conditions[this.getModelClass().primaryKey()] = recordId
803
-
804
- const newQuery = /**
805
- * Narrows the runtime value to the documented type.
806
- @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
807
-
808
- newQuery.where(conditions)
809
-
810
- const record = (await newQuery.first())
811
-
812
- if (!record) {
813
- throw new RecordNotFoundError(`Couldn't find ${this.getModelClass().name} with '${this.getModelClass().primaryKey()}'=${recordId}`)
814
- }
815
-
816
- return record
817
- }
818
-
819
- /**
820
- * Runs find by.
821
- * @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
822
- * @returns {Promise<InstanceType<MC> | null>} - Resolves with the by.
823
- */
824
- async findBy(conditions) {
825
- const newQuery = /**
826
- * Narrows the runtime value to the documented type.
827
- @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
828
-
829
- newQuery.where(conditions)
830
-
831
- return await newQuery.first()
832
- }
833
-
834
- /**
835
- * Runs find or create by.
836
- * @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
837
- * @param {function(InstanceType<MC>) : void} [callback] - Callback function.
838
- * @returns {Promise<InstanceType<MC>>} - Resolves with the or create by.
839
- */
840
- async findOrCreateBy(conditions, callback) {
841
- const record = await this.findOrInitializeBy(conditions, callback)
842
-
843
- if (record.isNewRecord()) {
844
- await record.save()
845
- }
846
-
847
- return record
848
- }
849
-
850
- /**
851
- * Runs find by or fail.
852
- * @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
853
- * @returns {Promise<InstanceType<MC>>} - Resolves with the by or fail.
854
- */
855
- async findByOrFail(conditions) {
856
- const record = await this.findBy(conditions)
857
-
858
- if (!record) {
859
- throw new Error("Record not found")
860
- }
861
-
862
- return record
863
- }
864
-
865
- /**
866
- * Runs find or initialize by.
867
- * @param {Record<string, ?>} conditions - Conditions.
868
- * @param {function(InstanceType<MC>) : void} [callback] - Callback function.
869
- * @returns {Promise<InstanceType<MC>>} - Resolves with the or initialize by.
870
- */
871
- async findOrInitializeBy(conditions, callback) {
872
- const record = await this.findBy(conditions)
873
-
874
- if (record) return record
875
-
876
- const ModelClass = this.getModelClass()
877
- const newRecord = /**
878
- * Narrows the runtime value to the documented type.
879
- @type {InstanceType<MC>} */ (new ModelClass(conditions))
880
-
881
- if (callback) {
882
- callback(newRecord)
883
- }
884
-
885
- return newRecord
886
- }
887
-
888
- /**
889
- * Runs first.
890
- * @returns {Promise<InstanceType<MC> | null>} - Resolves with the first.
891
- */
892
- async first() {
893
- const newQuery = this.clone().limit(1).reorder(`${this.driver.quoteTable(this.getModelClass().tableName())}.${this.driver.quoteColumn(this.getModelClass().orderableColumn())}`)
894
- const results = await newQuery.toArray()
895
-
896
- return results[0] || null
897
- }
898
-
899
- /**
900
- * Runs last.
901
- * @returns {Promise<InstanceType<MC> | null>} - Resolves with the last.
902
- */
903
- async last() {
904
- const primaryKey = this.getModelClass().primaryKey()
905
- const tableName = this.getModelClass().tableName()
906
- const results = await this.clone().reorder(`${this.driver.quoteTable(tableName)}.${this.driver.quoteColumn(primaryKey)} DESC`).limit(1).toArray()
907
-
908
- return results[0] || null
909
- }
910
-
911
- /**
912
- * Runs preload.
913
- * @param {import("./index.js").NestedPreloadRecord | string | Array<string | import("./index.js").NestedPreloadRecord>} data - Data payload.
914
- * @returns {this} - The preload.
915
- */
916
- preload(data) {
917
- const normalizedPreload = normalizePreloadRecord(data)
918
- incorporate(this._preload, normalizedPreload)
919
- return this
920
- }
921
-
922
- /**
923
- * Loads query results into model instances.
924
- * @returns {Promise<Array<InstanceType<MC>>>} - Resolves with the array.
925
- */
926
- async load() {
927
- const models = []
928
- const results = await this.results()
929
-
930
- for (const result of results) {
931
- const ModelClass = this.getModelClass()
932
- const model = /**
933
- * Narrows the runtime value to the documented type.
934
- @type {InstanceType<MC>} */ (new ModelClass())
935
-
936
- model.loadExistingRecord(result)
937
- models.push(model)
938
- }
939
-
940
- // Share a single cohort reference across every sibling record so that
941
- // auto-preload can batch lazy relationship access later.
942
- for (const model of models) {
943
- model._loadCohort = models
944
- }
945
-
946
- if (Object.keys(this._preload).length > 0 && models.length > 0) {
947
- const preloader = new Preloader({
948
- modelClass: this.modelClass,
949
- models,
950
- preload: this._preload,
951
- preloadSelects: this._preloadSelects,
952
- preloadSelectsExtra: this._preloadSelectsExtra
953
- })
954
-
955
- await preloader.run()
956
- }
957
-
958
- if (this._withCount.length > 0 && models.length > 0) {
959
- await runWithCount({
960
- entries: this._withCount,
961
- modelClass: this.modelClass,
962
- models
963
- })
964
- }
965
-
966
- if (this._queryData.length > 0 && models.length > 0) {
967
- await runQueryData({
968
- entries: this._queryData,
969
- rootModelClass: this.modelClass,
970
- rootModels: models
971
- })
972
- }
973
-
974
- return models
975
- }
976
-
977
- /**
978
- * Converts query results to array of model instances
979
- * @returns {Promise<Array<InstanceType<MC>>>} - Resolves with the array.
980
- */
981
- async toArray() {
982
- return await this.load()
983
- }
984
-
985
- /**
986
- * Plucks one or more columns directly from the database without instantiating models.
987
- * @param {...string|string[]} columns - Column names.
988
- * @returns {Promise<Array<?>>} - Resolves with the pluck.
989
- */
990
- async pluck(...columns) {
991
- const flatColumns = columns.flat()
992
-
993
- if (flatColumns.length === 0) throw new Error("No columns given to pluck")
994
-
995
- const modelClass = this.getModelClass()
996
- const tableName = modelClass.tableName()
997
- const attributeMap = modelClass.getAttributeNameToColumnNameMap()
998
- const columnNames = flatColumns.map((column) => attributeMap[column] || column)
999
-
1000
- const query = /**
1001
- * Narrows the runtime value to the documented type.
1002
- @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
1003
-
1004
- query._preload = {}
1005
- query._selects = []
1006
-
1007
- columnNames.forEach((columnName) => {
1008
- const selectSql = `${this.driver.quoteTable(tableName)}.${this.driver.quoteColumn(columnName)}`
1009
-
1010
- query.select(selectSql)
1011
- })
1012
-
1013
- const rows = await query._executeQuery({logName: query.queryLogName("Pluck")})
1014
-
1015
- if (columnNames.length === 1) {
1016
- const [columnName] = columnNames
1017
- return rows.map((row) => /**
316
+ * Runs select.
317
+ * @param {import("./index.js").SelectArgumentType} select - Select.
318
+ * @returns {this} - The select.
319
+ */
320
+ select(select) {
321
+ if (Array.isArray(select)) {
322
+ for (const selectEntry of select) {
323
+ this.select(selectEntry);
324
+ }
325
+ return this;
326
+ }
327
+ if (typeof select === "string") {
328
+ const trimmedSelect = select.trim();
329
+ if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmedSelect)) {
330
+ const modelClass = this.getModelClass();
331
+ const attributeMap = modelClass.getAttributeNameToColumnNameMap();
332
+ const columnName = attributeMap[trimmedSelect] || trimmedSelect;
333
+ const tableReference = this.rootTableReference();
334
+ const qualifiedColumn = `${this.driver.quoteTable(tableReference)}.${this.driver.quoteColumn(columnName)}`;
335
+ return super.select(qualifiedColumn);
336
+ }
337
+ }
338
+ // Object form keyed by target model name, e.g. `.select({Account: ["id"]})`.
339
+ // These limit the attributes loaded for preloaded relationship targets
340
+ // rather than the root query's SELECT clause.
341
+ if (isPlainObject(select)) {
342
+ this._mergePreloadSelect(this._preloadSelects, select);
343
+ return this;
344
+ }
345
+ return super.select(select);
346
+ }
347
+ /**
348
+ * Loads the default columns plus the given extra selects for preloaded
349
+ * relationship targets, keyed by target model name, e.g.
350
+ * `.selectsExtra({Account: ["(SELECT count(*) FROM projects) AS projects_count"]})`.
351
+ * Unlike `select({...})`, which narrows to only the listed columns, this keeps
352
+ * the default `SELECT *` columns and adds the extras on top.
353
+ * @param {Record<string, string | string[]>} select - Extra selects keyed by target model name.
354
+ * @returns {this} - This query, for chaining.
355
+ */
356
+ selectsExtra(select) {
357
+ this._mergePreloadSelect(this._preloadSelectsExtra, select);
358
+ return this;
359
+ }
360
+ /**
361
+ * Merges an object-form preload select (keyed by target model name) into the
362
+ * given target map, de-duplicating attribute/expression entries.
363
+ * @param {Record<string, string[]>} target - Map to merge into.
364
+ * @param {Record<string, string | string[]>} select - Object-form select.
365
+ * @returns {void} - No return value.
366
+ */
367
+ _mergePreloadSelect(target, select) {
368
+ for (const [modelName, attributes] of Object.entries(select)) {
369
+ const normalizedAttributes = Array.isArray(attributes) ? attributes : [attributes];
370
+ if (!target[modelName])
371
+ target[modelName] = [];
372
+ for (const attribute of normalizedAttributes) {
373
+ if (!target[modelName].includes(attribute))
374
+ target[modelName].push(attribute);
375
+ }
376
+ }
377
+ }
378
+ /**
379
+ * Runs root table reference.
380
+ * @returns {string} - Root table reference for query select qualification.
381
+ */
382
+ rootTableReference() {
383
+ const froms = this.getFroms();
384
+ const lastFrom = froms[froms.length - 1];
385
+ if (lastFrom && typeof /**
1018
386
  * Narrows the runtime value to the documented type.
1019
- @type {Record<string, ?>} */ (row)[columnName])
387
+ @type {?} */ (lastFrom).tableName === "string") {
388
+ return /** Narrows the runtime value to the documented type. @type {?} */ (lastFrom).tableName;
389
+ }
390
+ if (lastFrom && typeof /**
391
+ * Narrows the runtime value to the documented type.
392
+ @type {?} */ (lastFrom).plain === "string") {
393
+ const parsedReference = parseFromPlainTableReference(/**
394
+ * Narrows the runtime value to the documented type.
395
+ @type {?} */ (lastFrom).plain);
396
+ if (parsedReference)
397
+ return parsedReference;
398
+ }
399
+ return this.getTableReferenceForJoin();
400
+ }
401
+ /**
402
+ * Runs get model class.
403
+ * @returns {MC} - The model class.
404
+ */
405
+ getModelClass() {
406
+ if (!this.modelClass)
407
+ throw new Error("modelClass not set");
408
+ return this.modelClass;
409
+ }
410
+ /**
411
+ * Runs get join base path.
412
+ * @returns {string[]} - The join base path.
413
+ */
414
+ getJoinBasePath() {
415
+ return this._joinBasePath;
416
+ }
417
+ /**
418
+ * Runs get join tracker.
419
+ * @returns {import("./join-tracker.js").default} - The join tracker.
420
+ */
421
+ getJoinTracker() {
422
+ return this._joinTracker;
423
+ }
424
+ /**
425
+ * Runs get force qualify base table.
426
+ * @returns {boolean} - Whether to qualify base table.
427
+ */
428
+ getForceQualifyBaseTable() {
429
+ return this._forceQualifyBaseTable;
430
+ }
431
+ /**
432
+ * Runs set join base path.
433
+ * @param {string[]} joinBasePath - Join base path.
434
+ * @returns {this} - The query with updated base path.
435
+ */
436
+ setJoinBasePath(joinBasePath) {
437
+ this._joinBasePath = joinBasePath;
438
+ return this;
439
+ }
440
+ /**
441
+ * Runs with join path.
442
+ * @param {string[]} joinBasePath - Join base path.
443
+ * @returns {VelociousDatabaseQueryModelClassQuery<MC>} - The scoped query.
444
+ */
445
+ withJoinPath(joinBasePath) {
446
+ const scopedQuery = /**
447
+ * Narrows the runtime value to the documented type.
448
+ @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone());
449
+ scopedQuery._joinBasePath = joinBasePath;
450
+ scopedQuery._joinTracker = this._joinTracker;
451
+ return scopedQuery;
452
+ }
453
+ /**
454
+ * Runs resolve table name for join path.
455
+ * @param {string[]} path - Join path.
456
+ * @returns {string} - Table name for path.
457
+ */
458
+ _resolveTableNameForJoinPath(path) {
459
+ return this._resolveModelClassForJoinPath(path).tableName();
460
+ }
461
+ /**
462
+ * Runs resolve model class for join path.
463
+ * @param {string[]} path - Join path.
464
+ * @returns {typeof import("../record/index.js").default} - Target model class.
465
+ */
466
+ _resolveModelClassForJoinPath(path) {
467
+ let modelClass = this._joinTracker.getRootModelClass();
468
+ for (const relationshipName of path) {
469
+ const relationship = modelClass.getRelationshipByName(relationshipName);
470
+ const targetModelClass = relationship.getTargetModelClass();
471
+ if (!targetModelClass) {
472
+ throw new Error(`No target model class for ${modelClass.name}#${relationshipName}`);
473
+ }
474
+ modelClass = targetModelClass;
475
+ }
476
+ return modelClass;
477
+ }
478
+ /**
479
+ * Runs register join path.
480
+ * @param {string[]} path - Join path.
481
+ * @returns {{tableName: string, alias: string | undefined}} - The entry.
482
+ */
483
+ _registerJoinPath(path) {
484
+ const tableName = this._resolveTableNameForJoinPath(path);
485
+ return this._joinTracker.registerPath(path, tableName);
486
+ }
487
+ /**
488
+ * Runs get join table reference.
489
+ * @param {string[]} path - Join path.
490
+ * @returns {string} - Unquoted table reference (alias or table name).
491
+ */
492
+ getJoinTableReference(path) {
493
+ const entry = this._joinTracker.getEntry(path) || this._registerJoinPath(path);
494
+ return entry.alias || entry.tableName;
495
+ }
496
+ /**
497
+ * Runs get table reference for join.
498
+ * @param {...string} path - Join path segments.
499
+ * @returns {string} - Unquoted table reference (alias or table name).
500
+ */
501
+ getTableReferenceForJoin(...path) {
502
+ const fullPath = this._joinBasePath.concat(path);
503
+ return this.getJoinTableReference(fullPath);
504
+ }
505
+ /**
506
+ * Runs get table for join.
507
+ * @param {...string} path - Join path segments.
508
+ * @returns {string} - Quoted table name for join path.
509
+ */
510
+ getTableForJoin(...path) {
511
+ return this.driver.quoteTable(this.getTableReferenceForJoin(...path));
512
+ }
513
+ /**
514
+ * Runs scope.
515
+ * @param {import("../../utils/model-scope.js").ModelScopeDescriptor | string | string[]} pathOrScopeDescriptor - Scope descriptor or join path.
516
+ * @param {import("../../utils/model-scope.js").ModelScopeDescriptor} [maybeScopeDescriptor] - Scope descriptor when path is given.
517
+ * @returns {this} - Scoped query.
518
+ */
519
+ scope(pathOrScopeDescriptor, maybeScopeDescriptor) {
520
+ if (isModelScopeDescriptor(pathOrScopeDescriptor) && !maybeScopeDescriptor) {
521
+ return this._applyRootScope(pathOrScopeDescriptor);
522
+ }
523
+ if (!maybeScopeDescriptor) {
524
+ throw new Error("scope(path, descriptor) requires a scope descriptor");
525
+ }
526
+ return this._applyJoinPathScope({
527
+ joinPath: normalizeScopePath(/**
528
+ * Narrows the runtime value to the documented type.
529
+ @type {string | string[]} */ (pathOrScopeDescriptor)),
530
+ scopeDescriptor: maybeScopeDescriptor
531
+ });
532
+ }
533
+ /**
534
+ * Runs apply root scope.
535
+ * @param {import("../../utils/model-scope.js").ModelScopeDescriptor} scopeDescriptor - Scope descriptor.
536
+ * @returns {this} - Scoped query.
537
+ */
538
+ _applyRootScope(scopeDescriptor) {
539
+ if (!isModelScopeDescriptor(scopeDescriptor)) {
540
+ throw new Error("scope() expects a descriptor returned by defineScope(...).scope(...)");
541
+ }
542
+ if (scopeDescriptor.modelClass !== this.getModelClass()) {
543
+ throw new Error(`Cannot apply ${scopeDescriptor.modelClass.name} scope to ${this.getModelClass().name} query`);
544
+ }
545
+ const scopedQuery = /**
546
+ * Narrows the runtime value to the documented type.
547
+ @type {this | void} */ (scopeDescriptor.callback({
548
+ driver: this.driver,
549
+ modelClass: this.getModelClass(),
550
+ query: this,
551
+ table: this.rootTableReference()
552
+ }, ...scopeDescriptor.scopeArgs));
553
+ return scopedQuery || this;
554
+ }
555
+ /**
556
+ * Runs apply join path scope.
557
+ * @param {object} args - Join-path scope options.
558
+ * @param {string[]} args.joinPath - Join path relative to the current query.
559
+ * @param {import("../../utils/model-scope.js").ModelScopeDescriptor} args.scopeDescriptor - Scope descriptor.
560
+ * @returns {this} - Scoped query.
561
+ */
562
+ _applyJoinPathScope({ joinPath, scopeDescriptor }) {
563
+ if (!isModelScopeDescriptor(scopeDescriptor)) {
564
+ throw new Error("scope() expects a descriptor returned by defineScope(...).scope(...)");
565
+ }
566
+ const fullJoinPath = this.getJoinBasePath().concat(joinPath);
567
+ const targetModelClass = this._resolveModelClassForJoinPath(fullJoinPath);
568
+ if (scopeDescriptor.modelClass !== targetModelClass) {
569
+ throw new Error(`Cannot apply ${scopeDescriptor.modelClass.name} scope to join path ${fullJoinPath.join(".")} (${targetModelClass.name})`);
570
+ }
571
+ const scopedQuery = this.buildJoinScopeQuery(targetModelClass, fullJoinPath);
572
+ const originalJoinCount = scopedQuery._joins.length;
573
+ const originalWhereCount = scopedQuery._wheres.length;
574
+ const appliedQuery = /**
575
+ * Narrows the runtime value to the documented type.
576
+ @type {typeof scopedQuery | void} */ (scopeDescriptor.callback({
577
+ driver: scopedQuery.driver,
578
+ modelClass: targetModelClass,
579
+ path: [...fullJoinPath],
580
+ query: scopedQuery,
581
+ table: scopedQuery.getTableReferenceForJoin()
582
+ }, ...scopeDescriptor.scopeArgs)) || scopedQuery;
583
+ if (appliedQuery.getFroms().length !== scopedQuery.getFroms().length ||
584
+ appliedQuery.getGroups().length !== scopedQuery.getGroups().length ||
585
+ appliedQuery.getSelects().length !== scopedQuery.getSelects().length ||
586
+ appliedQuery._orders.length !== scopedQuery._orders.length ||
587
+ appliedQuery._limit !== scopedQuery._limit ||
588
+ appliedQuery._offset !== scopedQuery._offset ||
589
+ appliedQuery._page !== scopedQuery._page ||
590
+ appliedQuery._perPage !== scopedQuery._perPage ||
591
+ appliedQuery._distinct !== scopedQuery._distinct ||
592
+ Object.keys(appliedQuery._preload).length !== Object.keys(scopedQuery._preload).length) {
593
+ throw new Error("Joined-path scopes may only add where(...) and joins(...) clauses");
594
+ }
595
+ if (appliedQuery._joins.length > originalJoinCount) {
596
+ for (const join of appliedQuery._joins.slice(originalJoinCount)) {
597
+ if (join instanceof JoinObject) {
598
+ this._joins.push(new JoinObject(join.object, fullJoinPath));
599
+ }
600
+ else if (join instanceof JoinPlain) {
601
+ this._joins.push(join);
602
+ }
603
+ else {
604
+ this._joins.push(join);
605
+ }
606
+ }
607
+ }
608
+ if (appliedQuery._wheres.length > originalWhereCount) {
609
+ this._wheres.push(...appliedQuery._wheres.slice(originalWhereCount));
610
+ }
611
+ return this;
612
+ }
613
+ /**
614
+ * Runs build join scope query.
615
+ * @param {typeof import("../record/index.js").default} targetModelClass - Target model class.
616
+ * @param {string[]} joinPath - Join path.
617
+ * @returns {VelociousDatabaseQueryModelClassQuery<MC>} - The scoped join query.
618
+ */
619
+ buildJoinScopeQuery(targetModelClass, joinPath) {
620
+ const scopedQuery = /**
621
+ * Narrows the runtime value to the documented type.
622
+ @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (targetModelClass._newQuery());
623
+ scopedQuery._joinTracker = this._joinTracker;
624
+ scopedQuery._joinBasePath = joinPath;
625
+ scopedQuery._forceQualifyBaseTable = true;
626
+ return scopedQuery;
627
+ }
628
+ /**
629
+ * Runs destroy all.
630
+ * @returns {Promise<void>} - Resolves when complete.
631
+ */
632
+ async destroyAll() {
633
+ const records = await this.toArray();
634
+ for (const record of records) {
635
+ await record.destroy();
636
+ }
637
+ }
638
+ /**
639
+ * Executes a bulk UPDATE on all rows matching the query's WHERE
640
+ * clause. Bypasses model lifecycle callbacks — use this for
641
+ * efficient batch updates where per-row hooks aren't needed.
642
+ * @param {Record<string, ?>} data - camelCase attribute names → values.
643
+ * @returns {Promise<void>} - Resolves when the update completes.
644
+ */
645
+ async updateAll(data) {
646
+ const driver = this.driver;
647
+ const tableName = this.getModelClass().tableName();
648
+ const entries = Object.entries(data);
649
+ if (entries.length === 0)
650
+ return;
651
+ const setCols = entries.map(([key, value]) => {
652
+ const columnName = inflection.underscore(key);
653
+ const quoted = value === null ? "NULL" : driver.quote(value);
654
+ return `${driver.quoteColumn(columnName)} = ${quoted}`;
655
+ }).join(", ");
656
+ const joinsSql = new JoinsParser({ pretty: false, query: this }).toSql();
657
+ const whereSql = new WhereParser({ pretty: false, query: this }).toSql();
658
+ let sql;
659
+ if (joinsSql.length > 0) {
660
+ // Use a subquery for cross-driver compatibility (SQLite
661
+ // doesn't support UPDATE ... JOIN).
662
+ const pk = driver.quoteColumn(this.getModelClass().primaryKey());
663
+ const qt = driver.quoteTable(tableName);
664
+ sql = `UPDATE ${qt} SET ${setCols} WHERE ${pk} IN (SELECT ${qt}.${pk} FROM ${qt}${joinsSql}${whereSql})`;
665
+ }
666
+ else {
667
+ sql = `UPDATE ${driver.quoteTable(tableName)} SET ${setCols}${whereSql}`;
668
+ }
669
+ await driver.query(sql, { logName: this.queryLogName("Update All") });
670
+ }
671
+ /**
672
+ * Runs find.
673
+ * @param {number|string} recordId - Record id.
674
+ * @returns {Promise<InstanceType<MC>>} - Resolves with the find.
675
+ */
676
+ async find(recordId) {
677
+ /**
678
+ * Conditions.
679
+ @type {{[key: string]: number | string}} */
680
+ const conditions = {};
681
+ conditions[this.getModelClass().primaryKey()] = recordId;
682
+ const newQuery = /**
683
+ * Narrows the runtime value to the documented type.
684
+ @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone());
685
+ newQuery.where(conditions);
686
+ const record = (await newQuery.first());
687
+ if (!record) {
688
+ throw new RecordNotFoundError(`Couldn't find ${this.getModelClass().name} with '${this.getModelClass().primaryKey()}'=${recordId}`);
689
+ }
690
+ return record;
691
+ }
692
+ /**
693
+ * Runs find by.
694
+ * @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
695
+ * @returns {Promise<InstanceType<MC> | null>} - Resolves with the by.
696
+ */
697
+ async findBy(conditions) {
698
+ const newQuery = /**
699
+ * Narrows the runtime value to the documented type.
700
+ @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone());
701
+ newQuery.where(conditions);
702
+ return await newQuery.first();
703
+ }
704
+ /**
705
+ * Runs find or create by.
706
+ * @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
707
+ * @param {function(InstanceType<MC>) : void} [callback] - Callback function.
708
+ * @returns {Promise<InstanceType<MC>>} - Resolves with the or create by.
709
+ */
710
+ async findOrCreateBy(conditions, callback) {
711
+ const record = await this.findOrInitializeBy(conditions, callback);
712
+ if (record.isNewRecord()) {
713
+ await record.save();
714
+ }
715
+ return record;
716
+ }
717
+ /**
718
+ * Runs find by or fail.
719
+ * @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
720
+ * @returns {Promise<InstanceType<MC>>} - Resolves with the by or fail.
721
+ */
722
+ async findByOrFail(conditions) {
723
+ const record = await this.findBy(conditions);
724
+ if (!record) {
725
+ throw new Error("Record not found");
726
+ }
727
+ return record;
728
+ }
729
+ /**
730
+ * Runs find or initialize by.
731
+ * @param {Record<string, ?>} conditions - Conditions.
732
+ * @param {function(InstanceType<MC>) : void} [callback] - Callback function.
733
+ * @returns {Promise<InstanceType<MC>>} - Resolves with the or initialize by.
734
+ */
735
+ async findOrInitializeBy(conditions, callback) {
736
+ const record = await this.findBy(conditions);
737
+ if (record)
738
+ return record;
739
+ const ModelClass = this.getModelClass();
740
+ const newRecord = /**
741
+ * Narrows the runtime value to the documented type.
742
+ @type {InstanceType<MC>} */ (new ModelClass(conditions));
743
+ if (callback) {
744
+ callback(newRecord);
745
+ }
746
+ return newRecord;
747
+ }
748
+ /**
749
+ * Runs first.
750
+ * @returns {Promise<InstanceType<MC> | null>} - Resolves with the first.
751
+ */
752
+ async first() {
753
+ const newQuery = this.clone().limit(1).reorder(`${this.driver.quoteTable(this.getModelClass().tableName())}.${this.driver.quoteColumn(this.getModelClass().orderableColumn())}`);
754
+ const results = await newQuery.toArray();
755
+ return results[0] || null;
756
+ }
757
+ /**
758
+ * Runs last.
759
+ * @returns {Promise<InstanceType<MC> | null>} - Resolves with the last.
760
+ */
761
+ async last() {
762
+ const primaryKey = this.getModelClass().primaryKey();
763
+ const tableName = this.getModelClass().tableName();
764
+ const results = await this.clone().reorder(`${this.driver.quoteTable(tableName)}.${this.driver.quoteColumn(primaryKey)} DESC`).limit(1).toArray();
765
+ return results[0] || null;
766
+ }
767
+ /**
768
+ * Runs preload.
769
+ * @param {import("./index.js").NestedPreloadRecord | string | Array<string | import("./index.js").NestedPreloadRecord>} data - Data payload.
770
+ * @returns {this} - The preload.
771
+ */
772
+ preload(data) {
773
+ const normalizedPreload = normalizePreloadRecord(data);
774
+ incorporate(this._preload, normalizedPreload);
775
+ return this;
776
+ }
777
+ /**
778
+ * Loads query results into model instances.
779
+ * @returns {Promise<Array<InstanceType<MC>>>} - Resolves with the array.
780
+ */
781
+ async load() {
782
+ const models = [];
783
+ const results = await this.results();
784
+ for (const result of results) {
785
+ const ModelClass = this.getModelClass();
786
+ const model = /**
787
+ * Narrows the runtime value to the documented type.
788
+ @type {InstanceType<MC>} */ (new ModelClass());
789
+ model.loadExistingRecord(result);
790
+ models.push(model);
791
+ }
792
+ // Share a single cohort reference across every sibling record so that
793
+ // auto-preload can batch lazy relationship access later.
794
+ for (const model of models) {
795
+ model._loadCohort = models;
796
+ }
797
+ if (Object.keys(this._preload).length > 0 && models.length > 0) {
798
+ const preloader = new Preloader({
799
+ modelClass: this.modelClass,
800
+ models,
801
+ preload: this._preload,
802
+ preloadSelects: this._preloadSelects,
803
+ preloadSelectsExtra: this._preloadSelectsExtra
804
+ });
805
+ await preloader.run();
806
+ }
807
+ if (this._withCount.length > 0 && models.length > 0) {
808
+ await runWithCount({
809
+ entries: this._withCount,
810
+ modelClass: this.modelClass,
811
+ models
812
+ });
813
+ }
814
+ if (this._queryData.length > 0 && models.length > 0) {
815
+ await runQueryData({
816
+ entries: this._queryData,
817
+ rootModelClass: this.modelClass,
818
+ rootModels: models
819
+ });
820
+ }
821
+ return models;
822
+ }
823
+ /**
824
+ * Converts query results to array of model instances
825
+ * @returns {Promise<Array<InstanceType<MC>>>} - Resolves with the array.
826
+ */
827
+ async toArray() {
828
+ return await this.load();
1020
829
  }
1021
-
1022
- return rows.map((row) => {
1023
- const rowHash = /**
830
+ /**
831
+ * Plucks one or more columns directly from the database without instantiating models.
832
+ * @param {...string|string[]} columns - Column names.
833
+ * @returns {Promise<Array<?>>} - Resolves with the pluck.
834
+ */
835
+ async pluck(...columns) {
836
+ const flatColumns = columns.flat();
837
+ if (flatColumns.length === 0)
838
+ throw new Error("No columns given to pluck");
839
+ const modelClass = this.getModelClass();
840
+ const tableName = modelClass.tableName();
841
+ const attributeMap = modelClass.getAttributeNameToColumnNameMap();
842
+ const columnNames = flatColumns.map((column) => attributeMap[column] || column);
843
+ const query = /**
1024
844
  * Narrows the runtime value to the documented type.
1025
- @type {Record<string, ?>} */ (row)
1026
-
1027
- return columnNames.map((columnName) => rowHash[columnName])
1028
- })
1029
- }
1030
-
1031
- /**
1032
- * Runs where.
1033
- * @param {import("./index.js").WhereArgumentType} where - Where.
1034
- * @returns {this} This query instance
1035
- */
1036
- where(where) {
1037
- if (typeof where == "string") {
1038
- return super.where(where)
1039
- }
1040
-
1041
- if (isPlainObject(where)) {
1042
- const {resolvedHash, fallbackHash} = splitWhereHash({hash: where, modelClass: this.getModelClass()})
1043
- const joinObject = buildJoinObjectFromWhereHash({hash: where, modelClass: this.getModelClass()})
1044
-
1045
- if (Object.keys(joinObject).length > 0) {
1046
- this.joins(joinObject)
1047
- }
1048
-
1049
- if (Object.keys(resolvedHash).length > 0) {
1050
- const qualifyBaseTable = this.getForceQualifyBaseTable() || Object.keys(joinObject).length > 0
1051
- this._wheres.push(new WhereModelClassHash({
1052
- hash: resolvedHash,
1053
- modelClass: this.getModelClass(),
1054
- qualifyBaseTable,
1055
- query: this
1056
- }))
1057
- }
1058
-
1059
- if (Object.keys(fallbackHash).length > 0) {
1060
- super.where(fallbackHash)
1061
- }
1062
-
1063
- return this
1064
- }
1065
-
1066
- throw new Error(`Invalid type of where: ${typeof where} (${where.constructor.name})`)
1067
- }
1068
-
1069
- /**
1070
- * Runs ransack.
1071
- * @param {Record<string, ?>} params - Ransack-style params hash. Supports `s` key for sorting (e.g., `{s: "name asc"}`).
1072
- * @returns {this} - Query with Ransack filters and sort applied.
1073
- */
1074
- ransack(params) {
1075
- const {s, ...filterParams} = params
1076
- const group = normalizeRansackGroup(this.getModelClass(), filterParams)
1077
-
1078
- applyRansackGroup({group, query: this})
1079
-
1080
- if (typeof s === "string" && s.trim().length > 0) {
1081
- const sorts = parseRansackSort(this.getModelClass(), s)
1082
-
1083
- for (const sortDef of sorts) {
1084
- this.order({column: sortDef.attribute, direction: sortDef.direction})
1085
- }
1086
- }
1087
-
1088
- return this
1089
- }
1090
-
1091
- /**
1092
- * Runs where not.
1093
- * @param {import("./index.js").WhereArgumentType} where - Where.
1094
- * @returns {this} This query instance
1095
- */
1096
- whereNot(where) {
1097
- if (typeof where == "string") {
1098
- return super.whereNot(where)
1099
- }
1100
-
1101
- if (isPlainObject(where)) {
1102
- const {resolvedHash, fallbackHash} = splitWhereHash({hash: where, modelClass: this.getModelClass()})
1103
- const joinObject = buildJoinObjectFromWhereHash({hash: where, modelClass: this.getModelClass()})
1104
-
1105
- if (Object.keys(joinObject).length > 0) {
1106
- this.joins(joinObject)
1107
- }
1108
-
1109
- if (Object.keys(resolvedHash).length > 0) {
1110
- const qualifyBaseTable = this.getForceQualifyBaseTable() || Object.keys(joinObject).length > 0
1111
- this._wheres.push(new WhereNot(new WhereModelClassHash({
1112
- hash: resolvedHash,
1113
- modelClass: this.getModelClass(),
1114
- qualifyBaseTable,
1115
- query: this
1116
- })))
1117
- }
1118
-
1119
- if (Object.keys(fallbackHash).length > 0) {
1120
- super.whereNot(fallbackHash)
1121
- }
1122
-
1123
- return this
1124
- }
1125
-
1126
- throw new Error(`Invalid type of where: ${typeof where} (${where.constructor.name})`)
1127
- }
1128
-
1129
- /**
1130
- * Runs query log name.
1131
- * @param {string} operation - Query operation.
1132
- * @returns {string} - Query log name.
1133
- */
1134
- queryLogName(operation) {
1135
- return `${this.getModelClass().name} ${operation}`
1136
- }
845
+ @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone());
846
+ query._preload = {};
847
+ query._selects = [];
848
+ columnNames.forEach((columnName) => {
849
+ const selectSql = `${this.driver.quoteTable(tableName)}.${this.driver.quoteColumn(columnName)}`;
850
+ query.select(selectSql);
851
+ });
852
+ const rows = await query._executeQuery({ logName: query.queryLogName("Pluck") });
853
+ if (columnNames.length === 1) {
854
+ const [columnName] = columnNames;
855
+ return rows.map((row) => /**
856
+ * Narrows the runtime value to the documented type.
857
+ @type {Record<string, ?>} */ (row)[columnName]);
858
+ }
859
+ return rows.map((row) => {
860
+ const rowHash = /**
861
+ * Narrows the runtime value to the documented type.
862
+ @type {Record<string, ?>} */ (row);
863
+ return columnNames.map((columnName) => rowHash[columnName]);
864
+ });
865
+ }
866
+ /**
867
+ * Runs where.
868
+ * @param {import("./index.js").WhereArgumentType} where - Where.
869
+ * @returns {this} This query instance
870
+ */
871
+ where(where) {
872
+ if (typeof where == "string") {
873
+ return super.where(where);
874
+ }
875
+ if (isPlainObject(where)) {
876
+ const { resolvedHash, fallbackHash } = splitWhereHash({ hash: where, modelClass: this.getModelClass() });
877
+ const joinObject = buildJoinObjectFromWhereHash({ hash: where, modelClass: this.getModelClass() });
878
+ if (Object.keys(joinObject).length > 0) {
879
+ this.joins(joinObject);
880
+ }
881
+ if (Object.keys(resolvedHash).length > 0) {
882
+ const qualifyBaseTable = this.getForceQualifyBaseTable() || Object.keys(joinObject).length > 0;
883
+ this._wheres.push(new WhereModelClassHash({
884
+ hash: resolvedHash,
885
+ modelClass: this.getModelClass(),
886
+ qualifyBaseTable,
887
+ query: this
888
+ }));
889
+ }
890
+ if (Object.keys(fallbackHash).length > 0) {
891
+ super.where(fallbackHash);
892
+ }
893
+ return this;
894
+ }
895
+ throw new Error(`Invalid type of where: ${typeof where} (${where.constructor.name})`);
896
+ }
897
+ /**
898
+ * Runs ransack.
899
+ * @param {Record<string, ?>} params - Ransack-style params hash. Supports `s` key for sorting (e.g., `{s: "name asc"}`).
900
+ * @returns {this} - Query with Ransack filters and sort applied.
901
+ */
902
+ ransack(params) {
903
+ const { s, ...filterParams } = params;
904
+ const group = normalizeRansackGroup(this.getModelClass(), filterParams);
905
+ applyRansackGroup({ group, query: this });
906
+ if (typeof s === "string" && s.trim().length > 0) {
907
+ const sorts = parseRansackSort(this.getModelClass(), s);
908
+ for (const sortDef of sorts) {
909
+ this.order({ column: sortDef.attribute, direction: sortDef.direction });
910
+ }
911
+ }
912
+ return this;
913
+ }
914
+ /**
915
+ * Runs where not.
916
+ * @param {import("./index.js").WhereArgumentType} where - Where.
917
+ * @returns {this} This query instance
918
+ */
919
+ whereNot(where) {
920
+ if (typeof where == "string") {
921
+ return super.whereNot(where);
922
+ }
923
+ if (isPlainObject(where)) {
924
+ const { resolvedHash, fallbackHash } = splitWhereHash({ hash: where, modelClass: this.getModelClass() });
925
+ const joinObject = buildJoinObjectFromWhereHash({ hash: where, modelClass: this.getModelClass() });
926
+ if (Object.keys(joinObject).length > 0) {
927
+ this.joins(joinObject);
928
+ }
929
+ if (Object.keys(resolvedHash).length > 0) {
930
+ const qualifyBaseTable = this.getForceQualifyBaseTable() || Object.keys(joinObject).length > 0;
931
+ this._wheres.push(new WhereNot(new WhereModelClassHash({
932
+ hash: resolvedHash,
933
+ modelClass: this.getModelClass(),
934
+ qualifyBaseTable,
935
+ query: this
936
+ })));
937
+ }
938
+ if (Object.keys(fallbackHash).length > 0) {
939
+ super.whereNot(fallbackHash);
940
+ }
941
+ return this;
942
+ }
943
+ throw new Error(`Invalid type of where: ${typeof where} (${where.constructor.name})`);
944
+ }
945
+ /**
946
+ * Runs query log name.
947
+ * @param {string} operation - Query operation.
948
+ * @returns {string} - Query log name.
949
+ */
950
+ queryLogName(operation) {
951
+ return `${this.getModelClass().name} ${operation}`;
952
+ }
1137
953
  }
1138
-
1139
954
  /**
1140
955
  * Runs apply ransack group.
1141
956
  * @param {object} args - Options.
@@ -1143,14 +958,12 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
1143
958
  * @param {import("./model-class-query.js").default<?>} args.query - Query instance.
1144
959
  * @returns {void}
1145
960
  */
1146
- function applyRansackGroup({group, query}) {
1147
- const where = buildRansackGroupWhere({group, query})
1148
-
1149
- if (where) {
1150
- query._wheres.push(where)
1151
- }
961
+ function applyRansackGroup({ group, query }) {
962
+ const where = buildRansackGroupWhere({ group, query });
963
+ if (where) {
964
+ query._wheres.push(where);
965
+ }
1152
966
  }
1153
-
1154
967
  /**
1155
968
  * Runs build ransack group where.
1156
969
  * @param {object} args - Options.
@@ -1158,34 +971,31 @@ function applyRansackGroup({group, query}) {
1158
971
  * @param {import("./model-class-query.js").default<?>} args.query - Query instance.
1159
972
  * @returns {import("./where-base.js").default | null} - Combined where clause.
1160
973
  */
1161
- function buildRansackGroupWhere({group, query}) {
1162
- /**
1163
- * Wheres.
1164
- @type {import("./where-base.js").default[]} */
1165
- const wheres = []
1166
-
1167
- for (const condition of group.conditions) {
1168
- const where = buildRansackConditionWhere({condition, query})
1169
-
1170
- if (where) wheres.push(where)
1171
- }
1172
-
1173
- for (const grouping of group.groupings) {
1174
- const where = buildRansackGroupWhere({group: grouping, query})
1175
-
1176
- if (where) wheres.push(where)
1177
- }
1178
-
1179
- if (wheres.length < 1) return null
1180
- if (wheres.length === 1) return wheres[0]
1181
-
1182
- return new WhereCombinator({
1183
- combinator: group.combinator,
1184
- query,
1185
- wheres
1186
- })
974
+ function buildRansackGroupWhere({ group, query }) {
975
+ /**
976
+ * Wheres.
977
+ @type {import("./where-base.js").default[]} */
978
+ const wheres = [];
979
+ for (const condition of group.conditions) {
980
+ const where = buildRansackConditionWhere({ condition, query });
981
+ if (where)
982
+ wheres.push(where);
983
+ }
984
+ for (const grouping of group.groupings) {
985
+ const where = buildRansackGroupWhere({ group: grouping, query });
986
+ if (where)
987
+ wheres.push(where);
988
+ }
989
+ if (wheres.length < 1)
990
+ return null;
991
+ if (wheres.length === 1)
992
+ return wheres[0];
993
+ return new WhereCombinator({
994
+ combinator: group.combinator,
995
+ query,
996
+ wheres
997
+ });
1187
998
  }
1188
-
1189
999
  /**
1190
1000
  * Runs build ransack condition where.
1191
1001
  * @param {object} args - Options.
@@ -1193,26 +1003,24 @@ function buildRansackGroupWhere({group, query}) {
1193
1003
  * @param {import("./model-class-query.js").default<?>} args.query - Query instance.
1194
1004
  * @returns {import("./where-base.js").default | null} - Condition where clause.
1195
1005
  */
1196
- function buildRansackConditionWhere({condition, query}) {
1197
- /**
1198
- * Wheres.
1199
- @type {import("./where-base.js").default[]} */
1200
- const wheres = []
1201
-
1202
- for (const attribute of condition.attributes) {
1203
- wheres.push(buildRansackAttributeWhere({attribute, condition, query}))
1204
- }
1205
-
1206
- if (wheres.length < 1) return null
1207
- if (wheres.length === 1) return wheres[0]
1208
-
1209
- return new WhereCombinator({
1210
- combinator: condition.combinator,
1211
- query,
1212
- wheres
1213
- })
1006
+ function buildRansackConditionWhere({ condition, query }) {
1007
+ /**
1008
+ * Wheres.
1009
+ @type {import("./where-base.js").default[]} */
1010
+ const wheres = [];
1011
+ for (const attribute of condition.attributes) {
1012
+ wheres.push(buildRansackAttributeWhere({ attribute, condition, query }));
1013
+ }
1014
+ if (wheres.length < 1)
1015
+ return null;
1016
+ if (wheres.length === 1)
1017
+ return wheres[0];
1018
+ return new WhereCombinator({
1019
+ combinator: condition.combinator,
1020
+ query,
1021
+ wheres
1022
+ });
1214
1023
  }
1215
-
1216
1024
  /**
1217
1025
  * Runs build ransack attribute where.
1218
1026
  * @param {object} args - Options.
@@ -1221,32 +1029,26 @@ function buildRansackConditionWhere({condition, query}) {
1221
1029
  * @param {import("./model-class-query.js").default<?>} args.query - Query instance.
1222
1030
  * @returns {import("./where-base.js").default} - Attribute where clause.
1223
1031
  */
1224
- function buildRansackAttributeWhere({attribute, condition, query}) {
1225
- const hash = buildRansackAttributeHash({attribute, condition})
1226
- const joinObject = buildJoinObjectFromWhereHash({hash, modelClass: query.getModelClass()})
1227
-
1228
- if (Object.keys(joinObject).length > 0) {
1229
- query.joins(joinObject)
1230
- }
1231
-
1232
- const where = new WhereModelClassHash({
1233
- hash,
1234
- modelClass: query.getModelClass(),
1235
- qualifyBaseTable: true,
1236
- query
1237
- })
1238
-
1239
- if (condition.predicate === "not_eq" || condition.predicate === "not_in") {
1240
- return new WhereNot(where)
1241
- }
1242
-
1243
- if (condition.predicate === "null" && !condition.value) {
1244
- return new WhereNot(where)
1245
- }
1246
-
1247
- return where
1032
+ function buildRansackAttributeWhere({ attribute, condition, query }) {
1033
+ const hash = buildRansackAttributeHash({ attribute, condition });
1034
+ const joinObject = buildJoinObjectFromWhereHash({ hash, modelClass: query.getModelClass() });
1035
+ if (Object.keys(joinObject).length > 0) {
1036
+ query.joins(joinObject);
1037
+ }
1038
+ const where = new WhereModelClassHash({
1039
+ hash,
1040
+ modelClass: query.getModelClass(),
1041
+ qualifyBaseTable: true,
1042
+ query
1043
+ });
1044
+ if (condition.predicate === "not_eq" || condition.predicate === "not_in") {
1045
+ return new WhereNot(where);
1046
+ }
1047
+ if (condition.predicate === "null" && !condition.value) {
1048
+ return new WhereNot(where);
1049
+ }
1050
+ return where;
1248
1051
  }
1249
-
1250
1052
  /**
1251
1053
  * Runs build ransack attribute hash.
1252
1054
  * @param {object} args - Options.
@@ -1254,22 +1056,19 @@ function buildRansackAttributeWhere({attribute, condition, query}) {
1254
1056
  * @param {import("../../utils/ransack.js").RansackCondition} args.condition - Normalized Ransack condition.
1255
1057
  * @returns {Record<string, ?>} - Nested hash suitable for query where nodes.
1256
1058
  */
1257
- function buildRansackAttributeHash({attribute, condition}) {
1258
- if (condition.predicate === "eq" || condition.predicate === "in" || condition.predicate === "not_eq" || condition.predicate === "not_in") {
1259
- return buildNestedRansackHash({attribute, value: condition.value})
1260
- }
1261
-
1262
- if (condition.predicate === "null") {
1263
- return buildNestedRansackHash({attribute, value: null})
1264
- }
1265
-
1266
- return buildNestedRansackTupleHash({
1267
- attribute,
1268
- operator: ransackTupleOperator(condition.predicate),
1269
- value: ransackTupleValue(condition)
1270
- })
1059
+ function buildRansackAttributeHash({ attribute, condition }) {
1060
+ if (condition.predicate === "eq" || condition.predicate === "in" || condition.predicate === "not_eq" || condition.predicate === "not_in") {
1061
+ return buildNestedRansackHash({ attribute, value: condition.value });
1062
+ }
1063
+ if (condition.predicate === "null") {
1064
+ return buildNestedRansackHash({ attribute, value: null });
1065
+ }
1066
+ return buildNestedRansackTupleHash({
1067
+ attribute,
1068
+ operator: ransackTupleOperator(condition.predicate),
1069
+ value: ransackTupleValue(condition)
1070
+ });
1271
1071
  }
1272
-
1273
1072
  /**
1274
1073
  * Runs build nested ransack hash.
1275
1074
  * @param {object} args - Options.
@@ -1277,19 +1076,16 @@ function buildRansackAttributeHash({attribute, condition}) {
1277
1076
  * @param {?} args.value - Final value.
1278
1077
  * @returns {Record<string, ?>} - Nested hash suitable for query where nodes.
1279
1078
  */
1280
- function buildNestedRansackHash({attribute, value}) {
1281
- /**
1282
- * Hash.
1283
- @type {Record<string, ?>} */
1284
- let hash = {[attribute.attributeName]: value}
1285
-
1286
- for (let index = attribute.path.length - 1; index >= 0; index -= 1) {
1287
- hash = {[attribute.path[index]]: hash}
1288
- }
1289
-
1290
- return hash
1079
+ function buildNestedRansackHash({ attribute, value }) {
1080
+ /**
1081
+ * Hash.
1082
+ @type {Record<string, ?>} */
1083
+ let hash = { [attribute.attributeName]: value };
1084
+ for (let index = attribute.path.length - 1; index >= 0; index -= 1) {
1085
+ hash = { [attribute.path[index]]: hash };
1086
+ }
1087
+ return hash;
1291
1088
  }
1292
-
1293
1089
  /**
1294
1090
  * Runs build nested ransack tuple hash.
1295
1091
  * @param {object} args - Options.
@@ -1298,47 +1094,43 @@ function buildNestedRansackHash({attribute, value}) {
1298
1094
  * @param {?} args.value - Final value.
1299
1095
  * @returns {Record<string, ?>} - Nested tuple hash suitable for query.where.
1300
1096
  */
1301
- function buildNestedRansackTupleHash({attribute, operator, value}) {
1302
- /**
1303
- * Hash.
1304
- @type {Record<string, ?>} */
1305
- let hash = {
1306
- [attribute.attributeName]: [[attribute.attributeName, operator, value]]
1307
- }
1308
-
1309
- for (let index = attribute.path.length - 1; index >= 0; index -= 1) {
1310
- hash = {[attribute.path[index]]: hash}
1311
- }
1312
-
1313
- return hash
1097
+ function buildNestedRansackTupleHash({ attribute, operator, value }) {
1098
+ /**
1099
+ * Hash.
1100
+ @type {Record<string, ?>} */
1101
+ let hash = {
1102
+ [attribute.attributeName]: [[attribute.attributeName, operator, value]]
1103
+ };
1104
+ for (let index = attribute.path.length - 1; index >= 0; index -= 1) {
1105
+ hash = { [attribute.path[index]]: hash };
1106
+ }
1107
+ return hash;
1314
1108
  }
1315
-
1316
1109
  /**
1317
1110
  * Runs ransack tuple operator.
1318
1111
  * @param {import("../../utils/ransack.js").RansackPredicate} predicate - Ransack predicate.
1319
1112
  * @returns {"gt" | "gteq" | "lt" | "lteq" | "like"} - Query tuple operator.
1320
1113
  */
1321
1114
  function ransackTupleOperator(predicate) {
1322
- if (predicate === "gt" || predicate === "gteq" || predicate === "lt" || predicate === "lteq") {
1323
- return predicate
1324
- }
1325
-
1326
- return "like"
1115
+ if (predicate === "gt" || predicate === "gteq" || predicate === "lt" || predicate === "lteq") {
1116
+ return predicate;
1117
+ }
1118
+ return "like";
1327
1119
  }
1328
-
1329
1120
  /**
1330
1121
  * Runs ransack tuple value.
1331
1122
  * @param {import("../../utils/ransack.js").RansackCondition} condition - Ransack condition.
1332
1123
  * @returns {?} - Query tuple value.
1333
1124
  */
1334
1125
  function ransackTupleValue(condition) {
1335
- if (condition.predicate === "cont") return `%${condition.value}%`
1336
- if (condition.predicate === "start") return `${condition.value}%`
1337
- if (condition.predicate === "end") return `%${condition.value}`
1338
-
1339
- return condition.value
1126
+ if (condition.predicate === "cont")
1127
+ return `%${condition.value}%`;
1128
+ if (condition.predicate === "start")
1129
+ return `${condition.value}%`;
1130
+ if (condition.predicate === "end")
1131
+ return `%${condition.value}`;
1132
+ return condition.value;
1340
1133
  }
1341
-
1342
1134
  /**
1343
1135
  * Runs get relationship by name.
1344
1136
  * @param {typeof import("../record/index.js").default} modelClass - Model class.
@@ -1346,9 +1138,8 @@ function ransackTupleValue(condition) {
1346
1138
  * @returns {import("../record/relationships/base.js").default | undefined} - The relationship.
1347
1139
  */
1348
1140
  function getRelationshipByName(modelClass, relationshipName) {
1349
- return modelClass.getRelationshipsMap()[relationshipName]
1141
+ return modelClass.getRelationshipsMap()[relationshipName];
1350
1142
  }
1351
-
1352
1143
  /**
1353
1144
  * Runs resolve column name.
1354
1145
  * @param {typeof import("../record/index.js").default} modelClass - Model class.
@@ -1356,16 +1147,13 @@ function getRelationshipByName(modelClass, relationshipName) {
1356
1147
  * @returns {string | undefined} - The resolved column name.
1357
1148
  */
1358
1149
  function resolveColumnName(modelClass, key) {
1359
- const attributeMap = modelClass.getAttributeNameToColumnNameMap()
1360
-
1361
- if (attributeMap[key]) return attributeMap[key]
1362
-
1363
- const columnMap = modelClass.getColumnNameToAttributeNameMap()
1364
- const underscored = inflection.underscore(key)
1365
-
1366
- return columnMap[key] || columnMap[underscored] || undefined
1150
+ const attributeMap = modelClass.getAttributeNameToColumnNameMap();
1151
+ if (attributeMap[key])
1152
+ return attributeMap[key];
1153
+ const columnMap = modelClass.getColumnNameToAttributeNameMap();
1154
+ const underscored = inflection.underscore(key);
1155
+ return columnMap[key] || columnMap[underscored] || undefined;
1367
1156
  }
1368
-
1369
1157
  /**
1370
1158
  * Runs split where hash.
1371
1159
  * @param {object} args - Options.
@@ -1373,61 +1161,58 @@ function resolveColumnName(modelClass, key) {
1373
1161
  * @param {typeof import("../record/index.js").default} args.modelClass - Model class.
1374
1162
  * @returns {{resolvedHash: Record<string, ?>, fallbackHash: Record<string, ?>}} - Split hashes.
1375
1163
  */
1376
- function splitWhereHash({hash, modelClass}) {
1377
- /**
1378
- * Resolved hash.
1379
- @type {Record<string, ?>} */
1380
- const resolvedHash = {}
1381
- /**
1382
- * Fallback hash.
1383
- @type {Record<string, ?>} */
1384
- const fallbackHash = {}
1385
-
1386
- for (const key in hash) {
1387
- const value = hash[key]
1388
- const isNested = isPlainObject(value)
1389
- const relationship = getRelationshipByName(modelClass, key)
1390
-
1391
- if (isNested) {
1392
- if (relationship) {
1393
- const targetModelClass = relationship.getTargetModelClass()
1394
- if (!targetModelClass) {
1395
- fallbackHash[key] = value
1396
- continue
1164
+ function splitWhereHash({ hash, modelClass }) {
1165
+ /**
1166
+ * Resolved hash.
1167
+ @type {Record<string, ?>} */
1168
+ const resolvedHash = {};
1169
+ /**
1170
+ * Fallback hash.
1171
+ @type {Record<string, ?>} */
1172
+ const fallbackHash = {};
1173
+ for (const key in hash) {
1174
+ const value = hash[key];
1175
+ const isNested = isPlainObject(value);
1176
+ const relationship = getRelationshipByName(modelClass, key);
1177
+ if (isNested) {
1178
+ if (relationship) {
1179
+ const targetModelClass = relationship.getTargetModelClass();
1180
+ if (!targetModelClass) {
1181
+ fallbackHash[key] = value;
1182
+ continue;
1183
+ }
1184
+ const nestedResult = splitWhereHash({ hash: value, modelClass: targetModelClass });
1185
+ const nestedResolvedKeys = Object.keys(nestedResult.resolvedHash);
1186
+ const nestedFallbackKeys = Object.keys(nestedResult.fallbackHash);
1187
+ if (nestedResolvedKeys.length > 0) {
1188
+ resolvedHash[key] = nestedResult.resolvedHash;
1189
+ }
1190
+ if (nestedFallbackKeys.length > 0) {
1191
+ const tableName = targetModelClass.tableName();
1192
+ if (!fallbackHash[tableName])
1193
+ fallbackHash[tableName] = {};
1194
+ Object.assign(fallbackHash[tableName], nestedResult.fallbackHash);
1195
+ }
1196
+ }
1197
+ else {
1198
+ fallbackHash[key] = value;
1199
+ }
1397
1200
  }
1398
- const nestedResult = splitWhereHash({hash: value, modelClass: targetModelClass})
1399
- const nestedResolvedKeys = Object.keys(nestedResult.resolvedHash)
1400
- const nestedFallbackKeys = Object.keys(nestedResult.fallbackHash)
1401
-
1402
- if (nestedResolvedKeys.length > 0) {
1403
- resolvedHash[key] = nestedResult.resolvedHash
1201
+ else if (relationship && hasRelationshipWhereOperatorTuples(value)) {
1202
+ resolvedHash[key] = normalizeRelationshipWhereOperatorTuples(value);
1404
1203
  }
1405
-
1406
- if (nestedFallbackKeys.length > 0) {
1407
- const tableName = targetModelClass.tableName()
1408
-
1409
- if (!fallbackHash[tableName]) fallbackHash[tableName] = {}
1410
- Object.assign(fallbackHash[tableName], nestedResult.fallbackHash)
1204
+ else {
1205
+ const columnName = resolveColumnName(modelClass, key);
1206
+ if (columnName) {
1207
+ resolvedHash[columnName] = value;
1208
+ }
1209
+ else {
1210
+ fallbackHash[key] = value;
1211
+ }
1411
1212
  }
1412
- } else {
1413
- fallbackHash[key] = value
1414
- }
1415
- } else if (relationship && hasRelationshipWhereOperatorTuples(value)) {
1416
- resolvedHash[key] = normalizeRelationshipWhereOperatorTuples(value)
1417
- } else {
1418
- const columnName = resolveColumnName(modelClass, key)
1419
-
1420
- if (columnName) {
1421
- resolvedHash[columnName] = value
1422
- } else {
1423
- fallbackHash[key] = value
1424
- }
1425
- }
1426
- }
1427
-
1428
- return {resolvedHash, fallbackHash}
1213
+ }
1214
+ return { resolvedHash, fallbackHash };
1429
1215
  }
1430
-
1431
1216
  /**
1432
1217
  * Runs build join object from where hash.
1433
1218
  * @param {object} args - Options.
@@ -1435,143 +1220,122 @@ function splitWhereHash({hash, modelClass}) {
1435
1220
  * @param {typeof import("../record/index.js").default} args.modelClass - Model class.
1436
1221
  * @returns {Record<string, ?>} - Join object.
1437
1222
  */
1438
- function buildJoinObjectFromWhereHash({hash, modelClass}) {
1439
- /**
1440
- * Join object.
1441
- @type {Record<string, ?>} */
1442
- const joinObject = {}
1443
-
1444
- for (const key in hash) {
1445
- const value = hash[key]
1446
- const relationship = getRelationshipByName(modelClass, key)
1447
-
1448
- if (!relationship) continue
1449
-
1450
- if (isPlainObject(value)) {
1451
- const targetModelClass = relationship.getTargetModelClass()
1452
- if (!targetModelClass) continue
1453
- const nestedJoinObject = buildJoinObjectFromWhereHash({hash: value, modelClass: targetModelClass})
1454
-
1455
- joinObject[key] = Object.keys(nestedJoinObject).length > 0 ? nestedJoinObject : true
1456
- continue
1457
- }
1458
-
1459
- if (hasRelationshipWhereOperatorTuples(value)) {
1460
- joinObject[key] = true
1461
- }
1462
- }
1463
-
1464
- return joinObject
1223
+ function buildJoinObjectFromWhereHash({ hash, modelClass }) {
1224
+ /**
1225
+ * Join object.
1226
+ @type {Record<string, ?>} */
1227
+ const joinObject = {};
1228
+ for (const key in hash) {
1229
+ const value = hash[key];
1230
+ const relationship = getRelationshipByName(modelClass, key);
1231
+ if (!relationship)
1232
+ continue;
1233
+ if (isPlainObject(value)) {
1234
+ const targetModelClass = relationship.getTargetModelClass();
1235
+ if (!targetModelClass)
1236
+ continue;
1237
+ const nestedJoinObject = buildJoinObjectFromWhereHash({ hash: value, modelClass: targetModelClass });
1238
+ joinObject[key] = Object.keys(nestedJoinObject).length > 0 ? nestedJoinObject : true;
1239
+ continue;
1240
+ }
1241
+ if (hasRelationshipWhereOperatorTuples(value)) {
1242
+ joinObject[key] = true;
1243
+ }
1244
+ }
1245
+ return joinObject;
1465
1246
  }
1466
-
1467
- const relationshipWhereOperators = new Set(["eq", "notEq", "gt", "gteq", "lt", "lteq", "like", ">", ">=", "<", "<="])
1468
-
1247
+ const relationshipWhereOperators = new Set(["eq", "notEq", "gt", "gteq", "lt", "lteq", "like", ">", ">=", "<", "<="]);
1469
1248
  /**
1470
1249
  * Runs normalize relationship where operator.
1471
1250
  * @param {string} operator - Raw relationship where operator.
1472
1251
  * @returns {"eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like"} - Normalized operator.
1473
1252
  */
1474
1253
  function normalizeRelationshipWhereOperator(operator) {
1475
- const operatorAliases = {
1476
- "<": "lt",
1477
- "<=": "lteq",
1478
- ">": "gt",
1479
- ">=": "gteq"
1480
- }
1481
-
1482
- return /** Narrows the runtime value to the documented type. @type {"eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like"} */ (
1483
- operatorAliases[/**
1254
+ const operatorAliases = {
1255
+ "<": "lt",
1256
+ "<=": "lteq",
1257
+ ">": "gt",
1258
+ ">=": "gteq"
1259
+ };
1260
+ return /** Narrows the runtime value to the documented type. @type {"eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like"} */ (operatorAliases[ /**
1484
1261
  * Narrows the runtime value to the documented type.
1485
- @type {"<" | "<=" | ">" | ">="} */ (operator)] || operator
1486
- )
1262
+ @type {"<" | "<=" | ">" | ">="} */(operator)] || operator);
1487
1263
  }
1488
-
1489
1264
  /**
1490
1265
  * Runs is relationship where operator tuple.
1491
1266
  * @param {?} tupleValue - Candidate tuple.
1492
1267
  * @returns {boolean} - Whether this is a relationship where tuple.
1493
1268
  */
1494
1269
  function isRelationshipWhereOperatorTuple(tupleValue) {
1495
- if (!Array.isArray(tupleValue) || tupleValue.length < 3) {
1496
- return false
1497
- }
1498
-
1499
- return typeof tupleValue[0] === "string" &&
1500
- typeof tupleValue[1] === "string" &&
1501
- relationshipWhereOperators.has(tupleValue[1])
1270
+ if (!Array.isArray(tupleValue) || tupleValue.length < 3) {
1271
+ return false;
1272
+ }
1273
+ return typeof tupleValue[0] === "string" &&
1274
+ typeof tupleValue[1] === "string" &&
1275
+ relationshipWhereOperators.has(tupleValue[1]);
1502
1276
  }
1503
-
1504
1277
  /**
1505
1278
  * Runs normalize relationship where operator tuples.
1506
1279
  * @param {?} value - Candidate value.
1507
1280
  * @returns {Array<[string, "eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like", unknown]>} - Normalized tuples.
1508
1281
  */
1509
1282
  function normalizeRelationshipWhereOperatorTuples(value) {
1510
- if (!Array.isArray(value)) {
1511
- throw new Error(`Invalid relationship where tuple container type: ${typeof value}`)
1512
- }
1513
-
1514
- /**
1515
- * Normalized.
1516
- @type {Array<[string, "eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like", unknown]>} */
1517
- const normalized = []
1283
+ if (!Array.isArray(value)) {
1284
+ throw new Error(`Invalid relationship where tuple container type: ${typeof value}`);
1285
+ }
1286
+ /**
1287
+ * Normalized.
1288
+ @type {Array<[string, "eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like", unknown]>} */
1289
+ const normalized = [];
1518
1290
  /**
1519
1291
  * Add condition.
1520
1292
  * @param {?} conditionValue - Candidate nested condition.
1521
1293
  */
1522
1294
  const addCondition = (conditionValue) => {
1523
- if (isRelationshipWhereOperatorTuple(conditionValue)) {
1524
- const tuple = /**
1525
- * Narrows the runtime value to the documented type.
1526
- @type {[string, "eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like" | ">" | ">=" | "<" | "<=", unknown, ...Array<unknown>]} */ (conditionValue)
1527
- const normalizedOperator = normalizeRelationshipWhereOperator(tuple[1])
1528
-
1529
- normalized.push([
1530
- tuple[0],
1531
- normalizedOperator,
1532
- tuple[2]
1533
- ])
1534
-
1535
- if (tuple.length > 3) {
1536
- for (let index = 3; index < tuple.length; index += 1) {
1537
- addCondition(tuple[index])
1538
- }
1539
- }
1540
-
1541
- return
1542
- }
1543
-
1544
- if (!Array.isArray(conditionValue)) {
1545
- throw new Error("Relationship where conditions must be tuples")
1546
- }
1547
-
1548
- /**
1549
- * Narrows the runtime value to the documented type.
1550
- @type {Array<?>} */ (conditionValue).forEach((nestedConditionValue) => {
1551
- addCondition(nestedConditionValue)
1552
- })
1553
- }
1554
-
1555
- addCondition(value)
1556
-
1557
- if (normalized.length < 1) {
1558
- throw new Error("Relationship where tuple container cannot be empty")
1559
- }
1560
-
1561
- return normalized
1295
+ if (isRelationshipWhereOperatorTuple(conditionValue)) {
1296
+ const tuple = /**
1297
+ * Narrows the runtime value to the documented type.
1298
+ @type {[string, "eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like" | ">" | ">=" | "<" | "<=", unknown, ...Array<unknown>]} */ (conditionValue);
1299
+ const normalizedOperator = normalizeRelationshipWhereOperator(tuple[1]);
1300
+ normalized.push([
1301
+ tuple[0],
1302
+ normalizedOperator,
1303
+ tuple[2]
1304
+ ]);
1305
+ if (tuple.length > 3) {
1306
+ for (let index = 3; index < tuple.length; index += 1) {
1307
+ addCondition(tuple[index]);
1308
+ }
1309
+ }
1310
+ return;
1311
+ }
1312
+ if (!Array.isArray(conditionValue)) {
1313
+ throw new Error("Relationship where conditions must be tuples");
1314
+ }
1315
+ /**
1316
+ * Narrows the runtime value to the documented type.
1317
+ @type {Array<?>} */ (conditionValue).forEach((nestedConditionValue) => {
1318
+ addCondition(nestedConditionValue);
1319
+ });
1320
+ };
1321
+ addCondition(value);
1322
+ if (normalized.length < 1) {
1323
+ throw new Error("Relationship where tuple container cannot be empty");
1324
+ }
1325
+ return normalized;
1562
1326
  }
1563
-
1564
1327
  /**
1565
1328
  * Runs has relationship where operator tuples.
1566
1329
  * @param {?} value - Candidate relationship where value.
1567
1330
  * @returns {boolean} - Whether value can be normalized to relationship tuples.
1568
1331
  */
1569
1332
  function hasRelationshipWhereOperatorTuples(value) {
1570
- try {
1571
- normalizeRelationshipWhereOperatorTuples(value)
1572
-
1573
- return true
1574
- } catch {
1575
- return false
1576
- }
1333
+ try {
1334
+ normalizeRelationshipWhereOperatorTuples(value);
1335
+ return true;
1336
+ }
1337
+ catch {
1338
+ return false;
1339
+ }
1577
1340
  }
1341
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kZWwtY2xhc3MtcXVlcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZGF0YWJhc2UvcXVlcnkvbW9kZWwtY2xhc3MtcXVlcnkuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxjQUFjLENBQUE7QUFDeEMsT0FBTyxLQUFLLFVBQVUsTUFBTSxZQUFZLENBQUE7QUFDeEMsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLGlCQUFpQixDQUFBO0FBQzdDLE9BQU8sTUFBTSxNQUFNLGlCQUFpQixDQUFBO0FBQ3BDLE9BQU8sU0FBUyxNQUFNLGdCQUFnQixDQUFBO0FBQ3RDLE9BQU8sRUFBQyxzQkFBc0IsRUFBRSxZQUFZLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQTtBQUNwRSxPQUFPLEVBQUMsa0JBQWtCLEVBQUUsWUFBWSxFQUFDLE1BQU0saUJBQWlCLENBQUE7QUFDaEUsT0FBTyxhQUFhLE1BQU0sWUFBWSxDQUFBO0FBQ3RDLE9BQU8sVUFBVSxNQUFNLGtCQUFrQixDQUFBO0FBQ3pDLE9BQU8sU0FBUyxNQUFNLGlCQUFpQixDQUFBO0FBQ3ZDLE9BQU8sV0FBVyxNQUFNLG1CQUFtQixDQUFBO0FBQzNDLE9BQU8sbUJBQW1CLE1BQU0scUNBQXFDLENBQUE7QUFDckUsT0FBTyxFQUFDLHFCQUFxQixFQUFFLGdCQUFnQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFDOUUsT0FBTyxFQUFDLHNCQUFzQixFQUFDLE1BQU0sNEJBQTRCLENBQUE7QUFDakUsT0FBTyxlQUFlLE1BQU0sdUJBQXVCLENBQUE7QUFDbkQsT0FBTyxtQkFBbUIsTUFBTSw2QkFBNkIsQ0FBQTtBQUM3RCxPQUFPLFFBQVEsTUFBTSxnQkFBZ0IsQ0FBQTtBQUNyQyxPQUFPLFdBQVcsTUFBTSxpQ0FBaUMsQ0FBQTtBQUN6RCxPQUFPLFdBQVcsTUFBTSxpQ0FBaUMsQ0FBQTtBQUV6RDs7OztHQUlH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QUFDLENBQUMsT0FBTyxDQUFDLENBQUMsb0JBQW9CLEVBQUUsRUFBRTtZQUN0RSxZQUFZLENBQUMsb0JBQW9CLENBQUMsQ0FBQTtRQUNwQyxDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUMsQ0FBQTtJQUVELFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUVuQixJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxvREFBb0QsQ0FBQyxDQUFBO0lBQ3ZFLENBQUM7SUFFRCxPQUFPLFVBQVUsQ0FBQTtBQUNuQixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsa0NBQWtDLENBQUMsS0FBSztJQUMvQyxJQUFJLENBQUM7UUFDSCx3Q0FBd0MsQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUUvQyxPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLEtBQUssQ0FBQTtJQUNkLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCB7aW5jb3Jwb3JhdGV9IGZyb20gXCJpbmNvcnBvcmF0b3JcIlxuaW1wb3J0ICogYXMgaW5mbGVjdGlvbiBmcm9tIFwiaW5mbGVjdGlvblwiXG5pbXBvcnQge2lzUGxhaW5PYmplY3R9IGZyb20gXCJpcy1wbGFpbi1vYmplY3RcIlxuaW1wb3J0IExvZ2dlciBmcm9tIFwiLi4vLi4vbG9nZ2VyLmpzXCJcbmltcG9ydCBQcmVsb2FkZXIgZnJvbSBcIi4vcHJlbG9hZGVyLmpzXCJcbmltcG9ydCB7bm9ybWFsaXplUXVlcnlEYXRhU3BlYywgcnVuUXVlcnlEYXRhfSBmcm9tIFwiLi9xdWVyeS1kYXRhLmpzXCJcbmltcG9ydCB7bm9ybWFsaXplV2l0aENvdW50LCBydW5XaXRoQ291bnR9IGZyb20gXCIuL3dpdGgtY291bnQuanNcIlxuaW1wb3J0IERhdGFiYXNlUXVlcnkgZnJvbSBcIi4vaW5kZXguanNcIlxuaW1wb3J0IEpvaW5PYmplY3QgZnJvbSBcIi4vam9pbi1vYmplY3QuanNcIlxuaW1wb3J0IEpvaW5QbGFpbiBmcm9tIFwiLi9qb2luLXBsYWluLmpzXCJcbmltcG9ydCBKb2luVHJhY2tlciBmcm9tIFwiLi9qb2luLXRyYWNrZXIuanNcIlxuaW1wb3J0IFJlY29yZE5vdEZvdW5kRXJyb3IgZnJvbSBcIi4uL3JlY29yZC9yZWNvcmQtbm90LWZvdW5kLWVycm9yLmpzXCJcbmltcG9ydCB7bm9ybWFsaXplUmFuc2Fja0dyb3VwLCBwYXJzZVJhbnNhY2tTb3J0fSBmcm9tIFwiLi4vLi4vdXRpbHMvcmFuc2Fjay5qc1wiXG5pbXBvcnQge2lzTW9kZWxTY29wZURlc2NyaXB0b3J9IGZyb20gXCIuLi8uLi91dGlscy9tb2RlbC1zY29wZS5qc1wiXG5pbXBvcnQgV2hlcmVDb21iaW5hdG9yIGZyb20gXCIuL3doZXJlLWNvbWJpbmF0b3IuanNcIlxuaW1wb3J0IFdoZXJlTW9kZWxDbGFzc0hhc2ggZnJvbSBcIi4vd2hlcmUtbW9kZWwtY2xhc3MtaGFzaC5qc1wiXG5pbXBvcnQgV2hlcmVOb3QgZnJvbSBcIi4vd2hlcmUtbm90LmpzXCJcbmltcG9ydCBKb2luc1BhcnNlciBmcm9tIFwiLi4vcXVlcnktcGFyc2VyL2pvaW5zLXBhcnNlci5qc1wiXG5pbXBvcnQgV2hlcmVQYXJzZXIgZnJvbSBcIi4uL3F1ZXJ5LXBhcnNlci93aGVyZS1wYXJzZXIuanNcIlxuXG4vKipcbiAqIFJ1bnMgdW5xdW90ZSBzcWwgaWRlbnRpZmllci5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFBvdGVudGlhbGx5IHF1b3RlZCBTUUwgaWRlbnRpZmllci5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVW5xdW90ZWQgaWRlbnRpZmllci5cbiAqL1xuZnVuY3Rpb24gdW5xdW90ZVNxbElkZW50aWZpZXIodmFsdWUpIHtcbiAgY29uc3QgdHJpbW1lZCA9IHZhbHVlLnRyaW0oKVxuXG4gIGlmICh0cmltbWVkLmxlbmd0aCA+PSAyICYmICgodHJpbW1lZC5zdGFydHNXaXRoKFwiYFwiKSAmJiB0cmltbWVkLmVuZHNXaXRoKFwiYFwiKSkgfHwgKHRyaW1tZWQuc3RhcnRzV2l0aChcIlxcXCJcIikgJiYgdHJpbW1lZC5lbmRzV2l0aChcIlxcXCJcIikpKSkge1xuICAgIHJldHVybiB0cmltbWVkLnNsaWNlKDEsIC0xKVxuICB9XG5cbiAgaWYgKHRyaW1tZWQubGVuZ3RoID49IDIgJiYgdHJpbW1lZC5zdGFydHNXaXRoKFwiW1wiKSAmJiB0cmltbWVkLmVuZHNXaXRoKFwiXVwiKSkge1xuICAgIHJldHVybiB0cmltbWVkLnNsaWNlKDEsIC0xKVxuICB9XG5cbiAgcmV0dXJuIHRyaW1tZWRcbn1cblxuLyoqXG4gKiBSdW5zIHBhcnNlIGZyb20gcGxhaW4gdGFibGUgcmVmZXJlbmNlLlxuICogQHBhcmFtIHtzdHJpbmd9IGZyb21QbGFpbiAtIEZST00gY2xhdXNlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtzdHJpbmcgfCBudWxsfSAtIFBhcnNlZCB0YWJsZSByZWZlcmVuY2Ugb3IgbnVsbCB3aGVuIHVuc3VwcG9ydGVkLlxuICovXG5mdW5jdGlvbiBwYXJzZUZyb21QbGFpblRhYmxlUmVmZXJlbmNlKGZyb21QbGFpbikge1xuICBjb25zdCB0cmltbWVkID0gZnJvbVBsYWluLnRyaW0oKVxuXG4gIGlmICh0cmltbWVkLmxlbmd0aCA8IDEpIHJldHVybiBudWxsXG5cbiAgY29uc3QgYWxpYXNNYXRjaCA9IHRyaW1tZWQubWF0Y2goLyg/Ol58XFxzKSg/OkFTXFxzKyk/KFtgXCJdP1thLXpBLVpfXVthLXpBLVowLTlfXSpbYFwiXT98XFxbW2EtekEtWl9dW2EtekEtWjAtOV9dKlxcXSlcXHMqJC9pKVxuXG4gIGlmICghYWxpYXNNYXRjaCB8fCAhYWxpYXNNYXRjaFsxXSkgcmV0dXJuIG51bGxcblxuICByZXR1cm4gdW5xdW90ZVNxbElkZW50aWZpZXIoYWxpYXNNYXRjaFsxXSlcbn1cblxuLyoqXG4gKiBSdW5zIG5vcm1hbGl6ZSBzY29wZSBwYXRoLlxuICogQHBhcmFtIHtzdHJpbmcgfCBzdHJpbmdbXX0gcGF0aCAtIFNjb3BlIHBhdGggaW5wdXQuXG4gKiBAcmV0dXJucyB7c3RyaW5nW119IC0gTm9ybWFsaXplZCBwYXRoLlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVTY29wZVBhdGgocGF0aCkge1xuICBpZiAodHlwZW9mIHBhdGggPT09IFwic3RyaW5nXCIpIHtcbiAgICBpZiAocGF0aC5sZW5ndGggPCAxKSB0aHJvdyBuZXcgRXJyb3IoXCJTY29wZSBwYXRoIHN0cmluZ3MgbXVzdCBiZSBub24tZW1wdHlcIilcblxuICAgIHJldHVybiBbcGF0aF1cbiAgfVxuXG4gIGlmICghQXJyYXkuaXNBcnJheShwYXRoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBzY29wZSBwYXRoIHR5cGU6ICR7dHlwZW9mIHBhdGh9YClcbiAgfVxuXG4gIGZvciAoY29uc3QgZW50cnkgb2YgcGF0aCkge1xuICAgIGlmICh0eXBlb2YgZW50cnkgIT09IFwic3RyaW5nXCIgfHwgZW50cnkubGVuZ3RoIDwgMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU2NvcGUgcGF0aCBlbnRyaWVzIG11c3QgYmUgbm9uLWVtcHR5IHN0cmluZ3NcIilcbiAgICB9XG4gIH1cblxuICByZXR1cm4gWy4uLnBhdGhdXG59XG5cbi8qKlxuICogRGVlcC1jb3BpZXMgYSBwcmVsb2FkIHNlbGVjdCBtYXAgKGtleWVkIGJ5IG1vZGVsIG5hbWUgd2l0aCBhdHRyaWJ1dGUgYXJyYXlzKVxuICogc28gYSBjbG9uZWQgcXVlcnkncyBzZWxlY3Rpb25zIGNhbiBiZSBtdXRhdGVkIHdpdGhvdXQgYWZmZWN0aW5nIHRoZSBvcmlnaW5hbC5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgc3RyaW5nW10+fSBtYXAgLSBQcmVsb2FkIHNlbGVjdCBtYXAgdG8gY29weS5cbiAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT59IC0gQSBjb3B5IHdpdGggaW5kZXBlbmRlbnQgYXJyYXlzLlxuICovXG5mdW5jdGlvbiBjbG9uZVByZWxvYWRTZWxlY3RNYXAobWFwKSB7XG4gIC8qKlxuICAgKiBSZXN1bHQuXG4gICAgQHR5cGUge1JlY29yZDxzdHJpbmcsIHN0cmluZ1tdPn0gKi9cbiAgY29uc3QgcmVzdWx0ID0ge31cblxuICBmb3IgKGNvbnN0IFttb2RlbE5hbWUsIGF0dHJpYnV0ZXNdIG9mIE9iamVjdC5lbnRyaWVzKG1hcCkpIHtcbiAgICByZXN1bHRbbW9kZWxOYW1lXSA9IFsuLi5hdHRyaWJ1dGVzXVxuICB9XG5cbiAgcmV0dXJuIHJlc3VsdFxufVxuXG4vKipcbiAqIFJ1bnMgbm9ybWFsaXplIHByZWxvYWQgcmVjb3JkLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuL2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmQgfCBzdHJpbmcgfCBBcnJheTxzdHJpbmcgfCBpbXBvcnQoXCIuL2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmQ+fSBwcmVsb2FkIC0gUHJlbG9hZCBkYXRhIGluIHNob3J0aGFuZCBvciBuZXN0ZWQgZm9ybS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmR9IC0gTm9ybWFsaXplZCBwcmVsb2FkIHJlY29yZC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplUHJlbG9hZFJlY29yZChwcmVsb2FkKSB7XG4gIGlmICghcHJlbG9hZCkgcmV0dXJuIHt9XG5cbiAgaWYgKHR5cGVvZiBwcmVsb2FkID09IFwic3RyaW5nXCIpIHtcbiAgICByZXR1cm4ge1twcmVsb2FkXTogdHJ1ZX1cbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHByZWxvYWQpKSB7XG4gICAgLyoqXG4gICAgICogUmVzdWx0LlxuICAgICAgQHR5cGUge2ltcG9ydChcIi4vaW5kZXguanNcIikuTmVzdGVkUHJlbG9hZFJlY29yZH0gKi9cbiAgICBjb25zdCByZXN1bHQgPSB7fVxuXG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiBwcmVsb2FkKSB7XG4gICAgICBpZiAodHlwZW9mIGVudHJ5ID09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgcmVzdWx0W2VudHJ5XSA9IHRydWVcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUGxhaW5PYmplY3QoZW50cnkpKSB7XG4gICAgICAgIGluY29ycG9yYXRlKHJlc3VsdCwgbm9ybWFsaXplUHJlbG9hZFJlY29yZChlbnRyeSkpXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBwcmVsb2FkIGVudHJ5IHR5cGU6ICR7dHlwZW9mIGVudHJ5fWApXG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdFxuICB9XG5cbiAgaWYgKCFpc1BsYWluT2JqZWN0KHByZWxvYWQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHByZWxvYWQgdHlwZTogJHt0eXBlb2YgcHJlbG9hZH1gKVxuICB9XG5cbiAgLyoqXG4gICAqIFJlc3VsdC5cbiAgICBAdHlwZSB7aW1wb3J0KFwiLi9pbmRleC5qc1wiKS5OZXN0ZWRQcmVsb2FkUmVjb3JkfSAqL1xuICBjb25zdCByZXN1bHQgPSB7fVxuXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHByZWxvYWQpKSB7XG4gICAgaWYgKHZhbHVlID09PSB0cnVlIHx8IHZhbHVlID09PSBmYWxzZSkge1xuICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHZhbHVlID09IFwic3RyaW5nXCIgfHwgQXJyYXkuaXNBcnJheSh2YWx1ZSkgfHwgaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHtcbiAgICAgIHJlc3VsdFtrZXldID0gbm9ybWFsaXplUHJlbG9hZFJlY29yZCh2YWx1ZSlcbiAgICAgIGNvbnRpbnVlXG4gICAgfVxuXG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHByZWxvYWQgdmFsdWUgZm9yICR7a2V5fTogJHt0eXBlb2YgdmFsdWV9YClcbiAgfVxuXG4gIHJldHVybiByZXN1bHRcbn1cblxuLyoqXG4gKiBEZWZpbmVzIHRoaXMgdHlwZWRlZi5cbiAqIEB0ZW1wbGF0ZSB7dHlwZW9mIGltcG9ydChcIi4uL3JlY29yZC9pbmRleC5qc1wiKS5kZWZhdWx0fSBbTUM9dHlwZW9mIGltcG9ydChcIi4uL3JlY29yZC9pbmRleC5qc1wiKS5kZWZhdWx0XVxuICovXG4vKipcbiAqIERlZmluZXMgdGhpcyB0eXBlZGVmLlxuICogQHRlbXBsYXRlIHt0eXBlb2YgaW1wb3J0KFwiLi4vcmVjb3JkL2luZGV4LmpzXCIpLmRlZmF1bHR9IFtNQz10eXBlb2YgaW1wb3J0KFwiLi4vcmVjb3JkL2luZGV4LmpzXCIpLmRlZmF1bHRdXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi9pbmRleC5qc1wiKS5RdWVyeUFyZ3NUeXBlICYge21vZGVsQ2xhc3M6IE1DLCBqb2luQmFzZVBhdGg/OiBzdHJpbmdbXSwgam9pblRyYWNrZXI/OiBpbXBvcnQoXCIuL2pvaW4tdHJhY2tlci5qc1wiKS5kZWZhdWx0LCBmb3JjZVF1YWxpZnlCYXNlVGFibGU/OiBib29sZWFuLCB3aXRoQ291bnQ/OiBpbXBvcnQoXCIuL3dpdGgtY291bnQuanNcIikuV2l0aENvdW50RW50cnlbXSwgcXVlcnlEYXRhPzogaW1wb3J0KFwiLi9xdWVyeS1kYXRhLmpzXCIpLlF1ZXJ5RGF0YUVudHJ5W119fSBNb2RlbENsYXNzUXVlcnlBcmdzVHlwZVxuICovXG5cbi8qKlxuICogQSBnZW5lcmljIHF1ZXJ5IG92ZXIgc29tZSBtb2RlbCB0eXBlLlxuICogQHRlbXBsYXRlIHt0eXBlb2YgaW1wb3J0KFwiLi4vcmVjb3JkL2luZGV4LmpzXCIpLmRlZmF1bHR9IFtNQz10eXBlb2YgaW1wb3J0KFwiLi4vcmVjb3JkL2luZGV4LmpzXCIpLmRlZmF1bHRdXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZlbG9jaW91c0RhdGFiYXNlUXVlcnlNb2RlbENsYXNzUXVlcnkgZXh0ZW5kcyBEYXRhYmFzZVF1ZXJ5IHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7TW9kZWxDbGFzc1F1ZXJ5QXJnc1R5cGU8TUM+fSBhcmdzIC0gUXVlcnkgY29uc3RydWN0b3IgYXJndW1lbnRzLlxuICAgKi9cbiAgY29uc3RydWN0b3IoYXJncykge1xuICAgIGNvbnN0IHttb2RlbENsYXNzfSA9IGFyZ3NcblxuICAgIGlmICghbW9kZWxDbGFzcykgdGhyb3cgbmV3IEVycm9yKGBObyBtb2RlbENsYXNzIGdpdmVuIGluICR7T2JqZWN0LmtleXMoYXJncykuam9pbihcIiwgXCIpfWApXG5cbiAgICBzdXBlcihhcmdzKVxuICAgIHRoaXMubG9nZ2VyID0gbmV3IExvZ2dlcih0aGlzKVxuXG4gICAgLyoqXG4gICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgQHR5cGUge01DfSAqL1xuICAgIHRoaXMubW9kZWxDbGFzcyA9IG1vZGVsQ2xhc3NcblxuICAgIC8qKlxuICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgIEB0eXBlIHtzdHJpbmdbXX0gKi9cbiAgICB0aGlzLl9qb2luQmFzZVBhdGggPSBhcmdzLmpvaW5CYXNlUGF0aCB8fCBbXVxuICAgIHRoaXMuX2pvaW5UcmFja2VyID0gYXJncy5qb2luVHJhY2tlciB8fCBuZXcgSm9pblRyYWNrZXIoe21vZGVsQ2xhc3M6IHRoaXMubW9kZWxDbGFzc30pXG4gICAgdGhpcy5fZm9yY2VRdWFsaWZ5QmFzZVRhYmxlID0gQm9vbGVhbihhcmdzLmZvcmNlUXVhbGlmeUJhc2VUYWJsZSlcblxuICAgIC8qKlxuICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgIEB0eXBlIHtpbXBvcnQoXCIuL3dpdGgtY291bnQuanNcIikuV2l0aENvdW50RW50cnlbXX0gKi9cbiAgICB0aGlzLl93aXRoQ291bnQgPSBhcmdzLndpdGhDb3VudCA/IFsuLi5hcmdzLndpdGhDb3VudF0gOiBbXVxuXG4gICAgLyoqXG4gICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgQHR5cGUge2ltcG9ydChcIi4vcXVlcnktZGF0YS5qc1wiKS5RdWVyeURhdGFFbnRyeVtdfSAqL1xuICAgIHRoaXMuX3F1ZXJ5RGF0YSA9IGFyZ3MucXVlcnlEYXRhID8gWy4uLmFyZ3MucXVlcnlEYXRhXSA6IFtdXG4gIH1cblxuICAvKipcbiAgICogUnVucyBjbG9uZS5cbiAgICogQHJldHVybnMge3RoaXN9IC0gVGhlIGNsb25lLlxuICAgKi9cbiAgY2xvbmUoKSB7XG4gICAgY29uc3QgbmV3UXVlcnkgPSAvKipcbiAgICAgICAgICAgICAgICAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgICAgICAgICAgICAgICAgQHR5cGUge1ZlbG9jaW91c0RhdGFiYXNlUXVlcnlNb2RlbENsYXNzUXVlcnk8TUM+fSAqLyAobmV3IFZlbG9jaW91c0RhdGFiYXNlUXVlcnlNb2RlbENsYXNzUXVlcnkoe1xuICAgICAgZHJpdmVyOiB0aGlzLl9kcml2ZXJGbixcbiAgICAgIGZyb21zOiBbLi4udGhpcy5fZnJvbXNdLFxuICAgICAgaGFuZGxlcjogdGhpcy5oYW5kbGVyLmNsb25lKCksXG4gICAgICBncm91cHM6IFsuLi50aGlzLl9ncm91cHNdLFxuICAgICAgam9pbnM6IFsuLi50aGlzLl9qb2luc10sXG4gICAgICBsaW1pdDogdGhpcy5fbGltaXQsXG4gICAgICBtb2RlbENsYXNzOiB0aGlzLm1vZGVsQ2xhc3MsXG4gICAgICBvZmZzZXQ6IHRoaXMuX29mZnNldCxcbiAgICAgIG9yZGVyczogWy4uLnRoaXMuX29yZGVyc10sXG4gICAgICBwYWdlOiB0aGlzLl9wYWdlLFxuICAgICAgcGVyUGFnZTogdGhpcy5fcGVyUGFnZSxcbiAgICAgIHByZWxvYWQ6IHsuLi50aGlzLl9wcmVsb2FkfSxcbiAgICAgIHByZWxvYWRTZWxlY3RzOiBjbG9uZVByZWxvYWRTZWxlY3RNYXAodGhpcy5fcHJlbG9hZFNlbGVjdHMpLFxuICAgICAgcHJlbG9hZFNlbGVjdHNFeHRyYTogY2xvbmVQcmVsb2FkU2VsZWN0TWFwKHRoaXMuX3ByZWxvYWRTZWxlY3RzRXh0cmEpLFxuICAgICAgZGlzdGluY3Q6IHRoaXMuX2Rpc3RpbmN0LFxuICAgICAgc2VsZWN0czogWy4uLnRoaXMuX3NlbGVjdHNdLFxuICAgICAgd2hlcmVzOiBbLi4udGhpcy5fd2hlcmVzXSxcbiAgICAgIGpvaW5CYXNlUGF0aDogWy4uLnRoaXMuX2pvaW5CYXNlUGF0aF0sXG4gICAgICBqb2luVHJhY2tlcjogdGhpcy5fam9pblRyYWNrZXIuY2xvbmUoKSxcbiAgICAgIGZvcmNlUXVhbGlmeUJhc2VUYWJsZTogdGhpcy5fZm9yY2VRdWFsaWZ5QmFzZVRhYmxlLFxuICAgICAgd2l0aENvdW50OiBbLi4udGhpcy5fd2l0aENvdW50XSxcbiAgICAgIHF1ZXJ5RGF0YTogWy4uLnRoaXMuX3F1ZXJ5RGF0YV1cbiAgICB9KSlcblxuICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICByZXR1cm4gbmV3UXVlcnlcbiAgfVxuXG4gIC8qKlxuICAgKiBUZWxsIHRoZSBxdWVyeSB0byBhdHRhY2ggb25lIG9yIG1vcmUgYXNzb2NpYXRpb24gY291bnRzIG9udG8gZXZlcnlcbiAgICogbG9hZGVkIHJlY29yZC4gVGhlIGNvdW50cyBsYW5kIGFzIHJlZ3VsYXIgYXR0cmlidXRlcyBvbiBlYWNoIHJlY29yZDtcbiAgICogcmVhZCB0aGVtIHdpdGggYG1vZGVsLnJlYWRBdHRyaWJ1dGUoXCI8bmFtZT5Db3VudFwiKWAuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi93aXRoLWNvdW50LmpzXCIpLldpdGhDb3VudFNwZWN9IHNwZWMgLSBDb3VudCBzcGVjIGluIHNob3J0aGFuZCBvciBuZXN0ZWQgZm9ybS5cbiAgICogQHJldHVybnMge3RoaXN9IC0gVGhpcyBxdWVyeSwgZm9yIGNoYWluaW5nLlxuICAgKi9cbiAgd2l0aENvdW50KHNwZWMpIHtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIG5vcm1hbGl6ZVdpdGhDb3VudChzcGVjKSkge1xuICAgICAgdGhpcy5fd2l0aENvdW50LnB1c2goZW50cnkpXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRhY2ggb25lIG9yIG1vcmUgY29uc3VtZXItZGVmaW5lZCwgcGVyLXJvdyBjb21wdXRlZCB2YWx1ZXMgb250b1xuICAgKiBldmVyeSBsb2FkZWQgcm9vdCByZWNvcmQuIExlYWYgc3RyaW5ncyBpbiB0aGUgc3BlYyBhcmUgbmFtZXMgb2ZcbiAgICogZnVuY3Rpb25zIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB2aWEgYE1vZGVsLnF1ZXJ5RGF0YShuYW1lLCBmbilgLlxuICAgKiBOZXN0ZWQgb2JqZWN0IGtleXMgYXJlIHJlbGF0aW9uc2hpcCBuYW1lcyB0cmFjZWQgZnJvbSB0aGUgcm9vdCB0b1xuICAgKiB0aGUgbW9kZWwgdGhhdCBkZWNsYXJlcyB0aGUgZm4uIEV2ZXJ5IHJlc3VsdGluZyBTRUxFQ1QgYWxpYXMgaXNcbiAgICogYXR0YWNoZWQgdG8gdGhlICoqcm9vdCoqIHJlY29yZCAobm90IHRvIHRoZSBpbnRlcm1lZGlhdGUgam9pbmVkXG4gICAqIHJvd3MpOyByZWFkIHZhbHVlcyB3aXRoIGByZWNvcmQucXVlcnlEYXRhKGFsaWFzTmFtZSlgLlxuICAgKlxuICAgKiBTZWUgYWxzbyBgc3JjL2RhdGFiYXNlL3F1ZXJ5L3F1ZXJ5LWRhdGEuanNgLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vcXVlcnktZGF0YS5qc1wiKS5RdWVyeURhdGFTcGVjfSBzcGVjIC0gU3BlYyBpbiBzaG9ydGhhbmQgb3IgbmVzdGVkIGZvcm0uXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFRoaXMgcXVlcnksIGZvciBjaGFpbmluZy5cbiAgICovXG4gIHF1ZXJ5RGF0YShzcGVjKSB7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiBub3JtYWxpemVRdWVyeURhdGFTcGVjKHNwZWMpKSB7XG4gICAgICB0aGlzLl9xdWVyeURhdGEucHVzaChlbnRyeSlcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgdGFibGUgcmVmZXJlbmNlIChhbGlhcyBvciB0YWJsZSBuYW1lKSByZWdpc3RlcmVkIGZvciB0aGVcbiAgICogZ2l2ZW4gcmVsYXRpb25zaGlwIGNoYWluLCByZWxhdGl2ZSB0byB0aGUgcXVlcnkncyBjdXJyZW50IGpvaW4gYmFzZVxuICAgKiBwYXRoLiBDb252ZW5pZW5jZSB3cmFwcGVyIGFyb3VuZCBgZ2V0VGFibGVSZWZlcmVuY2VGb3JKb2luYCBmb3IgdXNlXG4gICAqIGluc2lkZSBgcXVlcnlEYXRhYCBjYWxsYmFja3Mgd2hlcmUgdGhlIHdyaXRlcidzIGludGVudCByZWFkcyBtb3JlXG4gICAqIG5hdHVyYWxseSBhcyBcImdpdmUgbWUgdGhlIHRhYmxlIG5hbWUgZm9yICd0YXNrcydcIi5cbiAgICogQHBhcmFtIHsuLi5zdHJpbmd9IHBhdGggLSBSZWxhdGlvbnNoaXAgcGF0aCBzZWdtZW50cy5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBVbnF1b3RlZCB0YWJsZSByZWZlcmVuY2UuXG4gICAqL1xuICB0YWJsZU5hbWVGb3IoLi4ucGF0aCkge1xuICAgIHJldHVybiB0aGlzLmdldFRhYmxlUmVmZXJlbmNlRm9ySm9pbiguLi5wYXRoKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgY291bnQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IC0gUmVzb2x2ZXMgd2l0aCB0aGUgY291bnQuXG4gICAqL1xuICBhc3luYyBjb3VudCgpIHtcbiAgICBpZiAodGhpcy5fbGltaXQgIT09IG51bGwgfHwgdGhpcy5fb2Zmc2V0ICE9PSBudWxsKSB7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5wYWdpbmF0ZWRDb3VudCgpXG4gICAgfVxuXG4gICAgLy8gR2VuZXJhdGUgY291bnQgU1FMXG4gICAgY29uc3QgcHJpbWFyeUtleSA9IGAke3RoaXMuZHJpdmVyLnF1b3RlVGFibGUodGhpcy5nZXRNb2RlbENsYXNzKCkudGFibGVOYW1lKCkpfS4ke3RoaXMuZHJpdmVyLnF1b3RlQ29sdW1uKHRoaXMuZ2V0TW9kZWxDbGFzcygpLnByaW1hcnlLZXkoKSl9YFxuICAgIGNvbnN0IGRpc3RpbmN0UHJlZml4ID0gdGhpcy5fZGlzdGluY3QgPyBcIkRJU1RJTkNUIFwiIDogXCJcIlxuICAgIGxldCBzcWwgPSBgQ09VTlQoJHtkaXN0aW5jdFByZWZpeH0ke3ByaW1hcnlLZXl9KWBcblxuICAgIGlmICh0aGlzLmRyaXZlci5nZXRUeXBlKCkgPT0gXCJwZ3NxbFwiKSBzcWwgKz0gXCI6OmludFwiXG5cbiAgICBzcWwgKz0gXCIgQVMgY291bnRcIlxuXG5cbiAgICAvLyBDbG9uZSBxdWVyeSBhbmQgZXhlY3V0ZSBjb3VudFxuICAgIGNvbnN0IGNvdW50UXVlcnkgPSB0aGlzLmNsb25lKClcblxuICAgIGNvdW50UXVlcnkuX2Rpc3RpbmN0ID0gZmFsc2VcbiAgICBjb3VudFF1ZXJ5Ll9zZWxlY3RzID0gW11cbiAgICBjb3VudFF1ZXJ5LnNlbGVjdChzcWwpXG5cbiAgICBjb25zdCByZXN1bHRzID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7e2NvdW50OiBudW1iZXJ9W119ICovIChhd2FpdCBjb3VudFF1ZXJ5Ll9leGVjdXRlUXVlcnkoe1xuICAgICAgbG9nTmFtZTogY291bnRRdWVyeS5xdWVyeUxvZ05hbWUoXCJDb3VudFwiKVxuICAgIH0pKVxuXG4gICAgLy8gVGhlIHF1ZXJ5IGlzbid0IGdyb3VwZWQgYW5kIGEgc2luZ2xlIHJlc3VsdCBoYXMgYmVlbiBnaXZlblxuICAgIGlmIChyZXN1bHRzLmxlbmd0aCA9PSAxKSB7XG4gICAgICByZXR1cm4gcmVzdWx0c1swXS5jb3VudFxuICAgIH1cblxuICAgIC8vIFRoZSBxdWVyeSBtYXkgYmUgZ3JvdXBlZCBhbmQgYSBsb3Qgb2YgZGlmZmVyZW50IGNvdW50cyBhIGdpdmVuXG4gICAgbGV0IGNvdW50UmVzdWx0ID0gMFxuXG4gICAgZm9yIChjb25zdCByZXN1bHQgb2YgcmVzdWx0cykge1xuICAgICAgaWYgKCEoXCJjb3VudFwiIGluIHJlc3VsdCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBjb3VudCByZXN1bHRcIilcbiAgICAgIH1cblxuICAgICAgY291bnRSZXN1bHQgKz0gcmVzdWx0LmNvdW50XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvdW50UmVzdWx0XG4gIH1cblxuICAvKipcbiAgICogUnVucyBwYWdpbmF0ZWQgY291bnQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IC0gUmVzb2x2ZXMgd2l0aCB0aGUgY291bnQgYWZ0ZXIgcGFnaW5hdGlvbiBpcyBhcHBsaWVkLlxuICAgKi9cbiAgYXN5bmMgcGFnaW5hdGVkQ291bnQoKSB7XG4gICAgY29uc3QgY291bnRRdWVyeSA9IHRoaXMuY2xvbmUoKVxuICAgIGNvbnN0IGNvdW50U3FsID0gdGhpcy5kcml2ZXIuZ2V0VHlwZSgpID09IFwicGdzcWxcIiA/IFwiQ09VTlQoKik6OmludFwiIDogXCJDT1VOVCgqKVwiXG4gICAgY29uc3Qgc3FsID0gW1xuICAgICAgYFNFTEVDVCAke2NvdW50U3FsfSBBUyAke3RoaXMuZHJpdmVyLnF1b3RlQ29sdW1uKFwiY291bnRcIil9YCxcbiAgICAgIGBGUk9NICgke2NvdW50UXVlcnkudG9TcWwoKX0pIEFTICR7dGhpcy5kcml2ZXIucXVvdGVUYWJsZShcInBhZ2luYXRlZF9jb3VudF9yb3dzXCIpfWBcbiAgICBdLmpvaW4oXCIgXCIpXG4gICAgY29uc3QgcmVzdWx0cyA9IC8qKlxuICAgICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgICAgQHR5cGUge3tjb3VudDogbnVtYmVyfVtdfSAqLyAoYXdhaXQgdGhpcy5kcml2ZXIucXVlcnkoXG4gICAgICBzcWwsXG4gICAgICB7bG9nTmFtZTogdGhpcy5xdWVyeUxvZ05hbWUoXCJDb3VudFwiKX1cbiAgICApKVxuXG4gICAgaWYgKHJlc3VsdHMubGVuZ3RoICE9IDEgfHwgIShcImNvdW50XCIgaW4gcmVzdWx0c1swXSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgY291bnQgcmVzdWx0XCIpXG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdHNbMF0uY291bnRcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNlbGVjdC5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL2luZGV4LmpzXCIpLlNlbGVjdEFyZ3VtZW50VHlwZX0gc2VsZWN0IC0gU2VsZWN0LlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBUaGUgc2VsZWN0LlxuICAgKi9cbiAgc2VsZWN0KHNlbGVjdCkge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHNlbGVjdCkpIHtcbiAgICAgIGZvciAoY29uc3Qgc2VsZWN0RW50cnkgb2Ygc2VsZWN0KSB7XG4gICAgICAgIHRoaXMuc2VsZWN0KHNlbGVjdEVudHJ5KVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpc1xuICAgIH1cblxuICAgIGlmICh0eXBlb2Ygc2VsZWN0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBjb25zdCB0cmltbWVkU2VsZWN0ID0gc2VsZWN0LnRyaW0oKVxuXG4gICAgICBpZiAoL15bYS16QS1aX11bYS16QS1aMC05X10qJC8udGVzdCh0cmltbWVkU2VsZWN0KSkge1xuICAgICAgICBjb25zdCBtb2RlbENsYXNzID0gdGhpcy5nZXRNb2RlbENsYXNzKClcbiAgICAgICAgY29uc3QgYXR0cmlidXRlTWFwID0gbW9kZWxDbGFzcy5nZXRBdHRyaWJ1dGVOYW1lVG9Db2x1bW5OYW1lTWFwKClcbiAgICAgICAgY29uc3QgY29sdW1uTmFtZSA9IGF0dHJpYnV0ZU1hcFt0cmltbWVkU2VsZWN0XSB8fCB0cmltbWVkU2VsZWN0XG4gICAgICAgIGNvbnN0IHRhYmxlUmVmZXJlbmNlID0gdGhpcy5yb290VGFibGVSZWZlcmVuY2UoKVxuICAgICAgICBjb25zdCBxdWFsaWZpZWRDb2x1bW4gPSBgJHt0aGlzLmRyaXZlci5xdW90ZVRhYmxlKHRhYmxlUmVmZXJlbmNlKX0uJHt0aGlzLmRyaXZlci5xdW90ZUNvbHVtbihjb2x1bW5OYW1lKX1gXG5cbiAgICAgICAgcmV0dXJuIHN1cGVyLnNlbGVjdChxdWFsaWZpZWRDb2x1bW4pXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gT2JqZWN0IGZvcm0ga2V5ZWQgYnkgdGFyZ2V0IG1vZGVsIG5hbWUsIGUuZy4gYC5zZWxlY3Qoe0FjY291bnQ6IFtcImlkXCJdfSlgLlxuICAgIC8vIFRoZXNlIGxpbWl0IHRoZSBhdHRyaWJ1dGVzIGxvYWRlZCBmb3IgcHJlbG9hZGVkIHJlbGF0aW9uc2hpcCB0YXJnZXRzXG4gICAgLy8gcmF0aGVyIHRoYW4gdGhlIHJvb3QgcXVlcnkncyBTRUxFQ1QgY2xhdXNlLlxuICAgIGlmIChpc1BsYWluT2JqZWN0KHNlbGVjdCkpIHtcbiAgICAgIHRoaXMuX21lcmdlUHJlbG9hZFNlbGVjdCh0aGlzLl9wcmVsb2FkU2VsZWN0cywgc2VsZWN0KVxuXG4gICAgICByZXR1cm4gdGhpc1xuICAgIH1cblxuICAgIHJldHVybiBzdXBlci5zZWxlY3Qoc2VsZWN0KVxuICB9XG5cbiAgLyoqXG4gICAqIExvYWRzIHRoZSBkZWZhdWx0IGNvbHVtbnMgcGx1cyB0aGUgZ2l2ZW4gZXh0cmEgc2VsZWN0cyBmb3IgcHJlbG9hZGVkXG4gICAqIHJlbGF0aW9uc2hpcCB0YXJnZXRzLCBrZXllZCBieSB0YXJnZXQgbW9kZWwgbmFtZSwgZS5nLlxuICAgKiBgLnNlbGVjdHNFeHRyYSh7QWNjb3VudDogW1wiKFNFTEVDVCBjb3VudCgqKSBGUk9NIHByb2plY3RzKSBBUyBwcm9qZWN0c19jb3VudFwiXX0pYC5cbiAgICogVW5saWtlIGBzZWxlY3Qoey4uLn0pYCwgd2hpY2ggbmFycm93cyB0byBvbmx5IHRoZSBsaXN0ZWQgY29sdW1ucywgdGhpcyBrZWVwc1xuICAgKiB0aGUgZGVmYXVsdCBgU0VMRUNUICpgIGNvbHVtbnMgYW5kIGFkZHMgdGhlIGV4dHJhcyBvbiB0b3AuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10+fSBzZWxlY3QgLSBFeHRyYSBzZWxlY3RzIGtleWVkIGJ5IHRhcmdldCBtb2RlbCBuYW1lLlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBUaGlzIHF1ZXJ5LCBmb3IgY2hhaW5pbmcuXG4gICAqL1xuICBzZWxlY3RzRXh0cmEoc2VsZWN0KSB7XG4gICAgdGhpcy5fbWVyZ2VQcmVsb2FkU2VsZWN0KHRoaXMuX3ByZWxvYWRTZWxlY3RzRXh0cmEsIHNlbGVjdClcblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogTWVyZ2VzIGFuIG9iamVjdC1mb3JtIHByZWxvYWQgc2VsZWN0IChrZXllZCBieSB0YXJnZXQgbW9kZWwgbmFtZSkgaW50byB0aGVcbiAgICogZ2l2ZW4gdGFyZ2V0IG1hcCwgZGUtZHVwbGljYXRpbmcgYXR0cmlidXRlL2V4cHJlc3Npb24gZW50cmllcy5cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT59IHRhcmdldCAtIE1hcCB0byBtZXJnZSBpbnRvLlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHN0cmluZyB8IHN0cmluZ1tdPn0gc2VsZWN0IC0gT2JqZWN0LWZvcm0gc2VsZWN0LlxuICAgKiBAcmV0dXJucyB7dm9pZH0gLSBObyByZXR1cm4gdmFsdWUuXG4gICAqL1xuICBfbWVyZ2VQcmVsb2FkU2VsZWN0KHRhcmdldCwgc2VsZWN0KSB7XG4gICAgZm9yIChjb25zdCBbbW9kZWxOYW1lLCBhdHRyaWJ1dGVzXSBvZiBPYmplY3QuZW50cmllcyhzZWxlY3QpKSB7XG4gICAgICBjb25zdCBub3JtYWxpemVkQXR0cmlidXRlcyA9IEFycmF5LmlzQXJyYXkoYXR0cmlidXRlcykgPyBhdHRyaWJ1dGVzIDogW2F0dHJpYnV0ZXNdXG5cbiAgICAgIGlmICghdGFyZ2V0W21vZGVsTmFtZV0pIHRhcmdldFttb2RlbE5hbWVdID0gW11cblxuICAgICAgZm9yIChjb25zdCBhdHRyaWJ1dGUgb2Ygbm9ybWFsaXplZEF0dHJpYnV0ZXMpIHtcbiAgICAgICAgaWYgKCF0YXJnZXRbbW9kZWxOYW1lXS5pbmNsdWRlcyhhdHRyaWJ1dGUpKSB0YXJnZXRbbW9kZWxOYW1lXS5wdXNoKGF0dHJpYnV0ZSlcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyByb290IHRhYmxlIHJlZmVyZW5jZS5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBSb290IHRhYmxlIHJlZmVyZW5jZSBmb3IgcXVlcnkgc2VsZWN0IHF1YWxpZmljYXRpb24uXG4gICAqL1xuICByb290VGFibGVSZWZlcmVuY2UoKSB7XG4gICAgY29uc3QgZnJvbXMgPSB0aGlzLmdldEZyb21zKClcbiAgICBjb25zdCBsYXN0RnJvbSA9IGZyb21zW2Zyb21zLmxlbmd0aCAtIDFdXG5cbiAgICBpZiAobGFzdEZyb20gJiYgdHlwZW9mIC8qKlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7P30gKi8gKGxhc3RGcm9tKS50YWJsZU5hbWUgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiAvKiogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLiBAdHlwZSB7P30gKi8gKGxhc3RGcm9tKS50YWJsZU5hbWVcbiAgICB9XG5cbiAgICBpZiAobGFzdEZyb20gJiYgdHlwZW9mIC8qKlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7P30gKi8gKGxhc3RGcm9tKS5wbGFpbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgY29uc3QgcGFyc2VkUmVmZXJlbmNlID0gcGFyc2VGcm9tUGxhaW5UYWJsZVJlZmVyZW5jZSgvKipcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHs/fSAqLyAobGFzdEZyb20pLnBsYWluKVxuXG4gICAgICBpZiAocGFyc2VkUmVmZXJlbmNlKSByZXR1cm4gcGFyc2VkUmVmZXJlbmNlXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuZ2V0VGFibGVSZWZlcmVuY2VGb3JKb2luKClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCBtb2RlbCBjbGFzcy5cbiAgICogQHJldHVybnMge01DfSAtIFRoZSBtb2RlbCBjbGFzcy5cbiAgICovXG4gIGdldE1vZGVsQ2xhc3MoKSB7XG4gICAgaWYgKCF0aGlzLm1vZGVsQ2xhc3MpIHRocm93IG5ldyBFcnJvcihcIm1vZGVsQ2xhc3Mgbm90IHNldFwiKVxuXG4gICAgcmV0dXJuIHRoaXMubW9kZWxDbGFzc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IGpvaW4gYmFzZSBwYXRoLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nW119IC0gVGhlIGpvaW4gYmFzZSBwYXRoLlxuICAgKi9cbiAgZ2V0Sm9pbkJhc2VQYXRoKCkge1xuICAgIHJldHVybiB0aGlzLl9qb2luQmFzZVBhdGhcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCBqb2luIHRyYWNrZXIuXG4gICAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL2pvaW4tdHJhY2tlci5qc1wiKS5kZWZhdWx0fSAtIFRoZSBqb2luIHRyYWNrZXIuXG4gICAqL1xuICBnZXRKb2luVHJhY2tlcigpIHtcbiAgICByZXR1cm4gdGhpcy5fam9pblRyYWNrZXJcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCBmb3JjZSBxdWFsaWZ5IGJhc2UgdGFibGUuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFdoZXRoZXIgdG8gcXVhbGlmeSBiYXNlIHRhYmxlLlxuICAgKi9cbiAgZ2V0Rm9yY2VRdWFsaWZ5QmFzZVRhYmxlKCkge1xuICAgIHJldHVybiB0aGlzLl9mb3JjZVF1YWxpZnlCYXNlVGFibGVcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNldCBqb2luIGJhc2UgcGF0aC5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gam9pbkJhc2VQYXRoIC0gSm9pbiBiYXNlIHBhdGguXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFRoZSBxdWVyeSB3aXRoIHVwZGF0ZWQgYmFzZSBwYXRoLlxuICAgKi9cbiAgc2V0Sm9pbkJhc2VQYXRoKGpvaW5CYXNlUGF0aCkge1xuICAgIHRoaXMuX2pvaW5CYXNlUGF0aCA9IGpvaW5CYXNlUGF0aFxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogUnVucyB3aXRoIGpvaW4gcGF0aC5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gam9pbkJhc2VQYXRoIC0gSm9pbiBiYXNlIHBhdGguXG4gICAqIEByZXR1cm5zIHtWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5TW9kZWxDbGFzc1F1ZXJ5PE1DPn0gLSBUaGUgc2NvcGVkIHF1ZXJ5LlxuICAgKi9cbiAgd2l0aEpvaW5QYXRoKGpvaW5CYXNlUGF0aCkge1xuICAgIGNvbnN0IHNjb3BlZFF1ZXJ5ID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHtWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5TW9kZWxDbGFzc1F1ZXJ5PE1DPn0gKi8gKHRoaXMuY2xvbmUoKSlcblxuICAgIHNjb3BlZFF1ZXJ5Ll9qb2luQmFzZVBhdGggPSBqb2luQmFzZVBhdGhcbiAgICBzY29wZWRRdWVyeS5fam9pblRyYWNrZXIgPSB0aGlzLl9qb2luVHJhY2tlclxuXG4gICAgcmV0dXJuIHNjb3BlZFF1ZXJ5XG4gIH1cblxuICAvKipcbiAgICogUnVucyByZXNvbHZlIHRhYmxlIG5hbWUgZm9yIGpvaW4gcGF0aC5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gcGF0aCAtIEpvaW4gcGF0aC5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBUYWJsZSBuYW1lIGZvciBwYXRoLlxuICAgKi9cbiAgX3Jlc29sdmVUYWJsZU5hbWVGb3JKb2luUGF0aChwYXRoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Jlc29sdmVNb2RlbENsYXNzRm9ySm9pblBhdGgocGF0aCkudGFibGVOYW1lKClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJlc29sdmUgbW9kZWwgY2xhc3MgZm9yIGpvaW4gcGF0aC5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gcGF0aCAtIEpvaW4gcGF0aC5cbiAgICogQHJldHVybnMge3R5cGVvZiBpbXBvcnQoXCIuLi9yZWNvcmQvaW5kZXguanNcIikuZGVmYXVsdH0gLSBUYXJnZXQgbW9kZWwgY2xhc3MuXG4gICAqL1xuICBfcmVzb2x2ZU1vZGVsQ2xhc3NGb3JKb2luUGF0aChwYXRoKSB7XG4gICAgbGV0IG1vZGVsQ2xhc3MgPSB0aGlzLl9qb2luVHJhY2tlci5nZXRSb290TW9kZWxDbGFzcygpXG5cbiAgICBmb3IgKGNvbnN0IHJlbGF0aW9uc2hpcE5hbWUgb2YgcGF0aCkge1xuICAgICAgY29uc3QgcmVsYXRpb25zaGlwID0gbW9kZWxDbGFzcy5nZXRSZWxhdGlvbnNoaXBCeU5hbWUocmVsYXRpb25zaGlwTmFtZSlcbiAgICAgIGNvbnN0IHRhcmdldE1vZGVsQ2xhc3MgPSByZWxhdGlvbnNoaXAuZ2V0VGFyZ2V0TW9kZWxDbGFzcygpXG5cbiAgICAgIGlmICghdGFyZ2V0TW9kZWxDbGFzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHRhcmdldCBtb2RlbCBjbGFzcyBmb3IgJHttb2RlbENsYXNzLm5hbWV9IyR7cmVsYXRpb25zaGlwTmFtZX1gKVxuICAgICAgfVxuXG4gICAgICBtb2RlbENsYXNzID0gdGFyZ2V0TW9kZWxDbGFzc1xuICAgIH1cblxuICAgIHJldHVybiBtb2RlbENsYXNzXG4gIH1cblxuICAvKipcbiAgICogUnVucyByZWdpc3RlciBqb2luIHBhdGguXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHBhdGggLSBKb2luIHBhdGguXG4gICAqIEByZXR1cm5zIHt7dGFibGVOYW1lOiBzdHJpbmcsIGFsaWFzOiBzdHJpbmcgfCB1bmRlZmluZWR9fSAtIFRoZSBlbnRyeS5cbiAgICovXG4gIF9yZWdpc3RlckpvaW5QYXRoKHBhdGgpIHtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSB0aGlzLl9yZXNvbHZlVGFibGVOYW1lRm9ySm9pblBhdGgocGF0aClcblxuICAgIHJldHVybiB0aGlzLl9qb2luVHJhY2tlci5yZWdpc3RlclBhdGgocGF0aCwgdGFibGVOYW1lKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IGpvaW4gdGFibGUgcmVmZXJlbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBwYXRoIC0gSm9pbiBwYXRoLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFVucXVvdGVkIHRhYmxlIHJlZmVyZW5jZSAoYWxpYXMgb3IgdGFibGUgbmFtZSkuXG4gICAqL1xuICBnZXRKb2luVGFibGVSZWZlcmVuY2UocGF0aCkge1xuICAgIGNvbnN0IGVudHJ5ID0gdGhpcy5fam9pblRyYWNrZXIuZ2V0RW50cnkocGF0aCkgfHwgdGhpcy5fcmVnaXN0ZXJKb2luUGF0aChwYXRoKVxuXG4gICAgcmV0dXJuIGVudHJ5LmFsaWFzIHx8IGVudHJ5LnRhYmxlTmFtZVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IHRhYmxlIHJlZmVyZW5jZSBmb3Igam9pbi5cbiAgICogQHBhcmFtIHsuLi5zdHJpbmd9IHBhdGggLSBKb2luIHBhdGggc2VnbWVudHMuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVW5xdW90ZWQgdGFibGUgcmVmZXJlbmNlIChhbGlhcyBvciB0YWJsZSBuYW1lKS5cbiAgICovXG4gIGdldFRhYmxlUmVmZXJlbmNlRm9ySm9pbiguLi5wYXRoKSB7XG4gICAgY29uc3QgZnVsbFBhdGggPSB0aGlzLl9qb2luQmFzZVBhdGguY29uY2F0KHBhdGgpXG5cbiAgICByZXR1cm4gdGhpcy5nZXRKb2luVGFibGVSZWZlcmVuY2UoZnVsbFBhdGgpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBnZXQgdGFibGUgZm9yIGpvaW4uXG4gICAqIEBwYXJhbSB7Li4uc3RyaW5nfSBwYXRoIC0gSm9pbiBwYXRoIHNlZ21lbnRzLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFF1b3RlZCB0YWJsZSBuYW1lIGZvciBqb2luIHBhdGguXG4gICAqL1xuICBnZXRUYWJsZUZvckpvaW4oLi4ucGF0aCkge1xuICAgIHJldHVybiB0aGlzLmRyaXZlci5xdW90ZVRhYmxlKHRoaXMuZ2V0VGFibGVSZWZlcmVuY2VGb3JKb2luKC4uLnBhdGgpKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc2NvcGUuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vLi4vdXRpbHMvbW9kZWwtc2NvcGUuanNcIikuTW9kZWxTY29wZURlc2NyaXB0b3IgfCBzdHJpbmcgfCBzdHJpbmdbXX0gcGF0aE9yU2NvcGVEZXNjcmlwdG9yIC0gU2NvcGUgZGVzY3JpcHRvciBvciBqb2luIHBhdGguXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vLi4vdXRpbHMvbW9kZWwtc2NvcGUuanNcIikuTW9kZWxTY29wZURlc2NyaXB0b3J9IFttYXliZVNjb3BlRGVzY3JpcHRvcl0gLSBTY29wZSBkZXNjcmlwdG9yIHdoZW4gcGF0aCBpcyBnaXZlbi5cbiAgICogQHJldHVybnMge3RoaXN9IC0gU2NvcGVkIHF1ZXJ5LlxuICAgKi9cbiAgc2NvcGUocGF0aE9yU2NvcGVEZXNjcmlwdG9yLCBtYXliZVNjb3BlRGVzY3JpcHRvcikge1xuICAgIGlmIChpc01vZGVsU2NvcGVEZXNjcmlwdG9yKHBhdGhPclNjb3BlRGVzY3JpcHRvcikgJiYgIW1heWJlU2NvcGVEZXNjcmlwdG9yKSB7XG4gICAgICByZXR1cm4gdGhpcy5fYXBwbHlSb290U2NvcGUocGF0aE9yU2NvcGVEZXNjcmlwdG9yKVxuICAgIH1cblxuICAgIGlmICghbWF5YmVTY29wZURlc2NyaXB0b3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInNjb3BlKHBhdGgsIGRlc2NyaXB0b3IpIHJlcXVpcmVzIGEgc2NvcGUgZGVzY3JpcHRvclwiKVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzLl9hcHBseUpvaW5QYXRoU2NvcGUoe1xuICAgICAgam9pblBhdGg6IG5vcm1hbGl6ZVNjb3BlUGF0aCgvKipcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHtzdHJpbmcgfCBzdHJpbmdbXX0gKi8gKHBhdGhPclNjb3BlRGVzY3JpcHRvcikpLFxuICAgICAgc2NvcGVEZXNjcmlwdG9yOiBtYXliZVNjb3BlRGVzY3JpcHRvclxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyBhcHBseSByb290IHNjb3BlLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uLy4uL3V0aWxzL21vZGVsLXNjb3BlLmpzXCIpLk1vZGVsU2NvcGVEZXNjcmlwdG9yfSBzY29wZURlc2NyaXB0b3IgLSBTY29wZSBkZXNjcmlwdG9yLlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBTY29wZWQgcXVlcnkuXG4gICAqL1xuICBfYXBwbHlSb290U2NvcGUoc2NvcGVEZXNjcmlwdG9yKSB7XG4gICAgaWYgKCFpc01vZGVsU2NvcGVEZXNjcmlwdG9yKHNjb3BlRGVzY3JpcHRvcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInNjb3BlKCkgZXhwZWN0cyBhIGRlc2NyaXB0b3IgcmV0dXJuZWQgYnkgZGVmaW5lU2NvcGUoLi4uKS5zY29wZSguLi4pXCIpXG4gICAgfVxuXG4gICAgaWYgKHNjb3BlRGVzY3JpcHRvci5tb2RlbENsYXNzICE9PSB0aGlzLmdldE1vZGVsQ2xhc3MoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgYXBwbHkgJHtzY29wZURlc2NyaXB0b3IubW9kZWxDbGFzcy5uYW1lfSBzY29wZSB0byAke3RoaXMuZ2V0TW9kZWxDbGFzcygpLm5hbWV9IHF1ZXJ5YClcbiAgICB9XG5cbiAgICBjb25zdCBzY29wZWRRdWVyeSA9IC8qKlxuICAgICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7dGhpcyB8IHZvaWR9ICovIChzY29wZURlc2NyaXB0b3IuY2FsbGJhY2soe1xuICAgICAgZHJpdmVyOiB0aGlzLmRyaXZlcixcbiAgICAgIG1vZGVsQ2xhc3M6IHRoaXMuZ2V0TW9kZWxDbGFzcygpLFxuICAgICAgcXVlcnk6IHRoaXMsXG4gICAgICB0YWJsZTogdGhpcy5yb290VGFibGVSZWZlcmVuY2UoKVxuICAgIH0sIC4uLnNjb3BlRGVzY3JpcHRvci5zY29wZUFyZ3MpKVxuXG4gICAgcmV0dXJuIHNjb3BlZFF1ZXJ5IHx8IHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGFwcGx5IGpvaW4gcGF0aCBzY29wZS5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBKb2luLXBhdGggc2NvcGUgb3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gYXJncy5qb2luUGF0aCAtIEpvaW4gcGF0aCByZWxhdGl2ZSB0byB0aGUgY3VycmVudCBxdWVyeS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi8uLi91dGlscy9tb2RlbC1zY29wZS5qc1wiKS5Nb2RlbFNjb3BlRGVzY3JpcHRvcn0gYXJncy5zY29wZURlc2NyaXB0b3IgLSBTY29wZSBkZXNjcmlwdG9yLlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBTY29wZWQgcXVlcnkuXG4gICAqL1xuICBfYXBwbHlKb2luUGF0aFNjb3BlKHtqb2luUGF0aCwgc2NvcGVEZXNjcmlwdG9yfSkge1xuICAgIGlmICghaXNNb2RlbFNjb3BlRGVzY3JpcHRvcihzY29wZURlc2NyaXB0b3IpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJzY29wZSgpIGV4cGVjdHMgYSBkZXNjcmlwdG9yIHJldHVybmVkIGJ5IGRlZmluZVNjb3BlKC4uLikuc2NvcGUoLi4uKVwiKVxuICAgIH1cblxuICAgIGNvbnN0IGZ1bGxKb2luUGF0aCA9IHRoaXMuZ2V0Sm9pbkJhc2VQYXRoKCkuY29uY2F0KGpvaW5QYXRoKVxuICAgIGNvbnN0IHRhcmdldE1vZGVsQ2xhc3MgPSB0aGlzLl9yZXNvbHZlTW9kZWxDbGFzc0ZvckpvaW5QYXRoKGZ1bGxKb2luUGF0aClcblxuICAgIGlmIChzY29wZURlc2NyaXB0b3IubW9kZWxDbGFzcyAhPT0gdGFyZ2V0TW9kZWxDbGFzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgYXBwbHkgJHtzY29wZURlc2NyaXB0b3IubW9kZWxDbGFzcy5uYW1lfSBzY29wZSB0byBqb2luIHBhdGggJHtmdWxsSm9pblBhdGguam9pbihcIi5cIil9ICgke3RhcmdldE1vZGVsQ2xhc3MubmFtZX0pYClcbiAgICB9XG5cbiAgICBjb25zdCBzY29wZWRRdWVyeSA9IHRoaXMuYnVpbGRKb2luU2NvcGVRdWVyeSh0YXJnZXRNb2RlbENsYXNzLCBmdWxsSm9pblBhdGgpXG4gICAgY29uc3Qgb3JpZ2luYWxKb2luQ291bnQgPSBzY29wZWRRdWVyeS5fam9pbnMubGVuZ3RoXG4gICAgY29uc3Qgb3JpZ2luYWxXaGVyZUNvdW50ID0gc2NvcGVkUXVlcnkuX3doZXJlcy5sZW5ndGhcbiAgICBjb25zdCBhcHBsaWVkUXVlcnkgPSAvKipcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7dHlwZW9mIHNjb3BlZFF1ZXJ5IHwgdm9pZH0gKi8gKHNjb3BlRGVzY3JpcHRvci5jYWxsYmFjayh7XG4gICAgICBkcml2ZXI6IHNjb3BlZFF1ZXJ5LmRyaXZlcixcbiAgICAgIG1vZGVsQ2xhc3M6IHRhcmdldE1vZGVsQ2xhc3MsXG4gICAgICBwYXRoOiBbLi4uZnVsbEpvaW5QYXRoXSxcbiAgICAgIHF1ZXJ5OiBzY29wZWRRdWVyeSxcbiAgICAgIHRhYmxlOiBzY29wZWRRdWVyeS5nZXRUYWJsZVJlZmVyZW5jZUZvckpvaW4oKVxuICAgIH0sIC4uLnNjb3BlRGVzY3JpcHRvci5zY29wZUFyZ3MpKSB8fCBzY29wZWRRdWVyeVxuXG4gICAgaWYgKGFwcGxpZWRRdWVyeS5nZXRGcm9tcygpLmxlbmd0aCAhPT0gc2NvcGVkUXVlcnkuZ2V0RnJvbXMoKS5sZW5ndGggfHxcbiAgICAgIGFwcGxpZWRRdWVyeS5nZXRHcm91cHMoKS5sZW5ndGggIT09IHNjb3BlZFF1ZXJ5LmdldEdyb3VwcygpLmxlbmd0aCB8fFxuICAgICAgYXBwbGllZFF1ZXJ5LmdldFNlbGVjdHMoKS5sZW5ndGggIT09IHNjb3BlZFF1ZXJ5LmdldFNlbGVjdHMoKS5sZW5ndGggfHxcbiAgICAgIGFwcGxpZWRRdWVyeS5fb3JkZXJzLmxlbmd0aCAhPT0gc2NvcGVkUXVlcnkuX29yZGVycy5sZW5ndGggfHxcbiAgICAgIGFwcGxpZWRRdWVyeS5fbGltaXQgIT09IHNjb3BlZFF1ZXJ5Ll9saW1pdCB8fFxuICAgICAgYXBwbGllZFF1ZXJ5Ll9vZmZzZXQgIT09IHNjb3BlZFF1ZXJ5Ll9vZmZzZXQgfHxcbiAgICAgIGFwcGxpZWRRdWVyeS5fcGFnZSAhPT0gc2NvcGVkUXVlcnkuX3BhZ2UgfHxcbiAgICAgIGFwcGxpZWRRdWVyeS5fcGVyUGFnZSAhPT0gc2NvcGVkUXVlcnkuX3BlclBhZ2UgfHxcbiAgICAgIGFwcGxpZWRRdWVyeS5fZGlzdGluY3QgIT09IHNjb3BlZFF1ZXJ5Ll9kaXN0aW5jdCB8fFxuICAgICAgT2JqZWN0LmtleXMoYXBwbGllZFF1ZXJ5Ll9wcmVsb2FkKS5sZW5ndGggIT09IE9iamVjdC5rZXlzKHNjb3BlZFF1ZXJ5Ll9wcmVsb2FkKS5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkpvaW5lZC1wYXRoIHNjb3BlcyBtYXkgb25seSBhZGQgd2hlcmUoLi4uKSBhbmQgam9pbnMoLi4uKSBjbGF1c2VzXCIpXG4gICAgfVxuXG4gICAgaWYgKGFwcGxpZWRRdWVyeS5fam9pbnMubGVuZ3RoID4gb3JpZ2luYWxKb2luQ291bnQpIHtcbiAgICAgIGZvciAoY29uc3Qgam9pbiBvZiBhcHBsaWVkUXVlcnkuX2pvaW5zLnNsaWNlKG9yaWdpbmFsSm9pbkNvdW50KSkge1xuICAgICAgICBpZiAoam9pbiBpbnN0YW5jZW9mIEpvaW5PYmplY3QpIHtcbiAgICAgICAgICB0aGlzLl9qb2lucy5wdXNoKG5ldyBKb2luT2JqZWN0KGpvaW4ub2JqZWN0LCBmdWxsSm9pblBhdGgpKVxuICAgICAgICB9IGVsc2UgaWYgKGpvaW4gaW5zdGFuY2VvZiBKb2luUGxhaW4pIHtcbiAgICAgICAgICB0aGlzLl9qb2lucy5wdXNoKGpvaW4pXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5fam9pbnMucHVzaChqb2luKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGFwcGxpZWRRdWVyeS5fd2hlcmVzLmxlbmd0aCA+IG9yaWdpbmFsV2hlcmVDb3VudCkge1xuICAgICAgdGhpcy5fd2hlcmVzLnB1c2goLi4uYXBwbGllZFF1ZXJ5Ll93aGVyZXMuc2xpY2Uob3JpZ2luYWxXaGVyZUNvdW50KSlcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgYnVpbGQgam9pbiBzY29wZSBxdWVyeS5cbiAgICogQHBhcmFtIHt0eXBlb2YgaW1wb3J0KFwiLi4vcmVjb3JkL2luZGV4LmpzXCIpLmRlZmF1bHR9IHRhcmdldE1vZGVsQ2xhc3MgLSBUYXJnZXQgbW9kZWwgY2xhc3MuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IGpvaW5QYXRoIC0gSm9pbiBwYXRoLlxuICAgKiBAcmV0dXJucyB7VmVsb2Npb3VzRGF0YWJhc2VRdWVyeU1vZGVsQ2xhc3NRdWVyeTxNQz59IC0gVGhlIHNjb3BlZCBqb2luIHF1ZXJ5LlxuICAgKi9cbiAgYnVpbGRKb2luU2NvcGVRdWVyeSh0YXJnZXRNb2RlbENsYXNzLCBqb2luUGF0aCkge1xuICAgIGNvbnN0IHNjb3BlZFF1ZXJ5ID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHtWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5TW9kZWxDbGFzc1F1ZXJ5PE1DPn0gKi8gKHRhcmdldE1vZGVsQ2xhc3MuX25ld1F1ZXJ5KCkpXG5cbiAgICBzY29wZWRRdWVyeS5fam9pblRyYWNrZXIgPSB0aGlzLl9qb2luVHJhY2tlclxuICAgIHNjb3BlZFF1ZXJ5Ll9qb2luQmFzZVBhdGggPSBqb2luUGF0aFxuICAgIHNjb3BlZFF1ZXJ5Ll9mb3JjZVF1YWxpZnlCYXNlVGFibGUgPSB0cnVlXG5cbiAgICByZXR1cm4gc2NvcGVkUXVlcnlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGRlc3Ryb3kgYWxsLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgZGVzdHJveUFsbCgpIHtcbiAgICBjb25zdCByZWNvcmRzID0gYXdhaXQgdGhpcy50b0FycmF5KClcblxuICAgIGZvciAoY29uc3QgcmVjb3JkIG9mIHJlY29yZHMpIHtcbiAgICAgIGF3YWl0IHJlY29yZC5kZXN0cm95KClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZXMgYSBidWxrIFVQREFURSBvbiBhbGwgcm93cyBtYXRjaGluZyB0aGUgcXVlcnkncyBXSEVSRVxuICAgKiBjbGF1c2UuIEJ5cGFzc2VzIG1vZGVsIGxpZmVjeWNsZSBjYWxsYmFja3Mg4oCUIHVzZSB0aGlzIGZvclxuICAgKiBlZmZpY2llbnQgYmF0Y2ggdXBkYXRlcyB3aGVyZSBwZXItcm93IGhvb2tzIGFyZW4ndCBuZWVkZWQuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgPz59IGRhdGEgLSBjYW1lbENhc2UgYXR0cmlidXRlIG5hbWVzIOKGkiB2YWx1ZXMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gdGhlIHVwZGF0ZSBjb21wbGV0ZXMuXG4gICAqL1xuICBhc3luYyB1cGRhdGVBbGwoZGF0YSkge1xuICAgIGNvbnN0IGRyaXZlciA9IHRoaXMuZHJpdmVyXG4gICAgY29uc3QgdGFibGVOYW1lID0gdGhpcy5nZXRNb2RlbENsYXNzKCkudGFibGVOYW1lKClcbiAgICBjb25zdCBlbnRyaWVzID0gT2JqZWN0LmVudHJpZXMoZGF0YSlcblxuICAgIGlmIChlbnRyaWVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuXG5cbiAgICBjb25zdCBzZXRDb2xzID0gZW50cmllcy5tYXAoKFtrZXksIHZhbHVlXSkgPT4ge1xuICAgICAgY29uc3QgY29sdW1uTmFtZSA9IGluZmxlY3Rpb24udW5kZXJzY29yZShrZXkpXG4gICAgICBjb25zdCBxdW90ZWQgPSB2YWx1ZSA9PT0gbnVsbCA/IFwiTlVMTFwiIDogZHJpdmVyLnF1b3RlKHZhbHVlKVxuXG4gICAgICByZXR1cm4gYCR7ZHJpdmVyLnF1b3RlQ29sdW1uKGNvbHVtbk5hbWUpfSA9ICR7cXVvdGVkfWBcbiAgICB9KS5qb2luKFwiLCBcIilcblxuICAgIGNvbnN0IGpvaW5zU3FsID0gbmV3IEpvaW5zUGFyc2VyKHtwcmV0dHk6IGZhbHNlLCBxdWVyeTogdGhpc30pLnRvU3FsKClcbiAgICBjb25zdCB3aGVyZVNxbCA9IG5ldyBXaGVyZVBhcnNlcih7cHJldHR5OiBmYWxzZSwgcXVlcnk6IHRoaXN9KS50b1NxbCgpXG4gICAgbGV0IHNxbFxuXG4gICAgaWYgKGpvaW5zU3FsLmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIFVzZSBhIHN1YnF1ZXJ5IGZvciBjcm9zcy1kcml2ZXIgY29tcGF0aWJpbGl0eSAoU1FMaXRlXG4gICAgICAvLyBkb2Vzbid0IHN1cHBvcnQgVVBEQVRFIC4uLiBKT0lOKS5cbiAgICAgIGNvbnN0IHBrID0gZHJpdmVyLnF1b3RlQ29sdW1uKHRoaXMuZ2V0TW9kZWxDbGFzcygpLnByaW1hcnlLZXkoKSlcbiAgICAgIGNvbnN0IHF0ID0gZHJpdmVyLnF1b3RlVGFibGUodGFibGVOYW1lKVxuXG4gICAgICBzcWwgPSBgVVBEQVRFICR7cXR9IFNFVCAke3NldENvbHN9IFdIRVJFICR7cGt9IElOIChTRUxFQ1QgJHtxdH0uJHtwa30gRlJPTSAke3F0fSR7am9pbnNTcWx9JHt3aGVyZVNxbH0pYFxuICAgIH0gZWxzZSB7XG4gICAgICBzcWwgPSBgVVBEQVRFICR7ZHJpdmVyLnF1b3RlVGFibGUodGFibGVOYW1lKX0gU0VUICR7c2V0Q29sc30ke3doZXJlU3FsfWBcbiAgICB9XG5cbiAgICBhd2FpdCBkcml2ZXIucXVlcnkoc3FsLCB7bG9nTmFtZTogdGhpcy5xdWVyeUxvZ05hbWUoXCJVcGRhdGUgQWxsXCIpfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGZpbmQuXG4gICAqIEBwYXJhbSB7bnVtYmVyfHN0cmluZ30gcmVjb3JkSWQgLSBSZWNvcmQgaWQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTxNQz4+fSAtIFJlc29sdmVzIHdpdGggdGhlIGZpbmQuXG4gICAqL1xuICBhc3luYyBmaW5kKHJlY29yZElkKSB7XG4gICAgLyoqXG4gICAgICogQ29uZGl0aW9ucy5cbiAgICAgIEB0eXBlIHt7W2tleTogc3RyaW5nXTogbnVtYmVyIHwgc3RyaW5nfX0gKi9cbiAgICBjb25zdCBjb25kaXRpb25zID0ge31cblxuICAgIGNvbmRpdGlvbnNbdGhpcy5nZXRNb2RlbENsYXNzKCkucHJpbWFyeUtleSgpXSA9IHJlY29yZElkXG5cbiAgICBjb25zdCBuZXdRdWVyeSA9IC8qKlxuICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7VmVsb2Npb3VzRGF0YWJhc2VRdWVyeU1vZGVsQ2xhc3NRdWVyeTxNQz59ICovICh0aGlzLmNsb25lKCkpXG5cbiAgICBuZXdRdWVyeS53aGVyZShjb25kaXRpb25zKVxuXG4gICAgY29uc3QgcmVjb3JkID0gKGF3YWl0IG5ld1F1ZXJ5LmZpcnN0KCkpXG5cbiAgICBpZiAoIXJlY29yZCkge1xuICAgICAgdGhyb3cgbmV3IFJlY29yZE5vdEZvdW5kRXJyb3IoYENvdWxkbid0IGZpbmQgJHt0aGlzLmdldE1vZGVsQ2xhc3MoKS5uYW1lfSB3aXRoICcke3RoaXMuZ2V0TW9kZWxDbGFzcygpLnByaW1hcnlLZXkoKX0nPSR7cmVjb3JkSWR9YClcbiAgICB9XG5cbiAgICByZXR1cm4gcmVjb3JkXG4gIH1cblxuICAvKipcbiAgICogUnVucyBmaW5kIGJ5LlxuICAgKiBAcGFyYW0ge3tba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXJ9fSBjb25kaXRpb25zIC0gQ29uZGl0aW9ucyBoYXNoIGtleWVkIGJ5IGF0dHJpYnV0ZSBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxJbnN0YW5jZVR5cGU8TUM+IHwgbnVsbD59IC0gUmVzb2x2ZXMgd2l0aCB0aGUgYnkuXG4gICAqL1xuICBhc3luYyBmaW5kQnkoY29uZGl0aW9ucykge1xuICAgIGNvbnN0IG5ld1F1ZXJ5ID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHtWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5TW9kZWxDbGFzc1F1ZXJ5PE1DPn0gKi8gKHRoaXMuY2xvbmUoKSlcblxuICAgIG5ld1F1ZXJ5LndoZXJlKGNvbmRpdGlvbnMpXG5cbiAgICByZXR1cm4gYXdhaXQgbmV3UXVlcnkuZmlyc3QoKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZmluZCBvciBjcmVhdGUgYnkuXG4gICAqIEBwYXJhbSB7e1trZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlcn19IGNvbmRpdGlvbnMgLSBDb25kaXRpb25zIGhhc2gga2V5ZWQgYnkgYXR0cmlidXRlIG5hbWUuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb24oSW5zdGFuY2VUeXBlPE1DPikgOiB2b2lkfSBbY2FsbGJhY2tdIC0gQ2FsbGJhY2sgZnVuY3Rpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTxNQz4+fSAtIFJlc29sdmVzIHdpdGggdGhlIG9yIGNyZWF0ZSBieS5cbiAgICovXG4gIGFzeW5jIGZpbmRPckNyZWF0ZUJ5KGNvbmRpdGlvbnMsIGNhbGxiYWNrKSB7XG4gICAgY29uc3QgcmVjb3JkID0gYXdhaXQgdGhpcy5maW5kT3JJbml0aWFsaXplQnkoY29uZGl0aW9ucywgY2FsbGJhY2spXG5cbiAgICBpZiAocmVjb3JkLmlzTmV3UmVjb3JkKCkpIHtcbiAgICAgIGF3YWl0IHJlY29yZC5zYXZlKClcbiAgICB9XG5cbiAgICByZXR1cm4gcmVjb3JkXG4gIH1cblxuICAvKipcbiAgICogUnVucyBmaW5kIGJ5IG9yIGZhaWwuXG4gICAqIEBwYXJhbSB7e1trZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlcn19IGNvbmRpdGlvbnMgLSBDb25kaXRpb25zIGhhc2gga2V5ZWQgYnkgYXR0cmlidXRlIG5hbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTxNQz4+fSAtIFJlc29sdmVzIHdpdGggdGhlIGJ5IG9yIGZhaWwuXG4gICAqL1xuICBhc3luYyBmaW5kQnlPckZhaWwoY29uZGl0aW9ucykge1xuICAgIGNvbnN0IHJlY29yZCA9IGF3YWl0IHRoaXMuZmluZEJ5KGNvbmRpdGlvbnMpXG5cbiAgICBpZiAoIXJlY29yZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVjb3JkIG5vdCBmb3VuZFwiKVxuICAgIH1cblxuICAgIHJldHVybiByZWNvcmRcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGZpbmQgb3IgaW5pdGlhbGl6ZSBieS5cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gY29uZGl0aW9ucyAtIENvbmRpdGlvbnMuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb24oSW5zdGFuY2VUeXBlPE1DPikgOiB2b2lkfSBbY2FsbGJhY2tdIC0gQ2FsbGJhY2sgZnVuY3Rpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTxNQz4+fSAtIFJlc29sdmVzIHdpdGggdGhlIG9yIGluaXRpYWxpemUgYnkuXG4gICAqL1xuICBhc3luYyBmaW5kT3JJbml0aWFsaXplQnkoY29uZGl0aW9ucywgY2FsbGJhY2spIHtcbiAgICBjb25zdCByZWNvcmQgPSBhd2FpdCB0aGlzLmZpbmRCeShjb25kaXRpb25zKVxuXG4gICAgaWYgKHJlY29yZCkgcmV0dXJuIHJlY29yZFxuXG4gICAgY29uc3QgTW9kZWxDbGFzcyA9IHRoaXMuZ2V0TW9kZWxDbGFzcygpXG4gICAgY29uc3QgbmV3UmVjb3JkID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgQHR5cGUge0luc3RhbmNlVHlwZTxNQz59ICovIChuZXcgTW9kZWxDbGFzcyhjb25kaXRpb25zKSlcblxuICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgY2FsbGJhY2sobmV3UmVjb3JkKVxuICAgIH1cblxuICAgIHJldHVybiBuZXdSZWNvcmRcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGZpcnN0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxJbnN0YW5jZVR5cGU8TUM+IHwgbnVsbD59IC0gUmVzb2x2ZXMgd2l0aCB0aGUgZmlyc3QuXG4gICAqL1xuICBhc3luYyBmaXJzdCgpIHtcbiAgICBjb25zdCBuZXdRdWVyeSA9IHRoaXMuY2xvbmUoKS5saW1pdCgxKS5yZW9yZGVyKGAke3RoaXMuZHJpdmVyLnF1b3RlVGFibGUodGhpcy5nZXRNb2RlbENsYXNzKCkudGFibGVOYW1lKCkpfS4ke3RoaXMuZHJpdmVyLnF1b3RlQ29sdW1uKHRoaXMuZ2V0TW9kZWxDbGFzcygpLm9yZGVyYWJsZUNvbHVtbigpKX1gKVxuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBuZXdRdWVyeS50b0FycmF5KClcblxuICAgIHJldHVybiByZXN1bHRzWzBdIHx8IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGxhc3QuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTxNQz4gfCBudWxsPn0gLSBSZXNvbHZlcyB3aXRoIHRoZSBsYXN0LlxuICAgKi9cbiAgYXN5bmMgbGFzdCgpIHtcbiAgICBjb25zdCBwcmltYXJ5S2V5ID0gdGhpcy5nZXRNb2RlbENsYXNzKCkucHJpbWFyeUtleSgpXG4gICAgY29uc3QgdGFibGVOYW1lID0gdGhpcy5nZXRNb2RlbENsYXNzKCkudGFibGVOYW1lKClcbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgdGhpcy5jbG9uZSgpLnJlb3JkZXIoYCR7dGhpcy5kcml2ZXIucXVvdGVUYWJsZSh0YWJsZU5hbWUpfS4ke3RoaXMuZHJpdmVyLnF1b3RlQ29sdW1uKHByaW1hcnlLZXkpfSBERVNDYCkubGltaXQoMSkudG9BcnJheSgpXG5cbiAgICByZXR1cm4gcmVzdWx0c1swXSB8fCBudWxsXG4gIH1cblxuICAvKipcbiAgICogUnVucyBwcmVsb2FkLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vaW5kZXguanNcIikuTmVzdGVkUHJlbG9hZFJlY29yZCB8IHN0cmluZyB8IEFycmF5PHN0cmluZyB8IGltcG9ydChcIi4vaW5kZXguanNcIikuTmVzdGVkUHJlbG9hZFJlY29yZD59IGRhdGEgLSBEYXRhIHBheWxvYWQuXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFRoZSBwcmVsb2FkLlxuICAgKi9cbiAgcHJlbG9hZChkYXRhKSB7XG4gICAgY29uc3Qgbm9ybWFsaXplZFByZWxvYWQgPSBub3JtYWxpemVQcmVsb2FkUmVjb3JkKGRhdGEpXG4gICAgaW5jb3Jwb3JhdGUodGhpcy5fcHJlbG9hZCwgbm9ybWFsaXplZFByZWxvYWQpXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkcyBxdWVyeSByZXN1bHRzIGludG8gbW9kZWwgaW5zdGFuY2VzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxJbnN0YW5jZVR5cGU8TUM+Pj59IC0gUmVzb2x2ZXMgd2l0aCB0aGUgYXJyYXkuXG4gICAqL1xuICBhc3luYyBsb2FkKCkge1xuICAgIGNvbnN0IG1vZGVscyA9IFtdXG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRoaXMucmVzdWx0cygpXG5cbiAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7XG4gICAgICBjb25zdCBNb2RlbENsYXNzID0gdGhpcy5nZXRNb2RlbENsYXNzKClcbiAgICAgIGNvbnN0IG1vZGVsID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7SW5zdGFuY2VUeXBlPE1DPn0gKi8gKG5ldyBNb2RlbENsYXNzKCkpXG5cbiAgICAgIG1vZGVsLmxvYWRFeGlzdGluZ1JlY29yZChyZXN1bHQpXG4gICAgICBtb2RlbHMucHVzaChtb2RlbClcbiAgICB9XG5cbiAgICAvLyBTaGFyZSBhIHNpbmdsZSBjb2hvcnQgcmVmZXJlbmNlIGFjcm9zcyBldmVyeSBzaWJsaW5nIHJlY29yZCBzbyB0aGF0XG4gICAgLy8gYXV0by1wcmVsb2FkIGNhbiBiYXRjaCBsYXp5IHJlbGF0aW9uc2hpcCBhY2Nlc3MgbGF0ZXIuXG4gICAgZm9yIChjb25zdCBtb2RlbCBvZiBtb2RlbHMpIHtcbiAgICAgIG1vZGVsLl9sb2FkQ29ob3J0ID0gbW9kZWxzXG4gICAgfVxuXG4gICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuX3ByZWxvYWQpLmxlbmd0aCA+IDAgJiYgbW9kZWxzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IHByZWxvYWRlciA9IG5ldyBQcmVsb2FkZXIoe1xuICAgICAgICBtb2RlbENsYXNzOiB0aGlzLm1vZGVsQ2xhc3MsXG4gICAgICAgIG1vZGVscyxcbiAgICAgICAgcHJlbG9hZDogdGhpcy5fcHJlbG9hZCxcbiAgICAgICAgcHJlbG9hZFNlbGVjdHM6IHRoaXMuX3ByZWxvYWRTZWxlY3RzLFxuICAgICAgICBwcmVsb2FkU2VsZWN0c0V4dHJhOiB0aGlzLl9wcmVsb2FkU2VsZWN0c0V4dHJhXG4gICAgICB9KVxuXG4gICAgICBhd2FpdCBwcmVsb2FkZXIucnVuKClcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fd2l0aENvdW50Lmxlbmd0aCA+IDAgJiYgbW9kZWxzLmxlbmd0aCA+IDApIHtcbiAgICAgIGF3YWl0IHJ1bldpdGhDb3VudCh7XG4gICAgICAgIGVudHJpZXM6IHRoaXMuX3dpdGhDb3VudCxcbiAgICAgICAgbW9kZWxDbGFzczogdGhpcy5tb2RlbENsYXNzLFxuICAgICAgICBtb2RlbHNcbiAgICAgIH0pXG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX3F1ZXJ5RGF0YS5sZW5ndGggPiAwICYmIG1vZGVscy5sZW5ndGggPiAwKSB7XG4gICAgICBhd2FpdCBydW5RdWVyeURhdGEoe1xuICAgICAgICBlbnRyaWVzOiB0aGlzLl9xdWVyeURhdGEsXG4gICAgICAgIHJvb3RNb2RlbENsYXNzOiB0aGlzLm1vZGVsQ2xhc3MsXG4gICAgICAgIHJvb3RNb2RlbHM6IG1vZGVsc1xuICAgICAgfSlcbiAgICB9XG5cbiAgICByZXR1cm4gbW9kZWxzXG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgcXVlcnkgcmVzdWx0cyB0byBhcnJheSBvZiBtb2RlbCBpbnN0YW5jZXNcbiAgICogQHJldHVybnMge1Byb21pc2U8QXJyYXk8SW5zdGFuY2VUeXBlPE1DPj4+fSAtIFJlc29sdmVzIHdpdGggdGhlIGFycmF5LlxuICAgKi9cbiAgYXN5bmMgdG9BcnJheSgpIHtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5sb2FkKClcbiAgfVxuXG4gIC8qKlxuICAgKiBQbHVja3Mgb25lIG9yIG1vcmUgY29sdW1ucyBkaXJlY3RseSBmcm9tIHRoZSBkYXRhYmFzZSB3aXRob3V0IGluc3RhbnRpYXRpbmcgbW9kZWxzLlxuICAgKiBAcGFyYW0gey4uLnN0cmluZ3xzdHJpbmdbXX0gY29sdW1ucyAtIENvbHVtbiBuYW1lcy5cbiAgICogQHJldHVybnMge1Byb21pc2U8QXJyYXk8Pz4+fSAtIFJlc29sdmVzIHdpdGggdGhlIHBsdWNrLlxuICAgKi9cbiAgYXN5bmMgcGx1Y2soLi4uY29sdW1ucykge1xuICAgIGNvbnN0IGZsYXRDb2x1bW5zID0gY29sdW1ucy5mbGF0KClcblxuICAgIGlmIChmbGF0Q29sdW1ucy5sZW5ndGggPT09IDApIHRocm93IG5ldyBFcnJvcihcIk5vIGNvbHVtbnMgZ2l2ZW4gdG8gcGx1Y2tcIilcblxuICAgIGNvbnN0IG1vZGVsQ2xhc3MgPSB0aGlzLmdldE1vZGVsQ2xhc3MoKVxuICAgIGNvbnN0IHRhYmxlTmFtZSA9IG1vZGVsQ2xhc3MudGFibGVOYW1lKClcbiAgICBjb25zdCBhdHRyaWJ1dGVNYXAgPSBtb2RlbENsYXNzLmdldEF0dHJpYnV0ZU5hbWVUb0NvbHVtbk5hbWVNYXAoKVxuICAgIGNvbnN0IGNvbHVtbk5hbWVzID0gZmxhdENvbHVtbnMubWFwKChjb2x1bW4pID0+IGF0dHJpYnV0ZU1hcFtjb2x1bW5dIHx8IGNvbHVtbilcblxuICAgIGNvbnN0IHF1ZXJ5ID0gLyoqXG4gICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgIEB0eXBlIHtWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5TW9kZWxDbGFzc1F1ZXJ5PE1DPn0gKi8gKHRoaXMuY2xvbmUoKSlcblxuICAgIHF1ZXJ5Ll9wcmVsb2FkID0ge31cbiAgICBxdWVyeS5fc2VsZWN0cyA9IFtdXG5cbiAgICBjb2x1bW5OYW1lcy5mb3JFYWNoKChjb2x1bW5OYW1lKSA9PiB7XG4gICAgICBjb25zdCBzZWxlY3RTcWwgPSBgJHt0aGlzLmRyaXZlci5xdW90ZVRhYmxlKHRhYmxlTmFtZSl9LiR7dGhpcy5kcml2ZXIucXVvdGVDb2x1bW4oY29sdW1uTmFtZSl9YFxuXG4gICAgICBxdWVyeS5zZWxlY3Qoc2VsZWN0U3FsKVxuICAgIH0pXG5cbiAgICBjb25zdCByb3dzID0gYXdhaXQgcXVlcnkuX2V4ZWN1dGVRdWVyeSh7bG9nTmFtZTogcXVlcnkucXVlcnlMb2dOYW1lKFwiUGx1Y2tcIil9KVxuXG4gICAgaWYgKGNvbHVtbk5hbWVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgY29uc3QgW2NvbHVtbk5hbWVdID0gY29sdW1uTmFtZXNcbiAgICAgIHJldHVybiByb3dzLm1hcCgocm93KSA9PiAvKipcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7UmVjb3JkPHN0cmluZywgPz59ICovIChyb3cpW2NvbHVtbk5hbWVdKVxuICAgIH1cblxuICAgIHJldHVybiByb3dzLm1hcCgocm93KSA9PiB7XG4gICAgICBjb25zdCByb3dIYXNoID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgQHR5cGUge1JlY29yZDxzdHJpbmcsID8+fSAqLyAocm93KVxuXG4gICAgICByZXR1cm4gY29sdW1uTmFtZXMubWFwKChjb2x1bW5OYW1lKSA9PiByb3dIYXNoW2NvbHVtbk5hbWVdKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyB3aGVyZS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL2luZGV4LmpzXCIpLldoZXJlQXJndW1lbnRUeXBlfSB3aGVyZSAtIFdoZXJlLlxuICAgKiBAcmV0dXJucyB7dGhpc30gVGhpcyBxdWVyeSBpbnN0YW5jZVxuICAgKi9cbiAgd2hlcmUod2hlcmUpIHtcbiAgICBpZiAodHlwZW9mIHdoZXJlID09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiBzdXBlci53aGVyZSh3aGVyZSlcbiAgICB9XG5cbiAgICBpZiAoaXNQbGFpbk9iamVjdCh3aGVyZSkpIHtcbiAgICAgIGNvbnN0IHtyZXNvbHZlZEhhc2gsIGZhbGxiYWNrSGFzaH0gPSBzcGxpdFdoZXJlSGFzaCh7aGFzaDogd2hlcmUsIG1vZGVsQ2xhc3M6IHRoaXMuZ2V0TW9kZWxDbGFzcygpfSlcbiAgICAgIGNvbnN0IGpvaW5PYmplY3QgPSBidWlsZEpvaW5PYmplY3RGcm9tV2hlcmVIYXNoKHtoYXNoOiB3aGVyZSwgbW9kZWxDbGFzczogdGhpcy5nZXRNb2RlbENsYXNzKCl9KVxuXG4gICAgICBpZiAoT2JqZWN0LmtleXMoam9pbk9iamVjdCkubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLmpvaW5zKGpvaW5PYmplY3QpXG4gICAgICB9XG5cbiAgICAgIGlmIChPYmplY3Qua2V5cyhyZXNvbHZlZEhhc2gpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgcXVhbGlmeUJhc2VUYWJsZSA9IHRoaXMuZ2V0Rm9yY2VRdWFsaWZ5QmFzZVRhYmxlKCkgfHwgT2JqZWN0LmtleXMoam9pbk9iamVjdCkubGVuZ3RoID4gMFxuICAgICAgICB0aGlzLl93aGVyZXMucHVzaChuZXcgV2hlcmVNb2RlbENsYXNzSGFzaCh7XG4gICAgICAgICAgaGFzaDogcmVzb2x2ZWRIYXNoLFxuICAgICAgICAgIG1vZGVsQ2xhc3M6IHRoaXMuZ2V0TW9kZWxDbGFzcygpLFxuICAgICAgICAgIHF1YWxpZnlCYXNlVGFibGUsXG4gICAgICAgICAgcXVlcnk6IHRoaXNcbiAgICAgICAgfSkpXG4gICAgICB9XG5cbiAgICAgIGlmIChPYmplY3Qua2V5cyhmYWxsYmFja0hhc2gpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgc3VwZXIud2hlcmUoZmFsbGJhY2tIYXNoKVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpc1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB0eXBlIG9mIHdoZXJlOiAke3R5cGVvZiB3aGVyZX0gKCR7d2hlcmUuY29uc3RydWN0b3IubmFtZX0pYClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJhbnNhY2suXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgPz59IHBhcmFtcyAtIFJhbnNhY2stc3R5bGUgcGFyYW1zIGhhc2guIFN1cHBvcnRzIGBzYCBrZXkgZm9yIHNvcnRpbmcgKGUuZy4sIGB7czogXCJuYW1lIGFzY1wifWApLlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBRdWVyeSB3aXRoIFJhbnNhY2sgZmlsdGVycyBhbmQgc29ydCBhcHBsaWVkLlxuICAgKi9cbiAgcmFuc2FjayhwYXJhbXMpIHtcbiAgICBjb25zdCB7cywgLi4uZmlsdGVyUGFyYW1zfSA9IHBhcmFtc1xuICAgIGNvbnN0IGdyb3VwID0gbm9ybWFsaXplUmFuc2Fja0dyb3VwKHRoaXMuZ2V0TW9kZWxDbGFzcygpLCBmaWx0ZXJQYXJhbXMpXG5cbiAgICBhcHBseVJhbnNhY2tHcm91cCh7Z3JvdXAsIHF1ZXJ5OiB0aGlzfSlcblxuICAgIGlmICh0eXBlb2YgcyA9PT0gXCJzdHJpbmdcIiAmJiBzLnRyaW0oKS5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBzb3J0cyA9IHBhcnNlUmFuc2Fja1NvcnQodGhpcy5nZXRNb2RlbENsYXNzKCksIHMpXG5cbiAgICAgIGZvciAoY29uc3Qgc29ydERlZiBvZiBzb3J0cykge1xuICAgICAgICB0aGlzLm9yZGVyKHtjb2x1bW46IHNvcnREZWYuYXR0cmlidXRlLCBkaXJlY3Rpb246IHNvcnREZWYuZGlyZWN0aW9ufSlcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgd2hlcmUgbm90LlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vaW5kZXguanNcIikuV2hlcmVBcmd1bWVudFR5cGV9IHdoZXJlIC0gV2hlcmUuXG4gICAqIEByZXR1cm5zIHt0aGlzfSBUaGlzIHF1ZXJ5IGluc3RhbmNlXG4gICAqL1xuICB3aGVyZU5vdCh3aGVyZSkge1xuICAgIGlmICh0eXBlb2Ygd2hlcmUgPT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHN1cGVyLndoZXJlTm90KHdoZXJlKVxuICAgIH1cblxuICAgIGlmIChpc1BsYWluT2JqZWN0KHdoZXJlKSkge1xuICAgICAgY29uc3Qge3Jlc29sdmVkSGFzaCwgZmFsbGJhY2tIYXNofSA9IHNwbGl0V2hlcmVIYXNoKHtoYXNoOiB3aGVyZSwgbW9kZWxDbGFzczogdGhpcy5nZXRNb2RlbENsYXNzKCl9KVxuICAgICAgY29uc3Qgam9pbk9iamVjdCA9IGJ1aWxkSm9pbk9iamVjdEZyb21XaGVyZUhhc2goe2hhc2g6IHdoZXJlLCBtb2RlbENsYXNzOiB0aGlzLmdldE1vZGVsQ2xhc3MoKX0pXG5cbiAgICAgIGlmIChPYmplY3Qua2V5cyhqb2luT2JqZWN0KS5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuam9pbnMoam9pbk9iamVjdClcbiAgICAgIH1cblxuICAgICAgaWYgKE9iamVjdC5rZXlzKHJlc29sdmVkSGFzaCkubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBxdWFsaWZ5QmFzZVRhYmxlID0gdGhpcy5nZXRGb3JjZVF1YWxpZnlCYXNlVGFibGUoKSB8fCBPYmplY3Qua2V5cyhqb2luT2JqZWN0KS5sZW5ndGggPiAwXG4gICAgICAgIHRoaXMuX3doZXJlcy5wdXNoKG5ldyBXaGVyZU5vdChuZXcgV2hlcmVNb2RlbENsYXNzSGFzaCh7XG4gICAgICAgICAgaGFzaDogcmVzb2x2ZWRIYXNoLFxuICAgICAgICAgIG1vZGVsQ2xhc3M6IHRoaXMuZ2V0TW9kZWxDbGFzcygpLFxuICAgICAgICAgIHF1YWxpZnlCYXNlVGFibGUsXG4gICAgICAgICAgcXVlcnk6IHRoaXNcbiAgICAgICAgfSkpKVxuICAgICAgfVxuXG4gICAgICBpZiAoT2JqZWN0LmtleXMoZmFsbGJhY2tIYXNoKS5sZW5ndGggPiAwKSB7XG4gICAgICAgIHN1cGVyLndoZXJlTm90KGZhbGxiYWNrSGFzaClcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXNcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdHlwZSBvZiB3aGVyZTogJHt0eXBlb2Ygd2hlcmV9ICgke3doZXJlLmNvbnN0cnVjdG9yLm5hbWV9KWApXG4gIH1cblxuICAvKipcbiAgICogUnVucyBxdWVyeSBsb2cgbmFtZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG9wZXJhdGlvbiAtIFF1ZXJ5IG9wZXJhdGlvbi5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBRdWVyeSBsb2cgbmFtZS5cbiAgICovXG4gIHF1ZXJ5TG9nTmFtZShvcGVyYXRpb24pIHtcbiAgICByZXR1cm4gYCR7dGhpcy5nZXRNb2RlbENsYXNzKCkubmFtZX0gJHtvcGVyYXRpb259YFxuICB9XG59XG5cbi8qKlxuICogUnVucyBhcHBseSByYW5zYWNrIGdyb3VwLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi8uLi91dGlscy9yYW5zYWNrLmpzXCIpLlJhbnNhY2tHcm91cH0gYXJncy5ncm91cCAtIE5vcm1hbGl6ZWQgUmFuc2FjayBncm91cC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi9tb2RlbC1jbGFzcy1xdWVyeS5qc1wiKS5kZWZhdWx0PD8+fSBhcmdzLnF1ZXJ5IC0gUXVlcnkgaW5zdGFuY2UuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gYXBwbHlSYW5zYWNrR3JvdXAoe2dyb3VwLCBxdWVyeX0pIHtcbiAgY29uc3Qgd2hlcmUgPSBidWlsZFJhbnNhY2tHcm91cFdoZXJlKHtncm91cCwgcXVlcnl9KVxuXG4gIGlmICh3aGVyZSkge1xuICAgIHF1ZXJ5Ll93aGVyZXMucHVzaCh3aGVyZSlcbiAgfVxufVxuXG4vKipcbiAqIFJ1bnMgYnVpbGQgcmFuc2FjayBncm91cCB3aGVyZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vLi4vdXRpbHMvcmFuc2Fjay5qc1wiKS5SYW5zYWNrR3JvdXB9IGFyZ3MuZ3JvdXAgLSBOb3JtYWxpemVkIFJhbnNhY2sgZ3JvdXAuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4vbW9kZWwtY2xhc3MtcXVlcnkuanNcIikuZGVmYXVsdDw/Pn0gYXJncy5xdWVyeSAtIFF1ZXJ5IGluc3RhbmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4vd2hlcmUtYmFzZS5qc1wiKS5kZWZhdWx0IHwgbnVsbH0gLSBDb21iaW5lZCB3aGVyZSBjbGF1c2UuXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkUmFuc2Fja0dyb3VwV2hlcmUoe2dyb3VwLCBxdWVyeX0pIHtcbiAgLyoqXG4gICAqIFdoZXJlcy5cbiAgICBAdHlwZSB7aW1wb3J0KFwiLi93aGVyZS1iYXNlLmpzXCIpLmRlZmF1bHRbXX0gKi9cbiAgY29uc3Qgd2hlcmVzID0gW11cblxuICBmb3IgKGNvbnN0IGNvbmRpdGlvbiBvZiBncm91cC5jb25kaXRpb25zKSB7XG4gICAgY29uc3Qgd2hlcmUgPSBidWlsZFJhbnNhY2tDb25kaXRpb25XaGVyZSh7Y29uZGl0aW9uLCBxdWVyeX0pXG5cbiAgICBpZiAod2hlcmUpIHdoZXJlcy5wdXNoKHdoZXJlKVxuICB9XG5cbiAgZm9yIChjb25zdCBncm91cGluZyBvZiBncm91cC5ncm91cGluZ3MpIHtcbiAgICBjb25zdCB3aGVyZSA9IGJ1aWxkUmFuc2Fja0dyb3VwV2hlcmUoe2dyb3VwOiBncm91cGluZywgcXVlcnl9KVxuXG4gICAgaWYgKHdoZXJlKSB3aGVyZXMucHVzaCh3aGVyZSlcbiAgfVxuXG4gIGlmICh3aGVyZXMubGVuZ3RoIDwgMSkgcmV0dXJuIG51bGxcbiAgaWYgKHdoZXJlcy5sZW5ndGggPT09IDEpIHJldHVybiB3aGVyZXNbMF1cblxuICByZXR1cm4gbmV3IFdoZXJlQ29tYmluYXRvcih7XG4gICAgY29tYmluYXRvcjogZ3JvdXAuY29tYmluYXRvcixcbiAgICBxdWVyeSxcbiAgICB3aGVyZXNcbiAgfSlcbn1cblxuLyoqXG4gKiBSdW5zIGJ1aWxkIHJhbnNhY2sgY29uZGl0aW9uIHdoZXJlLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi8uLi91dGlscy9yYW5zYWNrLmpzXCIpLlJhbnNhY2tDb25kaXRpb259IGFyZ3MuY29uZGl0aW9uIC0gTm9ybWFsaXplZCBSYW5zYWNrIGNvbmRpdGlvbi5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi9tb2RlbC1jbGFzcy1xdWVyeS5qc1wiKS5kZWZhdWx0PD8+fSBhcmdzLnF1ZXJ5IC0gUXVlcnkgaW5zdGFuY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi93aGVyZS1iYXNlLmpzXCIpLmRlZmF1bHQgfCBudWxsfSAtIENvbmRpdGlvbiB3aGVyZSBjbGF1c2UuXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkUmFuc2Fja0NvbmRpdGlvbldoZXJlKHtjb25kaXRpb24sIHF1ZXJ5fSkge1xuICAvKipcbiAgICogV2hlcmVzLlxuICAgIEB0eXBlIHtpbXBvcnQoXCIuL3doZXJlLWJhc2UuanNcIikuZGVmYXVsdFtdfSAqL1xuICBjb25zdCB3aGVyZXMgPSBbXVxuXG4gIGZvciAoY29uc3QgYXR0cmlidXRlIG9mIGNvbmRpdGlvbi5hdHRyaWJ1dGVzKSB7XG4gICAgd2hlcmVzLnB1c2goYnVpbGRSYW5zYWNrQXR0cmlidXRlV2hlcmUoe2F0dHJpYnV0ZSwgY29uZGl0aW9uLCBxdWVyeX0pKVxuICB9XG5cbiAgaWYgKHdoZXJlcy5sZW5ndGggPCAxKSByZXR1cm4gbnVsbFxuICBpZiAod2hlcmVzLmxlbmd0aCA9PT0gMSkgcmV0dXJuIHdoZXJlc1swXVxuXG4gIHJldHVybiBuZXcgV2hlcmVDb21iaW5hdG9yKHtcbiAgICBjb21iaW5hdG9yOiBjb25kaXRpb24uY29tYmluYXRvcixcbiAgICBxdWVyeSxcbiAgICB3aGVyZXNcbiAgfSlcbn1cblxuLyoqXG4gKiBSdW5zIGJ1aWxkIHJhbnNhY2sgYXR0cmlidXRlIHdoZXJlLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi8uLi91dGlscy9yYW5zYWNrLmpzXCIpLlJhbnNhY2tBdHRyaWJ1dGV9IGFyZ3MuYXR0cmlidXRlIC0gTm9ybWFsaXplZCBSYW5zYWNrIGF0dHJpYnV0ZS5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vLi4vdXRpbHMvcmFuc2Fjay5qc1wiKS5SYW5zYWNrQ29uZGl0aW9ufSBhcmdzLmNvbmRpdGlvbiAtIE5vcm1hbGl6ZWQgUmFuc2FjayBjb25kaXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4vbW9kZWwtY2xhc3MtcXVlcnkuanNcIikuZGVmYXVsdDw/Pn0gYXJncy5xdWVyeSAtIFF1ZXJ5IGluc3RhbmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4vd2hlcmUtYmFzZS5qc1wiKS5kZWZhdWx0fSAtIEF0dHJpYnV0ZSB3aGVyZSBjbGF1c2UuXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkUmFuc2Fja0F0dHJpYnV0ZVdoZXJlKHthdHRyaWJ1dGUsIGNvbmRpdGlvbiwgcXVlcnl9KSB7XG4gIGNvbnN0IGhhc2ggPSBidWlsZFJhbnNhY2tBdHRyaWJ1dGVIYXNoKHthdHRyaWJ1dGUsIGNvbmRpdGlvbn0pXG4gIGNvbnN0IGpvaW5PYmplY3QgPSBidWlsZEpvaW5PYmplY3RGcm9tV2hlcmVIYXNoKHtoYXNoLCBtb2RlbENsYXNzOiBxdWVyeS5nZXRNb2RlbENsYXNzKCl9KVxuXG4gIGlmIChPYmplY3Qua2V5cyhqb2luT2JqZWN0KS5sZW5ndGggPiAwKSB7XG4gICAgcXVlcnkuam9pbnMoam9pbk9iamVjdClcbiAgfVxuXG4gIGNvbnN0IHdoZXJlID0gbmV3IFdoZXJlTW9kZWxDbGFzc0hhc2goe1xuICAgIGhhc2gsXG4gICAgbW9kZWxDbGFzczogcXVlcnkuZ2V0TW9kZWxDbGFzcygpLFxuICAgIHF1YWxpZnlCYXNlVGFibGU6IHRydWUsXG4gICAgcXVlcnlcbiAgfSlcblxuICBpZiAoY29uZGl0aW9uLnByZWRpY2F0ZSA9PT0gXCJub3RfZXFcIiB8fCBjb25kaXRpb24ucHJlZGljYXRlID09PSBcIm5vdF9pblwiKSB7XG4gICAgcmV0dXJuIG5ldyBXaGVyZU5vdCh3aGVyZSlcbiAgfVxuXG4gIGlmIChjb25kaXRpb24ucHJlZGljYXRlID09PSBcIm51bGxcIiAmJiAhY29uZGl0aW9uLnZhbHVlKSB7XG4gICAgcmV0dXJuIG5ldyBXaGVyZU5vdCh3aGVyZSlcbiAgfVxuXG4gIHJldHVybiB3aGVyZVxufVxuXG4vKipcbiAqIFJ1bnMgYnVpbGQgcmFuc2FjayBhdHRyaWJ1dGUgaGFzaC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vLi4vdXRpbHMvcmFuc2Fjay5qc1wiKS5SYW5zYWNrQXR0cmlidXRlfSBhcmdzLmF0dHJpYnV0ZSAtIE5vcm1hbGl6ZWQgUmFuc2FjayBhdHRyaWJ1dGUuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uLy4uL3V0aWxzL3JhbnNhY2suanNcIikuUmFuc2Fja0NvbmRpdGlvbn0gYXJncy5jb25kaXRpb24gLSBOb3JtYWxpemVkIFJhbnNhY2sgY29uZGl0aW9uLlxuICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsID8+fSAtIE5lc3RlZCBoYXNoIHN1aXRhYmxlIGZvciBxdWVyeSB3aGVyZSBub2Rlcy5cbiAqL1xuZnVuY3Rpb24gYnVpbGRSYW5zYWNrQXR0cmlidXRlSGFzaCh7YXR0cmlidXRlLCBjb25kaXRpb259KSB7XG4gIGlmIChjb25kaXRpb24ucHJlZGljYXRlID09PSBcImVxXCIgfHwgY29uZGl0aW9uLnByZWRpY2F0ZSA9PT0gXCJpblwiIHx8IGNvbmRpdGlvbi5wcmVkaWNhdGUgPT09IFwibm90X2VxXCIgfHwgY29uZGl0aW9uLnByZWRpY2F0ZSA9PT0gXCJub3RfaW5cIikge1xuICAgIHJldHVybiBidWlsZE5lc3RlZFJhbnNhY2tIYXNoKHthdHRyaWJ1dGUsIHZhbHVlOiBjb25kaXRpb24udmFsdWV9KVxuICB9XG5cbiAgaWYgKGNvbmRpdGlvbi5wcmVkaWNhdGUgPT09IFwibnVsbFwiKSB7XG4gICAgcmV0dXJuIGJ1aWxkTmVzdGVkUmFuc2Fja0hhc2goe2F0dHJpYnV0ZSwgdmFsdWU6IG51bGx9KVxuICB9XG5cbiAgcmV0dXJuIGJ1aWxkTmVzdGVkUmFuc2Fja1R1cGxlSGFzaCh7XG4gICAgYXR0cmlidXRlLFxuICAgIG9wZXJhdG9yOiByYW5zYWNrVHVwbGVPcGVyYXRvcihjb25kaXRpb24ucHJlZGljYXRlKSxcbiAgICB2YWx1ZTogcmFuc2Fja1R1cGxlVmFsdWUoY29uZGl0aW9uKVxuICB9KVxufVxuXG4vKipcbiAqIFJ1bnMgYnVpbGQgbmVzdGVkIHJhbnNhY2sgaGFzaC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vLi4vdXRpbHMvcmFuc2Fjay5qc1wiKS5SYW5zYWNrQXR0cmlidXRlfSBhcmdzLmF0dHJpYnV0ZSAtIE5vcm1hbGl6ZWQgUmFuc2FjayBhdHRyaWJ1dGUuXG4gKiBAcGFyYW0gez99IGFyZ3MudmFsdWUgLSBGaW5hbCB2YWx1ZS5cbiAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBOZXN0ZWQgaGFzaCBzdWl0YWJsZSBmb3IgcXVlcnkgd2hlcmUgbm9kZXMuXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkTmVzdGVkUmFuc2Fja0hhc2goe2F0dHJpYnV0ZSwgdmFsdWV9KSB7XG4gIC8qKlxuICAgKiBIYXNoLlxuICAgIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi9cbiAgbGV0IGhhc2ggPSB7W2F0dHJpYnV0ZS5hdHRyaWJ1dGVOYW1lXTogdmFsdWV9XG5cbiAgZm9yIChsZXQgaW5kZXggPSBhdHRyaWJ1dGUucGF0aC5sZW5ndGggLSAxOyBpbmRleCA+PSAwOyBpbmRleCAtPSAxKSB7XG4gICAgaGFzaCA9IHtbYXR0cmlidXRlLnBhdGhbaW5kZXhdXTogaGFzaH1cbiAgfVxuXG4gIHJldHVybiBoYXNoXG59XG5cbi8qKlxuICogUnVucyBidWlsZCBuZXN0ZWQgcmFuc2FjayB0dXBsZSBoYXNoLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi8uLi91dGlscy9yYW5zYWNrLmpzXCIpLlJhbnNhY2tBdHRyaWJ1dGV9IGFyZ3MuYXR0cmlidXRlIC0gTm9ybWFsaXplZCBSYW5zYWNrIGF0dHJpYnV0ZS5cbiAqIEBwYXJhbSB7XCJndFwiIHwgXCJndGVxXCIgfCBcImx0XCIgfCBcImx0ZXFcIiB8IFwibGlrZVwifSBhcmdzLm9wZXJhdG9yIC0gVHVwbGUgb3BlcmF0b3IuXG4gKiBAcGFyYW0gez99IGFyZ3MudmFsdWUgLSBGaW5hbCB2YWx1ZS5cbiAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBOZXN0ZWQgdHVwbGUgaGFzaCBzdWl0YWJsZSBmb3IgcXVlcnkud2hlcmUuXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkTmVzdGVkUmFuc2Fja1R1cGxlSGFzaCh7YXR0cmlidXRlLCBvcGVyYXRvciwgdmFsdWV9KSB7XG4gIC8qKlxuICAgKiBIYXNoLlxuICAgIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi9cbiAgbGV0IGhhc2ggPSB7XG4gICAgW2F0dHJpYnV0ZS5hdHRyaWJ1dGVOYW1lXTogW1thdHRyaWJ1dGUuYXR0cmlidXRlTmFtZSwgb3BlcmF0b3IsIHZhbHVlXV1cbiAgfVxuXG4gIGZvciAobGV0IGluZGV4ID0gYXR0cmlidXRlLnBhdGgubGVuZ3RoIC0gMTsgaW5kZXggPj0gMDsgaW5kZXggLT0gMSkge1xuICAgIGhhc2ggPSB7W2F0dHJpYnV0ZS5wYXRoW2luZGV4XV06IGhhc2h9XG4gIH1cblxuICByZXR1cm4gaGFzaFxufVxuXG4vKipcbiAqIFJ1bnMgcmFuc2FjayB0dXBsZSBvcGVyYXRvci5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vLi4vdXRpbHMvcmFuc2Fjay5qc1wiKS5SYW5zYWNrUHJlZGljYXRlfSBwcmVkaWNhdGUgLSBSYW5zYWNrIHByZWRpY2F0ZS5cbiAqIEByZXR1cm5zIHtcImd0XCIgfCBcImd0ZXFcIiB8IFwibHRcIiB8IFwibHRlcVwiIHwgXCJsaWtlXCJ9IC0gUXVlcnkgdHVwbGUgb3BlcmF0b3IuXG4gKi9cbmZ1bmN0aW9uIHJhbnNhY2tUdXBsZU9wZXJhdG9yKHByZWRpY2F0ZSkge1xuICBpZiAocHJlZGljYXRlID09PSBcImd0XCIgfHwgcHJlZGljYXRlID09PSBcImd0ZXFcIiB8fCBwcmVkaWNhdGUgPT09IFwibHRcIiB8fCBwcmVkaWNhdGUgPT09IFwibHRlcVwiKSB7XG4gICAgcmV0dXJuIHByZWRpY2F0ZVxuICB9XG5cbiAgcmV0dXJuIFwibGlrZVwiXG59XG5cbi8qKlxuICogUnVucyByYW5zYWNrIHR1cGxlIHZhbHVlLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi8uLi91dGlscy9yYW5zYWNrLmpzXCIpLlJhbnNhY2tDb25kaXRpb259IGNvbmRpdGlvbiAtIFJhbnNhY2sgY29uZGl0aW9uLlxuICogQHJldHVybnMgez99IC0gUXVlcnkgdHVwbGUgdmFsdWUuXG4gKi9cbmZ1bmN0aW9uIHJhbnNhY2tUdXBsZVZhbHVlKGNvbmRpdGlvbikge1xuICBpZiAoY29uZGl0aW9uLnByZWRpY2F0ZSA9PT0gXCJjb250XCIpIHJldHVybiBgJSR7Y29uZGl0aW9uLnZhbHVlfSVgXG4gIGlmIChjb25kaXRpb24ucHJlZGljYXRlID09PSBcInN0YXJ0XCIpIHJldHVybiBgJHtjb25kaXRpb24udmFsdWV9JWBcbiAgaWYgKGNvbmRpdGlvbi5wcmVkaWNhdGUgPT09IFwiZW5kXCIpIHJldHVybiBgJSR7Y29uZGl0aW9uLnZhbHVlfWBcblxuICByZXR1cm4gY29uZGl0aW9uLnZhbHVlXG59XG5cbi8qKlxuICogUnVucyBnZXQgcmVsYXRpb25zaGlwIGJ5IG5hbWUuXG4gKiBAcGFyYW0ge3R5cGVvZiBpbXBvcnQoXCIuLi9yZWNvcmQvaW5kZXguanNcIikuZGVmYXVsdH0gbW9kZWxDbGFzcyAtIE1vZGVsIGNsYXNzLlxuICogQHBhcmFtIHtzdHJpbmd9IHJlbGF0aW9uc2hpcE5hbWUgLSBSZWxhdGlvbnNoaXAgbmFtZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9yZWNvcmQvcmVsYXRpb25zaGlwcy9iYXNlLmpzXCIpLmRlZmF1bHQgfCB1bmRlZmluZWR9IC0gVGhlIHJlbGF0aW9uc2hpcC5cbiAqL1xuZnVuY3Rpb24gZ2V0UmVsYXRpb25zaGlwQnlOYW1lKG1vZGVsQ2xhc3MsIHJlbGF0aW9uc2hpcE5hbWUpIHtcbiAgcmV0dXJuIG1vZGVsQ2xhc3MuZ2V0UmVsYXRpb25zaGlwc01hcCgpW3JlbGF0aW9uc2hpcE5hbWVdXG59XG5cbi8qKlxuICogUnVucyByZXNvbHZlIGNvbHVtbiBuYW1lLlxuICogQHBhcmFtIHt0eXBlb2YgaW1wb3J0KFwiLi4vcmVjb3JkL2luZGV4LmpzXCIpLmRlZmF1bHR9IG1vZGVsQ2xhc3MgLSBNb2RlbCBjbGFzcy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgLSBBdHRyaWJ1dGUgb3IgY29sdW1uIG5hbWUuXG4gKiBAcmV0dXJucyB7c3RyaW5nIHwgdW5kZWZpbmVkfSAtIFRoZSByZXNvbHZlZCBjb2x1bW4gbmFtZS5cbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZUNvbHVtbk5hbWUobW9kZWxDbGFzcywga2V5KSB7XG4gIGNvbnN0IGF0dHJpYnV0ZU1hcCA9IG1vZGVsQ2xhc3MuZ2V0QXR0cmlidXRlTmFtZVRvQ29sdW1uTmFtZU1hcCgpXG5cbiAgaWYgKGF0dHJpYnV0ZU1hcFtrZXldKSByZXR1cm4gYXR0cmlidXRlTWFwW2tleV1cblxuICBjb25zdCBjb2x1bW5NYXAgPSBtb2RlbENsYXNzLmdldENvbHVtbk5hbWVUb0F0dHJpYnV0ZU5hbWVNYXAoKVxuICBjb25zdCB1bmRlcnNjb3JlZCA9IGluZmxlY3Rpb24udW5kZXJzY29yZShrZXkpXG5cbiAgcmV0dXJuIGNvbHVtbk1hcFtrZXldIHx8IGNvbHVtbk1hcFt1bmRlcnNjb3JlZF0gfHwgdW5kZWZpbmVkXG59XG5cbi8qKlxuICogUnVucyBzcGxpdCB3aGVyZSBoYXNoLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gYXJncy5oYXNoIC0gV2hlcmUgaGFzaC5cbiAqIEBwYXJhbSB7dHlwZW9mIGltcG9ydChcIi4uL3JlY29yZC9pbmRleC5qc1wiKS5kZWZhdWx0fSBhcmdzLm1vZGVsQ2xhc3MgLSBNb2RlbCBjbGFzcy5cbiAqIEByZXR1cm5zIHt7cmVzb2x2ZWRIYXNoOiBSZWNvcmQ8c3RyaW5nLCA/PiwgZmFsbGJhY2tIYXNoOiBSZWNvcmQ8c3RyaW5nLCA/Pn19IC0gU3BsaXQgaGFzaGVzLlxuICovXG5mdW5jdGlvbiBzcGxpdFdoZXJlSGFzaCh7aGFzaCwgbW9kZWxDbGFzc30pIHtcbiAgLyoqXG4gICAqIFJlc29sdmVkIGhhc2guXG4gICAgQHR5cGUge1JlY29yZDxzdHJpbmcsID8+fSAqL1xuICBjb25zdCByZXNvbHZlZEhhc2ggPSB7fVxuICAvKipcbiAgICogRmFsbGJhY2sgaGFzaC5cbiAgICBAdHlwZSB7UmVjb3JkPHN0cmluZywgPz59ICovXG4gIGNvbnN0IGZhbGxiYWNrSGFzaCA9IHt9XG5cbiAgZm9yIChjb25zdCBrZXkgaW4gaGFzaCkge1xuICAgIGNvbnN0IHZhbHVlID0gaGFzaFtrZXldXG4gICAgY29uc3QgaXNOZXN0ZWQgPSBpc1BsYWluT2JqZWN0KHZhbHVlKVxuICAgIGNvbnN0IHJlbGF0aW9uc2hpcCA9IGdldFJlbGF0aW9uc2hpcEJ5TmFtZShtb2RlbENsYXNzLCBrZXkpXG5cbiAgICBpZiAoaXNOZXN0ZWQpIHtcbiAgICAgIGlmIChyZWxhdGlvbnNoaXApIHtcbiAgICAgICAgY29uc3QgdGFyZ2V0TW9kZWxDbGFzcyA9IHJlbGF0aW9uc2hpcC5nZXRUYXJnZXRNb2RlbENsYXNzKClcbiAgICAgICAgaWYgKCF0YXJnZXRNb2RlbENsYXNzKSB7XG4gICAgICAgICAgZmFsbGJhY2tIYXNoW2tleV0gPSB2YWx1ZVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbmVzdGVkUmVzdWx0ID0gc3BsaXRXaGVyZUhhc2goe2hhc2g6IHZhbHVlLCBtb2RlbENsYXNzOiB0YXJnZXRNb2RlbENsYXNzfSlcbiAgICAgICAgY29uc3QgbmVzdGVkUmVzb2x2ZWRLZXlzID0gT2JqZWN0LmtleXMobmVzdGVkUmVzdWx0LnJlc29sdmVkSGFzaClcbiAgICAgICAgY29uc3QgbmVzdGVkRmFsbGJhY2tLZXlzID0gT2JqZWN0LmtleXMobmVzdGVkUmVzdWx0LmZhbGxiYWNrSGFzaClcblxuICAgICAgICBpZiAobmVzdGVkUmVzb2x2ZWRLZXlzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICByZXNvbHZlZEhhc2hba2V5XSA9IG5lc3RlZFJlc3VsdC5yZXNvbHZlZEhhc2hcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChuZXN0ZWRGYWxsYmFja0tleXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNvbnN0IHRhYmxlTmFtZSA9IHRhcmdldE1vZGVsQ2xhc3MudGFibGVOYW1lKClcblxuICAgICAgICAgIGlmICghZmFsbGJhY2tIYXNoW3RhYmxlTmFtZV0pIGZhbGxiYWNrSGFzaFt0YWJsZU5hbWVdID0ge31cbiAgICAgICAgICBPYmplY3QuYXNzaWduKGZhbGxiYWNrSGFzaFt0YWJsZU5hbWVdLCBuZXN0ZWRSZXN1bHQuZmFsbGJhY2tIYXNoKVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBmYWxsYmFja0hhc2hba2V5XSA9IHZhbHVlXG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChyZWxhdGlvbnNoaXAgJiYgaGFzUmVsYXRpb25zaGlwV2hlcmVPcGVyYXRvclR1cGxlcyh2YWx1ZSkpIHtcbiAgICAgIHJlc29sdmVkSGFzaFtrZXldID0gbm9ybWFsaXplUmVsYXRpb25zaGlwV2hlcmVPcGVyYXRvclR1cGxlcyh2YWx1ZSlcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgY29sdW1uTmFtZSA9IHJlc29sdmVDb2x1bW5OYW1lKG1vZGVsQ2xhc3MsIGtleSlcblxuICAgICAgaWYgKGNvbHVtbk5hbWUpIHtcbiAgICAgICAgcmVzb2x2ZWRIYXNoW2NvbHVtbk5hbWVdID0gdmFsdWVcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZhbGxiYWNrSGFzaFtrZXldID0gdmFsdWVcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4ge3Jlc29sdmVkSGFzaCwgZmFsbGJhY2tIYXNofVxufVxuXG4vKipcbiAqIFJ1bnMgYnVpbGQgam9pbiBvYmplY3QgZnJvbSB3aGVyZSBoYXNoLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gYXJncy5oYXNoIC0gV2hlcmUgaGFzaC5cbiAqIEBwYXJhbSB7dHlwZW9mIGltcG9ydChcIi4uL3JlY29yZC9pbmRleC5qc1wiKS5kZWZhdWx0fSBhcmdzLm1vZGVsQ2xhc3MgLSBNb2RlbCBjbGFzcy5cbiAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBKb2luIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gYnVpbGRKb2luT2JqZWN0RnJvbVdoZXJlSGFzaCh7aGFzaCwgbW9kZWxDbGFzc30pIHtcbiAgLyoqXG4gICAqIEpvaW4gb2JqZWN0LlxuICAgIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi9cbiAgY29uc3Qgam9pbk9iamVjdCA9IHt9XG5cbiAgZm9yIChjb25zdCBrZXkgaW4gaGFzaCkge1xuICAgIGNvbnN0IHZhbHVlID0gaGFzaFtrZXldXG4gICAgY29uc3QgcmVsYXRpb25zaGlwID0gZ2V0UmVsYXRpb25zaGlwQnlOYW1lKG1vZGVsQ2xhc3MsIGtleSlcblxuICAgIGlmICghcmVsYXRpb25zaGlwKSBjb250aW51ZVxuXG4gICAgaWYgKGlzUGxhaW5PYmplY3QodmFsdWUpKSB7XG4gICAgICBjb25zdCB0YXJnZXRNb2RlbENsYXNzID0gcmVsYXRpb25zaGlwLmdldFRhcmdldE1vZGVsQ2xhc3MoKVxuICAgICAgaWYgKCF0YXJnZXRNb2RlbENsYXNzKSBjb250aW51ZVxuICAgICAgY29uc3QgbmVzdGVkSm9pbk9iamVjdCA9IGJ1aWxkSm9pbk9iamVjdEZyb21XaGVyZUhhc2goe2hhc2g6IHZhbHVlLCBtb2RlbENsYXNzOiB0YXJnZXRNb2RlbENsYXNzfSlcblxuICAgICAgam9pbk9iamVjdFtrZXldID0gT2JqZWN0LmtleXMobmVzdGVkSm9pbk9iamVjdCkubGVuZ3RoID4gMCA/IG5lc3RlZEpvaW5PYmplY3QgOiB0cnVlXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmIChoYXNSZWxhdGlvbnNoaXBXaGVyZU9wZXJhdG9yVHVwbGVzKHZhbHVlKSkge1xuICAgICAgam9pbk9iamVjdFtrZXldID0gdHJ1ZVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBqb2luT2JqZWN0XG59XG5cbmNvbnN0IHJlbGF0aW9uc2hpcFdoZXJlT3BlcmF0b3JzID0gbmV3IFNldChbXCJlcVwiLCBcIm5vdEVxXCIsIFwiZ3RcIiwgXCJndGVxXCIsIFwibHRcIiwgXCJsdGVxXCIsIFwibGlrZVwiLCBcIj5cIiwgXCI+PVwiLCBcIjxcIiwgXCI8PVwiXSlcblxuLyoqXG4gKiBSdW5zIG5vcm1hbGl6ZSByZWxhdGlvbnNoaXAgd2hlcmUgb3BlcmF0b3IuXG4gKiBAcGFyYW0ge3N0cmluZ30gb3BlcmF0b3IgLSBSYXcgcmVsYXRpb25zaGlwIHdoZXJlIG9wZXJhdG9yLlxuICogQHJldHVybnMge1wiZXFcIiB8IFwibm90RXFcIiB8IFwiZ3RcIiB8IFwiZ3RlcVwiIHwgXCJsdFwiIHwgXCJsdGVxXCIgfCBcImxpa2VcIn0gLSBOb3JtYWxpemVkIG9wZXJhdG9yLlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVSZWxhdGlvbnNoaXBXaGVyZU9wZXJhdG9yKG9wZXJhdG9yKSB7XG4gIGNvbnN0IG9wZXJhdG9yQWxpYXNlcyA9IHtcbiAgICBcIjxcIjogXCJsdFwiLFxuICAgIFwiPD1cIjogXCJsdGVxXCIsXG4gICAgXCI+XCI6IFwiZ3RcIixcbiAgICBcIj49XCI6IFwiZ3RlcVwiXG4gIH1cblxuICByZXR1cm4gLyoqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS4gQHR5cGUge1wiZXFcIiB8IFwibm90RXFcIiB8IFwiZ3RcIiB8IFwiZ3RlcVwiIHwgXCJsdFwiIHwgXCJsdGVxXCIgfCBcImxpa2VcIn0gKi8gKFxuICAgIG9wZXJhdG9yQWxpYXNlc1svKipcbiAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHtcIjxcIiB8IFwiPD1cIiB8IFwiPlwiIHwgXCI+PVwifSAqLyAob3BlcmF0b3IpXSB8fCBvcGVyYXRvclxuICApXG59XG5cbi8qKlxuICogUnVucyBpcyByZWxhdGlvbnNoaXAgd2hlcmUgb3BlcmF0b3IgdHVwbGUuXG4gKiBAcGFyYW0gez99IHR1cGxlVmFsdWUgLSBDYW5kaWRhdGUgdHVwbGUuXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHRoaXMgaXMgYSByZWxhdGlvbnNoaXAgd2hlcmUgdHVwbGUuXG4gKi9cbmZ1bmN0aW9uIGlzUmVsYXRpb25zaGlwV2hlcmVPcGVyYXRvclR1cGxlKHR1cGxlVmFsdWUpIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KHR1cGxlVmFsdWUpIHx8IHR1cGxlVmFsdWUubGVuZ3RoIDwgMykge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG5cbiAgcmV0dXJuIHR5cGVvZiB0dXBsZVZhbHVlWzBdID09PSBcInN0cmluZ1wiICYmXG4gICAgdHlwZW9mIHR1cGxlVmFsdWVbMV0gPT09IFwic3RyaW5nXCIgJiZcbiAgICByZWxhdGlvbnNoaXBXaGVyZU9wZXJhdG9ycy5oYXModHVwbGVWYWx1ZVsxXSlcbn1cblxuLyoqXG4gKiBSdW5zIG5vcm1hbGl6ZSByZWxhdGlvbnNoaXAgd2hlcmUgb3BlcmF0b3IgdHVwbGVzLlxuICogQHBhcmFtIHs/fSB2YWx1ZSAtIENhbmRpZGF0ZSB2YWx1ZS5cbiAqIEByZXR1cm5zIHtBcnJheTxbc3RyaW5nLCBcImVxXCIgfCBcIm5vdEVxXCIgfCBcImd0XCIgfCBcImd0ZXFcIiB8IFwibHRcIiB8IFwibHRlcVwiIHwgXCJsaWtlXCIsIHVua25vd25dPn0gLSBOb3JtYWxpemVkIHR1cGxlcy5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplUmVsYXRpb25zaGlwV2hlcmVPcGVyYXRvclR1cGxlcyh2YWx1ZSkge1xuICBpZiAoIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHJlbGF0aW9uc2hpcCB3aGVyZSB0dXBsZSBjb250YWluZXIgdHlwZTogJHt0eXBlb2YgdmFsdWV9YClcbiAgfVxuXG4gIC8qKlxuICAgKiBOb3JtYWxpemVkLlxuICAgIEB0eXBlIHtBcnJheTxbc3RyaW5nLCBcImVxXCIgfCBcIm5vdEVxXCIgfCBcImd0XCIgfCBcImd0ZXFcIiB8IFwibHRcIiB8IFwibHRlcVwiIHwgXCJsaWtlXCIsIHVua25vd25dPn0gKi9cbiAgY29uc3Qgbm9ybWFsaXplZCA9IFtdXG4gICAgLyoqXG4gICAgICogQWRkIGNvbmRpdGlvbi5cbiAgICAgKiBAcGFyYW0gez99IGNvbmRpdGlvblZhbHVlIC0gQ2FuZGlkYXRlIG5lc3RlZCBjb25kaXRpb24uXG4gICAgICovXG4gICAgY29uc3QgYWRkQ29uZGl0aW9uID0gKGNvbmRpdGlvblZhbHVlKSA9PiB7XG4gICAgICBpZiAoaXNSZWxhdGlvbnNoaXBXaGVyZU9wZXJhdG9yVHVwbGUoY29uZGl0aW9uVmFsdWUpKSB7XG4gICAgICAgIGNvbnN0IHR1cGxlID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgQHR5cGUge1tzdHJpbmcsIFwiZXFcIiB8IFwibm90RXFcIiB8IFwiZ3RcIiB8IFwiZ3RlcVwiIHwgXCJsdFwiIHwgXCJsdGVxXCIgfCBcImxpa2VcIiB8IFwiPlwiIHwgXCI+PVwiIHwgXCI8XCIgfCBcIjw9XCIsIHVua25vd24sIC4uLkFycmF5PHVua25vd24+XX0gKi8gKGNvbmRpdGlvblZhbHVlKVxuICAgICAgICBjb25zdCBub3JtYWxpemVkT3BlcmF0b3IgPSBub3JtYWxpemVSZWxhdGlvbnNoaXBXaGVyZU9wZXJhdG9yKHR1cGxlWzFdKVxuXG4gICAgICAgIG5vcm1hbGl6ZWQucHVzaChbXG4gICAgICAgICAgdHVwbGVbMF0sXG4gICAgICAgICAgbm9ybWFsaXplZE9wZXJhdG9yLFxuICAgICAgICAgIHR1cGxlWzJdXG4gICAgICAgIF0pXG5cbiAgICAgICAgaWYgKHR1cGxlLmxlbmd0aCA+IDMpIHtcbiAgICAgICAgICBmb3IgKGxldCBpbmRleCA9IDM7IGluZGV4IDwgdHVwbGUubGVuZ3RoOyBpbmRleCArPSAxKSB7XG4gICAgICAgICAgICBhZGRDb25kaXRpb24odHVwbGVbaW5kZXhdKVxuICAgICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGNvbmRpdGlvblZhbHVlKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVsYXRpb25zaGlwIHdoZXJlIGNvbmRpdGlvbnMgbXVzdCBiZSB0dXBsZXNcIilcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICBAdHlwZSB7QXJyYXk8Pz59ICovIChjb25kaXRpb25WYWx1ZSkuZm9yRWFjaCgobmVzdGVkQ29uZGl0aW9uVmFsdWUpID0+IHtcbiAgICAgIGFkZENvbmRpdGlvbihuZXN0ZWRDb25kaXRpb25WYWx1ZSlcbiAgICB9KVxuICB9XG5cbiAgYWRkQ29uZGl0aW9uKHZhbHVlKVxuXG4gIGlmIChub3JtYWxpemVkLmxlbmd0aCA8IDEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZWxhdGlvbnNoaXAgd2hlcmUgdHVwbGUgY29udGFpbmVyIGNhbm5vdCBiZSBlbXB0eVwiKVxuICB9XG5cbiAgcmV0dXJuIG5vcm1hbGl6ZWRcbn1cblxuLyoqXG4gKiBSdW5zIGhhcyByZWxhdGlvbnNoaXAgd2hlcmUgb3BlcmF0b3IgdHVwbGVzLlxuICogQHBhcmFtIHs/fSB2YWx1ZSAtIENhbmRpZGF0ZSByZWxhdGlvbnNoaXAgd2hlcmUgdmFsdWUuXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHZhbHVlIGNhbiBiZSBub3JtYWxpemVkIHRvIHJlbGF0aW9uc2hpcCB0dXBsZXMuXG4gKi9cbmZ1bmN0aW9uIGhhc1JlbGF0aW9uc2hpcFdoZXJlT3BlcmF0b3JUdXBsZXModmFsdWUpIHtcbiAgdHJ5IHtcbiAgICBub3JtYWxpemVSZWxhdGlvbnNoaXBXaGVyZU9wZXJhdG9yVHVwbGVzKHZhbHVlKVxuXG4gICAgcmV0dXJuIHRydWVcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cbiJdfQ==